blob: 1d14d5af034c177c9f2341bed6062e12ab46595a [file] [log] [blame]
// Copyright 2020 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 subtle_test
import (
"bytes"
"encoding/hex"
"fmt"
"testing"
"github.com/google/tink/go/aead/subtle"
"github.com/google/tink/go/subtle/random"
"github.com/google/tink/go/testutil"
)
func TestAESGCMSIVRejectsInvalidKeyLength(t *testing.T) {
invalidKeySizes := []uint32{4, 8, 12, 15, 17, 24, 30, 31, 33, 64, 128}
for _, keySize := range invalidKeySizes {
key := random.GetRandomBytes(keySize)
if _, err := subtle.NewAESGCMSIV(key); err == nil {
t.Errorf("expected error with invalid key-size %d", keySize)
}
}
}
func TestAESGCMSIVRandomNonceProducesDifferentCiphertexts(t *testing.T) {
nSample := 1 << 17
key := random.GetRandomBytes(16)
pt := []byte{}
ad := []byte{}
a, _ := subtle.NewAESGCMSIV(key)
ctSet := make(map[string]bool)
for i := 0; i < nSample; i++ {
ct, _ := a.Encrypt(pt, ad)
ctHex := hex.EncodeToString(ct)
if _, existed := ctSet[ctHex]; existed {
t.Errorf("nonce is repeated after %d samples", i)
}
ctSet[ctHex] = true
}
}
func TestAESGCMSIVModifyCiphertext(t *testing.T) {
ad := random.GetRandomBytes(33)
key := random.GetRandomBytes(16)
pt := random.GetRandomBytes(32)
a, _ := subtle.NewAESGCMSIV(key)
ct, _ := a.Encrypt(pt, ad)
// flipping bits
for i := 0; i < len(ct); i++ {
tmp := ct[i]
for j := 0; j < 8; j++ {
ct[i] ^= 1 << uint8(j)
if _, err := a.Decrypt(ct, ad); err == nil {
t.Errorf("expect an error when flipping bit of ciphertext: byte %d, bit %d", i, j)
}
ct[i] = tmp
}
}
// truncated ciphertext
for i := 1; i < len(ct); i++ {
if _, err := a.Decrypt(ct[:i], ad); err == nil {
t.Errorf("expect an error ciphertext is truncated until byte %d", i)
}
}
// modify associated data
for i := 0; i < len(ad); i++ {
tmp := ad[i]
for j := 0; j < 8; j++ {
ad[i] ^= 1 << uint8(j)
if _, err := a.Decrypt(ct, ad); err == nil {
t.Errorf("expect an error when flipping bit of ad: byte %d, bit %d", i, j)
}
ad[i] = tmp
}
}
}
func TestAESGCMSIVWycheproofCases(t *testing.T) {
testutil.SkipTestIfTestSrcDirIsNotSet(t)
suite := new(AEADSuite)
if err := testutil.PopulateSuite(suite, "aes_gcm_siv_test.json"); err != nil {
t.Fatalf("failed populating suite: %s", err)
}
for _, group := range suite.TestGroups {
for _, test := range group.Tests {
caseName := fmt.Sprintf("%s-%s(%d):Case-%d", suite.Algorithm, group.Type, group.KeySize, test.CaseID)
t.Run("DecryptOnly/"+caseName, func(t *testing.T) { runWycheproofDecryptOnly(t, test) })
t.Run("EncryptDecrypt/"+caseName, func(t *testing.T) { runWycheproofEncryptDecrypt(t, test) })
}
}
}
func runWycheproofDecryptOnly(t *testing.T, testCase *AEADCase) {
aead, err := subtle.NewAESGCMSIV(testCase.Key)
if err != nil {
t.Fatalf("cannot create aead, error: %v", err)
}
var combinedCt []byte
combinedCt = append(combinedCt, testCase.Iv...)
combinedCt = append(combinedCt, testCase.Ct...)
combinedCt = append(combinedCt, testCase.Tag...)
decrypted, err := aead.Decrypt(combinedCt, testCase.Aad)
switch testCase.Result {
case "valid":
if err != nil {
t.Errorf("unexpected error in test-case: %v", err)
} else if !bytes.Equal(decrypted, testCase.Msg) {
t.Errorf(
"incorrect decryption: actual: %s; expected %s",
hex.EncodeToString(decrypted), hex.EncodeToString(testCase.Msg))
}
case "invalid":
if err == nil && bytes.Equal(testCase.Ct, decrypted) {
t.Error("successfully decrypted invalid test-case")
}
default:
t.Errorf("unknown test-case result: %s", testCase.Result)
}
}
func runWycheproofEncryptDecrypt(t *testing.T, testCase *AEADCase) {
aead, err := subtle.NewAESGCMSIV(testCase.Key)
if err != nil {
t.Fatalf("cannot create aead, error: %v", err)
}
ct, err := aead.Encrypt(testCase.Msg, testCase.Aad)
if err != nil {
if testCase.Result != "invalid" {
t.Errorf("unexpected error in test-case: %v", err)
}
return
}
decrypted, err := aead.Decrypt(ct, testCase.Aad)
switch testCase.Result {
case "valid":
if err != nil {
t.Errorf("unexpected error in test-case: %v", err)
} else if !bytes.Equal(decrypted, testCase.Msg) {
t.Errorf(
"incorrect decryption: actual: %s; expected %s",
hex.EncodeToString(decrypted), hex.EncodeToString(testCase.Msg))
}
case "invalid":
if err == nil && bytes.Equal(ct, decrypted) {
t.Error("successfully decrypted invalid test-case")
}
default:
t.Errorf("unknown test-case result: %s", testCase.Result)
}
}