lib/rbnacl/hmac/sha256.rb in rbnacl-5.0.0 vs lib/rbnacl/hmac/sha256.rb in rbnacl-6.0.0
- old
+ new
@@ -20,25 +20,90 @@
sodium_type :auth
sodium_primitive :hmacsha256
sodium_constant :BYTES
sodium_constant :KEYBYTES
- sodium_function :auth_hmacsha256,
- :crypto_auth_hmacsha256,
- [: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,
- [: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