Add Pwhash test vectors from PyNaCl and RbNaCl.

Pwhash::Algorithm renamed to Mode to be more like other libsodium bindings.
Cryptobox#encrypt now returns {encrypted, nonce} identical to SecretBox.
master
Didactic Drunk 2019-07-01 10:37:45 -07:00
parent 92ac0ef6d4
commit 769e02e4c7
12 changed files with 500 additions and 24 deletions

View File

@ -34,7 +34,7 @@ Crystal bindings for the [libsodium API](https://libsodium.gitbook.io/doc/)
- [x] Complete libsodium implementation including `key`, `salt`, `personal` and fully selectable output sizes.
- [ ] [SipHash](https://libsodium.gitbook.io/doc/hashing/short-input_hashing)
- [Password Hashing](https://libsodium.gitbook.io/doc/password_hashing)
- [x] [Argon2](https://libsodium.gitbook.io/doc/password_hashing/the_argon2i_function) (Use for new applications)
- [x] [x] [Argon2](https://libsodium.gitbook.io/doc/password_hashing/the_argon2i_function) (Use for new applications)
- [ ] [Scrypt](https://libsodium.gitbook.io/doc/advanced/scrypt) (For compatibility with older applications)
- Other
- [x] [Key Derivation](https://libsodium.gitbook.io/doc/key_derivation)

View File

@ -0,0 +1,6 @@
# Reference data taken from libsodium's test/default/box_seed.c
# and test/default/box_seed.exp.
# The seed comes from box_seed.c, the public and secret keys
# come from box_seed.exp where they are directly concatenated.
# Fmt: <seed> <tab> <public_key> || <secret_key>
77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a ed7749b4d989f6957f3bfde6c56767e988e21c9f8784d91d610011cd553f9b06accd44eb8e93319c0570bc11005c0e0189d34ff02f6c17773411ad191293c98f

View File

@ -0,0 +1,92 @@
[
{
"passwd": "gCb0SBnpxkdLZdWe",
"mode": "crypt",
"dgst_len": 20,
"iters": 4,
"salt": "kSmmBSy5uyC4",
"pwhash": "$argon2i$v=19$m=131072,t=4,p=1$a1NtbUJTeTV1eUM0$gNxxt8jHCHaKDUcbdP3ugX9i+BA",
"maxmem": 131072
},
{
"passwd": "mu3KbBv3",
"mode": "crypt",
"dgst_len": 17,
"iters": 4,
"salt": "kvPMDFk4yT9sZI",
"pwhash": "$argon2i$v=19$m=32768,t=4,p=1$a3ZQTURGazR5VDlzWkk$V+L2XhLr+F/EevADgyfo+bM",
"maxmem": 32768
},
{
"passwd": "Bxrsg5L0A0",
"mode": "crypt",
"dgst_len": 17,
"iters": 3,
"salt": "Z5c5VUWXSJcSbr",
"pwhash": "$argon2i$v=19$m=65536,t=3,p=1$WjVjNVZVV1hTSmNTYnI$BqyrFpvLJUCFaf9cQAFH1Ms",
"maxmem": 65536
},
{
"passwd": "EQmTLQ2ET",
"mode": "crypt",
"dgst_len": 30,
"iters": 3,
"salt": "8aWdz2IL",
"pwhash": "$argon2i$v=19$m=32768,t=3,p=1$OGFXZHoySUw$U6F0Tm/c/gyjJyMi4SWjLS+8dpuiKFK0OZje6iEZ",
"maxmem": 32768
},
{
"passwd": "9wQdHVSks3tbXx",
"mode": "crypt",
"dgst_len": 19,
"iters": 5,
"salt": "HW4AgInQoU",
"pwhash": "$argon2i$v=19$m=65536,t=5,p=1$SFc0QWdJblFvVQ$IwHIJ6VP1vIV7xrKm+mlI1nupA",
"maxmem": 65536
},
{
"passwd": "XRGHrq53wJ1LWgV",
"mode": "crypt",
"dgst_len": 27,
"iters": 5,
"salt": "Dr57DsF3",
"pwhash": "$argon2i$v=19$m=131072,t=5,p=1$RHI1N0RzRjM$shLAeDv4NbeHN9Sce+jaoEHIjUTP6OnGOtZ1",
"maxmem": 131072
},
{
"passwd": "JVoDvUkiJgtm",
"mode": "crypt",
"dgst_len": 17,
"iters": 5,
"salt": "C5jzAUY8D",
"pwhash": "$argon2i$v=19$m=131072,t=5,p=1$QzVqekFVWThE$SqZ2XYLggynRZgYlsWFiXGI",
"maxmem": 131072
},
{
"passwd": "eZf6zOck",
"mode": "crypt",
"dgst_len": 16,
"iters": 3,
"salt": "ID0CNHQR",
"pwhash": "$argon2i$v=19$m=65536,t=3,p=1$SUQwQ05IUVI$ShibIsTX2z5mclt4TKyAkQ",
"maxmem": 65536
},
{
"passwd": "nPeXb5WW",
"mode": "crypt",
"dgst_len": 26,
"iters": 5,
"salt": "DibJwvJWarySIIic",
"pwhash": "$argon2i$v=19$m=16384,t=5,p=1$RGliSnd2SldhcnlTSUlpYw$3n/DLofidmz8LPnM925hbm+4He/iKjAlvG4",
"maxmem": 16384
},
{
"passwd": "Vgv3CCRnqkgTO2co",
"mode": "crypt",
"dgst_len": 17,
"iters": 5,
"salt": "MfmTsCzom",
"pwhash": "$argon2i$v=19$m=131072,t=5,p=1$TWZtVHNDem9t$1W2xtNO3w3BylGxOHuX/IZ0",
"maxmem": 131072
}
]

View File

@ -0,0 +1,102 @@
[
{
"iters": 1,
"maxmem": 131072,
"dgst_len": 30,
"passwd": "6GaBkxnU",
"salt": "SIWAuVklLU",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=131072,t=1,p=1$U0lXQXVWa2xMVQ$+EaGmstgtSas9elKIXLVqcybaYJIBWifLeLWkFAZ",
"mode": "crypt"
},
{
"iters": 3,
"maxmem": 65536,
"dgst_len": 31,
"passwd": "JU1K5W8rzP1K",
"salt": "9Jve1X5OQ2tp",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=65536,t=3,p=1$OUp2ZTFYNU9RMnRw$7yApdAtgdaPQZWisUa58lb328fR+kgznHqQqcafaCg",
"mode": "crypt"
},
{
"iters": 2,
"maxmem": 131072,
"dgst_len": 20,
"passwd": "zBqdT3A3WReQFO",
"salt": "ahTuAAVQ6",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=131072,t=2,p=1$YWhUdUFBVlE2$jLdOXTu7R5XVuLKyHoEKVojIYsM",
"mode": "crypt"
},
{
"iters": 5,
"maxmem": 262144,
"dgst_len": 30,
"passwd": "FF3gKe0hL",
"salt": "XYpBw246J",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=262144,t=5,p=1$WFlwQncyNDZK$8D7TbKnOi9PMuhooK9HUJLTKdPBXD9CZ5/dE4p0r",
"mode": "crypt"
},
{
"iters": 4,
"maxmem": 131072,
"dgst_len": 20,
"passwd": "tUhcdnSMH",
"salt": "qGQAKPomg08",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=131072,t=4,p=1$cUdRQUtQb21nMDg$7kj3MDpz4aOZazen9BrazcIiMQE",
"mode": "crypt"
},
{
"iters": 5,
"maxmem": 131072,
"dgst_len": 19,
"passwd": "oxx700QV8RVHQA2l",
"salt": "r8R7NqsNyb",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=131072,t=5,p=1$cjhSN05xc055Yg$yHz0aPvCukbkMw1oXaKejEkG6Q",
"mode": "crypt"
},
{
"iters": 4,
"maxmem": 262144,
"dgst_len": 27,
"passwd": "zTKzEfuKI4",
"salt": "ajbUgkhOX9bxaD",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=262144,t=4,p=1$YWpiVWdraE9YOWJ4YUQ$h0NTYkqWF6qEpVnLP4Bqsk7oYjG4DNyn6+q0",
"mode": "crypt"
},
{
"iters": 2,
"maxmem": 65536,
"dgst_len": 21,
"passwd": "DicnLJsOvUTGBSAx",
"salt": "djp2efSTgmrz",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=65536,t=2,p=1$ZGpwMmVmU1RnbXJ6$Ar5DxZsxCAjUrGrBZPsa0vOVhjvk",
"mode": "crypt"
},
{
"iters": 1,
"maxmem": 32768,
"dgst_len": 30,
"passwd": "HyURt4Ofuwivg8",
"salt": "9tArBEgW8GU",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=32768,t=1,p=1$OXRBckJFZ1c4R1U$l/6y/kKeMPSk3WQb+bM4ir3bGj5yxj+/r6Wi/D8A",
"mode": "crypt"
},
{
"iters": 2,
"maxmem": 65536,
"dgst_len": 31,
"passwd": "ikt3keViPK0S",
"salt": "4Wh4LpHrUy",
"construct": "argon2id",
"pwhash": "$argon2id$v=19$m=65536,t=2,p=1$NFdoNExwSHJVeQ$MrbDWj1XHpotj2+n6vs5KF+2E0oUGt9Ge/mo0IJ0tA",
"mode": "crypt"
}
]

View File

@ -0,0 +1,92 @@
[
{
"passwd": "5qflFfSWpOvQ",
"mode": "raw",
"dgst_len": 20,
"iters": 5,
"salt": "QIA9x2qmhRVmdRCU",
"pwhash": "3eb202f3e4b0e2c078031f724103ea526fe2a065",
"maxmem": 16384
},
{
"passwd": "pf1SMoxVb54r",
"mode": "raw",
"dgst_len": 26,
"iters": 4,
"salt": "NPBA55CsQp9wsWKy",
"pwhash": "b7173ea20f6eb6946d3044542fc75ef5dda0d9c94acf86d834ca",
"maxmem": 131072
},
{
"passwd": "bg9Laxjhrk8MUyhM",
"mode": "raw",
"dgst_len": 18,
"iters": 4,
"salt": "exKErRXWGdCDRSop",
"pwhash": "9c7957beb49f1c5e868d6a04f34d1da821f6",
"maxmem": 65536
},
{
"passwd": "n95X5vWQncMXlP",
"mode": "raw",
"dgst_len": 17,
"iters": 3,
"salt": "gxSD9VHiGF0oou1k",
"pwhash": "b605e0557e9f57455f246e474e93648595",
"maxmem": 32768
},
{
"passwd": "5G8iiXVYwI",
"mode": "raw",
"dgst_len": 29,
"iters": 4,
"salt": "GcjAUSZ4pLAZsDHL",
"pwhash": "5fa4d3b86c8ca981dbc3ea4cbbd015030bda8bd444d4039309e88b23c7",
"maxmem": 32768
},
{
"passwd": "cUu3ACKqAHnI54Eh",
"mode": "raw",
"dgst_len": 23,
"iters": 3,
"salt": "6H99IAjhJQ2WFgom",
"pwhash": "6202e1b58e65a658d1adcc0584fafd6373e565d6fd8348",
"maxmem": 32768
},
{
"passwd": "jBB3PBZ8v1H1aga",
"mode": "raw",
"dgst_len": 20,
"iters": 4,
"salt": "L3vcnvwJbLJTdvKx",
"pwhash": "f3d792b3edbf49441c269c22c2641e724cb21ef0",
"maxmem": 16384
},
{
"passwd": "WGA58n0DVW9FT",
"mode": "raw",
"dgst_len": 18,
"iters": 3,
"salt": "qN6Q3h3lzJtXcMkH",
"pwhash": "ec9dd7f5503cc5b74ab1fc8ac6cad426327f",
"maxmem": 65536
},
{
"passwd": "rxB2Op3fo17s6",
"mode": "raw",
"dgst_len": 27,
"iters": 5,
"salt": "xw9IrU6uf4E4hBo3",
"pwhash": "ffe9c857e686ab40f8758415acd6d3409acfe80d54bac24bcacfa3",
"maxmem": 65536
},
{
"passwd": "JyjdXkjHxGiGjg",
"mode": "raw",
"dgst_len": 30,
"iters": 5,
"salt": "rN0D8NoVbNBnlEex",
"pwhash": "fab6d8b5e1849c99f5261c15ff502b1bb245f8076efa5e01cbbdc1903512",
"maxmem": 32768
}
]

View File

@ -0,0 +1,102 @@
[
{
"iters": 1,
"mode": "raw",
"salt": "RPgjpKWKmH7otL58",
"dgst_len": 25,
"construct": "argon2id",
"passwd": "jfuT8oJu2Fg",
"pwhash": "959f27c6ac7a7f9d4cebb7bb1cc05833810079e4e384f687a7",
"maxmem": 131072
},
{
"iters": 4,
"mode": "raw",
"salt": "hsvjdI3ckgfMke6x",
"dgst_len": 19,
"construct": "argon2id",
"passwd": "J2TU89T68L",
"pwhash": "f45619dcd98553c38a4f311904a06e888dd5dd",
"maxmem": 32768
},
{
"iters": 3,
"mode": "raw",
"salt": "oCSdi7b6I3UYftj6",
"dgst_len": 23,
"construct": "argon2id",
"passwd": "ZTgoKeVg",
"pwhash": "823cd743a9378b0013a61b275d8a8d61b4abf465e3c758",
"maxmem": 65536
},
{
"iters": 3,
"mode": "raw",
"salt": "BcZv9BmKSL1BZXBD",
"dgst_len": 25,
"construct": "argon2id",
"passwd": "3bDtmljuB86",
"pwhash": "a667a360356b3658656cc51feda5abc3c9932d1e3b4a398633",
"maxmem": 16384
},
{
"iters": 5,
"mode": "raw",
"salt": "hqiuuNWIOLHft77r",
"dgst_len": 20,
"construct": "argon2id",
"passwd": "410nLopRL2Pt6yT",
"pwhash": "7274d6a9be2b52feab9b346df1abee1a68ec5c79",
"maxmem": 65536
},
{
"iters": 1,
"mode": "raw",
"salt": "ZP3u5yVZTAl0F33z",
"dgst_len": 31,
"construct": "argon2id",
"passwd": "0pXnCEpVlR",
"pwhash": "d14d136cae8ca735e0fe03d2c618f904cff07a525579d0dc67d813b223ac7a",
"maxmem": 32768
},
{
"iters": 3,
"mode": "raw",
"salt": "QWWo5rUeD3nBv0dF",
"dgst_len": 28,
"construct": "argon2id",
"passwd": "vl50xKRCK0EHNRY",
"pwhash": "23560c5771bb56d02c8129effd4ff2c70d2f28e1912636ff1a4f11a6",
"maxmem": 262144
},
{
"iters": 5,
"mode": "raw",
"salt": "OADldcmnqJHY6tkc",
"dgst_len": 24,
"construct": "argon2id",
"passwd": "EuXIuKCdFq",
"pwhash": "bae0f9ff8143a141bfb8b8629414eba2c51f122b2524e73d",
"maxmem": 65536
},
{
"iters": 2,
"mode": "raw",
"salt": "cxYQAFWsKbji4Y0e",
"dgst_len": 30,
"construct": "argon2id",
"passwd": "2su5ROWRMZLOOWbv",
"pwhash": "6341329de527593dbd479e24ca02b7f6bfcc29a6c74def655db74808e199",
"maxmem": 32768
},
{
"iters": 1,
"mode": "raw",
"salt": "Zk6vLoBZZA8lgzKL",
"dgst_len": 19,
"construct": "argon2id",
"passwd": "7mPYiXjrwLw",
"pwhash": "84dc96e740c84cc52855c3f7c1b5b05070d14a",
"maxmem": 65536
}
]

View File

@ -0,0 +1,6 @@
# generated reference vectors for crypto_seal_box
# Format: <recipient sk> <tab> <recipient pk> <tab> <pt_len>:<plaintext> <tab> <cr_len>:<ciphertext> [<tab> ...]
# all fields are hex encoded
77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a 8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a 131:be075fc53c81f2d5cf141316ebeb0c7b5228c52a4c62cbd44b66849b64244ffce5ecbaaf33bd751a1ac728d45e6c61296cdc3c01233561f41db66cce314adb310e3be8250c46f06dceea3a7fa1348057e2f6556ad6b1318a024a838f21af1fde048977eb48f59ffd4924ca1c60902e52f0a089bc76897040e082f937763848645e0705 179:199c808806a62c1be56951023ad3396b0ce0ef2c5b9ca688ac96d2d06ca43f65d314400cc9bbefb23dd26f824c9cb553f81e8c894ea9a553f4d777c77b66d5a6925da3f5961c5f7147172db5597ac14210066ee3ee13e6230a9a9610e9cddbf24094f54fbbf6694c08a436cec39ff5a373656d9584f4df9dd8c817e2e597540628d0ee21a6524a3fcf3eabdc0968390bd260a47366ead7f71cc2e774d411d96f3497c7e10291937bc16dc46a111686b85a8c86
7fdc652e0f714cc6f6d5f7bf1aab9da7fcaa5b27f1f7763f31a659cc6ddd60d5 695ec87c37afbb70771a1a048e08d7c70a25b7d710e23a5814248128f3db035d 0: 48:017f873a1536b35eac54f729e0f05ea5c5a96f9c221327d70bf46497b3b33007a84d0b93667ea189ad4dfcc016f727d1
1bcdb90ac2996d3e5598a404fd8753bae482ec821a64e306e15416228bae7212 6415b1fe7bb4dc602097f607249df89eb59cf2e75be1cb74abfc0664dc0f0a3d 1:eb 49:dbe788125ef86d2d4049feb371cf25e2a52a0d71505eeb2ebff526e859e6495c3c278fa7ba88e41c92c711a0ddbd3bdf09

View File

@ -40,7 +40,7 @@ describe Sodium::CryptoBox::SecretKey do
# Encrypt a message for Bob using his public key, signing it with Alice's
# secret key
box = alice.box bob.public_key
nonce, encrypted = box.encrypt_easy data
encrypted, nonce = box.encrypt_easy data
# Decrypt the message using Bob's secret key, and verify its signature against
# Alice's public key

View File

@ -1,5 +1,47 @@
require "../spec_helper"
require "../../src/sodium/pwhash"
require "json"
def test_vectors(filename, pwmode)
pwhash = Sodium::Pwhash.new
buf = File.read Path[__DIR__].join("..", "data", filename)
vectors = Array(Hash(String, String | Int32)).from_json(buf).map do |h|
{
salt: h["salt"].to_s,
pass: h["passwd"].to_s,
mode: h["mode"].to_s,
ops: h["iters"].to_i,
mem: h["maxmem"].to_i * 1024,
dgst_len: h["dgst_len"].to_i,
hash: h["pwhash"].to_s,
# h: h,
}
end
vectors.each do |h|
case h[:mode]
when "argon2i"
pwhash.mode = Sodium::Pwhash::Mode::Argon2i13
pwhash.verify h[:hash], h[:pass]
when "argon2id"
pwhash.mode = Sodium::Pwhash::Mode::Argon2id13
pwhash.verify h[:hash], h[:pass]
when "raw"
pwhash.opslimit = h[:ops].to_u64
pwhash.memlimit = h[:mem].to_u64
pwhash.mode = pwmode
# p pwhash, h
key = pwhash.key_derive salt: h[:salt].to_slice, pass: h[:pass], key_bytes: h[:dgst_len]
key.should eq h[:hash].hexbytes
else
# p h
puts "unhandled mode #{h[:mode]}"
next
# raise "unhandled mode #{h[:mode]}"
end
end
end
private def pw_min
pwhash = Sodium::Pwhash.new
@ -26,7 +68,7 @@ describe Sodium::Pwhash do
pwhash.needs_rehash?(hash).should be_true
end
it "key_derive fails without an algorithm" do
it "key_derive fails without a mode" do
pwhash = pw_min
expect_raises(ArgumentError) do
pwhash.key_derive pwhash.salt, "foo", 16
@ -35,7 +77,7 @@ describe Sodium::Pwhash do
it "derives a key from a password" do
pwhash = pw_min
pwhash.algorithm = Sodium::Pwhash::Algorithm::Argon2id13
pwhash.mode = Sodium::Pwhash::Mode::Argon2id13
salt = pwhash.salt
key1 = pwhash.key_derive salt, "foo", 16
key2 = pwhash.key_derive salt, "foo", 16
@ -46,6 +88,35 @@ describe Sodium::Pwhash do
key1.should eq key2
key1.should_not eq key3
key1.should_not eq key4
# BUG: validate against known passwords
end
it "PyNaCl key vectors" do
test_vectors "modular_crypt_argon2i_hashes.json", Sodium::Pwhash::Mode::Argon2i13
test_vectors "modular_crypt_argon2id_hashes.json", Sodium::Pwhash::Mode::Argon2id13
test_vectors "raw_argon2i_hashes.json", Sodium::Pwhash::Mode::Argon2i13
test_vectors "raw_argon2id_hashes.json", Sodium::Pwhash::Mode::Argon2id13
end
# from libsodium/test/default/pwhash_argon2id.c
it "RbNaCl key vectors" do
pwhash = Sodium::Pwhash.new
pwhash.mode = Sodium::Pwhash::Mode::Argon2id13
pwhash.opslimit = 5_u64
pwhash.memlimit = 7_256_678_u64
key_len = 155
pass = "a347ae92bce9f80f6f595a4480fc9c2fe7e7d7148d371e9487d75f5c23008ffae0" \
"65577a928febd9b1973a5a95073acdbeb6a030cfc0d79caa2dc5cd011cef02c08d" \
"a232d76d52dfbca38ca8dcbd665b17d1665f7cf5fe59772ec909733b24de97d6f5" \
"8d220b20c60d7c07ec1fd93c52c31020300c6c1facd77937a597c7a6".hexbytes
salt = "5541fbc995d5c197ba290346d2c559de".hexbytes
expected = "18acec5d6507739f203d1f5d9f1d862f7c2cdac4f19d2bdff64487e60d969e3ced6" \
"15337b9eec6ac4461c6ca07f0939741e57c24d0005c7ea171a0ee1e7348249d135b" \
"38f222e4dad7b9a033ed83f5ca27277393e316582033c74affe2566a2bea47f91f0" \
"fd9fe49ece7e1f79f3ad6e9b23e0277c8ecc4b313225748dd2a80f5679534a0700e" \
"246a79a49b3f74eb89ec6205fe1eeb941c73b1fcf1".hexbytes
key = pwhash.key_derive salt, pass, key_len
key.should eq expected
end
end

View File

@ -1,6 +1,7 @@
require "./lib_sodium"
require "./wipe"
require "./crypto_box/secret_key"
require "./nonce"
module Sodium
class CryptoBox
@ -24,7 +25,7 @@ module Sodium
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}
{dst, nonce}
end
def decrypt_easy(src)

View File

@ -20,10 +20,11 @@ module Sodium
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.
STR_SIZE = LibSodium.crypto_pwhash_strbytes
SALT_SIZE = LibSodium.crypto_pwhash_saltbytes
STR_SIZE = LibSodium.crypto_pwhash_strbytes
# Use the most recent algorithm Argon2id13 for new applications.
enum Algorithm
enum Mode
Argon2i13 = 1
Argon2id13 = 2
end
@ -33,7 +34,7 @@ module Sodium
property memlimit = MEMLIMIT_INTERACTIVE
# Used by and must be set before calling #key_derive
property algorithm : Algorithm?
property mode : Mode?
# Apply the most recent password hashing algorithm agains a password.
# Returns a opaque String which includes:
@ -73,28 +74,30 @@ module Sodium
end
end
# Returns a consistent key based on [salt, pass, key_bytes, algorithm, ops_limit, mem_limit]
# Returns a consistent key based on [salt, pass, key_bytes, mode, ops_limit, mem_limit]
#
# Must set an algorithm before calling.
def key_derive(salt : Bytes, pass : Bytes, key_bytes) : Bytes
if alg = algorithm
key = Bytes.new key_bytes
if LibSodium.crypto_pwhash(key, key.bytesize, pass, pass.bytesize, salt, @opslimit, @memlimit, alg) != 0
raise Sodium::Error.new("crypto_pwhash_str")
end
key
else
raise ArgumentError.new("algorithm not set")
end
end
# Must set a mode before calling.
def key_derive(salt, pass, key_bytes)
key_derive salt.to_slice, pass.to_slice, key_bytes
end
def key_derive(salt : Bytes, pass : Bytes, key_bytes) : Bytes
raise "salt expected #{SALT_SIZE} bytes, got #{salt.bytesize} " if salt.bytesize != SALT_SIZE
if m = mode
key = Bytes.new key_bytes
if LibSodium.crypto_pwhash(key, key.bytesize, pass, pass.bytesize, salt, @opslimit, @memlimit, m) != 0
raise Sodium::Error.new("crypto_pwhash_str")
end
key
else
raise ArgumentError.new("mode not set")
end
end
# Returns a random salt for use with #key_derive
def salt
Random::Secure.random_bytes LibSodium.crypto_pwhash_saltbytes
Random::Secure.random_bytes SALT_SIZE
end
end
end

View File

@ -1,5 +1,6 @@
require "./lib_sodium"
require "./key"
require "./nonce"
module Sodium
# [https://libsodium.gitbook.io/doc/secret-key_cryptography](https://libsodium.gitbook.io/doc/secret-key_cryptography)