blob: f11d107ba589d5ff2761dd514aca9c6c2efc7774 [file] [log] [blame]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package hpke
import (
"bytes"
"math/rand"
"testing"
"github.com/google/tink/go/subtle/random"
"github.com/google/tink/go/subtle"
pb "github.com/google/tink/go/proto/hpke_go_proto"
)
func TestNewEncryptDecryptUnknownKEM(t *testing.T) {
params := validParams(t)
params.Kem = pb.HpkeKem_KEM_UNKNOWN
pubKey, privKey := pubPrivKeys(t, params)
if _, err := NewEncrypt(pubKey); err == nil {
t.Error("NewEncrypt(unknown KEM): got success, want err")
}
if _, err := NewDecrypt(privKey); err == nil {
t.Error("NewDecrypt(unknown KEM): got success, want err")
}
}
func TestNewEncryptDecryptUnknownKDF(t *testing.T) {
params := validParams(t)
params.Kdf = pb.HpkeKdf_KDF_UNKNOWN
pubKey, privKey := pubPrivKeys(t, params)
if _, err := NewEncrypt(pubKey); err == nil {
t.Error("NewEncrypt(unknown KDF): got success, want err")
}
if _, err := NewDecrypt(privKey); err == nil {
t.Error("NewDecrypt(unknown KDF): got success, want err")
}
}
func TestNewEncryptDecryptUnknownAEAD(t *testing.T) {
params := validParams(t)
params.Aead = pb.HpkeAead_AEAD_UNKNOWN
pubKey, privKey := pubPrivKeys(t, params)
if _, err := NewEncrypt(pubKey); err == nil {
t.Error("NewEncrypt(unknown AEAD): got success, want err")
}
if _, err := NewDecrypt(privKey); err == nil {
t.Error("NewDecrypt(unknown AEAD): got success, want err")
}
}
func TestNewEncryptDecryptMissingParams(t *testing.T) {
pubKey, privKey := pubPrivKeys(t, nil)
if _, err := NewEncrypt(pubKey); err == nil {
t.Error("NewEncrypt(missing params): got success, want err")
}
if _, err := NewDecrypt(privKey); err == nil {
t.Error("NewDecrypt(missing params): got success, want err")
}
}
func TestNewEncryptMissingPubKeyBytes(t *testing.T) {
pubKey, _ := pubPrivKeys(t, validParams(t))
pubKey.PublicKey = nil
if _, err := NewEncrypt(pubKey); err == nil {
t.Error("NewEncrypt(nil pub key): got success, want err")
}
pubKey.PublicKey = []byte{}
if _, err := NewEncrypt(pubKey); err == nil {
t.Error("NewEncrypt(zero-length pub key): got success, want err")
}
}
func TestNewDecryptMissingPrivKeyBytes(t *testing.T) {
_, privKey := pubPrivKeys(t, validParams(t))
privKey.PrivateKey = nil
if _, err := NewDecrypt(privKey); err == nil {
t.Error("NewDecrypt(nil priv key): got success, want err")
}
privKey.PrivateKey = []byte{}
if _, err := NewDecrypt(privKey); err == nil {
t.Error("NewDecrypt(zero-length priv key): got success, want err")
}
}
func TestEncryptDecrypt(t *testing.T) {
aeadIDs := []pb.HpkeAead{pb.HpkeAead_AES_128_GCM, pb.HpkeAead_AES_256_GCM, pb.HpkeAead_CHACHA20_POLY1305}
for _, aeadID := range aeadIDs {
params := &pb.HpkeParams{
Kem: pb.HpkeKem_DHKEM_X25519_HKDF_SHA256,
Kdf: pb.HpkeKdf_HKDF_SHA256,
Aead: aeadID,
}
pubKey, privKey := pubPrivKeys(t, params)
enc, err := NewEncrypt(pubKey)
if err != nil {
t.Fatalf("NewEncrypt: err %q", err)
}
dec, err := NewDecrypt(privKey)
if err != nil {
t.Fatalf("NewDecrypt: err %q", err)
}
wantPT := random.GetRandomBytes(200)
ctxInfo := random.GetRandomBytes(100)
ct, err := enc.Encrypt(wantPT, ctxInfo)
if err != nil {
t.Fatalf("Encrypt: err %q", err)
}
gotPT, err := dec.Decrypt(ct, ctxInfo)
if err != nil {
t.Fatalf("Decrypt: err %q", err)
}
if !bytes.Equal(gotPT, wantPT) {
t.Errorf("Decrypt: got %q, want %q", gotPT, wantPT)
}
}
}
func TestDecryptModifiedCiphertextOrContextInfo(t *testing.T) {
pubKey, privKey := pubPrivKeys(t, validParams(t))
enc, err := NewEncrypt(pubKey)
if err != nil {
t.Fatalf("NewEncrypt: err %q", err)
}
dec, err := NewDecrypt(privKey)
if err != nil {
t.Fatalf("NewDecrypt: err %q", err)
}
wantPT := random.GetRandomBytes(200)
ctxInfo := random.GetRandomBytes(100)
ct, err := enc.Encrypt(wantPT, ctxInfo)
if err != nil {
t.Fatalf("Encrypt: err %q", err)
}
gotPT, err := dec.Decrypt(ct, ctxInfo)
if err != nil {
t.Fatalf("Decrypt: err %q", err)
}
if !bytes.Equal(gotPT, wantPT) {
t.Errorf("Decrypt: got %q, want %q", gotPT, wantPT)
}
tests := []struct {
name string
ct []byte
ctxInfo []byte
}{
{"extended ct", append(ct, []byte("hi there")...), ctxInfo},
{"flip byte ct", flipRandByte(t, ct), ctxInfo},
{"short ct", ct[:len(ct)-5], ctxInfo},
{"empty ct", []byte{}, ctxInfo},
{"extended ctxInfo", ct, append(ctxInfo, []byte("hi there")...)},
{"flip byte ctxInfo", ct, flipRandByte(t, ctxInfo)},
{"short ctxInfo", ct, ctxInfo[:len(ctxInfo)-5]},
{"empty ctxInfo", ct, []byte{}},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if _, err := dec.Decrypt(test.ct, test.ctxInfo); err == nil {
t.Error("Decrypt: got success, want err")
}
})
}
}
func TestEncryptDecryptEmptyContextInfo(t *testing.T) {
pubKey, privKey := pubPrivKeys(t, validParams(t))
enc, err := NewEncrypt(pubKey)
if err != nil {
t.Fatalf("NewEncrypt: err %q", err)
}
dec, err := NewDecrypt(privKey)
if err != nil {
t.Fatalf("NewDecrypt: err %q", err)
}
wantPT := random.GetRandomBytes(200)
ctxInfo := []byte{}
ct, err := enc.Encrypt(wantPT, ctxInfo)
if err != nil {
t.Fatalf("Encrypt: err %q", err)
}
gotPT, err := dec.Decrypt(ct, ctxInfo)
if err != nil {
t.Fatalf("Decrypt: err %q", err)
}
if !bytes.Equal(gotPT, wantPT) {
t.Errorf("Decrypt: got %q, want %q", gotPT, wantPT)
}
}
// TestDecryptEncapsulatedKeyWithFlippedMSB checks that ciphertexts with its
// encapsulated key MSB flipped fails to decrypt. See details at b/213886185.
func TestDecryptEncapsulatedKeyWithFlippedMSB(t *testing.T) {
pubKey, privKey := pubPrivKeys(t, validParams(t))
enc, err := NewEncrypt(pubKey)
if err != nil {
t.Fatalf("NewEncrypt: err %q", err)
}
dec, err := NewDecrypt(privKey)
if err != nil {
t.Fatalf("NewDecrypt: err %q", err)
}
wantPT := random.GetRandomBytes(200)
ctxInfo := random.GetRandomBytes(100)
ct, err := enc.Encrypt(wantPT, ctxInfo)
if err != nil {
t.Fatalf("Encrypt: err %q", err)
}
gotPT, err := dec.Decrypt(ct, ctxInfo)
if err != nil {
t.Fatalf("Decrypt: err %q", err)
}
if !bytes.Equal(gotPT, wantPT) {
t.Errorf("Decrypt: got %q, want %q", gotPT, wantPT)
}
// Flip the MSB of the encapsulated key, which is the first 32 bytes of ct.
ct[31] = ct[31] ^ 128
if _, err := dec.Decrypt(ct, ctxInfo); err == nil {
t.Error("Decrypt with encapsulated key MSB flipped: got success, want err")
}
}
func validParams(t *testing.T) *pb.HpkeParams {
t.Helper()
return &pb.HpkeParams{
Kem: pb.HpkeKem_DHKEM_X25519_HKDF_SHA256,
Kdf: pb.HpkeKdf_HKDF_SHA256,
Aead: pb.HpkeAead_AES_256_GCM,
}
}
func pubPrivKeys(t *testing.T, params *pb.HpkeParams) (*pb.HpkePublicKey, *pb.HpkePrivateKey) {
t.Helper()
priv, err := subtle.GeneratePrivateKeyX25519()
if err != nil {
t.Fatalf("GeneratePrivateKeyX25519: err %q", err)
}
pub, err := subtle.PublicFromPrivateX25519(priv)
if err != nil {
t.Fatalf("PublicFromPrivateX25519: err %q", err)
}
pubKey := &pb.HpkePublicKey{
Version: 0,
Params: params,
PublicKey: pub,
}
privKey := &pb.HpkePrivateKey{
Version: 0,
PublicKey: pubKey,
PrivateKey: priv,
}
return pubKey, privKey
}
func flipRandByte(t *testing.T, b []byte) []byte {
t.Helper()
ret := make([]byte, len(b))
copy(ret, b)
randByte := rand.Intn(len(b))
ret[randByte] = ret[randByte] ^ 255
return ret
}