1// 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}
176