EncryptionEngine.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. package crypto
  2. import (
  3. "bytes"
  4. "crypto/hmac"
  5. "encoding/binary"
  6. "errors"
  7. "fmt"
  8. "github.com/jcmturner/gokrb5/types"
  9. "hash"
  10. )
  11. type EType interface {
  12. GetETypeID() int
  13. GetKeyByteSize() int // See "protocol key format" for defined values
  14. GetKeySeedBitLength() int // key-generation seed length, k
  15. GetDefaultStringToKeyParams() string // default string-to-key parameters (s2kparams)
  16. StringToKey(string, salt, s2kparams string) ([]byte, error) // string-to-key (UTF-8 string, UTF-8 string, opaque)->(protocol-key)
  17. RandomToKey(b []byte) []byte // random-to-key (bitstring[K])->(protocol-key)
  18. GetHMACBitLength() int // HMAC output size, h
  19. GetMessageBlockByteSize() int // message block size, m
  20. Encrypt(key, message []byte) ([]byte, []byte, error) // E function - encrypt (specific-key, state, octet string)->(state, octet string)
  21. Decrypt(key, ciphertext []byte) ([]byte, error) // D function
  22. GetCypherBlockBitLength() int // cipher block size, c
  23. GetConfounderByteSize() int // This is the same as the cipher block size but in bytes.
  24. DeriveKey(protocolKey, usage []byte) ([]byte, error) // DK key-derivation (protocol-key, integer)->(specific-key)
  25. DeriveRandom(protocolKey, usage []byte) ([]byte, error) // DR pseudo-random (protocol-key, octet-string)->(octet-string)
  26. VerifyChecksum(protocolKey, ct, pt []byte, usage int) bool
  27. GetHash() hash.Hash
  28. }
  29. func GetEtype(id int) (EType, error) {
  30. switch id {
  31. case 17:
  32. var et Aes128CtsHmacSha96
  33. return et, nil
  34. case 18:
  35. var et Aes256CtsHmacSha96
  36. return et, nil
  37. default:
  38. return nil, fmt.Errorf("Unknown or unsupported EType: %d", id)
  39. }
  40. }
  41. // RFC3961: DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state))
  42. // key - base key or protocol key. Likely to be a key from a keytab file
  43. // TODO usage - a constant
  44. // n - block size in bits (not bytes) - note if you use something like aes.BlockSize this is in bytes.
  45. // k - key length / key seed length in bits. Eg. for AES256 this value is 256
  46. // encrypt - the encryption function to use
  47. func deriveRandom(key, usage []byte, n, k int, e EType) ([]byte, error) {
  48. //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.
  49. nFoldUsage := Nfold(usage, n)
  50. //k-truncate implemented by creating a byte array the size of k (k is in bits hence /8)
  51. out := make([]byte, k/8)
  52. /*If the output of E is shorter than k bits, it is fed back into the encryption as many times as necessary.
  53. The construct is as follows (where | indicates concatentation):
  54. K1 = E(Key, n-fold(Constant), initial-cipher-state)
  55. K2 = E(Key, K1, initial-cipher-state)
  56. K3 = E(Key, K2, initial-cipher-state)
  57. K4 = ...
  58. DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)*/
  59. _, K, err := e.Encrypt(key, nFoldUsage)
  60. if err != nil {
  61. return out, err
  62. }
  63. for i := copy(out, K); i < len(out); {
  64. _, K, _ = e.Encrypt(key, K)
  65. i = i + copy(out[i:], K)
  66. }
  67. return out, nil
  68. }
  69. func zeroPad(b []byte, m int) ([]byte, error) {
  70. if m <= 0 {
  71. return nil, errors.New("Invalid message block size when padding")
  72. }
  73. if b == nil || len(b) == 0 {
  74. return nil, errors.New("Data not valid to pad: Zero size")
  75. }
  76. if l := len(b) % m; l != 0 {
  77. n := m - l
  78. z := make([]byte, n)
  79. b = append(b, z...)
  80. }
  81. return b, nil
  82. }
  83. func pkcs7Pad(b []byte, m int) ([]byte, error) {
  84. if m <= 0 {
  85. return nil, errors.New("Invalid message block size when padding")
  86. }
  87. if b == nil || len(b) == 0 {
  88. return nil, errors.New("Data not valid to pad: Zero size")
  89. }
  90. n := m - (len(b) % m)
  91. pb := make([]byte, len(b)+n)
  92. copy(pb, b)
  93. copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
  94. return pb, nil
  95. }
  96. func pkcs7Unpad(b []byte, m int) ([]byte, error) {
  97. if m <= 0 {
  98. return nil, errors.New("Invalid message block size when unpadding")
  99. }
  100. if b == nil || len(b) == 0 {
  101. return nil, errors.New("Padded data not valid: Zero size")
  102. }
  103. if len(b)%m != 0 {
  104. return nil, errors.New("Padded data not valid: Not multiple of message block size")
  105. }
  106. c := b[len(b)-1]
  107. n := int(c)
  108. if n == 0 || n > len(b) {
  109. return nil, errors.New("Padded data not valid: Data may not have been padded")
  110. }
  111. for i := 0; i < n; i++ {
  112. if b[len(b)-n+i] != c {
  113. return nil, errors.New("Padded data not valid")
  114. }
  115. }
  116. return b[:len(b)-n], nil
  117. }
  118. func DecryptEncPart(key []byte, pe types.EncryptedData, etype EType, usage uint32) ([]byte, error) {
  119. //TODO move this to the a method on the Encrypted data object and call that from here. update the KRB_CRED too
  120. //TODO create the etype based on the EType value in the EncPart and find the corresponding entry in the keytab
  121. //Derive the key
  122. //Key Usage Number: 3 - "AS-REP encrypted part (includes TGS session key or application session key), encrypted with the client key"
  123. //TODO need to consider PAdata for deriving key
  124. k, err := etype.DeriveKey(key, GetUsageKe(usage))
  125. if err != nil {
  126. return nil, fmt.Errorf("Error deriving key: %v", err)
  127. }
  128. // Strip off the checksum from the end
  129. b, err := etype.Decrypt(k, pe.Cipher[:len(pe.Cipher)-etype.GetHMACBitLength()/8])
  130. if err != nil {
  131. return nil, fmt.Errorf("Error decrypting: %v", err)
  132. }
  133. //Verify checksum
  134. if !etype.VerifyChecksum(key, pe.Cipher, b, 3) {
  135. return nil, errors.New("Error decrypting encrypted part: checksum verification failed")
  136. }
  137. //Remove the confounder bytes
  138. b = b[etype.GetConfounderByteSize():]
  139. if err != nil {
  140. return nil, fmt.Errorf("Error decrypting encrypted part: %v", err)
  141. }
  142. return b, nil
  143. }
  144. func GetChecksum(pt, key []byte, usage int, etype EType) ([]byte, error) {
  145. k, err := etype.DeriveKey(key, GetUsageKi(uint32(usage)))
  146. if err != nil {
  147. return nil, fmt.Errorf("Unable to derive key for checksum: %v", err)
  148. }
  149. mac := hmac.New(etype.GetHash, k)
  150. //TODO do I need to append the ivz before taking the hash?
  151. //ivz := make([]byte, etype.GetConfounderByteSize())
  152. //pt = append(ivz, pt...)
  153. //if r := len(pt)%etype.GetMessageBlockByteSize(); r != 0 {
  154. // t := make([]byte, etype.GetMessageBlockByteSize() - r)
  155. // pt = append(pt, t...)
  156. //}
  157. mac.Write(pt)
  158. return mac.Sum(nil), nil
  159. }
  160. func VerifyChecksum(key, ct, pt []byte, usage int, etype EType) bool {
  161. //The ciphertext output is the concatenation of the output of the basic
  162. //encryption function E and a (possibly truncated) HMAC using the
  163. //specified hash function H, both applied to the plaintext with a
  164. //random confounder prefix and sufficient padding to bring it to a
  165. //multiple of the message block size. When the HMAC is computed, the
  166. //key is used in the protocol key form.
  167. h := ct[len(ct)-etype.GetHMACBitLength()/8+1:]
  168. expectedMAC, _ := GetChecksum(pt, key, usage, etype)
  169. return hmac.Equal(h, expectedMAC[1:etype.GetHMACBitLength()/8])
  170. }
  171. /*
  172. Key Usage Numbers
  173. 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.
  174. Kc = DK(base-key, usage | 0x99);
  175. Ke = DK(base-key, usage | 0xAA);
  176. Ki = DK(base-key, usage | 0x55);
  177. */
  178. // un - usage number
  179. func GetUsageKc(un uint32) []byte {
  180. return getUsage(un, 0x99)
  181. }
  182. // un - usage number
  183. func GetUsageKe(un uint32) []byte {
  184. return getUsage(un, 0xAA)
  185. }
  186. // un - usage number
  187. func GetUsageKi(un uint32) []byte {
  188. return getUsage(un, 0x55)
  189. }
  190. func getUsage(un uint32, o byte) []byte {
  191. var buf bytes.Buffer
  192. binary.Write(&buf, binary.BigEndian, un)
  193. return append(buf.Bytes(), o)
  194. }
  195. var KeyUsageNumbers map[int]string = map[int]string{
  196. 1: "AS-REQ PA-ENC-TIMESTAMP padata timestamp, encrypted with the client key",
  197. 2: "AS-REP Ticket and TGS-REP Ticket (includes TGS session key or application session key), encrypted with the service key",
  198. 3: "AS-REP encrypted part (includes TGS session key or application session key), encrypted with the client key",
  199. 4: "TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the TGS session key",
  200. 5: "TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the TGS authenticator subkey",
  201. 6: "TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum, keyed with the TGS session key",
  202. 7: "TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes TGS authenticator subkey), encrypted with the TGS session key",
  203. 8: "TGS-REP encrypted part (includes application session key), encrypted with the TGS session key",
  204. 9: "TGS-REP encrypted part (includes application session key), encrypted with the TGS authenticator subkey",
  205. 10: "AP-REQ Authenticator cksum, keyed with the application session key",
  206. 11: "AP-REQ Authenticator (includes application authenticator subkey), encrypted with the application session key",
  207. 12: "AP-REP encrypted part (includes application session subkey), encrypted with the application session key",
  208. 13: "KRB-PRIV encrypted part, encrypted with a key chosen by the application",
  209. 14: "KRB-CRED encrypted part, encrypted with a key chosen by the application",
  210. 15: "KRB-SAFE cksum, keyed with a key chosen by the application",
  211. 19: "AD-KDC-ISSUED checksum",
  212. 1024: "Encryption for application use in protocols that do not specify key usage values",
  213. }