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.

sequenceDiagram participant Alice participant Bob Bob->>Bob: Generate RSA Key Pair Bob->>Alice: Send public key Alice->>Alice: Generate random AES key Alice->>Alice: Encrypt payload with AES Key Alice->>Alice: Encrypt AES key with RSA Public Key Alice->>Bob: Transmit encrypted payload + encrypted aes key Bob->>Bob: Decrypts encrypted AES key with private key Bob->>Bob: Uses AES key to decrypt payload

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)
}