| 1 | // Test vectors adapted from the Go x/crypto argon2 package. |
| 2 | module argon2 |
| 3 | |
| 4 | import encoding.hex |
| 5 | |
| 6 | const gen_kat_password = [ |
| 7 | u8(0x01), |
| 8 | 0x01, |
| 9 | 0x01, |
| 10 | 0x01, |
| 11 | 0x01, |
| 12 | 0x01, |
| 13 | 0x01, |
| 14 | 0x01, |
| 15 | 0x01, |
| 16 | 0x01, |
| 17 | 0x01, |
| 18 | 0x01, |
| 19 | 0x01, |
| 20 | 0x01, |
| 21 | 0x01, |
| 22 | 0x01, |
| 23 | 0x01, |
| 24 | 0x01, |
| 25 | 0x01, |
| 26 | 0x01, |
| 27 | 0x01, |
| 28 | 0x01, |
| 29 | 0x01, |
| 30 | 0x01, |
| 31 | 0x01, |
| 32 | 0x01, |
| 33 | 0x01, |
| 34 | 0x01, |
| 35 | 0x01, |
| 36 | 0x01, |
| 37 | 0x01, |
| 38 | 0x01, |
| 39 | ]! |
| 40 | const gen_kat_salt = [ |
| 41 | u8(0x02), |
| 42 | 0x02, |
| 43 | 0x02, |
| 44 | 0x02, |
| 45 | 0x02, |
| 46 | 0x02, |
| 47 | 0x02, |
| 48 | 0x02, |
| 49 | 0x02, |
| 50 | 0x02, |
| 51 | 0x02, |
| 52 | 0x02, |
| 53 | 0x02, |
| 54 | 0x02, |
| 55 | 0x02, |
| 56 | 0x02, |
| 57 | ]! |
| 58 | const gen_kat_secret = [u8(0x03), 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03]! |
| 59 | const gen_kat_aad = [u8(0x04), 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04]! |
| 60 | |
| 61 | struct TestVector { |
| 62 | mode int |
| 63 | time u32 |
| 64 | memory u32 |
| 65 | threads u8 |
| 66 | hash string |
| 67 | } |
| 68 | |
| 69 | const test_vectors = [ |
| 70 | TestVector{ |
| 71 | mode: argon2_i |
| 72 | time: 1 |
| 73 | memory: 64 |
| 74 | threads: 1 |
| 75 | hash: 'b9c401d1844a67d50eae3967dc28870b22e508092e861a37' |
| 76 | }, |
| 77 | TestVector{ |
| 78 | mode: argon2_d |
| 79 | time: 1 |
| 80 | memory: 64 |
| 81 | threads: 1 |
| 82 | hash: '8727405fd07c32c78d64f547f24150d3f2e703a89f981a19' |
| 83 | }, |
| 84 | TestVector{ |
| 85 | mode: argon2_id |
| 86 | time: 1 |
| 87 | memory: 64 |
| 88 | threads: 1 |
| 89 | hash: '655ad15eac652dc59f7170a7332bf49b8469be1fdb9c28bb' |
| 90 | }, |
| 91 | TestVector{ |
| 92 | mode: argon2_id |
| 93 | time: 2 |
| 94 | memory: 64 |
| 95 | threads: 2 |
| 96 | hash: '350ac37222f436ccb5c0972f1ebd3bf6b958bf2071841362' |
| 97 | }, |
| 98 | TestVector{ |
| 99 | mode: argon2_i |
| 100 | time: 3 |
| 101 | memory: 256 |
| 102 | threads: 2 |
| 103 | hash: 'f5bbf5d4c3836af13193053155b73ec7476a6a2eb93fd5e6' |
| 104 | }, |
| 105 | TestVector{ |
| 106 | mode: argon2_id |
| 107 | time: 4 |
| 108 | memory: 1024 |
| 109 | threads: 8 |
| 110 | hash: '8dafa8e004f8ea96bf7c0f93eecf67a6047476143d15577f' |
| 111 | }, |
| 112 | ]! |
| 113 | |
| 114 | fn test_argon2_known_answer_vectors() { |
| 115 | want_d := hex.decode('512b391b6f1162975371d30919734294f868e3be3984f3c1a13a4db9fabe4acb')! |
| 116 | got_d := derive_key(argon2_d, gen_kat_password[..], gen_kat_salt[..], gen_kat_secret[..], |
| 117 | gen_kat_aad[..], 3, 32, 4, u32(want_d.len))! |
| 118 | assert got_d == want_d |
| 119 | |
| 120 | want_i := hex.decode('c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016dd388d29952a4c4672b6ce8')! |
| 121 | got_i := derive_key(argon2_i, gen_kat_password[..], gen_kat_salt[..], gen_kat_secret[..], |
| 122 | gen_kat_aad[..], 3, 32, 4, u32(want_i.len))! |
| 123 | assert got_i == want_i |
| 124 | |
| 125 | want_id := hex.decode('0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659')! |
| 126 | got_id := derive_key(argon2_id, gen_kat_password[..], gen_kat_salt[..], gen_kat_secret[..], |
| 127 | gen_kat_aad[..], 3, 32, 4, u32(want_id.len))! |
| 128 | assert got_id == want_id |
| 129 | } |
| 130 | |
| 131 | fn test_argon2_reference_vectors() { |
| 132 | password := 'password'.bytes() |
| 133 | salt := 'somesalt'.bytes() |
| 134 | for vector in test_vectors { |
| 135 | want := hex.decode(vector.hash)! |
| 136 | got := derive_key(vector.mode, password, salt, []u8{}, []u8{}, vector.time, vector.memory, |
| 137 | vector.threads, u32(want.len))! |
| 138 | assert got == want |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | fn test_generate_from_password_and_compare() { |
| 143 | params := Params{ |
| 144 | time: 2 |
| 145 | memory: 64 |
| 146 | threads: 1 |
| 147 | key_len: 24 |
| 148 | salt_len: 16 |
| 149 | } |
| 150 | password := 'correct horse battery staple'.bytes() |
| 151 | hash := generate_from_password_with_params(password, params)! |
| 152 | assert hash.starts_with('\$argon2id\$v=19\$m=64,t=2,p=1\$') |
| 153 | compare_hash_and_password(password, hash.bytes())! |
| 154 | compare_hash_and_password('incorrect'.bytes(), hash.bytes()) or { |
| 155 | assert err.msg() == 'mismatched hash and password' |
| 156 | return |
| 157 | } |
| 158 | assert false |
| 159 | } |
| 160 | |
| 161 | fn test_generate_from_password_uses_defaults() { |
| 162 | hash := generate_from_password('hunter2'.bytes())! |
| 163 | assert hash.starts_with('\$argon2id\$v=19\$m=65536,t=3,p=4\$') |
| 164 | } |
| 165 | |