blob: 0ec8b99211c911a5e690fa99fbc3e8c22ae0fd7d [file] [log] [blame]
Scott Baker8487c5d2019-10-18 12:49:46 -07001// Package rfc4757 provides encryption and checksum methods as specified in RFC 4757
2package rfc4757
3
4import (
5 "crypto/hmac"
6 "crypto/rand"
7 "crypto/rc4"
8 "errors"
9 "fmt"
10
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 4757.
15func EncryptData(key, data []byte, e etype.EType) ([]byte, error) {
16 if len(key) != e.GetKeyByteSize() {
17 return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
18 }
19 rc4Cipher, err := rc4.NewCipher(key)
20 if err != nil {
21 return []byte{}, fmt.Errorf("error creating RC4 cipher: %v", err)
22 }
23 ed := make([]byte, len(data))
24 copy(ed, data)
25 rc4Cipher.XORKeyStream(ed, ed)
26 rc4Cipher.Reset()
27 return ed, nil
28}
29
30// DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 4757.
31func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
32 return EncryptData(key, data, e)
33}
34
35// EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
36// The encrypted data is concatenated with its RC4 header containing integrity checksum and confounder to create an encrypted message.
37func EncryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
38 confounder := make([]byte, e.GetConfounderByteSize()) // size = 8
39 _, err := rand.Read(confounder)
40 if err != nil {
41 return []byte{}, fmt.Errorf("error generating confounder: %v", err)
42 }
43 k1 := key
44 k2 := HMAC(k1, UsageToMSMsgType(usage))
45 toenc := append(confounder, data...)
46 chksum := HMAC(k2, toenc)
47 k3 := HMAC(k2, chksum)
48
49 ed, err := EncryptData(k3, toenc, e)
50 if err != nil {
51 return []byte{}, fmt.Errorf("error encrypting data: %v", err)
52 }
53
54 msg := append(chksum, ed...)
55 return msg, nil
56}
57
58// DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
59// The integrity of the message is also verified.
60func DecryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
61 checksum := data[:e.GetHMACBitLength()/8]
62 ct := data[e.GetHMACBitLength()/8:]
63 _, k2, k3 := deriveKeys(key, checksum, usage, export)
64
65 pt, err := DecryptData(k3, ct, e)
66 if err != nil {
67 return []byte{}, fmt.Errorf("error decrypting data: %v", err)
68 }
69
70 if !VerifyIntegrity(k2, pt, data, e) {
71 return []byte{}, errors.New("integrity checksum incorrect")
72 }
73 return pt[e.GetConfounderByteSize():], nil
74}
75
76// VerifyIntegrity checks the integrity checksum of the data matches that calculated from the decrypted data.
77func VerifyIntegrity(key, pt, data []byte, e etype.EType) bool {
78 chksum := HMAC(key, pt)
79 return hmac.Equal(chksum, data[:e.GetHMACBitLength()/8])
80}