1// Copyright 2020 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17package subtle_test 18 19import ( 20 "bytes" 21 "encoding/hex" 22 "fmt" 23 "testing" 24 25 "github.com/google/tink/go/aead/subtle" 26 "github.com/google/tink/go/subtle/random" 27 "github.com/google/tink/go/testutil" 28) 29 30func TestAESGCMSIVRejectsInvalidKeyLength(t *testing.T) { 31 invalidKeySizes := []uint32{4, 8, 12, 15, 17, 24, 30, 31, 33, 64, 128} 32 33 for _, keySize := range invalidKeySizes { 34 key := random.GetRandomBytes(keySize) 35 36 if _, err := subtle.NewAESGCMSIV(key); err == nil { 37 t.Errorf("expected error with invalid key-size %d", keySize) 38 } 39 } 40} 41 42func TestAESGCMSIVRandomNonceProducesDifferentCiphertexts(t *testing.T) { 43 nSample := 1 << 17 44 key := random.GetRandomBytes(16) 45 pt := []byte{} 46 ad := []byte{} 47 a, _ := subtle.NewAESGCMSIV(key) 48 ctSet := make(map[string]bool) 49 50 for i := 0; i < nSample; i++ { 51 ct, _ := a.Encrypt(pt, ad) 52 ctHex := hex.EncodeToString(ct) 53 54 if _, existed := ctSet[ctHex]; existed { 55 t.Errorf("nonce is repeated after %d samples", i) 56 } 57 ctSet[ctHex] = true 58 } 59} 60 61func TestAESGCMSIVModifyCiphertext(t *testing.T) { 62 ad := random.GetRandomBytes(33) 63 key := random.GetRandomBytes(16) 64 pt := random.GetRandomBytes(32) 65 a, _ := subtle.NewAESGCMSIV(key) 66 ct, _ := a.Encrypt(pt, ad) 67 // flipping bits 68 for i := 0; i < len(ct); i++ { 69 tmp := ct[i] 70 for j := 0; j < 8; j++ { 71 ct[i] ^= 1 << uint8(j) 72 if _, err := a.Decrypt(ct, ad); err == nil { 73 t.Errorf("expect an error when flipping bit of ciphertext: byte %d, bit %d", i, j) 74 } 75 ct[i] = tmp 76 } 77 } 78 // truncated ciphertext 79 for i := 1; i < len(ct); i++ { 80 if _, err := a.Decrypt(ct[:i], ad); err == nil { 81 t.Errorf("expect an error ciphertext is truncated until byte %d", i) 82 } 83 } 84 // modify associated data 85 for i := 0; i < len(ad); i++ { 86 tmp := ad[i] 87 for j := 0; j < 8; j++ { 88 ad[i] ^= 1 << uint8(j) 89 if _, err := a.Decrypt(ct, ad); err == nil { 90 t.Errorf("expect an error when flipping bit of ad: byte %d, bit %d", i, j) 91 } 92 ad[i] = tmp 93 } 94 } 95} 96 97func TestAESGCMSIVWycheproofCases(t *testing.T) { 98 testutil.SkipTestIfTestSrcDirIsNotSet(t) 99 suite := new(AEADSuite) 100 if err := testutil.PopulateSuite(suite, "aes_gcm_siv_test.json"); err != nil { 101 t.Fatalf("failed populating suite: %s", err) 102 } 103 for _, group := range suite.TestGroups { 104 for _, test := range group.Tests { 105 caseName := fmt.Sprintf("%s-%s(%d):Case-%d", suite.Algorithm, group.Type, group.KeySize, test.CaseID) 106 t.Run("DecryptOnly/"+caseName, func(t *testing.T) { runWycheproofDecryptOnly(t, test) }) 107 t.Run("EncryptDecrypt/"+caseName, func(t *testing.T) { runWycheproofEncryptDecrypt(t, test) }) 108 } 109 } 110} 111 112func runWycheproofDecryptOnly(t *testing.T, testCase *AEADCase) { 113 aead, err := subtle.NewAESGCMSIV(testCase.Key) 114 if err != nil { 115 t.Fatalf("cannot create aead, error: %v", err) 116 } 117 118 var combinedCt []byte 119 combinedCt = append(combinedCt, testCase.Iv...) 120 combinedCt = append(combinedCt, testCase.Ct...) 121 combinedCt = append(combinedCt, testCase.Tag...) 122 decrypted, err := aead.Decrypt(combinedCt, testCase.Aad) 123 switch testCase.Result { 124 case "valid": 125 if err != nil { 126 t.Errorf("unexpected error in test-case: %v", err) 127 } else if !bytes.Equal(decrypted, testCase.Msg) { 128 t.Errorf( 129 "incorrect decryption: actual: %s; expected %s", 130 hex.EncodeToString(decrypted), hex.EncodeToString(testCase.Msg)) 131 } 132 case "invalid": 133 if err == nil && bytes.Equal(testCase.Ct, decrypted) { 134 t.Error("successfully decrypted invalid test-case") 135 } 136 default: 137 t.Errorf("unknown test-case result: %s", testCase.Result) 138 } 139} 140 141func runWycheproofEncryptDecrypt(t *testing.T, testCase *AEADCase) { 142 aead, err := subtle.NewAESGCMSIV(testCase.Key) 143 if err != nil { 144 t.Fatalf("cannot create aead, error: %v", err) 145 } 146 147 ct, err := aead.Encrypt(testCase.Msg, testCase.Aad) 148 if err != nil { 149 if testCase.Result != "invalid" { 150 t.Errorf("unexpected error in test-case: %v", err) 151 } 152 return 153 } 154 155 decrypted, err := aead.Decrypt(ct, testCase.Aad) 156 switch testCase.Result { 157 case "valid": 158 if err != nil { 159 t.Errorf("unexpected error in test-case: %v", err) 160 } else if !bytes.Equal(decrypted, testCase.Msg) { 161 t.Errorf( 162 "incorrect decryption: actual: %s; expected %s", 163 hex.EncodeToString(decrypted), hex.EncodeToString(testCase.Msg)) 164 } 165 case "invalid": 166 if err == nil && bytes.Equal(ct, decrypted) { 167 t.Error("successfully decrypted invalid test-case") 168 } 169 default: 170 t.Errorf("unknown test-case result: %s", testCase.Result) 171 } 172} 173