blob: 6f550fa8605c1b95af1a7dc02109c686eda01dbc [file] [log] [blame]
Scott Baker8461e152019-10-01 14:44:30 -07001// Package rfc3961 provides encryption and checksum methods as specified in RFC 3961
2package rfc3961
3
4import (
5 "crypto/cipher"
6 "crypto/des"
7 "crypto/hmac"
8 "crypto/rand"
9 "errors"
10 "fmt"
11
12 "gopkg.in/jcmturner/gokrb5.v7/crypto/common"
13 "gopkg.in/jcmturner/gokrb5.v7/crypto/etype"
14)
15
16// DES3EncryptData encrypts the data provided using DES3 and methods specific to the etype provided.
17func DES3EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
18 if len(key) != e.GetKeyByteSize() {
19 return nil, nil, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
20 }
21 data, _ = common.ZeroPad(data, e.GetMessageBlockByteSize())
22
23 block, err := des.NewTripleDESCipher(key)
24 if err != nil {
25 return nil, nil, fmt.Errorf("error creating cipher: %v", err)
26 }
27
28 //RFC 3961: initial cipher state All bits zero
29 ivz := make([]byte, des.BlockSize)
30
31 ct := make([]byte, len(data))
32 mode := cipher.NewCBCEncrypter(block, ivz)
33 mode.CryptBlocks(ct, data)
34 return ct[len(ct)-e.GetMessageBlockByteSize():], ct, nil
35}
36
37// DES3EncryptMessage encrypts the message provided using DES3 and methods specific to the etype provided.
38// The encrypted data is concatenated with its integrity hash to create an encrypted message.
39func DES3EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
40 //confounder
41 c := make([]byte, e.GetConfounderByteSize())
42 _, err := rand.Read(c)
43 if err != nil {
44 return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
45 }
46 plainBytes := append(c, message...)
47 plainBytes, _ = common.ZeroPad(plainBytes, e.GetMessageBlockByteSize())
48
49 // Derive key for encryption from usage
50 var k []byte
51 if usage != 0 {
52 k, err = e.DeriveKey(key, common.GetUsageKe(usage))
53 if err != nil {
54 return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
55 }
56 }
57
58 iv, b, err := e.EncryptData(k, plainBytes)
59 if err != nil {
60 return iv, b, fmt.Errorf("error encrypting data: %v", err)
61 }
62
63 // Generate and append integrity hash
64 ih, err := common.GetIntegrityHash(plainBytes, key, usage, e)
65 if err != nil {
66 return iv, b, fmt.Errorf("error encrypting data: %v", err)
67 }
68 b = append(b, ih...)
69 return iv, b, nil
70}
71
72// DES3DecryptData decrypts the data provided using DES3 and methods specific to the etype provided.
73func DES3DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
74 if len(key) != e.GetKeyByteSize() {
75 return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
76 }
77
78 if len(data) < des.BlockSize || len(data)%des.BlockSize != 0 {
79 return []byte{}, errors.New("ciphertext is not a multiple of the block size")
80 }
81 block, err := des.NewTripleDESCipher(key)
82 if err != nil {
83 return []byte{}, fmt.Errorf("error creating cipher: %v", err)
84 }
85 pt := make([]byte, len(data))
86 ivz := make([]byte, des.BlockSize)
87 mode := cipher.NewCBCDecrypter(block, ivz)
88 mode.CryptBlocks(pt, data)
89 return pt, nil
90}
91
92// DES3DecryptMessage decrypts the message provided using DES3 and methods specific to the etype provided.
93// The integrity of the message is also verified.
94func DES3DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
95 //Derive the key
96 k, err := e.DeriveKey(key, common.GetUsageKe(usage))
97 if err != nil {
98 return nil, fmt.Errorf("error deriving key: %v", err)
99 }
100 // Strip off the checksum from the end
101 b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
102 if err != nil {
103 return nil, fmt.Errorf("error decrypting: %v", err)
104 }
105 //Verify checksum
106 if !e.VerifyIntegrity(key, ciphertext, b, usage) {
107 return nil, errors.New("error decrypting: integrity verification failed")
108 }
109 //Remove the confounder bytes
110 return b[e.GetConfounderByteSize():], nil
111}
112
113// VerifyIntegrity verifies the integrity of cipertext bytes ct.
114func VerifyIntegrity(key, ct, pt []byte, usage uint32, etype etype.EType) bool {
115 //The ciphertext output is the concatenation of the output of the basic
116 //encryption function E and a (possibly truncated) HMAC using the
117 //specified hash function H, both applied to the plaintext with a
118 //random confounder prefix and sufficient padding to bring it to a
119 //multiple of the message block size. When the HMAC is computed, the
120 //key is used in the protocol key form.
121 h := make([]byte, etype.GetHMACBitLength()/8)
122 copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:])
123 expectedMAC, _ := common.GetIntegrityHash(pt, key, usage, etype)
124 return hmac.Equal(h, expectedMAC)
125}