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 "encoding/hex" 21 "testing" 22 23 "github.com/google/tink/go/streamingaead/subtle" 24) 25 26func TestAESGCMHKDFEncryptDecrypt(t *testing.T) { 27 testCases := []struct { 28 name string 29 keySizeInBytes int 30 segmentSize int 31 firstSegmentOffset int 32 plaintextSize int 33 chunkSize int 34 }{ 35 { 36 name: "small-1", 37 keySizeInBytes: 16, 38 segmentSize: 256, 39 firstSegmentOffset: 0, 40 plaintextSize: 20, 41 chunkSize: 64, 42 }, 43 { 44 name: "small-2", 45 keySizeInBytes: 16, 46 segmentSize: 512, 47 firstSegmentOffset: 0, 48 plaintextSize: 400, 49 chunkSize: 64, 50 }, 51 { 52 name: "small-offset-1", 53 keySizeInBytes: 16, 54 segmentSize: 256, 55 firstSegmentOffset: 8, 56 plaintextSize: 20, 57 chunkSize: 64, 58 }, 59 { 60 name: "small-offset-2", 61 keySizeInBytes: 16, 62 segmentSize: 512, 63 firstSegmentOffset: 8, 64 plaintextSize: 400, 65 chunkSize: 64, 66 }, 67 { 68 name: "empty-1", 69 keySizeInBytes: 16, 70 segmentSize: 256, 71 firstSegmentOffset: 0, 72 plaintextSize: 0, 73 chunkSize: 128, 74 }, 75 { 76 name: "empty-2", 77 keySizeInBytes: 16, 78 segmentSize: 256, 79 firstSegmentOffset: 8, 80 plaintextSize: 0, 81 chunkSize: 128, 82 }, 83 { 84 name: "medium-1", 85 keySizeInBytes: 16, 86 segmentSize: 256, 87 firstSegmentOffset: 0, 88 plaintextSize: 1024, 89 chunkSize: 128, 90 }, 91 { 92 name: "medium-2", 93 keySizeInBytes: 16, 94 segmentSize: 512, 95 firstSegmentOffset: 0, 96 plaintextSize: 3086, 97 chunkSize: 128, 98 }, 99 { 100 name: "medium-3", 101 keySizeInBytes: 32, 102 segmentSize: 1024, 103 firstSegmentOffset: 0, 104 plaintextSize: 12345, 105 chunkSize: 128, 106 }, 107 { 108 name: "large-chunks-1", 109 keySizeInBytes: 16, 110 segmentSize: 256, 111 firstSegmentOffset: 0, 112 plaintextSize: 1024, 113 chunkSize: 4096, 114 }, 115 { 116 name: "large-chunks-2", 117 keySizeInBytes: 16, 118 segmentSize: 512, 119 firstSegmentOffset: 0, 120 plaintextSize: 5086, 121 chunkSize: 4096, 122 }, 123 { 124 name: "large-chunks-3", 125 keySizeInBytes: 32, 126 segmentSize: 1024, 127 firstSegmentOffset: 0, 128 plaintextSize: 12345, 129 chunkSize: 5000, 130 }, 131 { 132 name: "medium-offset-1", 133 keySizeInBytes: 16, 134 segmentSize: 256, 135 firstSegmentOffset: 8, 136 plaintextSize: 1024, 137 chunkSize: 64, 138 }, 139 { 140 name: "medium-offset-2", 141 keySizeInBytes: 16, 142 segmentSize: 512, 143 firstSegmentOffset: 20, 144 plaintextSize: 3086, 145 chunkSize: 256, 146 }, 147 { 148 name: "medium-offset-3", 149 keySizeInBytes: 32, 150 segmentSize: 1024, 151 firstSegmentOffset: 10, 152 plaintextSize: 12345, 153 chunkSize: 5000, 154 }, 155 { 156 name: "last-segment-full-1", 157 keySizeInBytes: 16, 158 segmentSize: 256, 159 firstSegmentOffset: 0, 160 plaintextSize: 216, 161 chunkSize: 64, 162 }, 163 { 164 name: "last-segment-full-2", 165 keySizeInBytes: 16, 166 segmentSize: 256, 167 firstSegmentOffset: 16, 168 plaintextSize: 200, 169 chunkSize: 256, 170 }, 171 { 172 name: "last-segment-full-3", 173 keySizeInBytes: 16, 174 segmentSize: 256, 175 firstSegmentOffset: 16, 176 plaintextSize: 440, 177 chunkSize: 1024, 178 }, 179 { 180 name: "single-byte-1", 181 keySizeInBytes: 16, 182 segmentSize: 256, 183 firstSegmentOffset: 0, 184 plaintextSize: 1024, 185 chunkSize: 1, 186 }, 187 { 188 name: "single-byte-2", 189 keySizeInBytes: 32, 190 segmentSize: 512, 191 firstSegmentOffset: 0, 192 plaintextSize: 5086, 193 chunkSize: 1, 194 }, 195 } 196 for _, tc := range testCases { 197 t.Run(tc.name, func(t *testing.T) { 198 cipher, err := subtle.NewAESGCMHKDF(ikm, "SHA256", tc.keySizeInBytes, tc.segmentSize, tc.firstSegmentOffset) 199 if err != nil { 200 t.Errorf("Cannot create a cipher: %v", err) 201 } 202 203 pt, ct, err := encrypt(cipher, aad, tc.plaintextSize) 204 if err != nil { 205 t.Error(err) 206 } 207 208 if err := decrypt(cipher, aad, pt, ct, tc.chunkSize); err != nil { 209 t.Error(err) 210 } 211 }) 212 } 213} 214 215func TestAESGCMHKDFModifiedCiphertext(t *testing.T) { 216 ikm, err := hex.DecodeString("000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff") 217 if err != nil { 218 t.Fatal(err) 219 } 220 aad, err := hex.DecodeString("aabbccddeeff") 221 if err != nil { 222 t.Fatal(err) 223 } 224 225 const ( 226 keySizeInBytes = 16 227 segmentSize = 256 228 firstSegmentOffset = 8 229 plaintextSize = 1024 230 chunkSize = 128 231 ) 232 233 cipher, err := subtle.NewAESGCMHKDF(ikm, "SHA256", keySizeInBytes, segmentSize, firstSegmentOffset) 234 if err != nil { 235 t.Errorf("Cannot create a cipher: %v", err) 236 } 237 238 pt, ct, err := encrypt(cipher, aad, plaintextSize) 239 if err != nil { 240 t.Error(err) 241 } 242 243 t.Run("truncate ciphertext", func(t *testing.T) { 244 for i := 0; i < len(ct); i += 8 { 245 if err := decrypt(cipher, aad, pt, ct[:i], chunkSize); err == nil { 246 t.Errorf("expected error") 247 } 248 } 249 }) 250 t.Run("append to ciphertext", func(t *testing.T) { 251 sizes := []int{1, segmentSize - len(ct)%segmentSize, segmentSize} 252 for _, size := range sizes { 253 ct2 := append(ct, make([]byte, size)...) 254 if err := decrypt(cipher, aad, pt, ct2, chunkSize); err == nil { 255 t.Errorf("expected error") 256 } 257 } 258 }) 259 t.Run("flip bits", func(t *testing.T) { 260 for i := range ct { 261 ct2 := make([]byte, len(ct)) 262 copy(ct2, ct) 263 ct2[i] ^= byte(1) 264 if err := decrypt(cipher, aad, pt, ct2, chunkSize); err == nil { 265 t.Errorf("expected error") 266 } 267 } 268 }) 269 t.Run("delete segments", func(t *testing.T) { 270 for i := 0; i < len(ct)/segmentSize+1; i++ { 271 start, end := segmentPos(segmentSize, firstSegmentOffset, cipher.HeaderLength(), i) 272 if start > len(ct) { 273 break 274 } 275 if end > len(ct) { 276 end = len(ct) 277 } 278 ct2 := append(ct[:start], ct[end:]...) 279 if err := decrypt(cipher, aad, pt, ct2, chunkSize); err == nil { 280 t.Errorf("expected error") 281 } 282 } 283 }) 284 t.Run("duplicate segments", func(t *testing.T) { 285 for i := 0; i < len(ct)/segmentSize+1; i++ { 286 start, end := segmentPos(segmentSize, firstSegmentOffset, cipher.HeaderLength(), i) 287 if start > len(ct) { 288 break 289 } 290 if end > len(ct) { 291 end = len(ct) 292 } 293 ct2 := append(ct[:end], ct[start:]...) 294 if err := decrypt(cipher, aad, pt, ct2, chunkSize); err == nil { 295 t.Errorf("expected error") 296 } 297 } 298 }) 299 t.Run("modify aad", func(t *testing.T) { 300 for i := range aad { 301 aad2 := make([]byte, len(aad)) 302 copy(aad2, aad) 303 aad2[i] ^= byte(1) 304 if err := decrypt(cipher, aad2, pt, ct, chunkSize); err == nil { 305 t.Errorf("expected error") 306 } 307 } 308 }) 309} 310