EncryptionEngine.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package krb5crypto
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. )
  7. type EType interface {
  8. GetETypeID() int
  9. GetKeyByteSize() int // See protocol key format for defined values
  10. StringToKey(string, salt string, s2kparams []byte) (protocolKey []byte)
  11. GetDefaultStringToKeyParams() string // s2kparams
  12. GetKeySeedBitLength() int // key-generation seed length, k
  13. RandomToKey(b []byte) (protocolKey []byte)
  14. GetHMACBitLength() int // HMAC output size, h
  15. GetMessageBlockByteSize() int // message block size, m
  16. Encrypt(key, message []byte) (ct []byte, err error) // E function
  17. Decrypt(key, ciphertext []byte) (message []byte, err error) // D function
  18. GetCypherBlockBitLength() int // cipher block size, c
  19. GetConfounderByteSize() int // This is the same as the cipher block size but in bytes.
  20. DeriveKey(protocolKey, usage []byte) (specificKey []byte) // DK
  21. DeriveRandom(protocolKey, usage []byte) ([]byte, error) // DR
  22. }
  23. type encryptFunc func([]byte, []byte) ([]byte, error)
  24. // RFC3961: DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state))
  25. // key - base key or protocol key. Likely to be a key from a keytab file
  26. // TODO usage - a constant
  27. // n - block size in bits (not bytes) - note if you use something like aes.BlockSize this is in bytes.
  28. // k - key length / key seed length in bits. Eg. for AES256 this value is 256
  29. // encrypt - the encryption function to use
  30. func deriveRandom(key, usage []byte, n, k int, encrypt encryptFunc) ([]byte, error) {
  31. //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.
  32. nFoldUsage := Nfold(usage, n)
  33. //k-truncate implemented by creating a byte array the size of k (k is in bits hence /8)
  34. out := make([]byte, k/8)
  35. /*If the output of E is shorter than k bits, it is fed back into the encryption as many times as necessary.
  36. The construct is as follows (where | indicates concatentation):
  37. K1 = E(Key, n-fold(Constant), initial-cipher-state)
  38. K2 = E(Key, K1, initial-cipher-state)
  39. K3 = E(Key, K2, initial-cipher-state)
  40. K4 = ...
  41. DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)*/
  42. K, err := encrypt(key, nFoldUsage)
  43. if err != nil {
  44. return out, nil
  45. }
  46. for i := copy(out, K); i < len(out); {
  47. K, _ = encrypt(key, K)
  48. i = i + copy(out[i:], K)
  49. }
  50. return out, nil
  51. }
  52. func pkcs7Pad(b []byte, m int) ([]byte, error) {
  53. if m <= 0 {
  54. return nil, errors.New("Invalid message block size when padding")
  55. }
  56. if b == nil || len(b) == 0 {
  57. return nil, errors.New("Data not valid to pad: Zero size")
  58. }
  59. n := m - (len(b) % m)
  60. pb := make([]byte, len(b)+n)
  61. copy(pb, b)
  62. copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
  63. return pb, nil
  64. }
  65. func pkcs7Unpad(b []byte, m int) ([]byte, error) {
  66. if m <= 0 {
  67. return nil, errors.New("Invalid message block size when unpadding")
  68. }
  69. if b == nil || len(b) == 0 {
  70. return nil, errors.New("Padded data not valid: Zero size")
  71. }
  72. if len(b)%m != 0 {
  73. return nil, errors.New("Padded data not valid: Not multiple of message block size")
  74. }
  75. c := b[len(b)-1]
  76. n := int(c)
  77. if n == 0 || n > len(b) {
  78. return nil, errors.New("Padded data not valid: Data may not have been padded")
  79. }
  80. for i := 0; i < n; i++ {
  81. if b[len(b)-n+i] != c {
  82. return nil, errors.New("Padded data not valid")
  83. }
  84. }
  85. return b[:len(b)-n], nil
  86. }
  87. /*
  88. Key Usage Numbers
  89. 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.
  90. Kc = DK(base-key, usage | 0x99);
  91. Ke = DK(base-key, usage | 0xAA);
  92. Ki = DK(base-key, usage | 0x55);
  93. */
  94. // un - usage number
  95. func GetUsageKc(un uint32) []byte {
  96. return getUsage(un, 0x99)
  97. }
  98. // un - usage number
  99. func GetUsageKe(un uint32) []byte {
  100. return getUsage(un, 0xAA)
  101. }
  102. // un - usage number
  103. func GetUsageKi(un uint32) []byte {
  104. return getUsage(un, 0x55)
  105. }
  106. func getUsage(un uint32, o byte) []byte {
  107. var buf bytes.Buffer
  108. binary.Write(&buf, binary.BigEndian, un)
  109. return append(buf.Bytes(), o)
  110. }
  111. var KeyUsageNumbers map[int]string = map[int]string{
  112. 1: "AS-REQ PA-ENC-TIMESTAMP padata timestamp, encrypted with the client key",
  113. 2: "AS-REP Ticket and TGS-REP Ticket (includes TGS session key or application session key), encrypted with the service key",
  114. 3: "AS-REP encrypted part (includes TGS session key or application session key), encrypted with the client key",
  115. 4: "TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the TGS session key",
  116. 5: "TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the TGS authenticator subkey",
  117. 6: "TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum, keyed with the TGS session key",
  118. 7: "TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes TGS authenticator subkey), encrypted with the TGS session key",
  119. 8: "TGS-REP encrypted part (includes application session key), encrypted with the TGS session key",
  120. 9: "TGS-REP encrypted part (includes application session key), encrypted with the TGS authenticator subkey",
  121. 10: "AP-REQ Authenticator cksum, keyed with the application session key",
  122. 11: "AP-REQ Authenticator (includes application authenticator subkey), encrypted with the application session key",
  123. 12: "AP-REP encrypted part (includes application session subkey), encrypted with the application session key",
  124. 13: "KRB-PRIV encrypted part, encrypted with a key chosen by the application",
  125. 14: "KRB-CRED encrypted part, encrypted with a key chosen by the application",
  126. 15: "KRB-SAFE cksum, keyed with a key chosen by the application",
  127. 19: "AD-KDC-ISSUED checksum",
  128. 1024: "Encryption for application use in protocols that do not specify key usage values",
  129. }