1// 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 ciphertext output is the concatenation of the output of the basic 96 //encryption function E and a (possibly truncated) HMAC using the 97 //specified hash function H, both applied to the plaintext with a 98 //random confounder prefix and sufficient padding to bring it to a 99 //multiple of the message block size. When the HMAC is computed, the 100 //key is used in the protocol key form. 101 expectedMAC, _ := GetChecksumHash(msg, key, usage, etype) 102 return hmac.Equal(chksum, expectedMAC) 103} 104 105// GetUsageKc returns the checksum key usage value for the usage number un. 106// 107// RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below. 108// 109// Kc = DK(base-key, usage | 0x99); 110func GetUsageKc(un uint32) []byte { 111 return getUsage(un, 0x99) 112} 113 114// GetUsageKe returns the encryption key usage value for the usage number un 115// 116// RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below. 117// 118// Ke = DK(base-key, usage | 0xAA); 119func GetUsageKe(un uint32) []byte { 120 return getUsage(un, 0xAA) 121} 122 123// GetUsageKi returns the integrity key usage value for the usage number un 124// 125// RFC 3961: The "well-known constant" used for the DK function is the key usage number, expressed as four octets in big-endian order, followed by one octet indicated below. 126// 127// Ki = DK(base-key, usage | 0x55); 128func GetUsageKi(un uint32) []byte { 129 return getUsage(un, 0x55) 130} 131 132func getUsage(un uint32, o byte) []byte { 133 var buf bytes.Buffer 134 binary.Write(&buf, binary.BigEndian, un) 135 return append(buf.Bytes(), o) 136} 137 138// IterationsToS2Kparams converts the number of iterations as an integer to a string representation. 139func IterationsToS2Kparams(i uint32) string { 140 b := make([]byte, 4, 4) 141 binary.BigEndian.PutUint32(b, i) 142 return hex.EncodeToString(b) 143} 144