blob: ed9b169c5d9ec9e3c4e1f4b917a372bcae0ec77c [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001package rfc3961
2
3import (
4 "bytes"
5
6 "github.com/jcmturner/gokrb5/v8/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 // Keep feeding the output back into the encryption function until it is no longer short than k.
32 _, K, err := e.EncryptData(key, nFoldUsage)
33 if err != nil {
34 return out, err
35 }
36 for i := copy(out, K); i < len(out); {
37 _, K, _ = e.EncryptData(key, K)
38 i = i + copy(out[i:], K)
39 }
40 return out, nil
41}
42
43// DeriveKey derives a key from the protocol key based on the usage and the etype's specific methods.
44func DeriveKey(protocolKey, usage []byte, e etype.EType) ([]byte, error) {
45 r, err := e.DeriveRandom(protocolKey, usage)
46 if err != nil {
47 return nil, err
48 }
49 return e.RandomToKey(r), nil
50}
51
52// RandomToKey returns a key from the bytes provided according to the definition in RFC 3961.
53func RandomToKey(b []byte) []byte {
54 return b
55}
56
57// DES3RandomToKey returns a key from the bytes provided according to the definition in RFC 3961 for DES3 etypes.
58func DES3RandomToKey(b []byte) []byte {
59 r := fixWeakKey(stretch56Bits(b[:7]))
60 r2 := fixWeakKey(stretch56Bits(b[7:14]))
61 r = append(r, r2...)
62 r3 := fixWeakKey(stretch56Bits(b[14:21]))
63 r = append(r, r3...)
64 return r
65}
66
67// DES3StringToKey returns a key derived from the string provided according to the definition in RFC 3961 for DES3 etypes.
68func DES3StringToKey(secret, salt string, e etype.EType) ([]byte, error) {
69 s := secret + salt
70 tkey := e.RandomToKey(Nfold([]byte(s), e.GetKeySeedBitLength()))
71 return e.DeriveKey(tkey, []byte("kerberos"))
72}
73
74// PseudoRandom function as defined in RFC 3961
75func PseudoRandom(key, b []byte, e etype.EType) ([]byte, error) {
76 h := e.GetHashFunc()()
77 h.Write(b)
78 tmp := h.Sum(nil)[:e.GetMessageBlockByteSize()]
79 k, err := e.DeriveKey(key, []byte(prfconstant))
80 if err != nil {
81 return []byte{}, err
82 }
83 _, prf, err := e.EncryptData(k, tmp)
84 if err != nil {
85 return []byte{}, err
86 }
87 return prf, nil
88}
89
90func stretch56Bits(b []byte) []byte {
91 d := make([]byte, len(b), len(b))
92 copy(d, b)
93 var lb byte
94 for i, v := range d {
95 bv, nb := calcEvenParity(v)
96 d[i] = nb
97 if bv != 0 {
98 lb = lb | (1 << uint(i+1))
99 } else {
100 lb = lb &^ (1 << uint(i+1))
101 }
102 }
103 _, lb = calcEvenParity(lb)
104 d = append(d, lb)
105 return d
106}
107
108func calcEvenParity(b byte) (uint8, uint8) {
109 lowestbit := b & 0x01
110 // c counter of 1s in the first 7 bits of the byte
111 var c int
112 // Iterate over the highest 7 bits (hence p starts at 1 not zero) and count the 1s.
113 for p := 1; p < 8; p++ {
114 v := b & (1 << uint(p))
115 if v != 0 {
116 c++
117 }
118 }
119 if c%2 == 0 {
120 //Even number of 1s so set parity to 1
121 b = b | 1
122 } else {
123 //Odd number of 1s so set parity to 0
124 b = b &^ 1
125 }
126 return lowestbit, b
127}
128
129func fixWeakKey(b []byte) []byte {
130 if weak(b) {
131 b[7] ^= 0xF0
132 }
133 return b
134}
135
136func weak(b []byte) bool {
137 // weak keys from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-67r1.pdf
138 weakKeys := [4][]byte{
139 {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
140 {0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE},
141 {0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1},
142 {0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
143 }
144 semiWeakKeys := [12][]byte{
145 {0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E},
146 {0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01},
147 {0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1},
148 {0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01},
149 {0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE},
150 {0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01},
151 {0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1},
152 {0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E},
153 {0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE},
154 {0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E},
155 {0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
156 {0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1},
157 }
158 for _, k := range weakKeys {
159 if bytes.Equal(b, k) {
160 return true
161 }
162 }
163 for _, k := range semiWeakKeys {
164 if bytes.Equal(b, k) {
165 return true
166 }
167 }
168 return false
169}