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

     1  // Package rfc3961 provides encryption and checksum methods as specified in RFC 3961
     2  package rfc3961
     3  
     4  import (
     5  	"crypto/cipher"
     6  	"crypto/des"
     7  	"crypto/hmac"
     8  	"crypto/rand"
     9  	"errors"
    10  	"fmt"
    11  
    12  	"github.com/jcmturner/gokrb5/v8/crypto/common"
    13  	"github.com/jcmturner/gokrb5/v8/crypto/etype"
    14  )
    15  
    16  // DES3EncryptData encrypts the data provided using DES3 and methods specific to the etype provided.
    17  func DES3EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
    18  	if len(key) != e.GetKeyByteSize() {
    19  		return nil, nil, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
    20  	}
    21  	data, _ = common.ZeroPad(data, e.GetMessageBlockByteSize())
    22  
    23  	block, err := des.NewTripleDESCipher(key)
    24  	if err != nil {
    25  		return nil, nil, fmt.Errorf("error creating cipher: %v", err)
    26  	}
    27  
    28  	//RFC 3961: initial cipher state      All bits zero
    29  	ivz := make([]byte, des.BlockSize)
    30  
    31  	ct := make([]byte, len(data))
    32  	mode := cipher.NewCBCEncrypter(block, ivz)
    33  	mode.CryptBlocks(ct, data)
    34  	return ct[len(ct)-e.GetMessageBlockByteSize():], ct, nil
    35  }
    36  
    37  // DES3EncryptMessage encrypts the message provided using DES3 and methods specific to the etype provided.
    38  // The encrypted data is concatenated with its integrity hash to create an encrypted message.
    39  func DES3EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
    40  	//confounder
    41  	c := make([]byte, e.GetConfounderByteSize())
    42  	_, err := rand.Read(c)
    43  	if err != nil {
    44  		return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
    45  	}
    46  	plainBytes := append(c, message...)
    47  	plainBytes, _ = common.ZeroPad(plainBytes, e.GetMessageBlockByteSize())
    48  
    49  	// Derive key for encryption from usage
    50  	var k []byte
    51  	if usage != 0 {
    52  		k, err = e.DeriveKey(key, common.GetUsageKe(usage))
    53  		if err != nil {
    54  			return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
    55  		}
    56  	}
    57  
    58  	iv, b, err := e.EncryptData(k, plainBytes)
    59  	if err != nil {
    60  		return iv, b, fmt.Errorf("error encrypting data: %v", err)
    61  	}
    62  
    63  	// Generate and append integrity hash
    64  	ih, err := common.GetIntegrityHash(plainBytes, key, usage, e)
    65  	if err != nil {
    66  		return iv, b, fmt.Errorf("error encrypting data: %v", err)
    67  	}
    68  	b = append(b, ih...)
    69  	return iv, b, nil
    70  }
    71  
    72  // DES3DecryptData decrypts the data provided using DES3 and methods specific to the etype provided.
    73  func DES3DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
    74  	if len(key) != e.GetKeyByteSize() {
    75  		return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
    76  	}
    77  
    78  	if len(data) < des.BlockSize || len(data)%des.BlockSize != 0 {
    79  		return []byte{}, errors.New("ciphertext is not a multiple of the block size")
    80  	}
    81  	block, err := des.NewTripleDESCipher(key)
    82  	if err != nil {
    83  		return []byte{}, fmt.Errorf("error creating cipher: %v", err)
    84  	}
    85  	pt := make([]byte, len(data))
    86  	ivz := make([]byte, des.BlockSize)
    87  	mode := cipher.NewCBCDecrypter(block, ivz)
    88  	mode.CryptBlocks(pt, data)
    89  	return pt, nil
    90  }
    91  
    92  // DES3DecryptMessage decrypts the message provided using DES3 and methods specific to the etype provided.
    93  // The integrity of the message is also verified.
    94  func DES3DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
    95  	//Derive the key
    96  	k, err := e.DeriveKey(key, common.GetUsageKe(usage))
    97  	if err != nil {
    98  		return nil, fmt.Errorf("error deriving key: %v", err)
    99  	}
   100  	// Strip off the checksum from the end
   101  	b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
   102  	if err != nil {
   103  		return nil, fmt.Errorf("error decrypting: %v", err)
   104  	}
   105  	//Verify checksum
   106  	if !e.VerifyIntegrity(key, ciphertext, b, usage) {
   107  		return nil, errors.New("error decrypting: integrity verification failed")
   108  	}
   109  	//Remove the confounder bytes
   110  	return b[e.GetConfounderByteSize():], nil
   111  }
   112  
   113  // VerifyIntegrity verifies the integrity of cipertext bytes ct.
   114  func VerifyIntegrity(key, ct, pt []byte, usage uint32, etype etype.EType) bool {
   115  	h := make([]byte, etype.GetHMACBitLength()/8)
   116  	copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:])
   117  	expectedMAC, _ := common.GetIntegrityHash(pt, key, usage, etype)
   118  	return hmac.Equal(h, expectedMAC)
   119  }