blob: dab55be7583b92ecea26a2cc1548710d5c7e672b [file] [log] [blame]
khenaidoo7d3c5582021-08-11 18:09:44 -04001// Package common provides encryption methods common across encryption types
2package common
3
4import (
5 "bytes"
6 "crypto/hmac"
7 "encoding/binary"
8 "encoding/hex"
9 "errors"
10 "fmt"
11
12 "github.com/jcmturner/gokrb5/v8/crypto/etype"
13)
14
15// ZeroPad pads bytes with zeros to nearest multiple of message size m.
16func ZeroPad(b []byte, m int) ([]byte, error) {
17 if m <= 0 {
18 return nil, errors.New("Invalid message block size when padding")
19 }
20 if b == nil || len(b) == 0 {
21 return nil, errors.New("Data not valid to pad: Zero size")
22 }
23 if l := len(b) % m; l != 0 {
24 n := m - l
25 z := make([]byte, n)
26 b = append(b, z...)
27 }
28 return b, nil
29}
30
31// PKCS7Pad pads bytes according to RFC 2315 to nearest multiple of message size m.
32func PKCS7Pad(b []byte, m int) ([]byte, error) {
33 if m <= 0 {
34 return nil, errors.New("Invalid message block size when padding")
35 }
36 if b == nil || len(b) == 0 {
37 return nil, errors.New("Data not valid to pad: Zero size")
38 }
39 n := m - (len(b) % m)
40 pb := make([]byte, len(b)+n)
41 copy(pb, b)
42 copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
43 return pb, nil
44}
45
46// PKCS7Unpad removes RFC 2315 padding from byes where message size is m.
47func PKCS7Unpad(b []byte, m int) ([]byte, error) {
48 if m <= 0 {
49 return nil, errors.New("invalid message block size when unpadding")
50 }
51 if b == nil || len(b) == 0 {
52 return nil, errors.New("padded data not valid: Zero size")
53 }
54 if len(b)%m != 0 {
55 return nil, errors.New("padded data not valid: Not multiple of message block size")
56 }
57 c := b[len(b)-1]
58 n := int(c)
59 if n == 0 || n > len(b) {
60 return nil, errors.New("padded data not valid: Data may not have been padded")
61 }
62 for i := 0; i < n; i++ {
63 if b[len(b)-n+i] != c {
64 return nil, errors.New("padded data not valid")
65 }
66 }
67 return b[:len(b)-n], nil
68}
69
70// GetHash generates the keyed hash value according to the etype's hash function.
71func GetHash(pt, key []byte, usage []byte, etype etype.EType) ([]byte, error) {
72 k, err := etype.DeriveKey(key, usage)
73 if err != nil {
74 return nil, fmt.Errorf("unable to derive key for checksum: %v", err)
75 }
76 mac := hmac.New(etype.GetHashFunc(), k)
77 p := make([]byte, len(pt))
78 copy(p, pt)
79 mac.Write(p)
80 return mac.Sum(nil)[:etype.GetHMACBitLength()/8], nil
81}
82
83// GetChecksumHash returns a keyed checksum hash of the bytes provided.
84func GetChecksumHash(b, key []byte, usage uint32, etype etype.EType) ([]byte, error) {
85 return GetHash(b, key, GetUsageKc(usage), etype)
86}
87
88// GetIntegrityHash returns a keyed integrity hash of the bytes provided.
89func GetIntegrityHash(b, key []byte, usage uint32, etype etype.EType) ([]byte, error) {
90 return GetHash(b, key, GetUsageKi(usage), etype)
91}
92
93// VerifyChecksum compares the checksum of the msg bytes is the same as the checksum provided.
94func VerifyChecksum(key, chksum, msg []byte, usage uint32, etype etype.EType) bool {
95 //The encrypted message is a concatenation of the encrypted output and the hash HMAC.
96 expectedMAC, _ := GetChecksumHash(msg, key, usage, etype)
97 return hmac.Equal(chksum, expectedMAC)
98}
99
100// GetUsageKc returns the checksum key usage value for the usage number un.
101//
102// See RFC 3961 5.3 key-derivation function definition.
103func GetUsageKc(un uint32) []byte {
104 return getUsage(un, 0x99)
105}
106
107// GetUsageKe returns the encryption key usage value for the usage number un
108//
109// See RFC 3961 5.3 key-derivation function definition.
110func GetUsageKe(un uint32) []byte {
111 return getUsage(un, 0xAA)
112}
113
114// GetUsageKi returns the integrity key usage value for the usage number un
115//
116// See RFC 3961 5.3 key-derivation function definition.
117func GetUsageKi(un uint32) []byte {
118 return getUsage(un, 0x55)
119}
120
121func getUsage(un uint32, o byte) []byte {
122 var buf bytes.Buffer
123 binary.Write(&buf, binary.BigEndian, un)
124 return append(buf.Bytes(), o)
125}
126
127// IterationsToS2Kparams converts the number of iterations as an integer to a string representation.
128func IterationsToS2Kparams(i uint32) string {
129 b := make([]byte, 4, 4)
130 binary.BigEndian.PutUint32(b, i)
131 return hex.EncodeToString(b)
132}