1package argon2 2 3import ( 4 "bytes" 5 "encoding/hex" 6 "testing" 7) 8 9func TestHash(t *testing.T) { 10 vectors := []struct { 11 ctx *Context 12 password []byte 13 salt []byte 14 hash string 15 }{ 16 17 { 18 &Context{ 19 Iterations: 3, 20 Memory: 1 << 5, 21 Parallelism: 4, 22 Secret: bytes.Repeat([]byte{3}, 8), 23 AssociatedData: bytes.Repeat([]byte{4}, 12), 24 HashLen: 32, 25 Mode: ModeArgon2i, 26 Version: Version10, 27 }, 28 bytes.Repeat([]byte{1}, 32), 29 bytes.Repeat([]byte{2}, 16), 30 "87aeedd6517ab830cd9765cd8231abb2e647a5dee08f7c05e02fcb763335d0fd", 31 }, 32 { 33 &Context{ 34 Iterations: 3, 35 Memory: 1 << 5, 36 Parallelism: 4, 37 Secret: bytes.Repeat([]byte{3}, 8), 38 AssociatedData: bytes.Repeat([]byte{4}, 12), 39 HashLen: 32, 40 Mode: ModeArgon2i, 41 Version: Version13, 42 }, 43 bytes.Repeat([]byte{1}, 32), 44 bytes.Repeat([]byte{2}, 16), 45 "c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016dd388d29952a4c4672b6ce8", 46 }, 47 { 48 &Context{ 49 Iterations: 3, 50 Memory: 1 << 5, 51 Parallelism: 4, 52 Secret: bytes.Repeat([]byte{3}, 8), 53 AssociatedData: bytes.Repeat([]byte{4}, 12), 54 HashLen: 32, 55 Mode: ModeArgon2d, 56 Version: Version10, 57 }, 58 bytes.Repeat([]byte{1}, 32), 59 bytes.Repeat([]byte{2}, 16), 60 "96a9d4e5a1734092c85e29f410a45914a5dd1f5cbf08b2670da68a0285abf32b", 61 }, 62 { 63 &Context{ 64 Iterations: 3, 65 Memory: 1 << 5, 66 Parallelism: 4, 67 Secret: bytes.Repeat([]byte{3}, 8), 68 AssociatedData: bytes.Repeat([]byte{4}, 12), 69 HashLen: 32, 70 Mode: ModeArgon2d, 71 Version: Version13, 72 }, 73 bytes.Repeat([]byte{1}, 32), 74 bytes.Repeat([]byte{2}, 16), 75 "512b391b6f1162975371d30919734294f868e3be3984f3c1a13a4db9fabe4acb", 76 }, 77 { 78 &Context{ 79 Iterations: 3, 80 Memory: 1 << 5, 81 Parallelism: 4, 82 Secret: bytes.Repeat([]byte{3}, 8), 83 AssociatedData: bytes.Repeat([]byte{4}, 12), 84 HashLen: 32, 85 Mode: ModeArgon2id, 86 Version: Version10, 87 }, 88 bytes.Repeat([]byte{1}, 32), 89 bytes.Repeat([]byte{2}, 16), 90 "b64615f07789b66b645b67ee9ed3b377ae350b6bfcbb0fc95141ea8f322613c0", 91 }, 92 { 93 &Context{ 94 Iterations: 3, 95 Memory: 1 << 5, 96 Parallelism: 4, 97 Secret: bytes.Repeat([]byte{3}, 8), 98 AssociatedData: bytes.Repeat([]byte{4}, 12), 99 HashLen: 32, 100 Mode: ModeArgon2id, 101 Version: Version13, 102 }, 103 bytes.Repeat([]byte{1}, 32), 104 bytes.Repeat([]byte{2}, 16), 105 "0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659", 106 }, 107 } 108 109 for i, v := range vectors { 110 expected, _ := hex.DecodeString(v.hash) 111 hash, err := Hash(v.ctx, v.password, v.salt) 112 if err != nil { 113 t.Errorf("received error: %s (%d)", err, i) 114 } 115 if !bytes.Equal(hash, expected) { 116 t.Errorf("%d: got: %x", i, hash) 117 t.Errorf("%d: expected: %x", i, expected) 118 } 119 } 120 121} 122 123func TestHashEncoded(t *testing.T) { 124 ctx := NewContext(ModeArgon2d) 125 126 password = []byte("somepassword") 127 salt := []byte("somesalt") 128 129 expected := "$argon2d$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$THaZx86KeqT+xuygENqvxaYIk3zu4wH0UmqzBL/wrdQ" 130 131 s, err := HashEncoded(ctx, password, salt) 132 if err != nil { 133 t.Fatal(err) 134 } 135 if s != expected { 136 t.Fatalf("HashEncoded: got %q want %q", s, expected) 137 } 138 139 ctx.Version = Version10 140 expected = "$argon2d$v=16$m=4096,t=3,p=1$c29tZXNhbHQ$9zHzndOtdbtKI3zBlrpnnpjNj9FnrkeiK43kb8NuuMc" 141 142 s, err = HashEncoded(ctx, password, salt) 143 if err != nil { 144 t.Fatal(err) 145 } 146 if s != expected { 147 t.Fatalf("HashEncoded: got %q want %q", s, expected) 148 } 149} 150 151func TestHash_Error(t *testing.T) { 152 ctx := NewContext() 153 _, err := Hash(ctx, []byte("password"), []byte("s")) 154 if err != ErrSaltTooShort { 155 t.Errorf("got %q want %q", err, ErrSaltTooShort) 156 } 157 158 ctx = NewContext() 159 ctx.Mode = 99 160 _, err = Hash(ctx, []byte("password"), []byte("somesalt")) 161 if err != ErrIncorrectType { 162 t.Errorf("got %q want %q", err, ErrIncorrectType) 163 } 164 165 ctx = NewContext() 166 ctx.Memory = 4 167 _, err = Hash(ctx, []byte("password"), []byte("somesalt")) 168 if err != ErrMemoryTooLittle { 169 t.Errorf("got %q want %q", err, ErrMemoryTooLittle) 170 } 171} 172 173func TestVerify(t *testing.T) { 174 ctx := NewContext(ModeArgon2d) 175 testVerify(t, ctx) 176 177 ctx.Mode = ModeArgon2i 178 testVerify(t, ctx) 179} 180 181func TestVerifyEncoded(t *testing.T) { 182 ctx := NewContext(ModeArgon2d) 183 testVerifyEncoded(t, ctx) 184 185 ctx.Mode = ModeArgon2i 186 testVerifyEncoded(t, ctx) 187} 188 189func TestFlagClearPassword(t *testing.T) { 190 ctx := NewContext() 191 ctx.Flags = FlagDefault 192 password := []byte("somepassword") 193 salt := []byte("somesalt") 194 195 Hash(ctx, password, salt) 196 if !bytes.Equal([]byte("somepassword"), password) { 197 t.Fatalf("password slice is modified") 198 } 199 200 ctx.Flags = FlagClearPassword 201 Hash(ctx, password, salt) 202 if !bytes.Equal(make([]byte, len(password)), password) { 203 t.Fatalf("password slice is not cleared") 204 } 205} 206 207func TestFlagClearSecret(t *testing.T) { 208 ctx := NewContext() 209 ctx.Flags = FlagDefault 210 ctx.Secret = []byte("somesecret") 211 password := []byte("somepassword") 212 salt := []byte("somesalt") 213 214 Hash(ctx, password, salt) 215 if !bytes.Equal([]byte("somesecret"), ctx.Secret) { 216 t.Fatalf("secret slice is modified") 217 } 218 219 ctx.Flags = FlagClearSecret 220 Hash(ctx, password, salt) 221 if !bytes.Equal(make([]byte, len(ctx.Secret)), ctx.Secret) { 222 t.Fatalf("secret slice is not cleared") 223 } 224} 225 226func testVerifyEncoded(t *testing.T, ctx *Context) { 227 s, err := HashEncoded(ctx, []byte("somepassword"), []byte("somesalt")) 228 if err != nil { 229 t.Fatal(err) 230 } 231 232 pw := []byte("somepassword") 233 ok, err := VerifyEncoded(s, pw) 234 if err != nil { 235 t.Fatal(err) 236 } 237 if !ok { 238 t.Errorf("VerifyEncoded(s, []byte(%q)) = false want true", pw) 239 } 240 241 pw = []byte("someotherpassword") 242 ok, err = VerifyEncoded(s, pw) 243 if err != nil { 244 t.Fatal(err) 245 } 246 if ok { 247 t.Errorf("VerifyEncoded(s, []byte(%q)) = true want false", pw) 248 } 249} 250 251func testVerify(t *testing.T, ctx *Context) { 252 password := []byte("hunter2") 253 salt := []byte("somesalt") 254 hash, err := Hash(ctx, password, salt) 255 if err != nil { 256 t.Fatal(err) 257 } 258 259 // Test correct password 260 ok, err := Verify(ctx, hash, password, salt) 261 if err != nil { 262 t.Fatal(err) 263 } 264 if !ok { 265 t.Errorf("Verify(..) = false want true (%v)", ctx) 266 } 267 268 // Test incorrect password 269 ok, err = Verify(ctx, hash, []byte("hunter3"), salt) 270 if err != nil { 271 t.Fatal(err) 272 } 273 if ok { 274 t.Errorf("Verify(badpw) = true want false (%v)", ctx) 275 } 276 277 // Test incorrect salt 278 ok, err = Verify(ctx, hash, password, []byte("somepepper")) 279 if err != nil { 280 t.Fatal(err) 281 } 282 if ok { 283 t.Errorf("Verify(badsalt) = true want false (%v)", ctx) 284 } 285} 286