Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HMAC-SHA256/512 non 32 byte keys supporting #166

Merged
merged 8 commits into from
Feb 15, 2018
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be moved to #digest below so as to allow #update to be called multiple times. I'm also curious how this handles #update being called after it's been finalized. That should probably raise an exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @tarcieri. You can use this update multiple times.
But the point is, #update method without calling this line self.class.auth_hmacsha256_final(@state.clone, @authenticator) every time will be rewriting the @state. I can add spec test to compare with openssl multiple usage. But I know that it's work because I test it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is RbNaCl example:

pry(main)> key = ['07c0'].pack('H*')
pry(main)> hmac = RbNaCl::HMAC::SHA256.new(key)
pry(main)> hmac.update 'abcd'
pry(main)> hmac.update '1'
pry(main)> hmac.digest
=> "G\xCC[\xBDI\x1A\xA3\x95\xCD\xA2@\xC2\xB2L\xCD\xE9\x03kV\xDA\x7F\xAB@\xBE\xB5\xA7V\x1C\x11G\xBE\xD8"

OpenSSL example:

pry(main)> key = ['07c0'].pack('H*')
pry(main)> hmac = OpenSSL::HMAC.new(key, d)
pry(main)> hmac.update 'abcd'
pry(main)> hmac.update '1'
pry(main)> hmac.digest
=> "G\xCC[\xBDI\x1A\xA3\x95\xCD\xA2@\xC2\xB2L\xCD\xE9\x03kV\xDA\x7F\xAB@\xBE\xB5\xA7V\x1C\x11G\xBE\xD8"


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 crupto_auth_hmacsha256_state struct representation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

# 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is the answer #166 (comment)


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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And ditto here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is the answer #166 (comment)


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