diff --git a/spec/sodium/crypto_box/secret_key_spec.cr b/spec/sodium/crypto_box/secret_key_spec.cr index f577d2a..b2fe2f8 100644 --- a/spec/sodium/crypto_box/secret_key_spec.cr +++ b/spec/sodium/crypto_box/secret_key_spec.cr @@ -27,7 +27,7 @@ describe Sodium::CryptoBox::SecretKey do key1.public_key.bytes.should eq key2.public_key.bytes end - it "easy encrypt/decrypt" do + it "authenticated easy encrypt/decrypt" do data = "Hello World!" # Alice is the sender @@ -50,6 +50,21 @@ describe Sodium::CryptoBox::SecretKey do end end + it "unauthenticated seal encrypt/decrypt" do + data = "foo bar" + + # Bob is the recipient + bob = Sodium::CryptoBox::SecretKey.new + + # Encrypt a message for Bob using his public key. No signature. + encrypted = bob.public_key.encrypt data + + # Decrypt the message using Bob's secret key. + decrypted = bob.decrypt encrypted + + String.new(decrypted).should eq(data) + end + it "wipes keys" do check_wiped new_key_bytes end diff --git a/src/sodium/crypto_box/box.cr b/src/sodium/crypto_box/box.cr index 19e8dd5..a991e17 100644 --- a/src/sodium/crypto_box/box.cr +++ b/src/sodium/crypto_box/box.cr @@ -4,6 +4,8 @@ module Sodium::CryptoBox class Box include Wipe + MAC_SIZE = LibSodium.crypto_box_macbytes + # BUG: precompute size @[Wipe::Var] @bytes = Bytes.new(1) @@ -16,14 +18,14 @@ module Sodium::CryptoBox encrypt_easy src.to_slice end - def encrypt_easy(src : Bytes, dst = Bytes.new(src.bytesize + LibSodium::MAC_SIZE), nonce = Nonce.new) + def encrypt_easy(src : Bytes, dst = Bytes.new(src.bytesize + MAC_SIZE), nonce = Nonce.new) if LibSodium.crypto_box_easy(dst, src, src.bytesize, nonce.to_slice, @public_key.to_slice, @secret_key.to_slice) != 0 raise Error.new("crypto_box_easy") end {nonce, dst} end - def decrypt_easy(src : Bytes, dst = Bytes.new(src.bytesize - LibSodium::MAC_SIZE), nonce = Nonce.new) : Bytes + def decrypt_easy(src : Bytes, dst = Bytes.new(src.bytesize - MAC_SIZE), nonce = Nonce.new) : Bytes if LibSodium.crypto_box_open_easy(dst, src, src.bytesize, nonce.to_slice, @public_key.to_slice, @secret_key.to_slice) != 0 raise Error::DecryptionFailed.new("crypto_box_open_easy") end diff --git a/src/sodium/crypto_box/public_key.cr b/src/sodium/crypto_box/public_key.cr index 9670038..be01474 100644 --- a/src/sodium/crypto_box/public_key.cr +++ b/src/sodium/crypto_box/public_key.cr @@ -3,7 +3,8 @@ require "../lib_sodium" module Sodium::CryptoBox class PublicKey < Key include Wipe - KEY_SIZE = LibSodium.crypto_box_publickeybytes + KEY_SIZE = LibSodium.crypto_box_publickeybytes + SEAL_SIZE = LibSodium.crypto_box_sealbytes getter bytes : Bytes @@ -18,5 +19,18 @@ module Sodium::CryptoBox raise ArgumentError.new("Public key must be #{KEY_SIZE} bytes, got #{bytes.bytesize}") end end + + # Anonymously send messages to a recipient given its public key. + # For authenticated message use `secret_key.box(recipient_public_key).encrypt`. + def encrypt(src) + encrypt src.to_slice + end + + def encrypt(src : Bytes, dst : Bytes = Bytes.new(src.bytesize + SEAL_SIZE)) : Bytes + if LibSodium.crypto_box_seal(dst, src, src.bytesize, @bytes) != 0 + raise Sodium::Error.new("crypto_box_seal") + end + dst + end end end diff --git a/src/sodium/crypto_box/secret_key.cr b/src/sodium/crypto_box/secret_key.cr index 85c2355..f16c687 100644 --- a/src/sodium/crypto_box/secret_key.cr +++ b/src/sodium/crypto_box/secret_key.cr @@ -7,7 +7,7 @@ module Sodium::CryptoBox include Wipe KEY_SIZE = LibSodium.crypto_box_secretkeybytes SEED_SIZE = LibSodium.crypto_box_seedbytes - MAC_SIZE = LibSodium::MAC_SIZE + SEAL_SIZE = LibSodium.crypto_box_sealbytes getter public_key : PublicKey @@ -51,7 +51,7 @@ module Sodium::CryptoBox end end - # Return a Box containing a precomputed shared secret for use with encryption/decryption. + # Return a Box containing a precomputed shared secret for use with authenticated encryption/decryption. def box(public_key) : Box Box.new self, public_key end @@ -65,5 +65,18 @@ module Sodium::CryptoBox b.close end end + + # Anonymously receive messages without signatures. + # For authenticated messages use `secret_key.box(recipient_public_key).decrypt`. + def decrypt(src) + encrypt src.to_slice + end + + def decrypt(src : Bytes, dst : Bytes = Bytes.new(src.bytesize - SEAL_SIZE)) : Bytes + if LibSodium.crypto_box_seal_open(dst, src, src.bytesize, @public_key.bytes, @bytes) != 0 + raise Sodium::Error.new("crypto_box_seal_open") + end + dst + end end end diff --git a/src/sodium/lib_sodium.cr b/src/sodium/lib_sodium.cr index 8797456..9d24234 100644 --- a/src/sodium/lib_sodium.cr +++ b/src/sodium/lib_sodium.cr @@ -7,6 +7,7 @@ module Sodium fun crypto_box_secretkeybytes : LibC::SizeT fun crypto_box_seedbytes : LibC::SizeT fun crypto_box_noncebytes : LibC::SizeT + fun crypto_box_sealbytes : LibC::SizeT fun crypto_box_macbytes : LibC::SizeT fun crypto_sign_publickeybytes : LibC::SizeT fun crypto_sign_secretkeybytes : LibC::SizeT @@ -42,9 +43,7 @@ module Sodium fun crypto_generichash_blake2b_personalbytes : LibC::SizeT fun sodium_memzero(Pointer(LibC::UChar), LibC::SizeT) : Nil - NONCE_SIZE = crypto_box_noncebytes() - MAC_SIZE = crypto_box_macbytes() - SIGNATURE_SIZE = crypto_sign_bytes() + NONCE_SIZE = crypto_box_noncebytes() fun crypto_secretbox_easy( output : Pointer(LibC::UChar), @@ -225,8 +224,4 @@ module Sodium if LibSodium.crypto_secretbox_noncebytes != LibSodium.crypto_box_noncebytes raise "Assumptions in this library regarding nonce sizes may not be valid" end - - if LibSodium.crypto_secretbox_macbytes != LibSodium.crypto_box_macbytes - raise "Assumptions in this library regarding mac sizes may not be valid" - end end diff --git a/src/sodium/secret_box.cr b/src/sodium/secret_box.cr index f8935fd..4e329bc 100644 --- a/src/sodium/secret_box.cr +++ b/src/sodium/secret_box.cr @@ -15,7 +15,7 @@ module Sodium class SecretBox < Key KEY_SIZE = LibSodium.crypto_secretbox_keybytes NONCE_SIZE = LibSodium.crypto_secretbox_noncebytes - MAC_SIZE = LibSodium::MAC_SIZE + MAC_SIZE = LibSodium.crypto_secretbox_macbytes @[Wipe::Var] property bytes : Bytes diff --git a/src/sodium/sign/public_key.cr b/src/sodium/sign/public_key.cr index b311bf2..e9cd4dd 100644 --- a/src/sodium/sign/public_key.cr +++ b/src/sodium/sign/public_key.cr @@ -4,6 +4,7 @@ module Sodium class Sign::PublicKey < Key include Wipe KEY_SIZE = LibSodium.crypto_sign_publickeybytes + SIG_SIZE = LibSodium.crypto_sign_bytes getter bytes : Bytes @@ -26,7 +27,7 @@ module Sodium end def verify_detached(message : Bytes, sig : Bytes) - raise ArgumentError.new("Signature must be #{LibSodium::SIGNATURE_SIZE} bytes, got #{sig.bytesize}") if sig.bytesize != LibSodium::SIGNATURE_SIZE + raise ArgumentError.new("Signature must be #{SIG_SIZE} bytes, got #{sig.bytesize}") if sig.bytesize != SIG_SIZE v = LibSodium.crypto_sign_verify_detached sig, message, message.bytesize, @bytes if v != 0 diff --git a/src/sodium/sign/secret_key.cr b/src/sodium/sign/secret_key.cr index 005dff2..3222481 100644 --- a/src/sodium/sign/secret_key.cr +++ b/src/sodium/sign/secret_key.cr @@ -9,6 +9,7 @@ module Sodium # ``` class Sign::SecretKey < Sodium::Key KEY_SIZE = LibSodium.crypto_sign_secretkeybytes + SIG_SIZE = LibSodium.crypto_sign_bytes SEED_SIZE = LibSodium.crypto_sign_seedbytes getter public_key : PublicKey @@ -61,7 +62,7 @@ module Sodium end def sign_detached(message : Bytes) - sig = Bytes.new(LibSodium::SIGNATURE_SIZE) + sig = Bytes.new(SIG_SIZE) if LibSodium.crypto_sign_detached(sig, out sig_len, message, message.bytesize, @bytes) != 0 raise Error.new("crypto_sign_detached") end