blob: e04e9681c2a1a9f3e5b7a2cdb1745aae7c991c22 [file] [log] [blame]
Scott Baker8487c5d2019-10-18 12:49:46 -07001// Package crypto implements cryptographic functions for Kerberos 5 implementation.
2package crypto
3
4import (
5 "encoding/hex"
6 "fmt"
7
8 "gopkg.in/jcmturner/gokrb5.v7/crypto/etype"
9 "gopkg.in/jcmturner/gokrb5.v7/iana/chksumtype"
10 "gopkg.in/jcmturner/gokrb5.v7/iana/etypeID"
11 "gopkg.in/jcmturner/gokrb5.v7/iana/patype"
12 "gopkg.in/jcmturner/gokrb5.v7/types"
13)
14
15// GetEtype returns an instances of the required etype struct for the etype ID.
16func GetEtype(id int32) (etype.EType, error) {
17 switch id {
18 case etypeID.AES128_CTS_HMAC_SHA1_96:
19 var et Aes128CtsHmacSha96
20 return et, nil
21 case etypeID.AES256_CTS_HMAC_SHA1_96:
22 var et Aes256CtsHmacSha96
23 return et, nil
24 case etypeID.AES128_CTS_HMAC_SHA256_128:
25 var et Aes128CtsHmacSha256128
26 return et, nil
27 case etypeID.AES256_CTS_HMAC_SHA384_192:
28 var et Aes256CtsHmacSha384192
29 return et, nil
30 case etypeID.DES3_CBC_SHA1_KD:
31 var et Des3CbcSha1Kd
32 return et, nil
33 case etypeID.RC4_HMAC:
34 var et RC4HMAC
35 return et, nil
36 default:
37 return nil, fmt.Errorf("unknown or unsupported EType: %d", id)
38 }
39}
40
41// GetChksumEtype returns an instances of the required etype struct for the checksum ID.
42func GetChksumEtype(id int32) (etype.EType, error) {
43 switch id {
44 case chksumtype.HMAC_SHA1_96_AES128:
45 var et Aes128CtsHmacSha96
46 return et, nil
47 case chksumtype.HMAC_SHA1_96_AES256:
48 var et Aes256CtsHmacSha96
49 return et, nil
50 case chksumtype.HMAC_SHA256_128_AES128:
51 var et Aes128CtsHmacSha256128
52 return et, nil
53 case chksumtype.HMAC_SHA384_192_AES256:
54 var et Aes256CtsHmacSha384192
55 return et, nil
56 case chksumtype.HMAC_SHA1_DES3_KD:
57 var et Des3CbcSha1Kd
58 return et, nil
59 case chksumtype.KERB_CHECKSUM_HMAC_MD5:
60 var et RC4HMAC
61 return et, nil
62 //case chksumtype.KERB_CHECKSUM_HMAC_MD5_UNSIGNED:
63 // var et RC4HMAC
64 // return et, nil
65 default:
66 return nil, fmt.Errorf("unknown or unsupported checksum type: %d", id)
67 }
68}
69
70// GetKeyFromPassword generates an encryption key from the principal's password.
71func GetKeyFromPassword(passwd string, cname types.PrincipalName, realm string, etypeID int32, pas types.PADataSequence) (types.EncryptionKey, etype.EType, error) {
72 var key types.EncryptionKey
73 et, err := GetEtype(etypeID)
74 if err != nil {
75 return key, et, fmt.Errorf("error getting encryption type: %v", err)
76 }
77 sk2p := et.GetDefaultStringToKeyParams()
78 var salt string
79 var paID int32
80 for _, pa := range pas {
81 switch pa.PADataType {
82 case patype.PA_PW_SALT:
83 if paID > pa.PADataType {
84 continue
85 }
86 salt = string(pa.PADataValue)
87 case patype.PA_ETYPE_INFO:
88 if paID > pa.PADataType {
89 continue
90 }
91 var eti types.ETypeInfo
92 err := eti.Unmarshal(pa.PADataValue)
93 if err != nil {
94 return key, et, fmt.Errorf("error unmashaling PA Data to PA-ETYPE-INFO2: %v", err)
95 }
96 if etypeID != eti[0].EType {
97 et, err = GetEtype(eti[0].EType)
98 if err != nil {
99 return key, et, fmt.Errorf("error getting encryption type: %v", err)
100 }
101 }
102 salt = string(eti[0].Salt)
103 case patype.PA_ETYPE_INFO2:
104 if paID > pa.PADataType {
105 continue
106 }
107 var et2 types.ETypeInfo2
108 err := et2.Unmarshal(pa.PADataValue)
109 if err != nil {
110 return key, et, fmt.Errorf("error unmashalling PA Data to PA-ETYPE-INFO2: %v", err)
111 }
112 if etypeID != et2[0].EType {
113 et, err = GetEtype(et2[0].EType)
114 if err != nil {
115 return key, et, fmt.Errorf("error getting encryption type: %v", err)
116 }
117 }
118 if len(et2[0].S2KParams) == 4 {
119 sk2p = hex.EncodeToString(et2[0].S2KParams)
120 }
121 salt = et2[0].Salt
122 }
123 }
124 if salt == "" {
125 salt = cname.GetSalt(realm)
126 }
127 k, err := et.StringToKey(passwd, salt, sk2p)
128 if err != nil {
129 return key, et, fmt.Errorf("error deriving key from string: %+v", err)
130 }
131 key = types.EncryptionKey{
132 KeyType: etypeID,
133 KeyValue: k,
134 }
135 return key, et, nil
136}
137
138// GetEncryptedData encrypts the data provided and returns and EncryptedData type.
139// Pass a usage value of zero to use the key provided directly rather than deriving one.
140func GetEncryptedData(plainBytes []byte, key types.EncryptionKey, usage uint32, kvno int) (types.EncryptedData, error) {
141 var ed types.EncryptedData
142 et, err := GetEtype(key.KeyType)
143 if err != nil {
144 return ed, fmt.Errorf("error getting etype: %v", err)
145 }
146 _, b, err := et.EncryptMessage(key.KeyValue, plainBytes, usage)
147 if err != nil {
148 return ed, err
149 }
150
151 ed = types.EncryptedData{
152 EType: key.KeyType,
153 Cipher: b,
154 KVNO: kvno,
155 }
156 return ed, nil
157}
158
159// DecryptEncPart decrypts the EncryptedData.
160func DecryptEncPart(ed types.EncryptedData, key types.EncryptionKey, usage uint32) ([]byte, error) {
161 return DecryptMessage(ed.Cipher, key, usage)
162}
163
164// DecryptMessage decrypts the ciphertext and verifies the integrity.
165func DecryptMessage(ciphertext []byte, key types.EncryptionKey, usage uint32) ([]byte, error) {
166 et, err := GetEtype(key.KeyType)
167 if err != nil {
168 return []byte{}, fmt.Errorf("error decrypting: %v", err)
169 }
170 b, err := et.DecryptMessage(key.KeyValue, ciphertext, usage)
171 if err != nil {
172 return nil, fmt.Errorf("error decrypting: %v", err)
173 }
174 return b, nil
175}