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

     1  // Package crypto implements cryptographic functions for Kerberos 5 implementation.
     2  package crypto
     3  
     4  import (
     5  	"encoding/hex"
     6  	"fmt"
     7  
     8  	"github.com/jcmturner/gokrb5/v8/crypto/etype"
     9  	"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
    10  	"github.com/jcmturner/gokrb5/v8/iana/etypeID"
    11  	"github.com/jcmturner/gokrb5/v8/iana/patype"
    12  	"github.com/jcmturner/gokrb5/v8/types"
    13  )
    14  
    15  // GetEtype returns an instances of the required etype struct for the etype ID.
    16  func GetEtype(id int32) (etype.EType, error) {
    17  	switch id {
    18  	case etypeID.AES128_CTS_HMAC_SHA1_96:
    19  		var et Aes128CtsHmacSha96
    20  		return et, nil
    21  	case etypeID.AES256_CTS_HMAC_SHA1_96:
    22  		var et Aes256CtsHmacSha96
    23  		return et, nil
    24  	case etypeID.AES128_CTS_HMAC_SHA256_128:
    25  		var et Aes128CtsHmacSha256128
    26  		return et, nil
    27  	case etypeID.AES256_CTS_HMAC_SHA384_192:
    28  		var et Aes256CtsHmacSha384192
    29  		return et, nil
    30  	case etypeID.DES3_CBC_SHA1_KD:
    31  		var et Des3CbcSha1Kd
    32  		return et, nil
    33  	case etypeID.RC4_HMAC:
    34  		var et RC4HMAC
    35  		return et, nil
    36  	default:
    37  		return nil, fmt.Errorf("unknown or unsupported EType: %d", id)
    38  	}
    39  }
    40  
    41  // GetChksumEtype returns an instances of the required etype struct for the checksum ID.
    42  func GetChksumEtype(id int32) (etype.EType, error) {
    43  	switch id {
    44  	case chksumtype.HMAC_SHA1_96_AES128:
    45  		var et Aes128CtsHmacSha96
    46  		return et, nil
    47  	case chksumtype.HMAC_SHA1_96_AES256:
    48  		var et Aes256CtsHmacSha96
    49  		return et, nil
    50  	case chksumtype.HMAC_SHA256_128_AES128:
    51  		var et Aes128CtsHmacSha256128
    52  		return et, nil
    53  	case chksumtype.HMAC_SHA384_192_AES256:
    54  		var et Aes256CtsHmacSha384192
    55  		return et, nil
    56  	case chksumtype.HMAC_SHA1_DES3_KD:
    57  		var et Des3CbcSha1Kd
    58  		return et, nil
    59  	case chksumtype.KERB_CHECKSUM_HMAC_MD5:
    60  		var et RC4HMAC
    61  		return et, nil
    62  	//case chksumtype.KERB_CHECKSUM_HMAC_MD5_UNSIGNED:
    63  	//	var et RC4HMAC
    64  	//	return et, nil
    65  	default:
    66  		return nil, fmt.Errorf("unknown or unsupported checksum type: %d", id)
    67  	}
    68  }
    69  
    70  // GetKeyFromPassword generates an encryption key from the principal's password.
    71  func GetKeyFromPassword(passwd string, cname types.PrincipalName, realm string, etypeID int32, pas types.PADataSequence) (types.EncryptionKey, etype.EType, error) {
    72  	var key types.EncryptionKey
    73  	et, err := GetEtype(etypeID)
    74  	if err != nil {
    75  		return key, et, fmt.Errorf("error getting encryption type: %v", err)
    76  	}
    77  	sk2p := et.GetDefaultStringToKeyParams()
    78  	var salt string
    79  	var paID int32
    80  	for _, pa := range pas {
    81  		switch pa.PADataType {
    82  		case patype.PA_PW_SALT:
    83  			if paID > pa.PADataType {
    84  				continue
    85  			}
    86  			salt = string(pa.PADataValue)
    87  		case patype.PA_ETYPE_INFO:
    88  			if paID > pa.PADataType {
    89  				continue
    90  			}
    91  			var eti types.ETypeInfo
    92  			err := eti.Unmarshal(pa.PADataValue)
    93  			if err != nil {
    94  				return key, et, fmt.Errorf("error unmashaling PA Data to PA-ETYPE-INFO2: %v", err)
    95  			}
    96  			if etypeID != eti[0].EType {
    97  				et, err = GetEtype(eti[0].EType)
    98  				if err != nil {
    99  					return key, et, fmt.Errorf("error getting encryption type: %v", err)
   100  				}
   101  			}
   102  			salt = string(eti[0].Salt)
   103  		case patype.PA_ETYPE_INFO2:
   104  			if paID > pa.PADataType {
   105  				continue
   106  			}
   107  			var et2 types.ETypeInfo2
   108  			err := et2.Unmarshal(pa.PADataValue)
   109  			if err != nil {
   110  				return key, et, fmt.Errorf("error unmashalling PA Data to PA-ETYPE-INFO2: %v", err)
   111  			}
   112  			if etypeID != et2[0].EType {
   113  				et, err = GetEtype(et2[0].EType)
   114  				if err != nil {
   115  					return key, et, fmt.Errorf("error getting encryption type: %v", err)
   116  				}
   117  			}
   118  			if len(et2[0].S2KParams) == 4 {
   119  				sk2p = hex.EncodeToString(et2[0].S2KParams)
   120  			}
   121  			salt = et2[0].Salt
   122  		}
   123  	}
   124  	if salt == "" {
   125  		salt = cname.GetSalt(realm)
   126  	}
   127  	k, err := et.StringToKey(passwd, salt, sk2p)
   128  	if err != nil {
   129  		return key, et, fmt.Errorf("error deriving key from string: %+v", err)
   130  	}
   131  	key = types.EncryptionKey{
   132  		KeyType:  etypeID,
   133  		KeyValue: k,
   134  	}
   135  	return key, et, nil
   136  }
   137  
   138  // GetEncryptedData encrypts the data provided and returns and EncryptedData type.
   139  // Pass a usage value of zero to use the key provided directly rather than deriving one.
   140  func GetEncryptedData(plainBytes []byte, key types.EncryptionKey, usage uint32, kvno int) (types.EncryptedData, error) {
   141  	var ed types.EncryptedData
   142  	et, err := GetEtype(key.KeyType)
   143  	if err != nil {
   144  		return ed, fmt.Errorf("error getting etype: %v", err)
   145  	}
   146  	_, b, err := et.EncryptMessage(key.KeyValue, plainBytes, usage)
   147  	if err != nil {
   148  		return ed, err
   149  	}
   150  
   151  	ed = types.EncryptedData{
   152  		EType:  key.KeyType,
   153  		Cipher: b,
   154  		KVNO:   kvno,
   155  	}
   156  	return ed, nil
   157  }
   158  
   159  // DecryptEncPart decrypts the EncryptedData.
   160  func DecryptEncPart(ed types.EncryptedData, key types.EncryptionKey, usage uint32) ([]byte, error) {
   161  	return DecryptMessage(ed.Cipher, key, usage)
   162  }
   163  
   164  // DecryptMessage decrypts the ciphertext and verifies the integrity.
   165  func DecryptMessage(ciphertext []byte, key types.EncryptionKey, usage uint32) ([]byte, error) {
   166  	et, err := GetEtype(key.KeyType)
   167  	if err != nil {
   168  		return []byte{}, fmt.Errorf("error decrypting: %v", err)
   169  	}
   170  	b, err := et.DecryptMessage(key.KeyValue, ciphertext, usage)
   171  	if err != nil {
   172  		return nil, fmt.Errorf("error decrypting: %v", err)
   173  	}
   174  	return b, nil
   175  }