diff --git a/crypto/rfc3961/keyDerivation.go b/crypto/rfc3961/keyDerivation.go index e42bad8a..6ffaf497 100644 --- a/crypto/rfc3961/keyDerivation.go +++ b/crypto/rfc3961/keyDerivation.go @@ -1,6 +1,8 @@ package rfc3961 import ( + "bytes" + "gopkg.in/jcmturner/gokrb5.v6/crypto/etype" ) @@ -63,10 +65,10 @@ func RandomToKey(b []byte) []byte { // DES3RandomToKey returns a key from the bytes provided according to the definition in RFC 3961 for DES3 etypes. func DES3RandomToKey(b []byte) []byte { - r := stretch56Bits(b[:7]) - r2 := stretch56Bits(b[7:14]) + r := fixWeakKey(stretch56Bits(b[:7])) + r2 := fixWeakKey(stretch56Bits(b[7:14])) r = append(r, r2...) - r3 := stretch56Bits(b[14:21]) + r3 := fixWeakKey(stretch56Bits(b[14:21])) r = append(r, r3...) return r } @@ -132,3 +134,45 @@ func calcEvenParity(b byte) (uint8, uint8) { } return lowestbit, b } + +func fixWeakKey(b []byte) []byte { + if weak(b) { + b[7] ^= 0xF0 + } + return b +} + +func weak(b []byte) bool { + // weak keys from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-67r1.pdf + weakKeys := [4][]byte{ + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + {0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE}, + {0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1}, + {0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E}, + } + semiWeakKeys := [12][]byte{ + {0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E}, + {0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01}, + {0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1}, + {0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01}, + {0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE}, + {0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01}, + {0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1}, + {0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E}, + {0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE}, + {0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E}, + {0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE}, + {0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1}, + } + for _, k := range weakKeys { + if bytes.Equal(b, k) { + return true + } + } + for _, k := range semiWeakKeys { + if bytes.Equal(b, k) { + return true + } + } + return false +} diff --git a/crypto/rfc3961/keyDerivation_test.go b/crypto/rfc3961/keyDerivation_test.go new file mode 100644 index 00000000..66b464d9 --- /dev/null +++ b/crypto/rfc3961/keyDerivation_test.go @@ -0,0 +1,33 @@ +package rfc3961 + +import "testing" + +func TestFixWeakKey(t *testing.T) { + var weakKeys = []struct { + key []byte + lastbyte byte + }{ + {[]byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, byte(0xF1)}, + {[]byte{0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE}, byte(0x0E)}, + {[]byte{0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1}, byte(0x01)}, + {[]byte{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E}, byte(0xFE)}, + {[]byte{0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E}, byte(0xFE)}, + {[]byte{0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01}, byte(0xF1)}, + {[]byte{0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1}, byte(0x01)}, + {[]byte{0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01}, byte(0xF1)}, + {[]byte{0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE}, byte(0x0E)}, + {[]byte{0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01}, byte(0xF1)}, + {[]byte{0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1}, byte(0x01)}, + {[]byte{0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E}, byte(0xFE)}, + {[]byte{0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE}, byte(0x0E)}, + {[]byte{0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E}, byte(0xFE)}, + {[]byte{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE}, byte(0x0E)}, + {[]byte{0xFE, 0x2F, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1}, byte(0xF1)}, // Non weak key + } + for i, k := range weakKeys { + b := fixWeakKey(k.key) + if b[7] != weakKeys[i].lastbyte { + t.Errorf("key not fixed correctly %X - %X", b, weakKeys[i].lastbyte) + } + } +}