blob: 2be2fde0710d26459eee26826e53d24338a30e2d [file] [log] [blame]
Scott Bakered4efab2020-01-13 19:12:25 -08001// Package rfc3962 provides encryption and checksum methods as specified in RFC 3962
2package rfc3962
3
4import (
5 "crypto/rand"
6 "errors"
7 "fmt"
8
9 "gopkg.in/jcmturner/aescts.v1"
10 "gopkg.in/jcmturner/gokrb5.v7/crypto/common"
11 "gopkg.in/jcmturner/gokrb5.v7/crypto/etype"
12)
13
14// EncryptData encrypts the data provided using methods specific to the etype provided as defined in RFC 3962.
15func EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
16 if len(key) != e.GetKeyByteSize() {
17 return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
18 }
19 ivz := make([]byte, e.GetCypherBlockBitLength()/8)
20 return aescts.Encrypt(key, ivz, data)
21}
22
23// EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 3962.
24// The encrypted data is concatenated with its integrity hash to create an encrypted message.
25func EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
26 if len(key) != e.GetKeyByteSize() {
27 return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
28 }
29 //confounder
30 c := make([]byte, e.GetConfounderByteSize())
31 _, err := rand.Read(c)
32 if err != nil {
33 return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
34 }
35 plainBytes := append(c, message...)
36
37 // Derive key for encryption from usage
38 var k []byte
39 if usage != 0 {
40 k, err = e.DeriveKey(key, common.GetUsageKe(usage))
41 if err != nil {
42 return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
43 }
44 }
45
46 // Encrypt the data
47 iv, b, err := e.EncryptData(k, plainBytes)
48 if err != nil {
49 return iv, b, fmt.Errorf("error encrypting data: %v", err)
50 }
51
52 // Generate and append integrity hash
53 ih, err := common.GetIntegrityHash(plainBytes, key, usage, e)
54 if err != nil {
55 return iv, b, fmt.Errorf("error encrypting data: %v", err)
56 }
57 b = append(b, ih...)
58 return iv, b, nil
59}
60
61// DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 3962.
62func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
63 if len(key) != e.GetKeyByteSize() {
64 return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
65 }
66 ivz := make([]byte, e.GetCypherBlockBitLength()/8)
67 return aescts.Decrypt(key, ivz, data)
68}
69
70// DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 3962.
71// The integrity of the message is also verified.
72func DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
73 //Derive the key
74 k, err := e.DeriveKey(key, common.GetUsageKe(usage))
75 if err != nil {
76 return nil, fmt.Errorf("error deriving key: %v", err)
77 }
78 // Strip off the checksum from the end
79 b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
80 if err != nil {
81 return nil, err
82 }
83 //Verify checksum
84 if !e.VerifyIntegrity(key, ciphertext, b, usage) {
85 return nil, errors.New("integrity verification failed")
86 }
87 //Remove the confounder bytes
88 return b[e.GetConfounderByteSize():], nil
89}