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 30var aesKeySizes = []uint32{ 31 16, /*AES-128*/ 32 32, /*AES-256*/ 33} 34 35// Since the tag size depends on the Seal() function of crypto library, 36// this test checks that the tag size is always 128 bit. 37func TestAESGCMTagLength(t *testing.T) { 38 for _, keySize := range aesKeySizes { 39 key := random.GetRandomBytes(keySize) 40 a, _ := subtle.NewAESGCM(key) 41 ad := random.GetRandomBytes(32) 42 pt := random.GetRandomBytes(32) 43 ct, _ := a.Encrypt(pt, ad) 44 actualTagSize := len(ct) - subtle.AESGCMIVSize - len(pt) 45 if actualTagSize != subtle.AESGCMTagSize { 46 t.Errorf("tag size is not 128 bit, it is %d bit", actualTagSize*8) 47 } 48 } 49} 50 51func TestAESGCMKeySize(t *testing.T) { 52 for _, keySize := range aesKeySizes { 53 if _, err := subtle.NewAESGCM(make([]byte, keySize)); err != nil { 54 t.Errorf("unexpected error when key size is %d btyes", keySize) 55 } 56 if _, err := subtle.NewAESGCM(make([]byte, keySize+1)); err == nil { 57 t.Errorf("expect an error when key size is not supported %d", keySize) 58 } 59 } 60} 61 62func TestAESGCMEncryptDecrypt(t *testing.T) { 63 for _, keySize := range aesKeySizes { 64 key := random.GetRandomBytes(keySize) 65 a, err := subtle.NewAESGCM(key) 66 if err != nil { 67 t.Errorf("unexpected error when creating new cipher: %s", err) 68 } 69 ad := random.GetRandomBytes(5) 70 for ptSize := 0; ptSize < 75; ptSize++ { 71 pt := random.GetRandomBytes(uint32(ptSize)) 72 ct, err := a.Encrypt(pt, ad) 73 if err != nil { 74 t.Errorf("unexpected error in encryption: keySize %v, ptSize %v", keySize, ptSize) 75 } 76 decrypted, err := a.Decrypt(ct, ad) 77 if err != nil { 78 t.Errorf("unexpected error in decryption: keySize %v, ptSize %v", keySize, ptSize) 79 } 80 if !bytes.Equal(pt, decrypted) { 81 t.Errorf("decrypted text and plaintext don't match: keySize %v, ptSize %v", keySize, ptSize) 82 } 83 } 84 } 85} 86 87func TestAESGCMLongMessages(t *testing.T) { 88 ptSize := 16 89 for ptSize <= 1<<24 { 90 pt := random.GetRandomBytes(uint32(ptSize)) 91 ad := random.GetRandomBytes(uint32(ptSize / 3)) 92 for _, keySize := range aesKeySizes { 93 key := random.GetRandomBytes(keySize) 94 a, _ := subtle.NewAESGCM(key) 95 ct, _ := a.Encrypt(pt, ad) 96 decrypted, _ := a.Decrypt(ct, ad) 97 if !bytes.Equal(pt, decrypted) { 98 t.Errorf("decrypted text and plaintext don't match: keySize %v, ptSize %v", keySize, ptSize) 99 } 100 } 101 ptSize += 5 * ptSize / 11 102 } 103} 104 105func TestAESGCMModifyCiphertext(t *testing.T) { 106 ad := random.GetRandomBytes(33) 107 key := random.GetRandomBytes(16) 108 pt := random.GetRandomBytes(32) 109 a, _ := subtle.NewAESGCM(key) 110 ct, _ := a.Encrypt(pt, ad) 111 // flipping bits 112 for i := 0; i < len(ct); i++ { 113 tmp := ct[i] 114 for j := 0; j < 8; j++ { 115 ct[i] ^= 1 << uint8(j) 116 if _, err := a.Decrypt(ct, ad); err == nil { 117 t.Errorf("expect an error when flipping bit of ciphertext: byte %d, bit %d", i, j) 118 } 119 ct[i] = tmp 120 } 121 } 122 // truncated ciphertext 123 for i := 1; i < len(ct); i++ { 124 if _, err := a.Decrypt(ct[:i], ad); err == nil { 125 t.Errorf("expect an error ciphertext is truncated until byte %d", i) 126 } 127 } 128 // modify associated data 129 for i := 0; i < len(ad); i++ { 130 tmp := ad[i] 131 for j := 0; j < 8; j++ { 132 ad[i] ^= 1 << uint8(j) 133 if _, err := a.Decrypt(ct, ad); err == nil { 134 t.Errorf("expect an error when flipping bit of ad: byte %d, bit %d", i, j) 135 } 136 ad[i] = tmp 137 } 138 } 139 // replace ciphertext with a random string with a small, unacceptable size 140 for _, ctSize := range []uint32{subtle.AESGCMIVSize / 2, subtle.AESGCMIVSize - 1} { 141 smallCT := random.GetRandomBytes(ctSize) 142 emptyAD := []byte{} 143 if _, err := a.Decrypt(smallCT, emptyAD); err == nil { 144 t.Error("Decrypt: got success, want err") 145 } 146 } 147} 148 149/** 150 * This is a very simple test for the randomness of the nonce. 151 * The test simply checks that the multiple ciphertexts of the same 152 * message are distinct. 153 */ 154func TestAESGCMRandomNonce(t *testing.T) { 155 nSample := 1 << 17 156 key := random.GetRandomBytes(16) 157 pt := []byte{} 158 ad := []byte{} 159 a, _ := subtle.NewAESGCM(key) 160 ctSet := make(map[string]bool) 161 for i := 0; i < nSample; i++ { 162 ct, _ := a.Encrypt(pt, ad) 163 ctHex := hex.EncodeToString(ct) 164 _, existed := ctSet[ctHex] 165 if existed { 166 t.Errorf("nonce is repeated after %d samples", i) 167 } 168 ctSet[ctHex] = true 169 } 170} 171 172func TestAESGCMWycheproofCases(t *testing.T) { 173 testutil.SkipTestIfTestSrcDirIsNotSet(t) 174 suite := new(AEADSuite) 175 if err := testutil.PopulateSuite(suite, "aes_gcm_test.json"); err != nil { 176 t.Fatalf("failed populating suite: %s", err) 177 } 178 for _, group := range suite.TestGroups { 179 if err := subtle.ValidateAESKeySize(group.KeySize / 8); err != nil { 180 continue 181 } 182 if group.IvSize != subtle.AESGCMIVSize*8 { 183 continue 184 } 185 for _, test := range group.Tests { 186 caseName := fmt.Sprintf("%s-%s(%d,%d):Case-%d", 187 suite.Algorithm, group.Type, group.KeySize, group.TagSize, test.CaseID) 188 t.Run(caseName, func(t *testing.T) { runAESGCMWycheproofCase(t, test) }) 189 } 190 } 191} 192 193func runAESGCMWycheproofCase(t *testing.T, tc *AEADCase) { 194 var combinedCt []byte 195 combinedCt = append(combinedCt, tc.Iv...) 196 combinedCt = append(combinedCt, tc.Ct...) 197 combinedCt = append(combinedCt, tc.Tag...) 198 // create cipher and do encryption 199 cipher, err := subtle.NewAESGCM(tc.Key) 200 if err != nil { 201 t.Fatalf("cannot create new instance of AESGCM in test case: %s", err) 202 } 203 decrypted, err := cipher.Decrypt(combinedCt, tc.Aad) 204 if err != nil { 205 if tc.Result == "valid" { 206 t.Errorf("unexpected error in test case: %s", err) 207 } 208 } else { 209 if tc.Result == "invalid" { 210 t.Error("decrypted invalid test case") 211 } 212 if !bytes.Equal(decrypted, tc.Msg) { 213 t.Error("incorrect decryption in test case") 214 } 215 } 216} 217