Rename Sodium::Pwhash#store to #create.

Rename Sodium::Pwhash#key_derive to #derive_key.
Rename Sodium::Pwhash#kdf_derive to #derive_kdf.
Rename Sodium::CryptoBox#encrypt_easy to #encrypt.
Rename Sodium::CryptoBox#decrypt_easy to #decrypt.
Rename Sodium::SecretBox#encrypt_easy to #encrypt.
Rename Sodium::SecretBox#decrypt_easy to #decrypt.

Remove redundant Sodium::SecretBox#encrypt methods.
master
Didactic Drunk 2019-08-06 03:30:16 -07:00
parent 8ca9dc6ff9
commit fde955c509
7 changed files with 58 additions and 64 deletions

View File

@ -184,11 +184,11 @@ public_key.verify_detached message, signature
key = Sodium::SecretKey.new key = Sodium::SecretKey.new
message = "foobar" message = "foobar"
encrypted, nonce = key.encrypt_easy message encrypted, nonce = key.encrypt message
# On the other side. # On the other side.
key = Sodium::SecretKey.new key key = Sodium::SecretKey.new key
message = key.decrypt_easy encrypted, nonce message = key.decrypt encrypted, nonce
``` ```
### Blake2b ### Blake2b

View File

@ -73,12 +73,12 @@ describe Sodium::CryptoBox::SecretKey do
# Encrypt a message for Bob using his public key, signing it with Alice's # Encrypt a message for Bob using his public key, signing it with Alice's
# secret key # secret key
box = alice.box bob.public_key box = alice.box bob.public_key
encrypted, nonce = box.encrypt_easy data encrypted, nonce = box.encrypt data
# Decrypt the message using Bob's secret key, and verify its signature against # Decrypt the message using Bob's secret key, and verify its signature against
# Alice's public key # Alice's public key
bob.box alice.public_key do |box| bob.box alice.public_key do |box|
decrypted = box.decrypt_easy encrypted, nonce: nonce decrypted = box.decrypt encrypted, nonce: nonce
String.new(decrypted).should eq(data) String.new(decrypted).should eq(data)
end end
@ -102,10 +102,10 @@ describe Sodium::CryptoBox::SecretKey do
it "PyNaCl combined test vectors" do it "PyNaCl combined test vectors" do
combined_test_vectors.each do |vec| combined_test_vectors.each do |vec|
box_from_vec(vec) do |box1, box2, nonce, plaintext, ciphertext| box_from_vec(vec) do |box1, box2, nonce, plaintext, ciphertext|
encrypted, _ = box1.encrypt_easy plaintext, nonce: nonce encrypted, _ = box1.encrypt plaintext, nonce: nonce
encrypted.should eq ciphertext encrypted.should eq ciphertext
decrypted = box2.decrypt_easy ciphertext, nonce: nonce decrypted = box2.decrypt ciphertext, nonce: nonce
decrypted.should eq plaintext decrypted.should eq plaintext
end end
end end

View File

@ -1,5 +1,6 @@
require "../spec_helper" require "../spec_helper"
require "../../src/sodium/pwhash" require "../../src/sodium/pwhash"
require "../../src/sodium/kdf"
require "json" require "json"
def test_vectors(filename, pwmode) def test_vectors(filename, pwmode)
@ -32,7 +33,7 @@ def test_vectors(filename, pwmode)
pwhash.memlimit = h[:mem].to_u64 pwhash.memlimit = h[:mem].to_u64
pwhash.mode = pwmode pwhash.mode = pwmode
# p pwhash, h # p pwhash, h
key = pwhash.key_derive salt: h[:salt].to_slice, pass: h[:pass], key_bytes: h[:dgst_len] key = pwhash.derive_key salt: h[:salt].to_slice, pass: h[:pass], key_bytes: h[:dgst_len]
key.should eq h[:hash].hexbytes key.should eq h[:hash].hexbytes
else else
# p h # p h
@ -57,7 +58,7 @@ describe Sodium::Pwhash do
pwhash = pw_min pwhash = pw_min
pass = "1234" pass = "1234"
hash = pwhash.store pass hash = pwhash.create pass
pwhash.verify hash, pass pwhash.verify hash, pass
expect_raises(Sodium::Pwhash::PasswordVerifyError) do expect_raises(Sodium::Pwhash::PasswordVerifyError) do
pwhash.verify hash, "5678" pwhash.verify hash, "5678"
@ -68,10 +69,10 @@ describe Sodium::Pwhash do
pwhash.needs_rehash?(hash).should be_true pwhash.needs_rehash?(hash).should be_true
end end
it "key_derive fails without a mode" do it "derive_key fails without a mode" do
pwhash = pw_min pwhash = pw_min
expect_raises(ArgumentError) do expect_raises(ArgumentError) do
pwhash.key_derive pwhash.random_salt, "foo", 16 pwhash.derive_key pwhash.random_salt, "foo", 16
end end
end end
@ -79,10 +80,10 @@ describe Sodium::Pwhash do
pwhash = pw_min pwhash = pw_min
pwhash.mode = Sodium::Pwhash::Mode::Argon2id13 pwhash.mode = Sodium::Pwhash::Mode::Argon2id13
salt = pwhash.random_salt salt = pwhash.random_salt
key1 = pwhash.key_derive salt, "foo", 16 key1 = pwhash.derive_key salt, "foo", 16
key2 = pwhash.key_derive salt, "foo", 16 key2 = pwhash.derive_key salt, "foo", 16
key3 = pwhash.key_derive salt, "bar", 16 key3 = pwhash.derive_key salt, "bar", 16
key4 = pwhash.key_derive pwhash.random_salt, "foo", 16 key4 = pwhash.derive_key pwhash.random_salt, "foo", 16
key1.bytesize.should eq 16 key1.bytesize.should eq 16
key1.should eq key2 key1.should eq key2
@ -90,6 +91,13 @@ describe Sodium::Pwhash do
key1.should_not eq key4 key1.should_not eq key4
end end
it "derives a kdf from a password" do
pwhash = pw_min
pwhash.mode = Sodium::Pwhash::Mode::Argon2id13
salt = pwhash.random_salt
kdf = pwhash.derive_kdf salt, "foo", 32
end
it "PyNaCl key vectors" do it "PyNaCl key vectors" do
test_vectors "modular_crypt_argon2i_hashes.json", Sodium::Pwhash::Mode::Argon2i13 test_vectors "modular_crypt_argon2i_hashes.json", Sodium::Pwhash::Mode::Argon2i13
test_vectors "modular_crypt_argon2id_hashes.json", Sodium::Pwhash::Mode::Argon2id13 test_vectors "modular_crypt_argon2id_hashes.json", Sodium::Pwhash::Mode::Argon2id13
@ -116,7 +124,7 @@ describe Sodium::Pwhash do
"fd9fe49ece7e1f79f3ad6e9b23e0277c8ecc4b313225748dd2a80f5679534a0700e" \ "fd9fe49ece7e1f79f3ad6e9b23e0277c8ecc4b313225748dd2a80f5679534a0700e" \
"246a79a49b3f74eb89ec6205fe1eeb941c73b1fcf1".hexbytes "246a79a49b3f74eb89ec6205fe1eeb941c73b1fcf1".hexbytes
key = pwhash.key_derive salt, pass, key_len key = pwhash.derive_key salt, pass, key_len
key.should eq expected key.should eq expected
end end
end end

View File

@ -31,12 +31,12 @@ describe Sodium::SecretBox do
box = Sodium::SecretBox.new box = Sodium::SecretBox.new
message = "foobar" message = "foobar"
encrypted, nonce = box.encrypt_easy message encrypted, nonce = box.encrypt message
decrypted = box.decrypt_easy encrypted, nonce decrypted = box.decrypt encrypted, nonce: nonce
message.should eq String.new(decrypted) message.should eq String.new(decrypted)
expect_raises(Sodium::Error::DecryptionFailed) do expect_raises(Sodium::Error::DecryptionFailed) do
box.decrypt_easy "badmsgbadmsgbadmsgbadmsgbadmsg".to_slice, nonce box.decrypt "badmsgbadmsgbadmsgbadmsgbadmsg".to_slice, nonce
end end
end end
@ -44,10 +44,10 @@ describe Sodium::SecretBox do
combined_test_vectors.each do |vec| combined_test_vectors.each do |vec|
box, nonce, plaintext, ciphertext = box_from_test_vector vec box, nonce, plaintext, ciphertext = box_from_test_vector vec
encrypted = box.encrypt_easy plaintext, nonce encrypted, _ = box.encrypt plaintext, nonce: nonce
encrypted.should eq ciphertext encrypted.should eq ciphertext
decrypted = box.decrypt_easy encrypted, nonce decrypted = box.decrypt encrypted, nonce: nonce
plaintext.should eq decrypted plaintext.should eq decrypted
end end
end end

View File

@ -17,22 +17,22 @@ module Sodium
# TODO: precompute using crypto_box_beforenm # TODO: precompute using crypto_box_beforenm
end end
def encrypt_easy(src) def encrypt(src)
encrypt_easy src.to_slice encrypt src.to_slice
end end
def encrypt_easy(src : Bytes, dst = Bytes.new(src.bytesize + MAC_SIZE), nonce = Nonce.new) def encrypt(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 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") raise Error.new("crypto_box_easy")
end end
{dst, nonce} {dst, nonce}
end end
def decrypt_easy(src) def decrypt(src)
decrypt_easy src.to_slice decrypt src.to_slice
end end
def decrypt_easy(src : Bytes, dst = Bytes.new(src.bytesize - MAC_SIZE), nonce = Nonce.new) : Bytes 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 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") raise Error::DecryptionFailed.new("crypto_box_open_easy")
end end

View File

@ -4,7 +4,7 @@ require "./secure_buffer"
module Sodium module Sodium
# [Argon2 Password Hashing](https://libsodium.gitbook.io/doc/password_hashing/the_argon2i_function) # [Argon2 Password Hashing](https://libsodium.gitbook.io/doc/password_hashing/the_argon2i_function)
# * #store #verify #needs_rehash? are used together for password verification. # * #store #verify #needs_rehash? are used together for password verification.
# * #key_derive is used on it's own to generate password based keys. # * #derive_key is used on it's own to generate password based keys.
# #
# **See `examples/pwhash_selector.cr` for help on selecting parameters.** # **See `examples/pwhash_selector.cr` for help on selecting parameters.**
class Pwhash class Pwhash
@ -19,7 +19,8 @@ module Sodium
MEMLIMIT_MIN = LibSodium.crypto_pwhash_memlimit_min MEMLIMIT_MIN = LibSodium.crypto_pwhash_memlimit_min
MEMLIMIT_INTERACTIVE = LibSodium.crypto_pwhash_memlimit_interactive MEMLIMIT_INTERACTIVE = LibSodium.crypto_pwhash_memlimit_interactive
MEMLIMIT_MAX = LibSodium.crypto_pwhash_memlimit_max # Don't use this. Maximum of the library which is more ram than any computer. # Don't use this. Maximum of the library which is more ram than any computer.
MEMLIMIT_MAX = LibSodium.crypto_pwhash_memlimit_max
SALT_SIZE = LibSodium.crypto_pwhash_saltbytes SALT_SIZE = LibSodium.crypto_pwhash_saltbytes
STR_SIZE = LibSodium.crypto_pwhash_strbytes STR_SIZE = LibSodium.crypto_pwhash_strbytes
@ -34,7 +35,7 @@ module Sodium
# Specified in bytes. # Specified in bytes.
property memlimit = MEMLIMIT_INTERACTIVE property memlimit = MEMLIMIT_INTERACTIVE
# Used by and must be set before calling #key_derive # Used by and must be set before calling #derive_key
property mode : Mode? property mode : Mode?
# Apply the most recent password hashing algorithm agains a password. # Apply the most recent password hashing algorithm agains a password.
@ -42,7 +43,7 @@ module Sodium
# * the result of a memory-hard, CPU-intensive hash function applied to the password # * the result of a memory-hard, CPU-intensive hash function applied to the password
# * the automatically generated salt used for the previous computation # * the automatically generated salt used for the previous computation
# * the other parameters required to verify the password, including the algorithm identifier, its version, opslimit and memlimit. # * the other parameters required to verify the password, including the algorithm identifier, its version, opslimit and memlimit.
def store(pass) def create(pass)
outstr = Bytes.new STR_SIZE outstr = Bytes.new STR_SIZE
if LibSodium.crypto_pwhash_str(outstr, pass, pass.bytesize, @opslimit, @memlimit) != 0 if LibSodium.crypto_pwhash_str(outstr, pass, pass.bytesize, @opslimit, @memlimit) != 0
raise Sodium::Error.new("crypto_pwhash_str") raise Sodium::Error.new("crypto_pwhash_str")
@ -78,11 +79,11 @@ module Sodium
# Returns a consistent key based on [salt, pass, key_bytes, mode, ops_limit, mem_limit] in a SecureBuffer # Returns a consistent key based on [salt, pass, key_bytes, mode, ops_limit, mem_limit] in a SecureBuffer
# #
# Must set a mode before calling. # Must set a mode before calling.
def key_derive(salt, pass, key_bytes) def derive_key(salt, pass, key_bytes)
key_derive salt.to_slice, pass.to_slice, key_bytes derive_key salt.to_slice, pass.to_slice, key_bytes
end end
def key_derive(salt : Bytes, pass : Bytes, key_bytes) : SecureBuffer def derive_key(salt : Bytes, pass : Bytes, key_bytes) : SecureBuffer
raise "salt expected #{SALT_SIZE} bytes, got #{salt.bytesize} " if salt.bytesize != SALT_SIZE raise "salt expected #{SALT_SIZE} bytes, got #{salt.bytesize} " if salt.bytesize != SALT_SIZE
if m = mode if m = mode
@ -96,13 +97,13 @@ module Sodium
end end
end end
# Derives a key using key_derive and returns KDF.new(key) # Derives a key using derive_key and returns KDF.new(key)
def kdf_derive(salt, pass, key_bytes) : Kdf def derive_kdf(salt, pass, key_bytes) : Kdf
key = key_derive salt, pass, key_bytes key = derive_key salt, pass, key_bytes
Kdf.new key Kdf.new key
end end
# Returns a random salt for use with #key_derive # Returns a random salt for use with #derive_key
def random_salt def random_salt
Random::Secure.random_bytes SALT_SIZE Random::Secure.random_bytes SALT_SIZE
end end

View File

@ -9,11 +9,11 @@ module Sodium
# ```crystal # ```crystal
# key = Sodium::SecretBox.new # key = Sodium::SecretBox.new
# message = "foobar" # message = "foobar"
# encrypted, nonce = key.encrypt_easy message # encrypted, nonce = key.encrypt message
# #
# # On the other side. # # On the other side.
# key = Sodium::SecretBox.new key # key = Sodium::SecretBox.new key
# message = key.decrypt_easy encrypted, nonce # message = key.decrypt encrypted, nonce
# ``` # ```
class SecretBox < Key class SecretBox < Key
KEY_SIZE = LibSodium.crypto_secretbox_keybytes.to_i KEY_SIZE = LibSodium.crypto_secretbox_keybytes.to_i
@ -45,43 +45,28 @@ module Sodium
@buf = SecureBuffer.new bytes, erase: erase @buf = SecureBuffer.new bytes, erase: erase
end end
def encrypt_easy(data) def encrypt(data)
encrypt_easy data.to_slice encrypt data.to_slice
end end
def encrypt_easy(data, nonce : Nonce) def encrypt(src : Bytes, dst : Bytes = Bytes.new(src.bytesize + MAC_SIZE), nonce : Nonce = Nonce.new) : {Bytes, Nonce}
encrypt_easy data.to_slice, nonce
end
def encrypt_easy(data : Bytes)
nonce = Nonce.new
output = encrypt_easy data, nonce
{output, nonce}
end
def encrypt_easy(data : Bytes, nonce : Nonce) : Bytes
output = Bytes.new(data.bytesize + MAC_SIZE)
encrypt_easy(data, output, nonce)
end
def encrypt_easy(src : Bytes, dst : Bytes, nonce : Nonce) : Bytes
if dst.bytesize != (src.bytesize + MAC_SIZE) if dst.bytesize != (src.bytesize + MAC_SIZE)
raise ArgumentError.new("dst.bytesize must be src.bytesize + MAC_SIZE, got #{dst.bytesize}") raise ArgumentError.new("dst.bytesize must be src.bytesize + MAC_SIZE, got #{dst.bytesize}")
end end
if LibSodium.crypto_secretbox_easy(dst, src, src.bytesize, nonce.to_slice, self.to_slice) != 0 if LibSodium.crypto_secretbox_easy(dst, src, src.bytesize, nonce.to_slice, self.to_slice) != 0
raise Sodium::Error.new("crypto_secretbox_easy") raise Sodium::Error.new("crypto_secretbox_easy")
end end
dst {dst, nonce}
end end
def decrypt_easy(data : Bytes, nonce : Nonce) : Bytes def decrypt(src : Bytes, nonce : Nonce) : Bytes
output_size = data.bytesize - MAC_SIZE dst_size = src.bytesize - MAC_SIZE
raise Sodium::Error::DecryptionFailed.new("encrypted data too small #{data.bytesize}") if output_size <= 0 raise Sodium::Error::DecryptionFailed.new("encrypted data too small #{src.bytesize}") if dst_size <= 0
output = Bytes.new output_size dst = Bytes.new dst_size
decrypt_easy(data, output, nonce) decrypt(src, dst, nonce)
end end
def decrypt_easy(src : Bytes, dst : Bytes, nonce : Nonce) : Bytes def decrypt(src : Bytes, dst : Bytes, nonce : Nonce) : Bytes
if dst.bytesize != (src.bytesize - MAC_SIZE) if dst.bytesize != (src.bytesize - MAC_SIZE)
raise ArgumentError.new("dst.bytesize must be src.bytesize - MAC_SIZE, got #{dst.bytesize}") raise ArgumentError.new("dst.bytesize must be src.bytesize - MAC_SIZE, got #{dst.bytesize}")
end end