File: pbkdf.go

package info (click to toggle)
golang-github-azure-go-pkcs12 0.0~git20150623.0.a635c06-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 136 kB
  • ctags: 107
  • sloc: makefile: 2
file content (192 lines) | stat: -rw-r--r-- 6,119 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package pkcs12

import (
	"crypto/sha1"
	"math/big"
)

var (
	deriveKeyByAlg = map[string]func(salt, password []byte, iterations int) []byte{
		pbeWithSHAAnd3KeyTripleDESCBC: func(salt, password []byte, iterations int) []byte {
			return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24)
		},
		pbewithSHAAnd40BitRC2CBC: func(salt, password []byte, iterations int) []byte {
			return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5)
		},
	}
	deriveIVByAlg = map[string]func(salt, password []byte, iterations int) []byte{
		pbeWithSHAAnd3KeyTripleDESCBC: func(salt, password []byte, iterations int) []byte {
			return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
		},
		pbewithSHAAnd40BitRC2CBC: func(salt, password []byte, iterations int) []byte {
			return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
		},
	}
	deriveMacKeyByAlg = map[string]func(salt, password []byte, iterations int) []byte{
		sha1Algorithm: func(salt, password []byte, iterations int) []byte {
			return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 3, 20)
		},
	}
)

func sha1Sum(in []byte) []byte {
	sum := sha1.Sum(in)
	return sum[:]
}

func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) {
	// implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments

	//    Let H be a hash function built around a compression function f:

	//       Z_2^u x Z_2^v -> Z_2^u

	//    (that is, H has a chaining variable and output of length u bits, and
	//    the message input to the compression function of H is v bits).  The
	//    values for u and v are as follows:

	//            HASH FUNCTION     VALUE u        VALUE v
	//              MD2, MD5          128            512
	//                SHA-1           160            512
	//               SHA-224          224            512
	//               SHA-256          256            512
	//               SHA-384          384            1024
	//               SHA-512          512            1024
	//             SHA-512/224        224            1024
	//             SHA-512/256        256            1024

	//    Furthermore, let r be the iteration count.

	//    We assume here that u and v are both multiples of 8, as are the
	//    lengths of the password and salt strings (which we denote by p and s,
	//    respectively) and the number n of pseudorandom bits required.  In
	//    addition, u and v are of course non-zero.

	//    For information on security considerations for MD5 [19], see [25] and
	//    [1], and on those for MD2, see [18].

	//    The following procedure can be used to produce pseudorandom bits for
	//    a particular "purpose" that is identified by a byte called "ID".
	//    This standard specifies 3 different values for the ID byte:

	//    1.  If ID=1, then the pseudorandom bits being produced are to be used
	//        as key material for performing encryption or decryption.

	//    2.  If ID=2, then the pseudorandom bits being produced are to be used
	//        as an IV (Initial Value) for encryption or decryption.

	//    3.  If ID=3, then the pseudorandom bits being produced are to be used
	//        as an integrity key for MACing.

	//    1.  Construct a string, D (the "diversifier"), by concatenating v/8
	//        copies of ID.
	D := []byte{}
	for i := 0; i < v; i++ {
		D = append(D, ID)
	}

	//    2.  Concatenate copies of the salt together to create a string S of
	//        length v(ceiling(s/v)) bits (the final copy of the salt may be
	//        truncated to create S).  Note that if the salt is the empty
	//        string, then so is S.

	S := []byte{}
	{
		s := len(salt)
		times := s / v
		if s%v > 0 {
			times++
		}
		for len(S) < times*v {
			S = append(S, salt...)
		}
		S = S[:times*v]
	}

	//    3.  Concatenate copies of the password together to create a string P
	//        of length v(ceiling(p/v)) bits (the final copy of the password
	//        may be truncated to create P).  Note that if the password is the
	//        empty string, then so is P.

	P := []byte{}
	{
		s := len(password)
		times := s / v
		if s%v > 0 {
			times++
		}
		for len(P) < times*v {
			P = append(P, password...)
		}
		password = nil
		P = P[:times*v]
	}

	//    4.  Set I=S||P to be the concatenation of S and P.
	I := append(S, P...)

	//    5.  Set c=ceiling(n/u).
	c := size / u
	if size%u > 0 {
		c++
	}

	//    6.  For i=1, 2, ..., c, do the following:
	A := make([]byte, c*20)
	for i := 0; i < c; i++ {

		//        A.  Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
		//            H(H(H(... H(D||I))))
		Ai := hash(append(D, I...))
		for j := 1; j < r; j++ {
			Ai = hash(Ai[:])
		}
		copy(A[i*20:], Ai[:])

		if i < c-1 { // skip on last iteration

			//        B.  Concatenate copies of Ai to create a string B of length v
			//            bits (the final copy of Ai may be truncated to create B).
			B := []byte{}
			for len(B) < v {
				B = append(B, Ai[:]...)
			}
			B = B[:v]

			//        C.  Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit
			//            blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by
			//            setting I_j=(I_j+B+1) mod 2^v for each j.
			{
				Bbi := new(big.Int)
				Bbi.SetBytes(B)

				one := big.NewInt(1)

				for j := 0; j < len(I)/v; j++ {
					Ij := new(big.Int)
					Ij.SetBytes(I[j*v : (j+1)*v])
					Ij.Add(Ij, Bbi)
					Ij.Add(Ij, one)
					Ijb := Ij.Bytes()
					if len(Ijb) > v {
						Ijb = Ijb[len(Ijb)-v:]
					}
					copy(I[j*v:(j+1)*v], Ijb)
				}
			}
		}
	}
	//    7.  Concatenate A_1, A_2, ..., A_c together to form a pseudorandom
	//        bit string, A.

	//    8.  Use the first n bits of A as the output of this entire process.
	A = A[:size]

	return A

	//    If the above process is being used to generate a DES key, the process
	//    should be used to create 64 random bits, and the key's parity bits
	//    should be set after the 64 bits have been produced.  Similar concerns
	//    hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any
	//    similar keys with parity bits "built into them".
}