package kdbx import "encoding/binary" // BLAKE2b (RFC 7693). Argon2 is defined on top of it and the Go standard // library does not expose it, so it lives here with the RFC's test vectors. var blake2bIV = [8]uint64{ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, } var blake2bSigma = [10][16]byte{ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, } type blake2b struct { h [8]uint64 buf [128]byte n int // bytes buffered t uint64 // bytes compressed so far outLen int } // newBlake2b starts a hash producing outLen bytes, optionally keyed. func newBlake2b(outLen int, key []byte) *blake2b { b := &blake2b{outLen: outLen} b.h = blake2bIV b.h[0] ^= 0x01010000 ^ uint64(len(key))<<8 ^ uint64(outLen) if len(key) > 0 { var block [128]byte copy(block[:], key) b.Write(block[:]) } return b } func (b *blake2b) Write(p []byte) { for len(p) > 0 { if b.n == 128 { b.t += 128 b.compress(b.buf[:], false) b.n = 0 } n := copy(b.buf[b.n:], p) b.n += n p = p[n:] } } func (b *blake2b) Sum() []byte { for i := b.n; i < 128; i++ { b.buf[i] = 0 } b.t += uint64(b.n) b.compress(b.buf[:], true) out := make([]byte, 0, 64) for _, v := range b.h { out = binary.LittleEndian.AppendUint64(out, v) } return out[:b.outLen] } func (b *blake2b) compress(block []byte, last bool) { var m [16]uint64 for i := range m { m[i] = binary.LittleEndian.Uint64(block[i*8:]) } var v [16]uint64 copy(v[:8], b.h[:]) copy(v[8:], blake2bIV[:]) v[12] ^= b.t // v[13] ^= high 64 bits of the counter, always zero for our inputs. if last { v[14] = ^v[14] } for r := 0; r < 12; r++ { s := blake2bSigma[r%10] gb2(&v, 0, 4, 8, 12, m[s[0]], m[s[1]]) gb2(&v, 1, 5, 9, 13, m[s[2]], m[s[3]]) gb2(&v, 2, 6, 10, 14, m[s[4]], m[s[5]]) gb2(&v, 3, 7, 11, 15, m[s[6]], m[s[7]]) gb2(&v, 0, 5, 10, 15, m[s[8]], m[s[9]]) gb2(&v, 1, 6, 11, 12, m[s[10]], m[s[11]]) gb2(&v, 2, 7, 8, 13, m[s[12]], m[s[13]]) gb2(&v, 3, 4, 9, 14, m[s[14]], m[s[15]]) } for i := range b.h { b.h[i] ^= v[i] ^ v[i+8] } } func gb2(v *[16]uint64, a, b, c, d int, x, y uint64) { v[a] = v[a] + v[b] + x v[d] = rotr64(v[d]^v[a], 32) v[c] = v[c] + v[d] v[b] = rotr64(v[b]^v[c], 24) v[a] = v[a] + v[b] + y v[d] = rotr64(v[d]^v[a], 16) v[c] = v[c] + v[d] v[b] = rotr64(v[b]^v[c], 63) } func rotr64(v uint64, n uint) uint64 { return v>>n | v<<(64-n) } // blake2bSum hashes the concatenation of parts into outLen bytes. func blake2bSum(outLen int, parts ...[]byte) []byte { h := newBlake2b(outLen, nil) for _, p := range parts { h.Write(p) } return h.Sum() }