Hybrid encryption combines the strengths of both asymmetric encryption (such as RSA) and symmetric encryption (such as AES) to provide secure and efficient data encryption.
Overview Link to heading
This typically involves creating an random AES key and an RSA Key Pair. The client will encrypt the payload with AES and encrypt AES Key with public key of the reciever. Upon reciept, the reciever will decrypt the AES key and then decrypt the payload.
Hybrid encryption offers the benefits of asymmetric encryption, such as secure key exchange and encryption of the symmetric key, along with the efficiency and speed of symmetric encryption for bulk data encryption. This approach is commonly used interacting with payment providers to ensure secure and confidential transmission of sensitive payment information. In hybrid encryption, symmetric encryption is used for efficient bulk data encryption, while public key encryption (asymmetric encryption) is used for securely exchanging the symmetric key. This combination provides the benefits of both encryption methods, allowing secure communication between parties while maintaining performance efficiency.
Example Link to heading
Here is a sammple GoLang example for using hybrid encryption
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"fmt"
"io"
)
func main() {
// Generate RSA key pair
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
fmt.Println("Failed to generate RSA key pair:", err)
return
}
// Message to encrypt
message := []byte("Hello, world!")
// Generate random AES key
aesKey := make([]byte, 32) // 32 bytes for AES-256
_, err = rand.Read(aesKey)
if err != nil {
fmt.Println("Failed to generate AES key:", err)
return
}
// Encrypt the message using AES
encryptedMessage, err := encryptAES(message, aesKey)
if err != nil {
fmt.Println("Failed to encrypt message with AES:", err)
return
}
encodedEncryptedMessage := base64.StdEncoding.EncodeToString([]byte(encryptedMessage))
fmt.Println(string(encodedEncryptedMessage))
// Encrypt the AES key using RSA public key
encryptedAESKey, err := encryptRSA(aesKey, &privateKey.PublicKey)
if err != nil {
fmt.Println("Failed to encrypt AES key with RSA:", err)
return
}
// Decrypt the AES key using RSA private key
decryptedAESKey, err := decryptRSA(encryptedAESKey, privateKey)
if err != nil {
fmt.Println("Failed to decrypt AES key with RSA:", err)
return
}
// Decrypt the message using AES
decryptedMessage, err := decryptAES(encryptedMessage, decryptedAESKey)
if err != nil {
fmt.Println("Failed to decrypt message with AES:", err)
return
}
fmt.Println("Original message:", string(message))
fmt.Println("Decrypted message:", string(decryptedMessage))
}
// Encrypts the message using AES with a randomly generated IV
func encryptAES(message, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
encrypted := make([]byte, aes.BlockSize+len(message))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
cipher.NewCFBEncrypter(block, iv).XORKeyStream(encrypted[aes.BlockSize:], message)
return encrypted, nil
}
// Decrypts the message using AES with the given key and IV
func decryptAES(encrypted, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
decrypted := make([]byte, len(encrypted))
cipher.NewCFBDecrypter(block, iv).XORKeyStream(decrypted, encrypted)
return decrypted, nil
}
// Encrypts the data using RSA public key
func encryptRSA(data []byte, publicKey *rsa.PublicKey) ([]byte, error) {
return rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, data, nil)
}
// Decrypts the data using RSA private key
func decryptRSA(encryptedData []byte, privateKey *rsa.PrivateKey) ([]byte, error) {
return rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, encryptedData, nil)
}