-
Notifications
You must be signed in to change notification settings - Fork 82
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
Changes from 7 commits
c8ccf4f
0414fb3
5e03238
9f961e8
74a5f97
d0c5edc
def63ed
c23f841
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 crupto_auth_hmacsha256_state struct representation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And ditto here too. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
There was a problem hiding this comment.
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.There was a problem hiding this comment.
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 lineself.class.auth_hmacsha256_final(@state.clone, @authenticator)
every time will be rewriting the@state
. I can add spec test to compare withopenssl
multiple usage. But I know that it's work because I test it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here is RbNaCl example:
OpenSSL example: