Por supuesto, podemos cifrar datos con RSA OAEP, pero las claves son bastante grandes y el proceso es bastante intensivo. Nuestro salvador ha sido el uso de la criptografía de curva elíptica (ECC). Pero, en realidad podemos cifrar datos directamente con ECC, por lo que utilizamos un método de encapsulación de clave (KEM), que también se utiliza en los métodos PQC. Con esto, utilizamos un método de intercambio de claves Diffie-Hellman (DH), pero lo hacemos de forma offline.
Digamos que Bob quiere cifrar datos para Alice. Para ello, Bob tendrá una clave privada b y una clave pública b.G, y Alice tendrá una clave privada a y una clave pública a.G. El punto base en la curva elíptica es entonces G, y donde a.G es el punto G sumado a sí mismo a veces. Bob inicialmente obtiene la clave pública de Alice (a.G) de forma fiable. A continuación, tomará su clave privada (b) y realizará una operación Diffie-Hellman para obtener un punto resultante de a.B.G. A continuación, introduce esto en el método HKDF para expandir y extraer en una clave AES, junto con algunos datos de contexto. Esto derivará una clave secreta (SecretKey), que se utilizará para cifrar algún texto plano:
Bob también serializará su clave pública y la enviará junto con el mensaje. Esto también tendrá un valor hash que mostrará que el mensaje cifrado y la clave pública serializada no han sido manipulados.
Para descifrar, Alice deserializa la clave pública de Bob para producir b.G. A continuación, tomará su clave privada (a) y realizará una operación Diffie-Hellman para obtener a.b.G. Introducimos esto en una función HKDF con el contexto, que producirá la misma clave secreta que Bob (SecretKey). Alice podrá entonces descifrar el texto cifrado y revelar el mensaje.
Con el cifrado híbrido de clave pública (HPKE), utilizamos la clave pública de un destinatario para cifrar el texto plano utilizando un mecanismo de encapsulación de clave asimétrica (KEM). La clave se deriva utilizando una función de derivación de clave (KDF), y donde los datos se cifran con un cifrado autenticado con función de datos adicionales (AEAD). En este caso, utilizaremos: DHKEM_P256_HKDF_SHA256 (utilizando P256 como el KEM), DHKEM_P384_HKDF_SHA384 (utilizando P384 como el KEM), DHKEM_P521_HKDF_SHA512 (utilizando P521 como el KEM) o DHKEM_X25519_HKDF_SHA256 (utilizando X25519 como el KEM). En cada caso, HKDF se utiliza para generar la clave.
El código está [here]:
package main
import (
"fmt"
"os"
"strconv"
"github.com/tink-crypto/tink-go/v2/hybrid/hpke"
"github.com/tink-crypto/tink-go/v2/hybrid"
"github.com/tink-crypto/tink-go/v2/keyset"
)
func main() {
msg:="Testing"
context:="My Context"
method:=hpke.DHKEM_P256_HKDF_SHA256
m:=1
argCount := len(os.Args[1:])
if (argCount>0) {msg = os.Args[1]}
if (argCount>1) {context =os.Args[2]}
if (argCount>2) {m,_ =strconv.Atoi(os.Args[3])}
if (m==2) {method=hpke.DHKEM_P384_HKDF_SHA384
} else if (m==3) {method=hpke.DHKEM_P521_HKDF_SHA512
} else if (m==4) {method=hpke.DHKEM_X25519_HKDF_SHA256
}
plaintext := []byte(msg)
contextInfo := []byte(context)
params,_ := hpke.NewParameters(hpke.ParametersOpts{
KEMID: method,
KDFID: hpke.HKDFSHA256,
AEADID: hpke.AES256GCM,
Variant: hpke.VariantTink,
})
km := keyset.NewManager()
keyID, _ := km.AddNewKeyFromParameters(params)
if err := km.SetPrimary(keyID); err != nil {
}
privateKeyHandle, _ := km.Handle()
publicKeyHandle, _ := privateKeyHandle.Public()
encrypter, _ := hybrid.NewHybridEncrypt(publicKeyHandle)
decrypter, _ := hybrid.NewHybridDecrypt(privateKeyHandle)
ciphertext,_ := encrypter.Encrypt(plaintext, contextInfo)
decrypted,_ := decrypter.Decrypt(ciphertext, contextInfo)
fmt.Printf("Plaintext: %s\n\n",msg)
fmt.Printf("Method: %s\n\n",method)
fmt.Printf("Private key: %s\n\n",privateKeyHandle)
fmt.Printf("Public key: %s\n\n",publicKeyHandle)
fmt.Printf("Ciphertext: %x\n\n",ciphertext)
fmt.Printf("Decrypted: %s\n",decrypted)
}
Una muestra de ejecución para DHKEM-P256-HKDF-SHA256 es [here]:
Plaintext: Testing
Method: DHKEM-P256-HKDF-SHA256
Private key: primary_key_id:1203322961 key_info:{type_url:"type.googleapis.com/google.crypto.tink.HpkePrivateKey" status:ENABLED key_id:1203322961 output_prefix_type:TINK}
Public key: primary_key_id:1203322961 key_info:{type_url:"type.googleapis.com/google.crypto.tink.HpkePublicKey" status:ENABLED key_id:1203322961 output_prefix_type:TINK}
Ciphertext: 0147b94051043bdeb59abad6caebff20753dadfc0bf8a2d6131b6935f149afdc84b450dda4316d79bae3529eaafec63197a55ffd30c186ffea74bbcb811bfb2b93dacfeaab3b4cc8352534fd5f2e7252abac03553b16d607ea791df7c9
Decrypted: Testing