Crystal <= 0.34 backport `final` methods from crystal 0.35.
Crystal = 0.35 use new Digest::Base interface. Crystal > 0.35 futureport `hexfinal` method.master
parent
7155cee26c
commit
a8f716de09
|
@ -199,11 +199,11 @@ data = "data".to_slice
|
||||||
# output_size, key, salt, and personal are optional.
|
# output_size, key, salt, and personal are optional.
|
||||||
digest = Sodium::Digest::Blake2b.new out_size, key: key, salt: salt, personal: personal
|
digest = Sodium::Digest::Blake2b.new out_size, key: key, salt: salt, personal: personal
|
||||||
digest.update data
|
digest.update data
|
||||||
output = d.hexdigest
|
output = d.hexfinal
|
||||||
|
|
||||||
digest.reset # Reuse existing object to hash again.
|
digest.reset # Reuse existing object to hash again.
|
||||||
digest.update data
|
digest.update data
|
||||||
output = d.hexdigest
|
output = d.hexfinal
|
||||||
```
|
```
|
||||||
|
|
||||||
### Key derivation
|
### Key derivation
|
||||||
|
|
|
@ -15,14 +15,14 @@ Benchmark.ips(warmup: 0.5) do |bm|
|
||||||
bm.report "blake2b new obj per iter #{size}" do
|
bm.report "blake2b new obj per iter #{size}" do
|
||||||
d = Sodium::Digest::Blake2b.new 64
|
d = Sodium::Digest::Blake2b.new 64
|
||||||
d.update bufs[i]
|
d.update bufs[i]
|
||||||
d.digest
|
d.final
|
||||||
end
|
end
|
||||||
|
|
||||||
d = Sodium::Digest::Blake2b.new output_size
|
d = Sodium::Digest::Blake2b.new output_size
|
||||||
bm.report "blake2b reset per iter #{size}" do
|
bm.report "blake2b reset per iter #{size}" do
|
||||||
d.reset
|
d.reset
|
||||||
d.update bufs[i]
|
d.update bufs[i]
|
||||||
d.digest
|
d.final
|
||||||
end
|
end
|
||||||
|
|
||||||
d = Sodium::Digest::Blake2b.new output_size
|
d = Sodium::Digest::Blake2b.new output_size
|
||||||
|
@ -30,7 +30,7 @@ Benchmark.ips(warmup: 0.5) do |bm|
|
||||||
bm.report "blake2b reset reusing buffer per iter #{size}" do
|
bm.report "blake2b reset reusing buffer per iter #{size}" do
|
||||||
d.reset
|
d.reset
|
||||||
d.update bufs[i]
|
d.update bufs[i]
|
||||||
d.finish dst
|
d.final dst
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,17 +39,23 @@ Benchmark.ips(warmup: 0.5) do |bm|
|
||||||
bm.report "#{arg} new obj per iter #{size}" do
|
bm.report "#{arg} new obj per iter #{size}" do
|
||||||
d = OpenSSL::Digest.new arg
|
d = OpenSSL::Digest.new arg
|
||||||
d.update bufs[i]
|
d.update bufs[i]
|
||||||
d.digest
|
d.final
|
||||||
end
|
end
|
||||||
|
|
||||||
d = OpenSSL::Digest.new arg
|
d = OpenSSL::Digest.new arg
|
||||||
bm.report "#{arg} reset per iter #{size}" do
|
bm.report "#{arg} reset per iter #{size}" do
|
||||||
d.reset
|
d.reset
|
||||||
d.update bufs[i]
|
d.update bufs[i]
|
||||||
d.digest
|
d.final
|
||||||
end
|
end
|
||||||
|
|
||||||
# OpenSSL::Digest doesn't have a public .finish (yet)
|
d = OpenSSL::Digest.new arg
|
||||||
|
dst = Bytes.new d.digest_size
|
||||||
|
bm.report "#{arg} reset reusing buffer per iterr #{size}" do
|
||||||
|
d.reset
|
||||||
|
d.update bufs[i]
|
||||||
|
d.final dst
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,7 +34,7 @@ describe Sodium::Digest::Blake2b do
|
||||||
test_vectors.each do |vec|
|
test_vectors.each do |vec|
|
||||||
d = Sodium::Digest::Blake2b.new 64, key: vec[:key].hexbytes
|
d = Sodium::Digest::Blake2b.new 64, key: vec[:key].hexbytes
|
||||||
d.update vec[:input].hexbytes
|
d.update vec[:input].hexbytes
|
||||||
d.hexdigest.should eq vec[:output]
|
d.hexfinal.should eq vec[:output]
|
||||||
end
|
end
|
||||||
|
|
||||||
more_vectors.each do |vec|
|
more_vectors.each do |vec|
|
||||||
|
@ -42,7 +42,7 @@ describe Sodium::Digest::Blake2b do
|
||||||
personal = vec[:personal].empty? ? nil : vec[:personal].hexbytes
|
personal = vec[:personal].empty? ? nil : vec[:personal].hexbytes
|
||||||
d = Sodium::Digest::Blake2b.new vec[:out_len], key: vec[:key].hexbytes, salt: salt, personal: personal
|
d = Sodium::Digest::Blake2b.new vec[:out_len], key: vec[:key].hexbytes, salt: salt, personal: personal
|
||||||
d.update vec[:input].hexbytes
|
d.update vec[:input].hexbytes
|
||||||
d.hexdigest.should eq vec[:output]
|
d.hexfinal.should eq vec[:output]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,15 +58,15 @@ describe Sodium::Digest::Blake2b do
|
||||||
|
|
||||||
d = Sodium::Digest::Blake2b.new key: key, salt: salt, personal: personal
|
d = Sodium::Digest::Blake2b.new key: key, salt: salt, personal: personal
|
||||||
d.update "foo".to_slice
|
d.update "foo".to_slice
|
||||||
output = d.hexdigest
|
output = d.hexfinal
|
||||||
|
|
||||||
d = Sodium::Digest::Blake2b.new key: key, salt: salt2, personal: personal
|
d = Sodium::Digest::Blake2b.new key: key, salt: salt2, personal: personal
|
||||||
d.update "foo".to_slice
|
d.update "foo".to_slice
|
||||||
saltout = d.hexdigest
|
saltout = d.hexfinal
|
||||||
|
|
||||||
d = Sodium::Digest::Blake2b.new key: key, salt: salt, personal: personal2
|
d = Sodium::Digest::Blake2b.new key: key, salt: salt, personal: personal2
|
||||||
d.update "foo".to_slice
|
d.update "foo".to_slice
|
||||||
personalout = d.hexdigest
|
personalout = d.hexfinal
|
||||||
|
|
||||||
output.should_not eq saltout
|
output.should_not eq saltout
|
||||||
output.should_not eq personalout
|
output.should_not eq personalout
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
require "../lib_sodium"
|
require "../lib_sodium"
|
||||||
require "../wipe"
|
require "../wipe"
|
||||||
require "../secure_buffer"
|
require "../secure_buffer"
|
||||||
|
require "digest/base"
|
||||||
require "openssl/digest/digest_base"
|
require "openssl/digest/digest_base"
|
||||||
|
|
||||||
module Sodium::Digest
|
module Sodium::Digest
|
||||||
|
@ -13,11 +14,9 @@ module Sodium::Digest
|
||||||
# digest = Blake2b.new
|
# digest = Blake2b.new
|
||||||
# digest.update data
|
# digest.update data
|
||||||
# digest.update data
|
# digest.update data
|
||||||
# digest.hexdigest => String
|
# digest.hexfinal => String
|
||||||
# ```
|
# ```
|
||||||
class Blake2b
|
class Blake2b < ::Digest::Base
|
||||||
# provides copying digest/hexdigest methods
|
|
||||||
include OpenSSL::DigestBase
|
|
||||||
include Wipe
|
include Wipe
|
||||||
|
|
||||||
# 32
|
# 32
|
||||||
|
@ -40,11 +39,11 @@ module Sodium::Digest
|
||||||
# 64
|
# 64
|
||||||
OUT_SIZE_MAX = LibSodium.crypto_generichash_blake2b_bytes_max.to_i32
|
OUT_SIZE_MAX = LibSodium.crypto_generichash_blake2b_bytes_max.to_i32
|
||||||
|
|
||||||
getter digest_size
|
getter digest_size : Int32
|
||||||
|
|
||||||
@[Wipe::Var]
|
@[Wipe::Var]
|
||||||
@state = StaticArray(UInt8, 384).new 0
|
@state = StaticArray(UInt8, 384).new 0
|
||||||
@key_size = 0
|
getter key_size = 0
|
||||||
|
|
||||||
# implemented as static array's so clone works without jumping through hoops.
|
# implemented as static array's so clone works without jumping through hoops.
|
||||||
@[Wipe::Var]
|
@[Wipe::Var]
|
||||||
|
@ -57,7 +56,7 @@ module Sodium::Digest
|
||||||
# digest_size is selectable. Use 32 for Blake2b256 (libsodium default), 64 for Blake2b512
|
# digest_size is selectable. Use 32 for Blake2b256 (libsodium default), 64 for Blake2b512
|
||||||
# or any value between OUT_SIZE_MIN and OUT_SIZE_MAX. Many libsodium bindings only support [256] or [256 and 512] bit output.
|
# or any value between OUT_SIZE_MIN and OUT_SIZE_MAX. Many libsodium bindings only support [256] or [256 and 512] bit output.
|
||||||
#
|
#
|
||||||
# `key`, `salt`, and `personal` are all optional. Most other libsodium bindings don't support them.
|
# `key`, `salt`, and `personal` are all optional. Many other libsodium bindings don't support them.
|
||||||
# Check the other implementation(s) you need to interoperate with before using.
|
# Check the other implementation(s) you need to interoperate with before using.
|
||||||
def initialize(@digest_size : Int32 = OUT_SIZE, key : Bytes? | SecureBuffer? = nil, salt : Bytes? = nil, personal : Bytes? = nil)
|
def initialize(@digest_size : Int32 = OUT_SIZE, key : Bytes? | SecureBuffer? = nil, salt : Bytes? = nil, personal : Bytes? = nil)
|
||||||
if k = key
|
if k = key
|
||||||
|
@ -80,7 +79,57 @@ module Sodium::Digest
|
||||||
reset
|
reset
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset
|
# Compatibility with Crystal <= 0.35?(TBD)
|
||||||
|
{% unless @type.has_method?(:hexfinal) %}
|
||||||
|
def hexfinal : String
|
||||||
|
final.hexstring
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
# Compatibility with Crystal <= 0.32
|
||||||
|
{% unless @type.has_method?(:final) %}
|
||||||
|
# provides copying digest/hexdigest methods
|
||||||
|
include OpenSSL::DigestBase
|
||||||
|
|
||||||
|
def update(data : Bytes) : self
|
||||||
|
update_impl data
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset : self
|
||||||
|
reset_impl
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Destructive operation. Assumes you know what you are doing.
|
||||||
|
# Use .digest or .hexdigest instead.
|
||||||
|
def final
|
||||||
|
dst = Bytes.new @digest_size
|
||||||
|
final_impl dst
|
||||||
|
dst
|
||||||
|
end
|
||||||
|
|
||||||
|
# Used by OpenSSL::DigestBase for #digest and #hexdigest
|
||||||
|
# :nodoc:
|
||||||
|
protected def finish
|
||||||
|
final
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
def update_impl(data : Bytes) : Nil
|
||||||
|
if LibSodium.crypto_generichash_blake2b_update(@state.to_slice, data, data.bytesize) != 0
|
||||||
|
raise Sodium::Error.new("crypto_generichash_blake2b_update")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def final_impl(dst : Bytes) : Nil
|
||||||
|
ret = LibSodium.crypto_generichash_blake2b_final(@state.to_slice, dst, dst.bytesize)
|
||||||
|
if ret != 0
|
||||||
|
raise Sodium::Error.new("crypto_generichash_blake2b_final #{ret.inspect}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_impl : Nil
|
||||||
key = @key.to_unsafe
|
key = @key.to_unsafe
|
||||||
salt = @salt.to_unsafe
|
salt = @salt.to_unsafe
|
||||||
personal = @personal.to_unsafe
|
personal = @personal.to_unsafe
|
||||||
|
@ -90,33 +139,6 @@ module Sodium::Digest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(data : Bytes)
|
|
||||||
if LibSodium.crypto_generichash_blake2b_update(@state.to_slice, data, data.bytesize) != 0
|
|
||||||
raise Sodium::Error.new("crypto_generichash_blake2b_update")
|
|
||||||
end
|
|
||||||
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
# Destructive operation. Assumes you know what you are doing.
|
|
||||||
# Use .digest or .hexdigest instead.
|
|
||||||
def finish
|
|
||||||
dst = Bytes.new @digest_size
|
|
||||||
finish dst
|
|
||||||
dst
|
|
||||||
end
|
|
||||||
|
|
||||||
# Destructive operation. Assumes you know what you are doing.
|
|
||||||
# Use .digest or .hexdigest instead.
|
|
||||||
def finish(dst : Bytes) : Bytes
|
|
||||||
ret = LibSodium.crypto_generichash_blake2b_final(@state.to_slice, dst, dst.bytesize)
|
|
||||||
if ret != 0
|
|
||||||
raise Sodium::Error.new("crypto_generichash_blake2b_final #{ret.inspect}")
|
|
||||||
end
|
|
||||||
|
|
||||||
dst
|
|
||||||
end
|
|
||||||
|
|
||||||
def clone
|
def clone
|
||||||
dup
|
dup
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue