Мы, конечно, можем шифровать данные с помощью RSA OAEP, но ключи довольно большие, и это довольно трудоемкий процесс. Нашим спасителем стало использование эллиптической криптографии (ECC). Но мы можем фактически напрямую шифровать данные с помощью ECC, и поэтому мы используем метод key encapsulation method (KEM), который также используется в методах PQC. При этом мы используем метод обмена ключами Diffie-Hellman (DH), но делаем это в автономном режиме.
Предположим, Боб хочет зашифровать данные для Алисы. Для этого у Боба будет закрытый ключ b и открытый ключ b.G, а у Алисы будет закрытый ключ a и открытый ключ a.G. Базовая точка на эллиптической кривой тогда G, и где a.G — это точка G, добавленная сама к себе a раз. Боб изначально получает открытый ключ Алисы (a.G) доверенным способом. Затем он берет свой закрытый ключ (b) и выполняет операцию Diffie-Hellman, чтобы получить результирующую точку a.B.G. Затем он передает это в метод HKDF для расширения и извлечения в ключ AES, а также некоторые контекстные данные. Это позволит получить секретный ключ (SecretKey), который будет использоваться для шифрования некоторого открытого текста:
Боб также сериализует свой открытый ключ и отправляет его вместе с сообщением. Это также будет иметь хеш-значение, которое покажет, что зашифрованное сообщение и сериализованный открытый ключ не были изменены.
Чтобы расшифровать, Алиса десериализует открытый ключ Боба, чтобы получить b.G. Затем она берет свой закрытый ключ (a) и выполняет операцию Diffie-Hellman, чтобы получить a.b.G. Мы передаем это в функцию HKDF с контекстом, которая создаст тот же секретный ключ, что и у Боба (SecretKey). Затем Алиса сможет расшифровать зашифрованный текст и раскрыть сообщение.
С помощью Hybrid Public Key Encryption (HPKE) мы используем открытый ключ получателя для шифрования открытого текста с использованием асимметричного механизма key encapsulation mechanism (KEM). Ключ выводится с использованием функции вывода ключа (KDF), и где данные шифруются с помощью функции authenticated encryption with additional data (AEAD). В этом случае мы будем использовать: DHKEM_P256_HKDF_SHA256 (используя P256 в качестве KEM), DHKEM_P384_HKDF_SHA384 (используя P384 в качестве KEM), DHKEM_P521_HKDF_SHA512 (используя P521 в качестве KEM) или DHKEM_X25519_HKDF_SHA256 (используя X25519 в качестве KEM). В каждом случае HKDF используется для генерации ключа.
Код находится [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)
}
Пример запуска для DHKEM-P256-HKDF-SHA256 находится [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