From d556e1c909dcb09914d21d6c81c95d7df79c361f Mon Sep 17 00:00:00 2001 From: Didactic Drunk <1479616+didactic-drunk@users.noreply.github.com> Date: Tue, 6 Aug 2019 14:27:19 -0700 Subject: [PATCH] Use crypto_box_beforenmbytes to precompute CryptoBox shared key. --- examples/constants.cr | 5 +++ src/sodium/crypto_box.cr | 22 ++++++++++---- src/sodium/crypto_box/secret_key.cr | 2 -- src/sodium/lib_sodium.cr | 47 +++++++++++++++++++++-------- src/sodium/secure_buffer.cr | 2 +- src/sodium/sign/secret_key.cr | 8 ++--- 6 files changed, 61 insertions(+), 25 deletions(-) diff --git a/examples/constants.cr b/examples/constants.cr index 907d12c..826dafa 100644 --- a/examples/constants.cr +++ b/examples/constants.cr @@ -7,6 +7,11 @@ require "../src/sodium" {% end %} puts "" +{% for name in %w(MAC_SIZE NM_SIZE) %} + puts "Sodium::CryptoBox::{{ name.id }} #{Sodium::CryptoBox::{{ name.id }}}" +{% end %} +puts "" + {% for name in %w(KEY_SIZE SEED_SIZE SIG_SIZE) %} puts "Sodium::Sign::SecretKey::{{ name.id }} #{Sodium::Sign::SecretKey::{{ name.id }}}" {% end %} diff --git a/src/sodium/crypto_box.cr b/src/sodium/crypto_box.cr index a78dd6f..b00f55d 100644 --- a/src/sodium/crypto_box.cr +++ b/src/sodium/crypto_box.cr @@ -4,17 +4,27 @@ require "./crypto_box/secret_key" require "./nonce" module Sodium + # Use Sodium::CryptoBox::SecretKey#box class CryptoBox include Wipe MAC_SIZE = LibSodium.crypto_box_macbytes.to_i + # :nodoc: + NM_SIZE = LibSodium.crypto_box_beforenmbytes.to_i + raise "NM_SIZE=#{NM_SIZE}, assumed it was 32" if NM_SIZE != 32 - # BUG: precompute size @[Wipe::Var] - @bytes = Bytes.new(1) + @key = StaticArray(UInt8, 32).new 0 + # :nodoc: + # Used by SecretKey#box def initialize(@secret_key : SecretKey, @public_key : PublicKey) - # TODO: precompute using crypto_box_beforenm + # Precalculate key for later use. + # Large speed gains with small data sizes and many messages. + # Small speed gains with large data sizes or few messages. + if LibSodium.crypto_box_beforenm(@key, @public_key.to_slice, @secret_key.to_slice) != 0 + raise Error.new("crypto_box_beforenm") + end end # Encrypts data and returns {ciphertext, nonce} @@ -26,7 +36,7 @@ module Sodium # # Optionally supply a destination buffer. def encrypt(src : Bytes, dst = Bytes.new(src.bytesize + MAC_SIZE), nonce = Nonce.new) : {Bytes, Nonce} - if LibSodium.crypto_box_easy(dst, src, src.bytesize, nonce.to_slice, @public_key.to_slice, @secret_key.to_slice) != 0 + if LibSodium.crypto_box_easy_afternm(dst, src, src.bytesize, nonce.to_slice, @key.to_slice) != 0 raise Error.new("crypto_box_easy") end {dst, nonce} @@ -41,8 +51,8 @@ module Sodium # Returns decrypted message. # # Optionally supply a destination buffer. - def decrypt(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 + def decrypt(src : Bytes, dst = Bytes.new(src.bytesize - MAC_SIZE), nonce = Nonce.random) : Bytes + if LibSodium.crypto_box_open_easy_afternm(dst, src, src.bytesize, nonce.to_slice, @key) != 0 raise Error::DecryptionFailed.new("crypto_box_open_easy") end dst diff --git a/src/sodium/crypto_box/secret_key.cr b/src/sodium/crypto_box/secret_key.cr index 21c059d..a54b46e 100644 --- a/src/sodium/crypto_box/secret_key.cr +++ b/src/sodium/crypto_box/secret_key.cr @@ -5,8 +5,6 @@ require "../crypto_box" class Sodium::CryptoBox # Key used for encryption + authentication or encryption without authentication, not for unencrypted signing. - # - # If you don't want this behavior pass a duplicate of the key/seed to initialize(). class SecretKey < Key KEY_SIZE = LibSodium.crypto_box_secretkeybytes.to_i SEED_SIZE = LibSodium.crypto_box_seedbytes.to_i diff --git a/src/sodium/lib_sodium.cr b/src/sodium/lib_sodium.cr index 887622d..0965a3c 100644 --- a/src/sodium/lib_sodium.cr +++ b/src/sodium/lib_sodium.cr @@ -12,6 +12,7 @@ module Sodium fun crypto_box_noncebytes : LibC::SizeT fun crypto_box_sealbytes : LibC::SizeT fun crypto_box_macbytes : LibC::SizeT + fun crypto_box_beforenmbytes : LibC::SizeT fun crypto_sign_publickeybytes : LibC::SizeT fun crypto_sign_secretkeybytes : LibC::SizeT fun crypto_sign_bytes : LibC::SizeT @@ -148,22 +149,45 @@ module Sodium secret_key_output : Pointer(LibC::UChar) ) : LibC::Int - fun crypto_box_easy( - output : Pointer(LibC::UChar), - data : Pointer(LibC::UChar), - data_size : LibC::ULongLong, - nonce : Pointer(LibC::UChar), - recipient_public_key : Pointer(LibC::UChar), - sender_secret_key : Pointer(LibC::UChar) + fun crypto_box_beforenm( + k : Pointer(LibC::UChar), + pk : Pointer(LibC::UChar), + sk : Pointer(LibC::UChar) ) : LibC::Int - fun crypto_box_open_easy( + fun crypto_box_easy_afternm( output : Pointer(LibC::UChar), data : Pointer(LibC::UChar), data_size : LibC::ULongLong, nonce : Pointer(LibC::UChar), - sender_public_key : Pointer(LibC::UChar), - recipient_secret_key : Pointer(LibC::UChar) + key : Pointer(LibC::UChar) + ) : LibC::Int + + # TODO: possibly remove after switching to detached + fun crypto_box_open_easy_afternm( + output : Pointer(LibC::UChar), + data : Pointer(LibC::UChar), + data_size : LibC::ULongLong, + nonce : Pointer(LibC::UChar), + key : Pointer(LibC::UChar) + ) : LibC::Int + + fun crypto_box_detached_afternm( + output : Pointer(LibC::UChar), + mac : Pointer(LibC::UChar), + data : Pointer(LibC::UChar), + data_size : LibC::ULongLong, + nonce : Pointer(LibC::UChar), + key : Pointer(LibC::UChar) + ) : LibC::Int + + fun crypto_box_open_detached_afternm( + output : Pointer(LibC::UChar), + data : Pointer(LibC::UChar), + mac : Pointer(LibC::UChar), + data_size : LibC::ULongLong, + nonce : Pointer(LibC::UChar), + key : Pointer(LibC::UChar) ) : LibC::Int fun crypto_box_seal( @@ -294,8 +318,7 @@ module Sodium end end - # Constant time memory compare. - # Raises unless comparison succeeds. + # Constant time memory compare. Raises unless comparison succeeds. def self.memcmp!(a, b) raise Error::MemcmpFailed.new unless memcmp(a, b) true diff --git a/src/sodium/secure_buffer.cr b/src/sodium/secure_buffer.cr index 657fc49..df2ba81 100644 --- a/src/sodium/secure_buffer.cr +++ b/src/sodium/secure_buffer.cr @@ -2,12 +2,12 @@ require "./lib_sodium" require "./wipe" module Sodium + # Allocate guarded memory using [sodium_malloc](https://libsodium.gitbook.io/doc/memory_management) class SecureBuffer getter bytesize delegate :+, :[], :[]=, to: to_slice - # Allocate guarded memory using [sodium_malloc](https://libsodium.gitbook.io/doc/memory_management) def initialize(@bytesize : Int32) @ptr = LibSodium.sodium_malloc @bytesize end diff --git a/src/sodium/sign/secret_key.cr b/src/sodium/sign/secret_key.cr index 7b85451..2060fb7 100644 --- a/src/sodium/sign/secret_key.cr +++ b/src/sodium/sign/secret_key.cr @@ -3,15 +3,15 @@ require "../key" require "./public_key" module Sodium - # Key used for signing/verification only. + # Ed25519 secret key used for signing. # - # If you don't want this behavior pass a duplicate of the key/seed to initialize(). + # [https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures) # # Usage: # ``` - # key = SecretKey.new + # key = Sodium::Sign::SecretKey.new # sig = key.sign_detached data - # key.public_key.verify_detached data + # key.public_key.verify_detached data, sig # ``` class Sign::SecretKey < Sodium::Key KEY_SIZE = LibSodium.crypto_sign_secretkeybytes.to_i