github.com/jcmturner/gokrb5/v8@v8.4.4/crypto/rfc3961/keyDerivation.go (about) 1 package rfc3961 2 3 import ( 4 "bytes" 5 6 "github.com/jcmturner/gokrb5/v8/crypto/etype" 7 ) 8 9 const ( 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. 24 func 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. 44 func 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. 53 func 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. 58 func 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. 68 func 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 75 func 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 90 func 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 108 func 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 129 func fixWeakKey(b []byte) []byte { 130 if weak(b) { 131 b[7] ^= 0xF0 132 } 133 return b 134 } 135 136 func 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 }