github.com/jcmturner/gokrb5/v8@v8.4.4/crypto/rfc4757/encryption.go (about)

     1  // Package rfc4757 provides encryption and checksum methods as specified in RFC 4757
     2  package rfc4757
     3  
     4  import (
     5  	"crypto/hmac"
     6  	"crypto/rand"
     7  	"crypto/rc4"
     8  	"errors"
     9  	"fmt"
    10  
    11  	"github.com/jcmturner/gokrb5/v8/crypto/etype"
    12  )
    13  
    14  // EncryptData encrypts the data provided using methods specific to the etype provided as defined in RFC 4757.
    15  func EncryptData(key, data []byte, e etype.EType) ([]byte, error) {
    16  	if len(key) != e.GetKeyByteSize() {
    17  		return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
    18  	}
    19  	rc4Cipher, err := rc4.NewCipher(key)
    20  	if err != nil {
    21  		return []byte{}, fmt.Errorf("error creating RC4 cipher: %v", err)
    22  	}
    23  	ed := make([]byte, len(data))
    24  	copy(ed, data)
    25  	rc4Cipher.XORKeyStream(ed, ed)
    26  	rc4Cipher.Reset()
    27  	return ed, nil
    28  }
    29  
    30  // DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 4757.
    31  func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
    32  	return EncryptData(key, data, e)
    33  }
    34  
    35  // EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
    36  // The encrypted data is concatenated with its RC4 header containing integrity checksum and confounder to create an encrypted message.
    37  func EncryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
    38  	confounder := make([]byte, e.GetConfounderByteSize()) // size = 8
    39  	_, err := rand.Read(confounder)
    40  	if err != nil {
    41  		return []byte{}, fmt.Errorf("error generating confounder: %v", err)
    42  	}
    43  	k1 := key
    44  	k2 := HMAC(k1, UsageToMSMsgType(usage))
    45  	toenc := append(confounder, data...)
    46  	chksum := HMAC(k2, toenc)
    47  	k3 := HMAC(k2, chksum)
    48  
    49  	ed, err := EncryptData(k3, toenc, e)
    50  	if err != nil {
    51  		return []byte{}, fmt.Errorf("error encrypting data: %v", err)
    52  	}
    53  
    54  	msg := append(chksum, ed...)
    55  	return msg, nil
    56  }
    57  
    58  // DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
    59  // The integrity of the message is also verified.
    60  func DecryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
    61  	checksum := data[:e.GetHMACBitLength()/8]
    62  	ct := data[e.GetHMACBitLength()/8:]
    63  	_, k2, k3 := deriveKeys(key, checksum, usage, export)
    64  
    65  	pt, err := DecryptData(k3, ct, e)
    66  	if err != nil {
    67  		return []byte{}, fmt.Errorf("error decrypting data: %v", err)
    68  	}
    69  
    70  	if !VerifyIntegrity(k2, pt, data, e) {
    71  		return []byte{}, errors.New("integrity checksum incorrect")
    72  	}
    73  	return pt[e.GetConfounderByteSize():], nil
    74  }
    75  
    76  // VerifyIntegrity checks the integrity checksum of the data matches that calculated from the decrypted data.
    77  func VerifyIntegrity(key, pt, data []byte, e etype.EType) bool {
    78  	chksum := HMAC(key, pt)
    79  	return hmac.Equal(chksum, data[:e.GetHMACBitLength()/8])
    80  }