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 }