github.com/jcmturner/gokrb5/v8@v8.4.4/crypto/rfc8009/encryption.go (about) 1 // Package rfc8009 provides encryption and checksum methods as specified in RFC 8009 2 package rfc8009 3 4 import ( 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. 18 func 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. 32 func 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. 75 func 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. 89 func 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 109 func 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. 118 func 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 }