...
1
2
3
4
5
6
7
8
9 package bcrypt_pbkdf
10
11 import (
12 "crypto/sha512"
13 "errors"
14 "golang.org/x/crypto/blowfish"
15 )
16
17 const blockSize = 32
18
19
20
21 func Key(password, salt []byte, rounds, keyLen int) ([]byte, error) {
22 if rounds < 1 {
23 return nil, errors.New("bcrypt_pbkdf: number of rounds is too small")
24 }
25 if len(password) == 0 {
26 return nil, errors.New("bcrypt_pbkdf: empty password")
27 }
28 if len(salt) == 0 || len(salt) > 1<<20 {
29 return nil, errors.New("bcrypt_pbkdf: bad salt length")
30 }
31 if keyLen > 1024 {
32 return nil, errors.New("bcrypt_pbkdf: keyLen is too large")
33 }
34
35 numBlocks := (keyLen + blockSize - 1) / blockSize
36 key := make([]byte, numBlocks*blockSize)
37
38 h := sha512.New()
39 h.Write(password)
40 shapass := h.Sum(nil)
41
42 shasalt := make([]byte, 0, sha512.Size)
43 cnt, tmp := make([]byte, 4), make([]byte, blockSize)
44 for block := 1; block <= numBlocks; block++ {
45 h.Reset()
46 h.Write(salt)
47 cnt[0] = byte(block >> 24)
48 cnt[1] = byte(block >> 16)
49 cnt[2] = byte(block >> 8)
50 cnt[3] = byte(block)
51 h.Write(cnt)
52 bcryptHash(tmp, shapass, h.Sum(shasalt))
53
54 out := make([]byte, blockSize)
55 copy(out, tmp)
56 for i := 2; i <= rounds; i++ {
57 h.Reset()
58 h.Write(tmp)
59 bcryptHash(tmp, shapass, h.Sum(shasalt))
60 for j := 0; j < len(out); j++ {
61 out[j] ^= tmp[j]
62 }
63 }
64
65 for i, v := range out {
66 key[i*numBlocks+(block-1)] = v
67 }
68 }
69 return key[:keyLen], nil
70 }
71
72 var magic = []byte("OxychromaticBlowfishSwatDynamite")
73
74 func bcryptHash(out, shapass, shasalt []byte) {
75 c, err := blowfish.NewSaltedCipher(shapass, shasalt)
76 if err != nil {
77 panic(err)
78 }
79 for i := 0; i < 64; i++ {
80 blowfish.ExpandKey(shasalt, c)
81 blowfish.ExpandKey(shapass, c)
82 }
83 copy(out, magic)
84 for i := 0; i < 32; i += 8 {
85 for j := 0; j < 64; j++ {
86 c.Encrypt(out[i:i+8], out[i:i+8])
87 }
88 }
89
90 for i := 0; i < 32; i += 4 {
91 out[i+3], out[i+2], out[i+1], out[i] = out[i], out[i+1], out[i+2], out[i+3]
92 }
93 }
94
View as plain text