engine.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Cryptography methods for Kerberos.
  2. package engine
  3. import (
  4. "bytes"
  5. "crypto/hmac"
  6. "encoding/binary"
  7. "errors"
  8. "fmt"
  9. "github.com/jcmturner/gokrb5/crypto/etype"
  10. )
  11. // RFC 3961: DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state)).
  12. //
  13. // key: base key or protocol key. Likely to be a key from a keytab file.
  14. //
  15. // usage: a constant.
  16. //
  17. // n: block size in bits (not bytes) - note if you use something like aes.BlockSize this is in bytes.
  18. //
  19. // k: key length / key seed length in bits. Eg. for AES256 this value is 256.
  20. //
  21. // e: the encryption etype function to use.
  22. func DeriveRandom(key, usage []byte, n, k int, e etype.EType) ([]byte, error) {
  23. //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.
  24. nFoldUsage := Nfold(usage, n)
  25. //k-truncate implemented by creating a byte array the size of k (k is in bits hence /8)
  26. out := make([]byte, k/8)
  27. /*If the output of E is shorter than k bits, it is fed back into the encryption as many times as necessary.
  28. The construct is as follows (where | indicates concatentation):
  29. K1 = E(Key, n-fold(Constant), initial-cipher-state)
  30. K2 = E(Key, K1, initial-cipher-state)
  31. K3 = E(Key, K2, initial-cipher-state)
  32. K4 = ...
  33. DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)*/
  34. _, K, err := e.Encrypt(key, nFoldUsage)
  35. if err != nil {
  36. return out, err
  37. }
  38. for i := copy(out, K); i < len(out); {
  39. _, K, _ = e.Encrypt(key, K)
  40. i = i + copy(out[i:], K)
  41. }
  42. return out, nil
  43. }
  44. // Pad bytes b with zeros to nearest multiple of message size m.
  45. func ZeroPad(b []byte, m int) ([]byte, error) {
  46. if m <= 0 {
  47. return nil, errors.New("Invalid message block size when padding")
  48. }
  49. if b == nil || len(b) == 0 {
  50. return nil, errors.New("Data not valid to pad: Zero size")
  51. }
  52. if l := len(b) % m; l != 0 {
  53. n := m - l
  54. z := make([]byte, n)
  55. b = append(b, z...)
  56. }
  57. return b, nil
  58. }
  59. // Pad bytes b according to RFC 2315 to nearest multiple of message size m.
  60. func PKCS7Pad(b []byte, m int) ([]byte, error) {
  61. if m <= 0 {
  62. return nil, errors.New("Invalid message block size when padding")
  63. }
  64. if b == nil || len(b) == 0 {
  65. return nil, errors.New("Data not valid to pad: Zero size")
  66. }
  67. n := m - (len(b) % m)
  68. pb := make([]byte, len(b)+n)
  69. copy(pb, b)
  70. copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
  71. return pb, nil
  72. }
  73. // Remove RFC 2315 padding from byes b where message size is m.
  74. func PKCS7Unpad(b []byte, m int) ([]byte, error) {
  75. if m <= 0 {
  76. return nil, errors.New("Invalid message block size when unpadding")
  77. }
  78. if b == nil || len(b) == 0 {
  79. return nil, errors.New("Padded data not valid: Zero size")
  80. }
  81. if len(b)%m != 0 {
  82. return nil, errors.New("Padded data not valid: Not multiple of message block size")
  83. }
  84. c := b[len(b)-1]
  85. n := int(c)
  86. if n == 0 || n > len(b) {
  87. return nil, errors.New("Padded data not valid: Data may not have been padded")
  88. }
  89. for i := 0; i < n; i++ {
  90. if b[len(b)-n+i] != c {
  91. return nil, errors.New("Padded data not valid")
  92. }
  93. }
  94. return b[:len(b)-n], nil
  95. }
  96. func getHash(pt, key []byte, usage []byte, etype etype.EType) ([]byte, error) {
  97. k, err := etype.DeriveKey(key, usage)
  98. if err != nil {
  99. return nil, fmt.Errorf("Unable to derive key for checksum: %v", err)
  100. }
  101. mac := hmac.New(etype.GetHash, k)
  102. p := make([]byte, len(pt))
  103. copy(p, pt)
  104. mac.Write(p)
  105. return mac.Sum(nil)[:etype.GetHMACBitLength()/8], nil
  106. }
  107. // Get a keyed checksum hash of bytes b.
  108. func GetChecksumHash(b, key []byte, usage uint32, etype etype.EType) ([]byte, error) {
  109. return getHash(b, key, GetUsageKc(usage), etype)
  110. }
  111. // Get a keyed integrity hash of bytes b.
  112. func GetIntegrityHash(b, key []byte, usage uint32, etype etype.EType) ([]byte, error) {
  113. return getHash(b, key, GetUsageKi(usage), etype)
  114. }
  115. // Verify the integrity of cipertext bytes ct.
  116. func VerifyIntegrity(key, ct, pt []byte, usage uint32, etype etype.EType) bool {
  117. //The ciphertext output is the concatenation of the output of the basic
  118. //encryption function E and a (possibly truncated) HMAC using the
  119. //specified hash function H, both applied to the plaintext with a
  120. //random confounder prefix and sufficient padding to bring it to a
  121. //multiple of the message block size. When the HMAC is computed, the
  122. //key is used in the protocol key form.
  123. h := make([]byte, etype.GetHMACBitLength()/8)
  124. copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:])
  125. expectedMAC, _ := GetIntegrityHash(pt, key, usage, etype)
  126. return hmac.Equal(h, expectedMAC)
  127. }
  128. // Verify the checksum of the msg bytes is the same as the checksum provided.
  129. func VerifyChecksum(key, chksum, msg []byte, usage uint32, etype etype.EType) bool {
  130. //The ciphertext output is the concatenation of the output of the basic
  131. //encryption function E and a (possibly truncated) HMAC using the
  132. //specified hash function H, both applied to the plaintext with a
  133. //random confounder prefix and sufficient padding to bring it to a
  134. //multiple of the message block size. When the HMAC is computed, the
  135. //key is used in the protocol key form.
  136. expectedMAC, _ := GetChecksumHash(msg, key, usage, etype)
  137. return hmac.Equal(chksum, expectedMAC)
  138. }
  139. // Get the checksum key usage value for the usage number un.
  140. //
  141. // RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below.
  142. //
  143. // Kc = DK(base-key, usage | 0x99);
  144. func GetUsageKc(un uint32) []byte {
  145. return getUsage(un, 0x99)
  146. }
  147. // Get the encryption key usage value for the usage number un
  148. //
  149. // RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below.
  150. //
  151. // Ke = DK(base-key, usage | 0xAA);
  152. func GetUsageKe(un uint32) []byte {
  153. return getUsage(un, 0xAA)
  154. }
  155. // Get the integrity key usage value for the usage number un
  156. //
  157. // RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below.
  158. //
  159. // Ki = DK(base-key, usage | 0x55);
  160. func GetUsageKi(un uint32) []byte {
  161. return getUsage(un, 0x55)
  162. }
  163. func getUsage(un uint32, o byte) []byte {
  164. var buf bytes.Buffer
  165. binary.Write(&buf, binary.BigEndian, un)
  166. return append(buf.Bytes(), o)
  167. }