Internal switch to Crypto::Secret

This commit is contained in:
Didactic Drunk 2021-06-16 18:19:30 -07:00
parent 0e1b64b1bf
commit bd5e89dcd4
6 changed files with 78 additions and 42 deletions

View File

@ -89,15 +89,20 @@ end
end
it "dups" do
box1 = Sodium::Cipher::Aead::{{ name.id }}.new Bytes.new(Sodium::Cipher::Aead::{{ name.id }}::KEY_SIZE)
key = Bytes.new Sodium::Cipher::Aead::{{ name.id }}::KEY_SIZE
box1 = Sodium::Cipher::Aead::{{ name.id }}.new key
box2 = box1.dup
key1 = box1.key
key2 = box2.key
key2.readwrite
key2.to_slice[0] = 1_u8
key1.to_slice[0].should eq 0_u8
key1.should eq key2
key2.readwrite do |ks|
ks[0] = 1_u8
end
key1.readonly do |ks|
ks[0].should eq 0_u8
end
key1.should_not eq key2
end
end

View File

@ -26,8 +26,14 @@ require "../../../src/sodium/cipher/chalsa"
key1 = cipher1.key
key2 = cipher2.key
key2.to_slice[0] = 1_u8
key1.to_slice[0].should eq 0_u8
key1.should eq key2
key2.readwrite do |ks|
ks[0] = 1_u8
end
key1.readonly do |ks|
ks[0].should eq 0_u8
end
key1.should_not eq key2
end
end
{% end %}

View File

@ -34,14 +34,12 @@ private def box_from_vec(vec)
end
end
private def new_key_bytes
Sodium::CryptoBox::SecretKey.new.to_slice
end
describe Sodium::CryptoBox::SecretKey do
it "loads keys" do
key1 = Sodium::CryptoBox::SecretKey.new
key2 = Sodium::CryptoBox::SecretKey.new key1.to_slice, key1.public_key.to_slice
key2 = key1.key.readonly do |ks|
Sodium::CryptoBox::SecretKey.new ks, key1.public_key.to_slice
end
key1.to_slice.should eq key2.to_slice
key1.public_key.to_slice.should eq key2.public_key.to_slice
end

View File

@ -15,7 +15,6 @@ module Sodium::Cipher
def initialize(key : Crypto::Secret | Bytes, nonce = nil)
raise ArgumentError.new("key must be #{key_size} bytes, got #{key.bytesize}") if key.bytesize != key_size
@key = key.is_a?(Crypto::Secret) ? key : Sodium::SecureBuffer.new(key)
# self.key = key if key
self.nonce = nonce if nonce
end
@ -116,8 +115,11 @@ module Sodium::Cipher
def update(src : Bytes, dst : Bytes) : Bytes
if (k = @key) && (n = @nonce)
raise ArgumentError.new("src and dst bytesize must be identical") if src.bytesize != dst.bytesize
if LibSodium.crypto_stream_{{ val.id }}_xor_ic(dst, src, src.bytesize, n, @offset, k.to_slice) != 0
raise Sodium::Error.new("crypto_stream_{{ val.id }}_xor_ic")
k.readonly do |kslice|
if LibSodium.crypto_stream_{{ val.id }}_xor_ic(dst, src, src.bytesize, n, @offset, kslice) != 0
raise Sodium::Error.new("crypto_stream_{{ val.id }}_xor_ic")
end
end
@offset += src.bytesize
dst

View File

@ -39,19 +39,22 @@ class Sodium::CryptoBox
SEED_SIZE = LibSodium.crypto_box_seedbytes.to_i
SEAL_SIZE = LibSodium.crypto_box_sealbytes.to_i
getter key : Crypto::Secret
getter public_key : PublicKey
# Returns key
delegate_to_slice to: @sbuf
delegate_to_slice to: @key
@seed : SecureBuffer?
@seed : Crypto::Secret?
# Generate a new random secret/public key pair.
def initialize
@sbuf = SecureBuffer.new KEY_SIZE
@key = SecureBuffer.new KEY_SIZE
@public_key = PublicKey.new
if LibSodium.crypto_box_keypair(@public_key.to_slice, self.to_slice) != 0
raise Sodium::Error.new("crypto_box_keypair")
@key.readwrite do |kslice|
if LibSodium.crypto_box_keypair(@public_key.to_slice, kslice) != 0
raise Sodium::Error.new("crypto_box_keypair")
end
end
end
@ -59,14 +62,16 @@ class Sodium::CryptoBox
#
# Takes ownership of an existing key in a SecureBuffer.
# Recomputes the public key from a secret key if missing.
def initialize(@sbuf : SecureBuffer, pkey : Bytes? = nil)
raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{@sbuf.bytesize}") if @sbuf.bytesize != KEY_SIZE
def initialize(@key : Crypto::Secret, pkey : Bytes? = nil)
raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{@key.bytesize}") if @key.bytesize != KEY_SIZE
if pk = pkey
@public_key = PublicKey.new pk
else
@public_key = PublicKey.new
if LibSodium.crypto_scalarmult_base(@public_key.to_slice, self.to_slice) != 0
raise Sodium::Error.new("crypto_scalarmult_base")
@key.readonly do |kslice|
if LibSodium.crypto_scalarmult_base(@public_key.to_slice, kslice) != 0
raise Sodium::Error.new("crypto_scalarmult_base")
end
end
end
end
@ -77,13 +82,15 @@ class Sodium::CryptoBox
# Recomputes the public key from a secret key if missing.
def initialize(bytes : Bytes, pkey : Bytes? = nil)
raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{bytes.bytesize}") if bytes.bytesize != KEY_SIZE
@sbuf = SecureBuffer.new bytes
@key = SecureBuffer.new bytes
if pk = pkey
@public_key = PublicKey.new pk
else
@public_key = PublicKey.new
if LibSodium.crypto_scalarmult_base(@public_key.to_slice, self.to_slice) != 0
raise Sodium::Error.new("crypto_scalarmult_base")
@key.readonly do |kslice|
if LibSodium.crypto_scalarmult_base(@public_key.to_slice, kslice) != 0
raise Sodium::Error.new("crypto_scalarmult_base")
end
end
end
end
@ -93,30 +100,38 @@ class Sodium::CryptoBox
# Copies seed to a SecureBuffer.
def initialize(*, seed : Bytes, erase = false)
raise ArgumentError.new("Secret sign seed must be #{SEED_SIZE}, got #{seed.bytesize}") unless seed.bytesize == SEED_SIZE
@seed = SecureBuffer.new seed, erase: erase
@seed = seed = SecureBuffer.new seed, erase: erase
@sbuf = SecureBuffer.new KEY_SIZE
@key = SecureBuffer.new KEY_SIZE
@public_key = PublicKey.new
if LibSodium.crypto_box_seed_keypair(@public_key.to_slice, self.to_slice, seed) != 0
raise Sodium::Error.new("crypto_box_seed_keypair")
seed.readonly do |seed_slice|
@key.readwrite do |kslice|
if LibSodium.crypto_box_seed_keypair(@public_key.to_slice, kslice, seed_slice) != 0
raise Sodium::Error.new("crypto_box_seed_keypair")
end
end
end
end
# Derive a new secret/public key pair based on a consistent seed.
def initialize(*, seed : SecureBuffer)
def initialize(*, seed : Crypto::Secret)
raise ArgumentError.new("Secret sign seed must be #{SEED_SIZE}, got #{seed.bytesize}") unless seed.bytesize == SEED_SIZE
@seed = seed
@sbuf = SecureBuffer.new KEY_SIZE
@key = SecureBuffer.new KEY_SIZE
@public_key = PublicKey.new
if LibSodium.crypto_box_seed_keypair(@public_key.to_slice, self.to_slice, seed) != 0
raise Sodium::Error.new("crypto_box_seed_keypair")
seed.readonly do |seed_slice|
@key.readwrite do |kslice|
if LibSodium.crypto_box_seed_keypair(@public_key.to_slice, kslice, seed_slice) != 0
raise Sodium::Error.new("crypto_box_seed_keypair")
end
end
end
end
def seed
def seed : Crypto::Secret
# BUG: Generate seed if not set.
@seed.not_nil!.to_slice
@seed.not_nil!
end
# Return a Box containing a precomputed shared secret for use with authenticated encryption/decryption.
@ -159,8 +174,10 @@ class Sodium::CryptoBox
dst ||= Bytes.new dst_size
raise ArgumentError.new("dst.bytesize must be src.bytesize - SEAL_SIZE, got #{dst.bytesize}") unless dst.bytesize == dst_size
if LibSodium.crypto_box_seal_open(dst, src, src.bytesize, @public_key.to_slice, self.to_slice) != 0
raise Sodium::Error.new("crypto_box_seal_open")
@key.readonly do |kslice|
if LibSodium.crypto_box_seal_open(dst, src, src.bytesize, @public_key.to_slice, kslice) != 0
raise Sodium::Error.new("crypto_box_seal_open")
end
end
dst
end

View File

@ -62,15 +62,23 @@ module Sodium::Digest
#
# `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.
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? | Crypto::Secret? = nil, salt : Bytes? = nil, personal : Bytes? = nil)
if (k = key) && k.bytesize > 0
k = k.to_slice
raise ArgumentError.new("key larger than KEY_SIZE_MAX(#{KEY_SIZE_MAX}), got #{k.bytesize}") if k.bytesize > KEY_SIZE_MAX
# Test vectors contain small key sizes. Small keys shouldn't be used... Wtf?
Log.warn &.emit("key smaller than KEY_SIZE_MIN(#{KEY_SIZE_MIN}), got #{k.bytesize}") if k.bytesize < KEY_SIZE_MIN
# raise ArgumentError.new("key smaller than KEY_SIZE_MIN(#{KEY_SIZE_MIN}), got #{k.bytesize}") if k.bytesize < KEY_SIZE_MIN
case k
in Bytes
k.copy_to @key.to_slice
in Crypto::Secret
k.readonly do |k_slice|
k_slice.copy_to @key.to_slice
end
end
@key_size = k.bytesize
k.copy_to @key.to_slice
end
if sa = salt