Add `.copy_from` `.move_from` instead of *erase*
  Prefer `.random`
  Deprecate old `.initialize`
This commit is contained in:
Didactic Drunk 2022-04-28 12:14:35 -07:00
parent 98c3a2bff4
commit f036295aa3
3 changed files with 55 additions and 38 deletions

View File

@ -20,7 +20,7 @@ Crystal bindings for the [libsodium API](https://libsodium.gitbook.io/doc/)
- [Public-Key Cryptography](https://libsodium.gitbook.io/doc/public-key_cryptography) - [Public-Key Cryptography](https://libsodium.gitbook.io/doc/public-key_cryptography)
- [x] ☑ [Crypto Box Easy](https://libsodium.gitbook.io/doc/public-key_cryptography/authenticated_encryption) - [x] ☑ [Crypto Box Easy](https://libsodium.gitbook.io/doc/public-key_cryptography/authenticated_encryption)
- [x] [Sealed Box](https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes) - [x] [Sealed Box](https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes)
- [ ] [Combined Signatures](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures) - [x] [Combined Signatures](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures)
- [x] ☑ [Detached Signatures](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures) - [x] ☑ [Detached Signatures](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures)
- [ ] [Pre-hashed Signatures](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures) - [ ] [Pre-hashed Signatures](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures)
- [Secret-Key Cryptography](https://libsodium.gitbook.io/doc/secret-key_cryptography) - [Secret-Key Cryptography](https://libsodium.gitbook.io/doc/secret-key_cryptography)

View File

@ -31,18 +31,9 @@ end
describe Sodium::Sign::SecretKey do describe Sodium::Sign::SecretKey do
it "loads keys" do it "loads keys" do
key1 = Sodium::Sign::SecretKey.new key1 = Sodium::Sign::SecretKey.random
key2 = key1.key.readonly do |kslice| key2 = key1.key.readonly do |kslice|
Sodium::Sign::SecretKey.new kslice, key1.public_key.to_slice Sodium::Sign::SecretKey.copy_from kslice
end
key1.key.should eq key2.key
key1.public_key.to_slice.should eq key2.public_key.to_slice
end
it "recomputes the public key" do
key1 = Sodium::Sign::SecretKey.new
key2 = key1.key.readonly do |kslice|
Sodium::Sign::SecretKey.new kslice
end end
key1.key.should eq key2.key key1.key.should eq key2.key
key1.public_key.to_slice.should eq key2.public_key.to_slice key1.public_key.to_slice.should eq key2.public_key.to_slice
@ -52,7 +43,7 @@ describe Sodium::Sign::SecretKey do
seed = Bytes.new Sodium::Sign::SecretKey::SEED_SIZE seed = Bytes.new Sodium::Sign::SecretKey::SEED_SIZE
key1 = Sodium::Sign::SecretKey.new seed: seed key1 = Sodium::Sign::SecretKey.new seed: seed
key2 = key1.key.readonly do |kslice| key2 = key1.key.readonly do |kslice|
Sodium::Sign::SecretKey.new kslice Sodium::Sign::SecretKey.copy_from kslice
end end
key3 = Sodium::Sign::SecretKey.new seed: key2.seed key3 = Sodium::Sign::SecretKey.new seed: key2.seed
key1.key.should eq key2.key key1.key.should eq key2.key
@ -66,7 +57,7 @@ describe Sodium::Sign::SecretKey do
it "signs and verifies combined" do it "signs and verifies combined" do
message = "foo" message = "foo"
skey = Sodium::Sign::SecretKey.new skey = Sodium::Sign::SecretKey.random
sig = skey.sign message sig = skey.sign message
message2 = skey.public_key.verify_string sig message2 = skey.public_key.verify_string sig
@ -75,7 +66,7 @@ describe Sodium::Sign::SecretKey do
it "signs and verifies detached" do it "signs and verifies detached" do
message = "foo" message = "foo"
skey = Sodium::Sign::SecretKey.new skey = Sodium::Sign::SecretKey.random
sig = skey.sign_detached message sig = skey.sign_detached message
skey.public_key.verify_detached message, sig skey.public_key.verify_detached message, sig
@ -83,7 +74,7 @@ describe Sodium::Sign::SecretKey do
it "signs and fails" do it "signs and fails" do
message = "foo" message = "foo"
skey = Sodium::Sign::SecretKey.new skey = Sodium::Sign::SecretKey.random
sig = skey.sign_detached message sig = skey.sign_detached message
expect_raises Sodium::Error::VerificationFailed do expect_raises Sodium::Error::VerificationFailed do
@ -93,7 +84,7 @@ describe Sodium::Sign::SecretKey do
it "to_curve25519" do it "to_curve25519" do
message = "foo" message = "foo"
sskey = Sodium::Sign::SecretKey.new sskey = Sodium::Sign::SecretKey.random
cskey = sskey.to_curve25519 cskey = sskey.to_curve25519
spkey = sskey.public_key spkey = sskey.public_key

View File

@ -18,12 +18,12 @@ module Sodium
SIG_SIZE = LibSodium.crypto_sign_bytes.to_i SIG_SIZE = LibSodium.crypto_sign_bytes.to_i
SEED_SIZE = LibSodium.crypto_sign_seedbytes.to_i SEED_SIZE = LibSodium.crypto_sign_seedbytes.to_i
getter public_key : PublicKey
@[Deprecated("Switching to Crypto::Secret. Use `key.readonly` or `key.readwrite`")] @[Deprecated("Switching to Crypto::Secret. Use `key.readonly` or `key.readwrite`")]
delegate_to_slice to: @key delegate_to_slice to: @key
getter key : Crypto::Secret getter key : Crypto::Secret
getter public_key = PublicKey.new
@seed : Crypto::Secret? @seed : Crypto::Secret?
# Generates a new random secret/public key pair. # Generates a new random secret/public key pair.
@ -37,40 +37,54 @@ module Sodium
end end
end end
# Use existing secret and public keys.
# Copies secret key to a SecureBuffer.
# Recomputes the public key from a secret key if missing.
def initialize(bytes : Bytes, pkey : Bytes? = nil, *, erase = false)
raise ArgumentError.new("Secret sign key must be #{KEY_SIZE}, got #{bytes.bytesize}") unless bytes.bytesize == KEY_SIZE
@key = SecureBuffer.new bytes, erase: erase # Copies secret *key* to a `SecureBuffer`
if pk = pkey def self.copy_from(key : Bytes)
@public_key = PublicKey.new pk new SecureBuffer.copy_from(key)
end
# Copies secret *key* to a `SecureBuffer`
# Erases *key*
def self.move_from(key : Bytes)
new SecureBuffer.move_from(key)
end
# Copies secret *key* to a `SecureBuffer`
@[Deprecated("Use .copy_from or .move_from")]
def self.new(key : Bytes, erase = false)
raise ArgumentError.new("Secret sign key must be #{KEY_SIZE}, got #{key.bytesize}") unless key.bytesize == KEY_SIZE
if erase
move_from key
else else
@public_key = PublicKey.new copy_from key
@key.readwrite do |kslice| end
if LibSodium.crypto_sign_ed25519_sk_to_pk(@public_key.to_slice, kslice) != 0 end
raise Sodium::Error.new("crypto_sign_ed25519_sk_to_pk")
end # References existing Crypto::Secret
def initialize(@key : Crypto::Secret)
# Set @public_key
@key.readwrite do |kslice|
if LibSodium.crypto_sign_ed25519_sk_to_pk(@public_key.to_slice, kslice) != 0
raise Sodium::Error.new("crypto_sign_ed25519_sk_to_pk")
end end
end end
end end
# Derive a new secret/public key pair based on a consistent seed. # Derive a new secret/public key pair based on a consistent seed.
# Copies seed to a SecureBuffer. # Copies seed to a `SecureBuffer`
def initialize(*, seed : Bytes, erase = false) def self.new(*, seed : Bytes, erase = false)
raise ArgumentError.new("Secret sign seed must be #{SEED_SIZE}, got #{seed.bytesize}") unless seed.bytesize == SEED_SIZE raise ArgumentError.new("Secret sign seed must be #{SEED_SIZE}, got #{seed.bytesize}") unless seed.bytesize == SEED_SIZE
initialize(seed: SecureBuffer.new(seed, erase: erase)) new(seed: SecureBuffer.new(seed, erase: erase))
end end
# Derive a new secret/public key pair based on a consistent seed. # Derive a new secret/public key pair based on a consistent seed.
# References passed SecureBuffer # References passed `SecureBuffer`
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 raise ArgumentError.new("Secret sign seed must be #{SEED_SIZE}, got #{seed.bytesize}") unless seed.bytesize == SEED_SIZE
@seed = seed @seed = seed
@key = SecureBuffer.new KEY_SIZE @key = SecureBuffer.new KEY_SIZE
@public_key = PublicKey.new
seed.readonly do |seed_slice| seed.readonly do |seed_slice|
@key.readwrite do |kslice| @key.readwrite do |kslice|
if LibSodium.crypto_sign_seed_keypair(@public_key.to_slice, kslice, seed_slice) != 0 if LibSodium.crypto_sign_seed_keypair(@public_key.to_slice, kslice, seed_slice) != 0
@ -80,6 +94,18 @@ module Sodium
end end
end end
# :nodoc:
def initialize(random : Bool)
@key = SecureBuffer.new KEY_SIZE
@key.readwrite do |kslice|
if LibSodium.crypto_sign_keypair(@public_key.to_slice, kslice) != 0
raise Sodium::Error.new("crypto_sign_keypair")
end
end
end
getter seed : Crypto::Secret do getter seed : Crypto::Secret do
SecureBuffer.new(SEED_SIZE).tap do |seed_buf| SecureBuffer.new(SEED_SIZE).tap do |seed_buf|
@key.readonly do |kslice| @key.readonly do |kslice|