blob: 8c637a22d9934c7e3d28516b2826409507d7f0a9 [file] [log] [blame]
Scott Baker611f6bd2019-10-18 13:45:19 -07001package rfc3961
2
3import (
4 "bytes"
5
6 "gopkg.in/jcmturner/gokrb5.v7/crypto/etype"
7)
8
9const (
10 prfconstant = "prf"
11)
12
13// DeriveRandom implements the RFC 3961 defined function: DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state)).
14//
15// key: base key or protocol key. Likely to be a key from a keytab file.
16//
17// usage: a constant.
18//
19// n: block size in bits (not bytes) - note if you use something like aes.BlockSize this is in bytes.
20//
21// k: key length / key seed length in bits. Eg. for AES256 this value is 256.
22//
23// e: the encryption etype function to use.
24func DeriveRandom(key, usage []byte, e etype.EType) ([]byte, error) {
25 n := e.GetCypherBlockBitLength()
26 k := e.GetKeySeedBitLength()
27 //Ensure the usage constant is at least the size of the cypher block size. Pass it through the nfold algorithm that will "stretch" it if needs be.
28 nFoldUsage := Nfold(usage, n)
29 //k-truncate implemented by creating a byte array the size of k (k is in bits hence /8)
30 out := make([]byte, k/8)
31
32 /*If the output of E is shorter than k bits, it is fed back into the encryption as many times as necessary.
33 The construct is as follows (where | indicates concatenation):
34
35 K1 = E(Key, n-fold(Constant), initial-cipher-state)
36 K2 = E(Key, K1, initial-cipher-state)
37 K3 = E(Key, K2, initial-cipher-state)
38 K4 = ...
39
40 DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)*/
41 _, K, err := e.EncryptData(key, nFoldUsage)
42 if err != nil {
43 return out, err
44 }
45 for i := copy(out, K); i < len(out); {
46 _, K, _ = e.EncryptData(key, K)
47 i = i + copy(out[i:], K)
48 }
49 return out, nil
50}
51
52// DeriveKey derives a key from the protocol key based on the usage and the etype's specific methods.
53func DeriveKey(protocolKey, usage []byte, e etype.EType) ([]byte, error) {
54 r, err := e.DeriveRandom(protocolKey, usage)
55 if err != nil {
56 return nil, err
57 }
58 return e.RandomToKey(r), nil
59}
60
61// RandomToKey returns a key from the bytes provided according to the definition in RFC 3961.
62func RandomToKey(b []byte) []byte {
63 return b
64}
65
66// DES3RandomToKey returns a key from the bytes provided according to the definition in RFC 3961 for DES3 etypes.
67func DES3RandomToKey(b []byte) []byte {
68 r := fixWeakKey(stretch56Bits(b[:7]))
69 r2 := fixWeakKey(stretch56Bits(b[7:14]))
70 r = append(r, r2...)
71 r3 := fixWeakKey(stretch56Bits(b[14:21]))
72 r = append(r, r3...)
73 return r
74}
75
76// DES3StringToKey returns a key derived from the string provided according to the definition in RFC 3961 for DES3 etypes.
77func DES3StringToKey(secret, salt string, e etype.EType) ([]byte, error) {
78 s := secret + salt
79 tkey := e.RandomToKey(Nfold([]byte(s), e.GetKeySeedBitLength()))
80 return e.DeriveKey(tkey, []byte("kerberos"))
81}
82
83// PseudoRandom function as defined in RFC 3961
84func PseudoRandom(key, b []byte, e etype.EType) ([]byte, error) {
85 h := e.GetHashFunc()()
86 h.Write(b)
87 tmp := h.Sum(nil)[:e.GetMessageBlockByteSize()]
88 k, err := e.DeriveKey(key, []byte(prfconstant))
89 if err != nil {
90 return []byte{}, err
91 }
92 _, prf, err := e.EncryptData(k, tmp)
93 if err != nil {
94 return []byte{}, err
95 }
96 return prf, nil
97}
98
99func stretch56Bits(b []byte) []byte {
100 d := make([]byte, len(b), len(b))
101 copy(d, b)
102 var lb byte
103 for i, v := range d {
104 bv, nb := calcEvenParity(v)
105 d[i] = nb
106 if bv != 0 {
107 lb = lb | (1 << uint(i+1))
108 } else {
109 lb = lb &^ (1 << uint(i+1))
110 }
111 }
112 _, lb = calcEvenParity(lb)
113 d = append(d, lb)
114 return d
115}
116
117func calcEvenParity(b byte) (uint8, uint8) {
118 lowestbit := b & 0x01
119 // c counter of 1s in the first 7 bits of the byte
120 var c int
121 // Iterate over the highest 7 bits (hence p starts at 1 not zero) and count the 1s.
122 for p := 1; p < 8; p++ {
123 v := b & (1 << uint(p))
124 if v != 0 {
125 c++
126 }
127 }
128 if c%2 == 0 {
129 //Even number of 1s so set parity to 1
130 b = b | 1
131 } else {
132 //Odd number of 1s so set parity to 0
133 b = b &^ 1
134 }
135 return lowestbit, b
136}
137
138func fixWeakKey(b []byte) []byte {
139 if weak(b) {
140 b[7] ^= 0xF0
141 }
142 return b
143}
144
145func weak(b []byte) bool {
146 // weak keys from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-67r1.pdf
147 weakKeys := [4][]byte{
148 {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
149 {0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE},
150 {0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1},
151 {0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
152 }
153 semiWeakKeys := [12][]byte{
154 {0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E},
155 {0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01},
156 {0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1},
157 {0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01},
158 {0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE},
159 {0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01},
160 {0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1},
161 {0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E},
162 {0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE},
163 {0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E},
164 {0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
165 {0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1},
166 }
167 for _, k := range weakKeys {
168 if bytes.Equal(b, k) {
169 return true
170 }
171 }
172 for _, k := range semiWeakKeys {
173 if bytes.Equal(b, k) {
174 return true
175 }
176 }
177 return false
178}