From 5146a383f70effbf868866ab70847dc5ac0348b5 Mon Sep 17 00:00:00 2001 From: Didactic Drunk <1479616+didactic-drunk@users.noreply.github.com> Date: Sat, 30 Apr 2022 11:17:30 -0700 Subject: [PATCH] Crypto::Secret Prefer .random, .move_from, .copy_from Optimize #decrypt_string --- spec/sodium/secret_box_spec.cr | 6 +++--- src/sodium/secret_box.cr | 39 +++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/spec/sodium/secret_box_spec.cr b/spec/sodium/secret_box_spec.cr index 19c2914..f689e54 100644 --- a/spec/sodium/secret_box_spec.cr +++ b/spec/sodium/secret_box_spec.cr @@ -18,7 +18,7 @@ combined_test_vectors = [ ] private def box_from_test_vector(vec) - box = Sodium::SecretBox.new vec[:key].hexbytes + box = Sodium::SecretBox.copy_from vec[:key].hexbytes nonce = Sodium::Nonce.new vec[:nonce].hexbytes plaintext = vec[:plaintext].hexbytes ciphertext = vec[:ciphertext].hexbytes @@ -28,7 +28,7 @@ end describe Sodium::SecretBox do it "encrypts/decrypts" do - box = Sodium::SecretBox.new + box = Sodium::SecretBox.random message = "foobar" encrypted, nonce = box.encrypt message @@ -41,7 +41,7 @@ describe Sodium::SecretBox do end it "can't encrypt twice using the same nonce" do - box = Sodium::SecretBox.new + box = Sodium::SecretBox.random message = "foobar" encrypted, nonce = box.encrypt message diff --git a/src/sodium/secret_box.cr b/src/sodium/secret_box.cr index 343adbc..de8a347 100644 --- a/src/sodium/secret_box.cr +++ b/src/sodium/secret_box.cr @@ -5,6 +5,9 @@ require "./nonce" module Sodium # [https://libsodium.gitbook.io/doc/secret-key_cryptography](https://libsodium.gitbook.io/doc/secret-key_cryptography) # + # WARNING: Only use this class for compatibility with older applications already using SecretBox. + # Use `Sodium::Cipher::Aead::XChaCha20Poly1305Ietf` for new applications. + # # ``` # box = Sodium::SecretBox.new # message = "foobar" @@ -25,12 +28,30 @@ module Sodium # Encryption key getter key : Crypto::Secret - # Generate a new random key held in a SecureBuffer. + # Generate a new random key held in a `SecureBuffer` + def self.random + new SecureBuffer.random(KEY_SIZE) + end + + # Copy *key* to a new `SecureBuffer` + def self.copy_from(key : Bytes) + new SecureBuffer.copy_from(key) + end + + # Copy *key* to a new `SecureBuffer` + # + # Erases *key* after copying + def self.move_from(key : Bytes) + new SecureBuffer.copy_from(key) + end + + # Generate a new random key held in a `SecureBuffer` + @[Deprecated("Use .random")] def initialize @key = SecureBuffer.random KEY_SIZE end - # Use an existing Crypto::Secret. + # Use an existing `Crypto::Secret` def initialize(@key : Crypto::Secret) if @key.bytesize != KEY_SIZE raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{@key.bytesize}") @@ -38,9 +59,10 @@ module Sodium @key.readonly end - # Copy bytes to a new SecureBuffer + # Copy bytes to a new `SecureBuffer` # # Optionally erases bytes after copying if erase is set. + @[Deprecated("Use .copy_from or .move_from")] def initialize(bytes : Bytes, erase = false) if bytes.bytesize != KEY_SIZE raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{bytes.bytesize}") @@ -78,11 +100,12 @@ module Sodium end # Returns decrypted message as a `String`. - # - # Optionally supply a destination buffer. - def decrypt_string(src, dst : Bytes? = nil, *, nonce : Nonce) : String - msg = decrypt src.to_slice, dst, nonce: nonce - String.new msg + def decrypt_string(src, *, nonce : Nonce) : String + dsize = src.bytesize - MAC_SIZE + String.new(dsize) do |dst| + decrypt src.to_slice, dst.to_slice(dsize), nonce: nonce + {dsize, dsize} + end end # :nodoc: