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

     1  // Package common provides encryption methods common across encryption types
     2  package common
     3  
     4  import (
     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.
    16  func 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.
    32  func 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.
    47  func 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.
    71  func 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.
    84  func 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.
    89  func 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.
    94  func VerifyChecksum(key, chksum, msg []byte, usage uint32, etype etype.EType) bool {
    95  	//The encrypted message is a concatenation of the encrypted output and the hash HMAC.
    96  	expectedMAC, _ := GetChecksumHash(msg, key, usage, etype)
    97  	return hmac.Equal(chksum, expectedMAC)
    98  }
    99  
   100  // GetUsageKc returns the checksum key usage value for the usage number un.
   101  //
   102  // See RFC 3961 5.3 key-derivation function definition.
   103  func GetUsageKc(un uint32) []byte {
   104  	return getUsage(un, 0x99)
   105  }
   106  
   107  // GetUsageKe returns the encryption key usage value for the usage number un
   108  //
   109  // See RFC 3961 5.3 key-derivation function definition.
   110  func GetUsageKe(un uint32) []byte {
   111  	return getUsage(un, 0xAA)
   112  }
   113  
   114  // GetUsageKi returns the integrity key usage value for the usage number un
   115  //
   116  // See RFC 3961 5.3 key-derivation function definition.
   117  func GetUsageKi(un uint32) []byte {
   118  	return getUsage(un, 0x55)
   119  }
   120  
   121  func getUsage(un uint32, o byte) []byte {
   122  	var buf bytes.Buffer
   123  	binary.Write(&buf, binary.BigEndian, un)
   124  	return append(buf.Bytes(), o)
   125  }
   126  
   127  // IterationsToS2Kparams converts the number of iterations as an integer to a string representation.
   128  func IterationsToS2Kparams(i uint32) string {
   129  	b := make([]byte, 4, 4)
   130  	binary.BigEndian.PutUint32(b, i)
   131  	return hex.EncodeToString(b)
   132  }