Tất nhiên, chúng ta có thể mã hóa dữ liệu bằng RSA OAEP, nhưng các khóa khá lớn và tốn nhiều công sức xử lý. Vị cứu tinh của chúng ta là việc sử dụng mật mã đường cong elliptic (ECC). Nhưng, chúng ta thực sự có thể mã hóa trực tiếp dữ liệu bằng ECC, và vì vậy chúng ta sử dụng phương pháp đóng gói khóa (KEM), và phương pháp này cũng được sử dụng trong các phương pháp PQC. Với điều này, chúng ta sử dụng phương pháp trao đổi khóa Diffie-Hellman (DH) — nhưng thực hiện nó theo cách ngoại tuyến.
Giả sử Bob muốn mã hóa dữ liệu cho Alice. Vì điều này, Bob sẽ có một khóa riêng là b và một khóa công khai là b.G, và Alice sẽ có một khóa riêng là a và một khóa công khai là a.G. Điểm cơ sở trên đường cong elliptic sau đó là G, và trong đó a.G là điểm G được cộng với chính nó a lần. Bob ban đầu nhận được khóa công khai của Alice (a.G) một cách đáng tin cậy. Sau đó, anh ta sẽ lấy khóa riêng của mình (b) và thực hiện một thao tác Diffie-Hellman để cho ra một điểm kết quả là a.B.G. Tiếp theo, anh ta đưa điểm này vào phương pháp HKDF để mở rộng và trích xuất thành khóa AES, cùng với một số dữ liệu ngữ cảnh. Điều này sẽ tạo ra một khóa bí mật (SecretKey), và khóa này sẽ được sử dụng để mã hóa một số văn bản thuần túy:
Bob cũng sẽ tuần tự hóa khóa công khai của mình và gửi nó cùng với tin nhắn. Điều này cũng sẽ có một giá trị băm cho thấy rằng tin nhắn được mã hóa và khóa công khai được tuần tự hóa không bị giả mạo.
Để giải mã, Alice giải tuần tự hóa khóa công khai của Bob để tạo ra b.G. Sau đó, cô ấy sẽ lấy khóa riêng của mình (a) và thực hiện một thao tác Diffie-Hellman để lấy a.b.G. Chúng ta đưa điều này vào một hàm HKDF với ngữ cảnh, và hàm này sẽ tạo ra cùng một khóa bí mật như Bob (SecretKey). Sau đó, Alice sẽ có thể giải mã bản mã và tiết lộ tin nhắn.
Với Hybrid Public Key Encryption (HPKE), chúng ta sử dụng khóa công khai của người nhận để mã hóa văn bản thuần túy bằng cơ chế đóng gói khóa bất đối xứng (KEM). Khóa được lấy bằng cách sử dụng một hàm dẫn xuất khóa (KDF), và trong đó dữ liệu được mã hóa bằng mã hóa được xác thực với hàm dữ liệu bổ sung (AEAD). Trong trường hợp này, chúng ta sẽ sử dụng: DHKEM_P256_HKDF_SHA256 (sử dụng P256 làm KEM), DHKEM_P384_HKDF_SHA384 (sử dụng P384 làm KEM), DHKEM_P521_HKDF_SHA512 (sử dụng P521 làm KEM) hoặc DHKEM_X25519_HKDF_SHA256 (sử dụng X25519 làm KEM). Trong mỗi trường hợp, HKDF được sử dụng để tạo khóa.
Mã là [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)
}
Một mẫu chạy cho DHKEM-P256-HKDF-SHA256 là [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