Skip to content

Commit

Permalink
Merge pull request #166 from nsheremet/hmac_keysize_fix
Browse files Browse the repository at this point in the history
HMAC-SHA256/512 non 32 byte keys supporting
  • Loading branch information
tarcieri committed Feb 15, 2018
2 parents 028b1a1 + c23f841 commit 4cba02e
Show file tree
Hide file tree
Showing 14 changed files with 465 additions and 52 deletions.
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Metrics/AbcSize:

Metrics/BlockLength:
Max: 128
ExcludedMethods: [ 'describe' ]

Metrics/ClassLength:
Max: 128
Expand Down
81 changes: 73 additions & 8 deletions lib/rbnacl/hmac/sha256.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,88 @@ class SHA256 < Auth
sodium_constant :BYTES
sodium_constant :KEYBYTES

sodium_function :auth_hmacsha256,
:crypto_auth_hmacsha256,
%i[pointer pointer ulong_long pointer]
sodium_function :auth_hmacsha256_init,
:crypto_auth_hmacsha256_init,
%i[pointer pointer size_t]

sodium_function :auth_hmacsha256_verify,
:crypto_auth_hmacsha256_verify,
%i[pointer pointer ulong_long pointer]
sodium_function :auth_hmacsha256_update,
:crypto_auth_hmacsha256_update,
%i[pointer pointer ulong_long]

sodium_function :auth_hmacsha256_final,
:crypto_auth_hmacsha256_final,
%i[pointer pointer]

# Create instance without checking key length
#
# RFC 2104 HMAC
# The key for HMAC can be of any length.
#
# see https://tools.ietf.org/html/rfc2104#section-3
def initialize(key)
@key = Util.check_hmac_key(key, "#{self.class} key")
@state = State.new
@authenticator = Util.zeros(tag_bytes)

self.class.auth_hmacsha256_init(@state, key, key.bytesize)
end

# Compute authenticator for message
#
# @params [#to_str] message message to construct an authenticator for
def update(message)
self.class.auth_hmacsha256_update(@state, message, message.bytesize)
self.class.auth_hmacsha256_final(@state.clone, @authenticator)

hexdigest
end

# Return the authenticator, as raw bytes
#
# @return [String] The authenticator, as raw bytes
def digest
@authenticator
end

# Return the authenticator, as hex string
#
# @return [String] The authenticator, as hex string
def hexdigest
@authenticator.unpack("H*").last
end

private

def compute_authenticator(authenticator, message)
self.class.auth_hmacsha256(authenticator, message, message.bytesize, key)
state = State.new

self.class.auth_hmacsha256_init(state, key, key.bytesize)
self.class.auth_hmacsha256_update(state, message, message.bytesize)
self.class.auth_hmacsha256_final(state, authenticator)
end

# libsodium crypto_auth_hmacsha256_verify works only for 32 byte keys
# ref: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_auth/hmacsha256/auth_hmacsha256.c#L109
def verify_message(authenticator, message)
self.class.auth_hmacsha256_verify(authenticator, message, message.bytesize, key)
correct = Util.zeros(BYTES)
compute_authenticator(correct, message)
Util.verify32(correct, authenticator)
end
end

# The crypto_auth_hmacsha256_state struct representation
# ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_auth_hmacsha256.h
class SHA256State < FFI::Struct
layout :state, [:uint32, 8],
:count, :uint64,
:buf, [:uint8, 64]
end

# The crypto_hash_sha256_state struct representation
# ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_hash_sha256.h
class State < FFI::Struct
layout :ictx, SHA256State,
:octx, SHA256State
end
end
end
81 changes: 73 additions & 8 deletions lib/rbnacl/hmac/sha512.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,88 @@ class SHA512 < Auth
sodium_constant :BYTES
sodium_constant :KEYBYTES

sodium_function :auth_hmacsha512,
:crypto_auth_hmacsha512,
%i[pointer pointer ulong_long pointer]
sodium_function :auth_hmacsha512_init,
:crypto_auth_hmacsha512_init,
%i[pointer pointer size_t]

sodium_function :auth_hmacsha512_verify,
:crypto_auth_hmacsha512_verify,
%i[pointer pointer ulong_long pointer]
sodium_function :auth_hmacsha512_update,
:crypto_auth_hmacsha512_update,
%i[pointer pointer ulong_long]

sodium_function :auth_hmacsha512_final,
:crypto_auth_hmacsha512_final,
%i[pointer pointer]

# Create instance without checking key length
#
# RFC 2104 HMAC
# The key for HMAC can be of any length.
#
# see https://tools.ietf.org/html/rfc2104#section-3
def initialize(key)
@key = Util.check_hmac_key(key, "#{self.class} key")
@state = State.new
@authenticator = Util.zeros(tag_bytes)

self.class.auth_hmacsha512_init(@state, key, key.bytesize)
end

# Compute authenticator for message
#
# @params [#to_str] message message to construct an authenticator for
def update(message)
self.class.auth_hmacsha512_update(@state, message, message.bytesize)
self.class.auth_hmacsha512_final(@state.clone, @authenticator)

hexdigest
end

# Return the authenticator, as raw bytes
#
# @return [String] The authenticator, as raw bytes
def digest
@authenticator
end

# Return the authenticator, as hex string
#
# @return [String] The authenticator, as hex string
def hexdigest
@authenticator.unpack("H*").last
end

private

def compute_authenticator(authenticator, message)
self.class.auth_hmacsha512(authenticator, message, message.bytesize, key)
state = State.new

self.class.auth_hmacsha512_init(state, key, key.bytesize)
self.class.auth_hmacsha512_update(state, message, message.bytesize)
self.class.auth_hmacsha512_final(state, authenticator)
end

# libsodium crypto_auth_hmacsha512_verify works only for 32 byte keys
# ref: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_auth/hmacsha512/auth_hmacsha512.c#L109
def verify_message(authenticator, message)
self.class.auth_hmacsha512_verify(authenticator, message, message.bytesize, key)
correct = Util.zeros(BYTES)
compute_authenticator(correct, message)
Util.verify64(correct, authenticator)
end
end

# The crypto_auth_hmacsha512_state struct representation
# ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_auth_hmacsha512.h
class SHA512State < FFI::Struct
layout :state, [:uint64, 8],
:count, [:uint64, 2],
:buf, [:uint8, 128]
end

# The crypto_hash_sha512_state struct representation
# ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_hash_sha512.h
class State < FFI::Struct
layout :ictx, SHA512State,
:octx, SHA512State
end
end
end
79 changes: 71 additions & 8 deletions lib/rbnacl/hmac/sha512256.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,86 @@ class SHA512256 < Auth
sodium_constant :BYTES
sodium_constant :KEYBYTES

sodium_function :auth_hmacsha512256,
:crypto_auth_hmacsha512256,
%i[pointer pointer ulong_long pointer]
sodium_function :auth_hmacsha512256_init,
:crypto_auth_hmacsha512256_init,
%i[pointer pointer size_t]

sodium_function :auth_hmacsha512256_verify,
:crypto_auth_hmacsha512256_verify,
%i[pointer pointer ulong_long pointer]
sodium_function :auth_hmacsha512256_update,
:crypto_auth_hmacsha512256_update,
%i[pointer pointer ulong_long]

sodium_function :auth_hmacsha512256_final,
:crypto_auth_hmacsha512256_final,
%i[pointer pointer]

# Create instance without checking key length
#
# RFC 2104 HMAC
# The key for HMAC can be of any length.
#
# see https://tools.ietf.org/html/rfc2104#section-3
def initialize(key)
@key = Util.check_hmac_key(key, "#{self.class} key")
@state = State.new
@authenticator = Util.zeros(tag_bytes)

self.class.auth_hmacsha512256_init(@state, key, key.bytesize)
end

# Compute authenticator for message
#
# @params [#to_str] message message to construct an authenticator for
def update(message)
self.class.auth_hmacsha512256_update(@state, message, message.bytesize)
self.class.auth_hmacsha512256_final(@state.clone, @authenticator)

hexdigest
end

# Return the authenticator, as raw bytes
#
# @return [String] The authenticator, as raw bytes
def digest
@authenticator
end

# Return the authenticator, as hex string
#
# @return [String] The authenticator, as hex string
def hexdigest
@authenticator.unpack("H*").last
end

private

def compute_authenticator(authenticator, message)
self.class.auth_hmacsha512256(authenticator, message, message.bytesize, key)
state = State.new

self.class.auth_hmacsha512256_init(state, key, key.bytesize)
self.class.auth_hmacsha512256_update(state, message, message.bytesize)
self.class.auth_hmacsha512256_final(state, authenticator)
end

def verify_message(authenticator, message)
self.class.auth_hmacsha512256_verify(authenticator, message, message.bytesize, key)
correct = Util.zeros(BYTES)
compute_authenticator(correct, message)
Util.verify32(correct, authenticator)
end
end

# The crypto_auth_hmacsha512256_state struct representation
# ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_auth_hmacsha512256.h
class SHA512256State < FFI::Struct
layout :state, [:uint64, 8],
:count, [:uint64, 2],
:buf, [:uint8, 128]
end

# The crypto_hash_sha512_state struct representation
# ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_hash_sha512.h
class State < FFI::Struct
layout :ictx, SHA512256State,
:octx, SHA512256State
end
end
end
22 changes: 22 additions & 0 deletions lib/rbnacl/test_vectors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,28 @@ module RbNaCl
auth_hmacsha512: "b2a31b8d4e01afcab2ee545b5caf4e3d212a99d7b3a116a97cec8e83c32e107d" \
"270e3921f69016c267a63ab4b226449a0dee0dc7dcb897a9bce9d27d788f8e8d",

# HMAC-SHA Identifiers and Test Vectors
# ref: https://tools.ietf.org/html/rfc4231#section-4.8
#
auth_hmac_key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
"aaaaaa",
auth_hmac_data: "5468697320697320612074657374207573696e672061206c6172676572207468" \
"616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" \
"68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" \
"647320746f20626520686173686564206265666f7265206265696e6720757365" \
"642062792074686520484d414320616c676f726974686d2e",
auth_hmacsha256_tag: "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
auth_hmacsha512_tag: "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944" \
"b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58",
auth_hmacsha512256_tag: "bfaae3b4292b56d6170154cc089af73f79e089ecf27d4720eed6fd0a7ffcccf1",

auth_hmacsha256_mult_tag: "367a7a7e8292759844dcf820c90daa5fea5a4b769e537038cd0dc28290fbf2cb",
auth_hmacsha512_mult_tag: "1006b7bef1e24725ed55049c8b787b7b174f4afbe197124a389205c499956a90" \
"fea5c44b616a9e1a286d024c2880c67ae0e1ec7524530f15ae1086b144192d93",
auth_hmacsha512256_mult_tag: "bf280508996bba2bd590a2c1662d8c47fcceb8111bfcc4bdff5f2c28b0301449",
# AEAD ChaCha20-Poly1305 original implementation test vectors
# Taken from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
aead_chacha20poly1305_orig_key: "4290bcb154173531f314af57f3be3b5006da371ece272afa1b5dbdd1100a1007",
Expand Down

0 comments on commit 4cba02e

Please sign in to comment.