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