sodium.cr/spec/sodium/cipher/aead/chalsa_spec.cr

136 lines
4.8 KiB
Crystal

require "../../../spec_helper"
require "../../../../src/sodium/cipher/aead/chalsa"
detached_test_vectors = [
{
# Test vector from libsodium's xchacha20poly1305-ietf test
aead: "xchacha20-poly1305",
key: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
nonce: "07000000404142434445464748494a4b0000000000000000",
plaintext: "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e",
additional: "50515253c0c1c2c3c4c5c6c7",
ciphertext: "453c0693a7407f04ff4c56aedb17a3c0a1afff01174930fc22287c33dbcf0ac8b89ad929530a1bb3ab5e69f24c7f6070c8f840c9abb4f69fbfc8a7ff5126faeebbb55805ee9c1cf2ce5a57263287aec5780f04ec324c3514122cfc3231fc1a8b718a62863730a2702bb76366116bed09e0fd",
tag: "5c6d84b6b0c1abaf249d5dd0f7f5a7ea",
},
]
private def box_from_test_vector(vec)
box = Sodium::Cipher::Aead::XChaCha20Poly1305Ietf.new vec[:key].hexbytes
nonce = Sodium::Nonce.new vec[:nonce].hexbytes
plaintext = vec[:plaintext].hexbytes
ciphertext = vec[:ciphertext].hexbytes
additional = vec[:additional].hexbytes
tag = vec[:tag].hexbytes
{box, nonce, plaintext, ciphertext, additional, tag}
end
{% for name in %w(XChaCha20Poly1305Ietf) %}
describe Sodium::Cipher::Aead::{{ name.id }} do
it "encrypts/decrypts in combined mode" do
box = Sodium::Cipher::Aead::{{ name.id }}.random
message = "foo"
additional = "bar"
encrypted, nonce = box.encrypt message, additional: additional
decrypted = box.decrypt_string encrypted, nonce: nonce, additional: additional
decrypted.should eq message
# Wrong additional.
expect_raises(Sodium::Error::DecryptionFailed) do
box.decrypt encrypted, nonce: nonce, additional: "baz".to_slice
end
# Missing additional.
expect_raises(Sodium::Error::DecryptionFailed) do
box.decrypt encrypted, nonce: nonce
end
# Wrong data.
expect_raises(Sodium::Error::DecryptionFailed) do
box.decrypt "badmsgbadmsgbadmsgbadmsgbadmsg".to_slice, nonce: nonce
end
end
it "encrypts/decrypts in detached mode" do
box = Sodium::Cipher::Aead::{{ name.id }}.random
message = "foo"
additional = "bar"
mac, encrypted, nonce = box.encrypt_detached message, additional: additional
decrypted = box.decrypt_detached_string encrypted, nonce: nonce, mac: mac, additional: additional
decrypted.should eq message
# Wrong additional.
expect_raises(Sodium::Error::DecryptionFailed) do
box.decrypt_detached encrypted, nonce: nonce, mac: mac, additional: "baz".to_slice
end
# Missing additional.
expect_raises(Sodium::Error::DecryptionFailed) do
box.decrypt_detached encrypted, nonce: nonce, mac: mac
end
# Wrong data.
expect_raises(Sodium::Error::DecryptionFailed) do
box.decrypt_detached "badmsgbadmsgbadmsgbadmsgbadmsg".to_slice, nonce: nonce, mac: mac
end
end
it "can't encrypt twice using the same nonce" do
box = Sodium::Cipher::Aead::{{ name.id }}.random
message = "foo"
mac, encrypted, nonce = box.encrypt_detached message
expect_raises(Sodium::Nonce::Error::Reused) do
box.encrypt_detached message.to_slice, nonce: nonce
end
end
it "dups" do
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
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
describe Sodium::Cipher::Aead do
pending "Combined test vectors don't exist in libsodium, PyNaCl or RbNaCl. no ciphertext to compare against." do
combined_test_vectors.each do |vec|
box, nonce, plaintext, ciphertext, additional = box_from_test_vector vec
encrypted, _ = box.encrypt plaintext, nonce: nonce
encrypted.should eq ciphertext
decrypted = box.decrypt ciphertext, nonce: nonce
decrypted.should eq plaintext
end
end
it "PyNaCl detached test vectors" do
detached_test_vectors.each do |vec|
box, nonce, plaintext, ciphertext, additional, tag = box_from_test_vector vec
mac2, encrypted, _ = box.encrypt_detached plaintext, nonce: nonce, mac: tag, additional: additional
mac2.should eq tag
encrypted.should eq ciphertext
decrypted = box.decrypt_detached ciphertext, nonce: nonce, mac: tag, additional: additional
decrypted.should eq plaintext
end
end
end
{% end %}