From ea4fc4e9a610f060da1934bdf1285e4156508e0d Mon Sep 17 00:00:00 2001 From: Didactic Drunk <1479616+didactic-drunk@users.noreply.github.com> Date: Mon, 25 Nov 2019 06:44:33 -0800 Subject: [PATCH] Fix KEY_SIZE and NONCE_SIZE for non-ietf salsa/chacha ciphers. Allow dupping various classes. --- README.md | 8 ++++---- spec/sodium/cipher/aead/chalsa_spec.cr | 12 ++++++++++++ spec/sodium/cipher/chalsa_spec.cr | 11 +++++++++++ spec/sodium/digest/blake2b_spec.cr | 3 +++ spec/sodium/nonce_spec.cr | 8 ++++++++ src/sodium/cipher/aead/chalsa.cr | 4 ++++ src/sodium/cipher/chalsa.cr | 24 +++++++++++++++++++----- src/sodium/nonce.cr | 4 ++++ 8 files changed, 65 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4effe03..f95cc32 100644 --- a/README.md +++ b/README.md @@ -178,14 +178,14 @@ public_key.verify_detached message, signature ### Secret Key Encryption ```crystal -key = Sodium::SecretKey.new +box = Sodium::SecretBox.new message = "foobar" -encrypted, nonce = key.encrypt message +encrypted, nonce = box.encrypt message # On the other side. -key = Sodium::SecretKey.new key -message = key.decrypt encrypted, nonce +box = Sodium::SecretKey.new key +message = box.decrypt encrypted, nonce: nonce ``` ### Blake2b diff --git a/spec/sodium/cipher/aead/chalsa_spec.cr b/spec/sodium/cipher/aead/chalsa_spec.cr index d413972..c66cc6a 100644 --- a/spec/sodium/cipher/aead/chalsa_spec.cr +++ b/spec/sodium/cipher/aead/chalsa_spec.cr @@ -87,6 +87,18 @@ end box.encrypt_detached message.to_slice, nonce: nonce end end + + it "dups" do + box1 = Sodium::Cipher::Aead::{{ name.id }}.new Bytes.new(Sodium::Cipher::Aead::{{ name.id }}::KEY_SIZE) + 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 + end end describe Sodium::Cipher::Aead do diff --git a/spec/sodium/cipher/chalsa_spec.cr b/spec/sodium/cipher/chalsa_spec.cr index cd296a8..d13db83 100644 --- a/spec/sodium/cipher/chalsa_spec.cr +++ b/spec/sodium/cipher/chalsa_spec.cr @@ -25,5 +25,16 @@ require "../../../src/sodium/cipher/chalsa" cipher2.update(output).should eq data cipher2.final.should eq Bytes.new(0) end + + it "dups" do + cipher1 = Sodium::Cipher::{{ name.id }}.new Bytes.new(Sodium::Cipher::{{ name.id }}::KEY_SIZE) + cipher2 = cipher1.dup + + key1 = cipher1.key + key2 = cipher2.key + + key2.to_slice[0] = 1_u8 + key1.to_slice[0].should eq 0_u8 + end end {% end %} diff --git a/spec/sodium/digest/blake2b_spec.cr b/spec/sodium/digest/blake2b_spec.cr index e0ef3a8..bc00c5a 100644 --- a/spec/sodium/digest/blake2b_spec.cr +++ b/spec/sodium/digest/blake2b_spec.cr @@ -90,4 +90,7 @@ describe Sodium::Digest::Blake2b do Sodium::Digest::Blake2b.new personal: Bytes.new(128) end end + + pending "dups" do + end end diff --git a/spec/sodium/nonce_spec.cr b/spec/sodium/nonce_spec.cr index 1420beb..83831ea 100644 --- a/spec/sodium/nonce_spec.cr +++ b/spec/sodium/nonce_spec.cr @@ -28,4 +28,12 @@ describe Sodium::Nonce do nonce.to_slice.should eq one nonce.used?.should be_false end + + it "dups" do + nonce1 = Sodium::Nonce.zero + nonce2 = nonce1.dup + + nonce2.to_slice[0] = 1_u8 + nonce1.to_slice[0].should eq 0_u8 + end end diff --git a/src/sodium/cipher/aead/chalsa.cr b/src/sodium/cipher/aead/chalsa.cr index 74e68ec..98edc08 100644 --- a/src/sodium/cipher/aead/chalsa.cr +++ b/src/sodium/cipher/aead/chalsa.cr @@ -79,6 +79,10 @@ module Sodium::Cipher::Aead abstract def decrypt_detached(src : Bytes, dst : Bytes? = nil, *, nonce : Sodium::Nonce, mac : Bytes, additional : String | Bytes | Nil = nil) : Bytes protected abstract def key_size : Int32 protected abstract def mac_size : Int32 + + def dup + self.class.new @key.dup + end end {% for key, val in {"XChaCha20Poly1305Ietf" => "_xchacha20poly1305_ietf"} %} diff --git a/src/sodium/cipher/chalsa.cr b/src/sodium/cipher/chalsa.cr index eb46423..2c6713f 100644 --- a/src/sodium/cipher/chalsa.cr +++ b/src/sodium/cipher/chalsa.cr @@ -12,10 +12,13 @@ module Sodium::Cipher # Advanced usage. Don't touch. property offset = 0 + getter! key + getter! nonce + def initialize end - def initialize(key, nonce) + def initialize(key = nil, nonce = nil) self.key = key if key self.nonce = nonce if nonce end @@ -45,10 +48,12 @@ module Sodium::Cipher update src, Bytes.new(src.bytesize) end + private FINAL_BYTES = Bytes.new 0 + # Provided for compatibility with block or tagged ciphers. # Stream ciphers don't have additional data. def final - Bytes.new(0) + FINAL_BYTES end # Use as a CSPRNG. @@ -74,9 +79,15 @@ module Sodium::Cipher abstract def update(src : Bytes, dst : Bytes) abstract def key_size : Int32 abstract def nonce_size : Int32 + + def dup + self.class.new key: @key.try(&.dup), nonce: @nonce.try(&.dup) + end end - {% for key, val in {"XSalsa20" => "xsalsa20", "Salsa20" => "salsa20", "XChaCha20" => "xchacha20", "ChaCha20Ietf" => "chacha20_ietf", "ChaCha20" => "chacha20"} %} + {% for key, valtup in {"Xchacha16" => {"xchacha16", false}, "XSalsa20" => {"xsalsa20", false}, "Salsa20" => {"salsa20", false}, "XChaCha20" => {"xchacha20", false}, "ChaCha20Ietf" => {"chacha20_ietf", true}, "ChaCha20" => {"chacha20", false}} %} + {% val = valtup[0] %} + {% ietf = valtup[1] %} # These classes can be used to generate pseudo-random data from a key, # or as building blocks for implementing custom constructions, but they # are not alternatives to secretbox. @@ -89,6 +100,9 @@ module Sodium::Cipher # # WARNING: Not validated against test vectors. You should probably write some before using this class. class {{ key.id }} < Chalsa + KEY_SIZE = LibSodium.crypto_stream_chacha20_{{ ietf ? "ietf_".id : "".id }}keybytes.to_i32 + NONCE_SIZE = LibSodium.crypto_stream_chacha20_{{ ietf ? "ietf_".id : "".id }}noncebytes.to_i32 + # Xor's src with the cipher output and places in dst. # # src and dst may be the same object but should not overlap. @@ -106,11 +120,11 @@ module Sodium::Cipher end def key_size : Int32 - LibSodium.crypto_stream_chacha20_ietf_keybytes.to_i32 + KEY_SIZE end def nonce_size : Int32 - LibSodium.crypto_stream_chacha20_ietf_noncebytes.to_i32 + NONCE_SIZE end end {% end %} diff --git a/src/sodium/nonce.cr b/src/sodium/nonce.cr index 4484ef1..9ae45f1 100644 --- a/src/sodium/nonce.cr +++ b/src/sodium/nonce.cr @@ -44,6 +44,10 @@ module Sodium @used = true unless @reusable end + def dup + self.class.new @bytes.dup + end + module SerializeConverter def self.to_json(value : Nonce, json : JSON::Builder) json.string Base64.strict_encode(value.to_slice)