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

     1  // Package rfc3962 provides encryption and checksum methods as specified in RFC 3962
     2  package rfc3962
     3  
     4  import (
     5  	"crypto/rand"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/jcmturner/aescts/v2"
    10  	"github.com/jcmturner/gokrb5/v8/crypto/common"
    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 3962.
    15  func EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
    16  	if len(key) != e.GetKeyByteSize() {
    17  		return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
    18  	}
    19  	ivz := make([]byte, e.GetCypherBlockBitLength()/8)
    20  	return aescts.Encrypt(key, ivz, data)
    21  }
    22  
    23  // EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 3962.
    24  // The encrypted data is concatenated with its integrity hash to create an encrypted message.
    25  func EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
    26  	if len(key) != e.GetKeyByteSize() {
    27  		return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
    28  	}
    29  	//confounder
    30  	c := make([]byte, e.GetConfounderByteSize())
    31  	_, err := rand.Read(c)
    32  	if err != nil {
    33  		return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
    34  	}
    35  	plainBytes := append(c, message...)
    36  
    37  	// Derive key for encryption from usage
    38  	var k []byte
    39  	if usage != 0 {
    40  		k, err = e.DeriveKey(key, common.GetUsageKe(usage))
    41  		if err != nil {
    42  			return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
    43  		}
    44  	}
    45  
    46  	// Encrypt the data
    47  	iv, b, err := e.EncryptData(k, plainBytes)
    48  	if err != nil {
    49  		return iv, b, fmt.Errorf("error encrypting data: %v", err)
    50  	}
    51  
    52  	// Generate and append integrity hash
    53  	ih, err := common.GetIntegrityHash(plainBytes, key, usage, e)
    54  	if err != nil {
    55  		return iv, b, fmt.Errorf("error encrypting data: %v", err)
    56  	}
    57  	b = append(b, ih...)
    58  	return iv, b, nil
    59  }
    60  
    61  // DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 3962.
    62  func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
    63  	if len(key) != e.GetKeyByteSize() {
    64  		return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
    65  	}
    66  	ivz := make([]byte, e.GetCypherBlockBitLength()/8)
    67  	return aescts.Decrypt(key, ivz, data)
    68  }
    69  
    70  // DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 3962.
    71  // The integrity of the message is also verified.
    72  func DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
    73  	//Derive the key
    74  	k, err := e.DeriveKey(key, common.GetUsageKe(usage))
    75  	if err != nil {
    76  		return nil, fmt.Errorf("error deriving key: %v", err)
    77  	}
    78  	// Strip off the checksum from the end
    79  	b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	//Verify checksum
    84  	if !e.VerifyIntegrity(key, ciphertext, b, usage) {
    85  		return nil, errors.New("integrity verification failed")
    86  	}
    87  	//Remove the confounder bytes
    88  	return b[e.GetConfounderByteSize():], nil
    89  }