Fix KEY_SIZE and NONCE_SIZE for non-ietf salsa/chacha ciphers.

Allow dupping various classes.
This commit is contained in:
Didactic Drunk 2019-11-25 06:44:33 -08:00
parent d7f5b6e717
commit ea4fc4e9a6
8 changed files with 65 additions and 9 deletions

View File

@ -178,14 +178,14 @@ public_key.verify_detached message, signature
### Secret Key Encryption ### Secret Key Encryption
```crystal ```crystal
key = Sodium::SecretKey.new box = Sodium::SecretBox.new
message = "foobar" message = "foobar"
encrypted, nonce = key.encrypt message encrypted, nonce = box.encrypt message
# On the other side. # On the other side.
key = Sodium::SecretKey.new key box = Sodium::SecretKey.new key
message = key.decrypt encrypted, nonce message = box.decrypt encrypted, nonce: nonce
``` ```
### Blake2b ### Blake2b

View File

@ -87,6 +87,18 @@ end
box.encrypt_detached message.to_slice, nonce: nonce box.encrypt_detached message.to_slice, nonce: nonce
end end
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 end
describe Sodium::Cipher::Aead do describe Sodium::Cipher::Aead do

View File

@ -25,5 +25,16 @@ require "../../../src/sodium/cipher/chalsa"
cipher2.update(output).should eq data cipher2.update(output).should eq data
cipher2.final.should eq Bytes.new(0) cipher2.final.should eq Bytes.new(0)
end 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
{% end %} {% end %}

View File

@ -90,4 +90,7 @@ describe Sodium::Digest::Blake2b do
Sodium::Digest::Blake2b.new personal: Bytes.new(128) Sodium::Digest::Blake2b.new personal: Bytes.new(128)
end end
end end
pending "dups" do
end
end end

View File

@ -28,4 +28,12 @@ describe Sodium::Nonce do
nonce.to_slice.should eq one nonce.to_slice.should eq one
nonce.used?.should be_false nonce.used?.should be_false
end 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 end

View File

@ -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 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 key_size : Int32
protected abstract def mac_size : Int32 protected abstract def mac_size : Int32
def dup
self.class.new @key.dup
end
end end
{% for key, val in {"XChaCha20Poly1305Ietf" => "_xchacha20poly1305_ietf"} %} {% for key, val in {"XChaCha20Poly1305Ietf" => "_xchacha20poly1305_ietf"} %}

View File

@ -12,10 +12,13 @@ module Sodium::Cipher
# Advanced usage. Don't touch. # Advanced usage. Don't touch.
property offset = 0 property offset = 0
getter! key
getter! nonce
def initialize def initialize
end end
def initialize(key, nonce) def initialize(key = nil, nonce = nil)
self.key = key if key self.key = key if key
self.nonce = nonce if nonce self.nonce = nonce if nonce
end end
@ -45,10 +48,12 @@ module Sodium::Cipher
update src, Bytes.new(src.bytesize) update src, Bytes.new(src.bytesize)
end end
private FINAL_BYTES = Bytes.new 0
# Provided for compatibility with block or tagged ciphers. # Provided for compatibility with block or tagged ciphers.
# Stream ciphers don't have additional data. # Stream ciphers don't have additional data.
def final def final
Bytes.new(0) FINAL_BYTES
end end
# Use as a CSPRNG. # Use as a CSPRNG.
@ -74,9 +79,15 @@ module Sodium::Cipher
abstract def update(src : Bytes, dst : Bytes) abstract def update(src : Bytes, dst : Bytes)
abstract def key_size : Int32 abstract def key_size : Int32
abstract def nonce_size : Int32 abstract def nonce_size : Int32
def dup
self.class.new key: @key.try(&.dup), nonce: @nonce.try(&.dup)
end
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, # These classes can be used to generate pseudo-random data from a key,
# or as building blocks for implementing custom constructions, but they # or as building blocks for implementing custom constructions, but they
# are not alternatives to secretbox. # 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. # WARNING: Not validated against test vectors. You should probably write some before using this class.
class {{ key.id }} < Chalsa 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. # Xor's src with the cipher output and places in dst.
# #
# src and dst may be the same object but should not overlap. # src and dst may be the same object but should not overlap.
@ -106,11 +120,11 @@ module Sodium::Cipher
end end
def key_size : Int32 def key_size : Int32
LibSodium.crypto_stream_chacha20_ietf_keybytes.to_i32 KEY_SIZE
end end
def nonce_size : Int32 def nonce_size : Int32
LibSodium.crypto_stream_chacha20_ietf_noncebytes.to_i32 NONCE_SIZE
end end
end end
{% end %} {% end %}

View File

@ -44,6 +44,10 @@ module Sodium
@used = true unless @reusable @used = true unless @reusable
end end
def dup
self.class.new @bytes.dup
end
module SerializeConverter module SerializeConverter
def self.to_json(value : Nonce, json : JSON::Builder) def self.to_json(value : Nonce, json : JSON::Builder)
json.string Base64.strict_encode(value.to_slice) json.string Base64.strict_encode(value.to_slice)