// balloon -- Balloon password hashing function // Copyright (C) 2016-2024 Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // the Free Software Foundation, version 3 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this program. If not, see // . package balloon import ( "bytes" "crypto/rand" "crypto/sha256" "crypto/sha512" "encoding/hex" "testing" "testing/quick" ) func TestB(t *testing.T) { f := func(passwd, salt []byte, s, t uint8) bool { if len(passwd) == 0 || len(salt) == 0 { return true } B(sha512.New(), passwd, salt, uint64(s)%16+1, uint64(t)%16+1) return true } if err := quick.Check(f, nil); err != nil { t.Error(err) } } func TestH(t *testing.T) { f := func(passwd, salt []byte, s, t, p uint8) bool { if len(passwd) == 0 || len(salt) == 0 { return true } H(sha512.New, passwd, salt, int(s)%16+1, int(t)%16+1, int(p)%8+1) return true } if err := quick.Check(f, nil); err != nil { t.Error(err) } } func BenchmarkB(b *testing.B) { passwd := make([]byte, 8) rand.Read(passwd) salt := make([]byte, 8) rand.Read(salt) h := sha512.New() sCost := uint64(1 << 10 / h.Size()) b.ResetTimer() for i := 0; i < b.N; i++ { B(h, passwd, salt, sCost, 4) } } func BenchmarkH(b *testing.B) { passwd := make([]byte, 8) rand.Read(passwd) salt := make([]byte, 8) rand.Read(salt) sCost := 1 << 10 / sha512.New().Size() b.ResetTimer() for i := 0; i < b.N; i++ { H(sha512.New, passwd, salt, sCost, 4, 4) } } func mustHexDecode(s string) []byte { b, err := hex.DecodeString(s) if err != nil { panic(err) } return b } func TestVectors(t *testing.T) { // taken from Nettle 3.9 if !bytes.Equal( B(sha256.New(), []byte("password"), []byte("salt"), 1, 1), mustHexDecode("eefda4a8a75b461fa389c1dcfaf3e9dfacbc26f81f22e6f280d15cc18c417545"), ) { t.FailNow() } if !bytes.Equal( B(sha256.New(), []byte{0}, []byte{0}, 3, 3), mustHexDecode("4fc7e302ffa29ae0eac31166cee7a552d1d71135f4e0da66486fb68a749b73a4"), ) { t.FailNow() } if !bytes.Equal( B(sha256.New(), nil, []byte("salt"), 3, 3), mustHexDecode("5f02f8206f9cd212485c6bdf85527b698956701ad0852106f94b94ee94577378"), ) { t.FailNow() } if !bytes.Equal( B(sha256.New(), []byte("password"), nil, 3, 3), mustHexDecode("20aa99d7fe3f4df4bd98c655c5480ec98b143107a331fd491deda885c4d6a6cc"), ) { t.FailNow() } if !bytes.Equal( B(sha256.New(), []byte("hunter42"), []byte("examplesalt"), 1024, 3), mustHexDecode("716043dff777b44aa7b88dcbab12c078abecfac9d289c5b5195967aa63440dfb"), ) { t.FailNow() } }