blob: 54cff7b4629a8447178b45021ac5b828b67e09d8 [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// Package rfc8009 provides encryption and checksum methods as specified in RFC 8009
2package rfc8009
3
4import (
5 "crypto/aes"
6 "crypto/hmac"
7 "crypto/rand"
8 "errors"
9 "fmt"
10
11 "github.com/jcmturner/aescts/v2"
12 "github.com/jcmturner/gokrb5/v8/crypto/common"
13 "github.com/jcmturner/gokrb5/v8/crypto/etype"
14 "github.com/jcmturner/gokrb5/v8/iana/etypeID"
15)
16
17// EncryptData encrypts the data provided using methods specific to the etype provided as defined in RFC 8009.
18func EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
19 kl := e.GetKeyByteSize()
20 if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
21 kl = 32
22 }
23 if len(key) != kl {
24 return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
25 }
26 ivz := make([]byte, aes.BlockSize)
27 return aescts.Encrypt(key, ivz, data)
28}
29
30// EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 8009.
31// The encrypted data is concatenated with its integrity hash to create an encrypted message.
32func EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
33 kl := e.GetKeyByteSize()
34 if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
35 kl = 32
36 }
37 if len(key) != kl {
38 return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", kl, len(key))
39 }
40 if len(key) != e.GetKeyByteSize() {
41 }
42 //confounder
43 c := make([]byte, e.GetConfounderByteSize())
44 _, err := rand.Read(c)
45 if err != nil {
46 return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
47 }
48 plainBytes := append(c, message...)
49
50 // Derive key for encryption from usage
51 var k []byte
52 if usage != 0 {
53 k, err = e.DeriveKey(key, common.GetUsageKe(usage))
54 if err != nil {
55 return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
56 }
57 }
58
59 // Encrypt the data
60 iv, b, err := e.EncryptData(k, plainBytes)
61 if err != nil {
62 return iv, b, fmt.Errorf("error encrypting data: %v", err)
63 }
64
65 ivz := make([]byte, e.GetConfounderByteSize())
66 ih, err := GetIntegityHash(ivz, b, key, usage, e)
67 if err != nil {
68 return iv, b, fmt.Errorf("error encrypting data: %v", err)
69 }
70 b = append(b, ih...)
71 return iv, b, nil
72}
73
74// DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 8009.
75func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
76 kl := e.GetKeyByteSize()
77 if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
78 kl = 32
79 }
80 if len(key) != kl {
81 return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", kl, len(key))
82 }
83 ivz := make([]byte, aes.BlockSize)
84 return aescts.Decrypt(key, ivz, data)
85}
86
87// DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 8009.
88// The integrity of the message is also verified.
89func DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
90 //Derive the key
91 k, err := e.DeriveKey(key, common.GetUsageKe(usage))
92 if err != nil {
93 return nil, fmt.Errorf("error deriving key: %v", err)
94 }
95 // Strip off the checksum from the end
96 b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
97 if err != nil {
98 return nil, err
99 }
100 //Verify checksum
101 if !e.VerifyIntegrity(key, ciphertext, b, usage) {
102 return nil, errors.New("integrity verification failed")
103 }
104 //Remove the confounder bytes
105 return b[e.GetConfounderByteSize():], nil
106}
107
108// GetIntegityHash returns a keyed integrity hash of the bytes provided as defined in RFC 8009
109func GetIntegityHash(iv, c, key []byte, usage uint32, e etype.EType) ([]byte, error) {
110 // Generate and append integrity hash
111 // Rather than calculating the hash over the confounder and plaintext
112 // it is calculated over the iv concatenated with the AES cipher output.
113 ib := append(iv, c...)
114 return common.GetIntegrityHash(ib, key, usage, e)
115}
116
117// VerifyIntegrity verifies the integrity of cipertext bytes ct.
118func VerifyIntegrity(key, ct []byte, usage uint32, etype etype.EType) bool {
119 h := make([]byte, etype.GetHMACBitLength()/8)
120 copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:])
121 ivz := make([]byte, etype.GetConfounderByteSize())
122 ib := append(ivz, ct[:len(ct)-(etype.GetHMACBitLength()/8)]...)
123 expectedMAC, _ := common.GetIntegrityHash(ib, key, usage, etype)
124 return hmac.Equal(h, expectedMAC)
125}