1 // Copyright 2017 Google Inc. 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 17 package com.google.crypto.tink.subtle; 18 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.fail; 21 import static org.junit.Assume.assumeTrue; 22 23 import com.google.crypto.tink.InsecureSecretKeyAccess; 24 import com.google.crypto.tink.StreamingAead; 25 import com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey; 26 import com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingParameters; 27 import com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingParameters.HashType; 28 import com.google.crypto.tink.testing.StreamingTestUtil; 29 import com.google.crypto.tink.testing.StreamingTestUtil.SeekableByteBufferChannel; 30 import com.google.crypto.tink.testing.TestUtil; 31 import com.google.crypto.tink.util.SecretBytes; 32 import java.nio.ByteBuffer; 33 import java.nio.channels.WritableByteChannel; 34 import java.security.GeneralSecurityException; 35 import org.junit.BeforeClass; 36 import org.junit.Rule; 37 import org.junit.Test; 38 import org.junit.experimental.theories.DataPoints; 39 import org.junit.experimental.theories.FromDataPoints; 40 import org.junit.experimental.theories.Theories; 41 import org.junit.experimental.theories.Theory; 42 import org.junit.rules.TemporaryFolder; 43 import org.junit.runner.RunWith; 44 45 /** 46 * Test for {@code AesGcmHkdfStreaming}-implementation of {@code StreamingAead}-primitive. 47 */ 48 @RunWith(Theories.class) 49 public class AesGcmHkdfStreamingTest { 50 @Rule public TemporaryFolder tmpFolder = new TemporaryFolder(); 51 52 @DataPoints("vanillaImplementationTestVectors") 53 public static AesGcmHkdfStreamingTestVector[] vanillaImplementationTestVectors; 54 55 @DataPoints("randomAccessTestVectors") 56 public static AesGcmHkdfStreamingTestVector[] randomAccessTestVectors; 57 58 @DataPoints("singleBytesTestVectors") 59 public static AesGcmHkdfStreamingTestVector[] singleBytesTestVectors; 60 61 @DataPoints("skipWithStreamTestVectors") 62 public static AesGcmHkdfStreamingTestVector[] skipWithStreamTestVectors; 63 64 private static AesGcmHkdfStreaming defaultAesHkdfStreamingInstance; 65 66 /** 67 * Encrypts and decrypts some plaintext in a stream and checks that the expected plaintext is 68 * returned. 69 */ 70 @Theory testEncryptDecrypt( @romDataPoints"vanillaImplementationTestVectors") AesGcmHkdfStreamingTestVector t)71 public void testEncryptDecrypt( 72 @FromDataPoints("vanillaImplementationTestVectors") AesGcmHkdfStreamingTestVector t) 73 throws Exception { 74 StreamingTestUtil.testEncryptDecrypt( 75 t.directConstructorAgs, 76 t.directConstructorAgs.getFirstSegmentOffset(), 77 t.plaintextSize, 78 t.chunkSize); 79 } 80 81 @Theory testEncryptDecryptDifferentInstances( @romDataPoints"vanillaImplementationTestVectors") AesGcmHkdfStreamingTestVector t)82 public void testEncryptDecryptDifferentInstances( 83 @FromDataPoints("vanillaImplementationTestVectors") AesGcmHkdfStreamingTestVector t) 84 throws Exception { 85 assumeTrue(t.keyObjectAgs != null); 86 StreamingTestUtil.testEncryptDecryptDifferentInstances( 87 t.directConstructorAgs, 88 t.keyObjectAgs, 89 t.keyObjectAgs.getFirstSegmentOffset(), 90 t.plaintextSize, 91 t.chunkSize); 92 } 93 94 /** Encrypt and then decrypt partially, and check that the result is the same. */ 95 @Theory testEncryptDecryptRandomAccess( @romDataPoints"randomAccessTestVectors") AesGcmHkdfStreamingTestVector t)96 public void testEncryptDecryptRandomAccess( 97 @FromDataPoints("randomAccessTestVectors") AesGcmHkdfStreamingTestVector t) throws Exception { 98 StreamingTestUtil.testEncryptDecryptRandomAccess( 99 t.directConstructorAgs, t.directConstructorAgs.getFirstSegmentOffset(), t.plaintextSize); 100 } 101 102 @Theory testEncryptSingleBytes( @romDataPoints"singleBytesTestVectors") AesGcmHkdfStreamingTestVector t)103 public void testEncryptSingleBytes( 104 @FromDataPoints("singleBytesTestVectors") AesGcmHkdfStreamingTestVector t) throws Exception { 105 StreamingTestUtil.testEncryptSingleBytes(t.directConstructorAgs, t.plaintextSize); 106 } 107 108 @Theory testSkipWithStream( @romDataPoints"skipWithStreamTestVectors") AesGcmHkdfStreamingTestVector t)109 public void testSkipWithStream( 110 @FromDataPoints("skipWithStreamTestVectors") AesGcmHkdfStreamingTestVector t) 111 throws Exception { 112 StreamingTestUtil.testSkipWithStream( 113 t.directConstructorAgs, 114 t.directConstructorAgs.getFirstSegmentOffset(), 115 t.plaintextSize, 116 t.chunkSize); 117 } 118 119 /** 120 * Encrypts and decrypts a with non-ASCII characters using CharsetEncoders and CharsetDecoders. 121 */ 122 @Test testEncryptDecryptString()123 public void testEncryptDecryptString() throws Exception { 124 StreamingTestUtil.testEncryptDecryptString(defaultAesHkdfStreamingInstance); 125 } 126 127 /** Test encryption with a simulated ciphertext channel, which has only a limited capacity. */ 128 @Test testEncryptLimitedCiphertextChannel()129 public void testEncryptLimitedCiphertextChannel() throws Exception { 130 // Test vector with a suitably large plaintext size. 131 AesGcmHkdfStreamingTestVector t = singleBytesTestVectors[3]; 132 byte[] aad = Hex.decode("aabbccddeeff"); 133 byte[] plaintext = StreamingTestUtil.generatePlaintext(t.plaintextSize); 134 ByteBuffer ciphertext = 135 ByteBuffer.allocate((int) t.directConstructorAgs.expectedCiphertextSize(t.plaintextSize)); 136 WritableByteChannel ctChannel = new SeekableByteBufferChannel(ciphertext, 100); 137 WritableByteChannel encChannel = 138 ((StreamingAead) t.directConstructorAgs).newEncryptingChannel(ctChannel, aad); 139 ByteBuffer plaintextBuffer = ByteBuffer.wrap(plaintext); 140 int loops = 0; 141 while (plaintextBuffer.remaining() > 0) { 142 encChannel.write(plaintextBuffer); 143 loops += 1; 144 if (loops > 100000) { 145 fail("Too many loops"); 146 } 147 } 148 encChannel.close(); 149 assertFalse(encChannel.isOpen()); 150 StreamingTestUtil.isValidCiphertext(t.directConstructorAgs, plaintext, aad, ciphertext.array()); 151 } 152 153 // Modifies the ciphertext. Checks that decryption either results in correct plaintext 154 // or an exception. 155 // The following modifications are tested: 156 // (1) truncate ciphertext 157 // (2) append stuff 158 // (3) flip bits 159 // (4) remove segments 160 // (5) duplicate segments 161 // (6) modify aad 162 @Test testModifiedCiphertext()163 public void testModifiedCiphertext() throws Exception { 164 // Test vector with a short ikm. 165 AesGcmHkdfStreamingTestVector t = vanillaImplementationTestVectors[0]; 166 StreamingTestUtil.testModifiedCiphertext( 167 t.directConstructorAgs, 168 t.directConstructorAgs.getCiphertextSegmentSize(), 169 t.directConstructorAgs.getFirstSegmentOffset()); 170 } 171 172 @Test testModifiedCiphertextWithSeekableByteChannel()173 public void testModifiedCiphertextWithSeekableByteChannel() throws Exception { 174 // Test vector with a short ikm. 175 AesGcmHkdfStreamingTestVector t = vanillaImplementationTestVectors[0]; 176 StreamingTestUtil.testModifiedCiphertextWithSeekableByteChannel( 177 t.directConstructorAgs, 178 t.directConstructorAgs.getCiphertextSegmentSize(), 179 t.directConstructorAgs.getFirstSegmentOffset()); 180 } 181 182 /** Encrypt and decrypt a long ciphertext. */ 183 @Test testEncryptDecryptLong()184 public void testEncryptDecryptLong() throws Exception { 185 if (TestUtil.isAndroid()) { 186 System.out.println("testEncryptDecryptLong doesn't work on Android, skipping"); 187 return; 188 } 189 long plaintextSize = (1L << 32) + 1234567; 190 StreamingTestUtil.testEncryptDecryptLong(defaultAesHkdfStreamingInstance, plaintextSize); 191 } 192 193 /** Encrypt some plaintext to a file, then decrypt from the file */ 194 @Test testFileEncryption()195 public void testFileEncryption() throws Exception { 196 int plaintextSize = 1 << 20; 197 StreamingTestUtil.testFileEncryption( 198 defaultAesHkdfStreamingInstance, tmpFolder.newFile(), plaintextSize); 199 } 200 201 @BeforeClass setUp()202 public static void setUp() throws Exception { 203 vanillaImplementationTestVectors = 204 new AesGcmHkdfStreamingTestVector[] { 205 // Short initial key material. 206 new AesGcmHkdfStreamingTestVector( 207 /* keySizeInBytes= */ 16, 208 /* ciphertextSegmentSize= */ 256, 209 /* firstSegmentOffset= */ 8, 210 HashType.SHA256, 211 /* ikm= */ "000102030405060708090a0b0c0d0e0f", 212 /* plaintextSize= */ 20, 213 /* chunkSize= */ 64), 214 // Ciphertext smaller than one segment. 215 new AesGcmHkdfStreamingTestVector( 216 /* keySizeInBytes= */ 16, 217 /* ciphertextSegmentSize= */ 256, 218 /* firstSegmentOffset= */ 0, 219 HashType.SHA1, 220 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 221 /* plaintextSize= */ 20, 222 /* chunkSize= */ 64), 223 new AesGcmHkdfStreamingTestVector( 224 /* keySizeInBytes= */ 16, 225 /* ciphertextSegmentSize= */ 512, 226 /* firstSegmentOffset= */ 0, 227 HashType.SHA256, 228 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 229 /* plaintextSize= */ 400, 230 /* chunkSize= */ 64), 231 // Ciphertext smaller than one segment, with a non-zero offset. 232 new AesGcmHkdfStreamingTestVector( 233 /* keySizeInBytes= */ 16, 234 /* ciphertextSegmentSize= */ 256, 235 /* firstSegmentOffset= */ 8, 236 HashType.SHA512, 237 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 238 /* plaintextSize= */ 20, 239 /* chunkSize= */ 64), 240 new AesGcmHkdfStreamingTestVector( 241 /* keySizeInBytes= */ 16, 242 /* ciphertextSegmentSize= */ 512, 243 /* firstSegmentOffset= */ 8, 244 HashType.SHA1, 245 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 246 /* plaintextSize= */ 400, 247 /* chunkSize= */ 64), 248 // Empty plaintext. 249 new AesGcmHkdfStreamingTestVector( 250 /* keySizeInBytes= */ 16, 251 /* ciphertextSegmentSize= */ 256, 252 /* firstSegmentOffset= */ 0, 253 HashType.SHA256, 254 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 255 /* plaintextSize= */ 0, 256 /* chunkSize= */ 128), 257 new AesGcmHkdfStreamingTestVector( 258 /* keySizeInBytes= */ 16, 259 /* ciphertextSegmentSize= */ 256, 260 /* firstSegmentOffset= */ 8, 261 HashType.SHA512, 262 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 263 /* plaintextSize= */ 0, 264 /* chunkSize= */ 128), 265 // Ciphertext contains more than one segment. 266 new AesGcmHkdfStreamingTestVector( 267 /* keySizeInBytes= */ 16, 268 /* ciphertextSegmentSize= */ 256, 269 /* firstSegmentOffset= */ 0, 270 HashType.SHA1, 271 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 272 /* plaintextSize= */ 1024, 273 /* chunkSize= */ 128), 274 new AesGcmHkdfStreamingTestVector( 275 /* keySizeInBytes= */ 16, 276 /* ciphertextSegmentSize= */ 512, 277 /* firstSegmentOffset= */ 0, 278 HashType.SHA256, 279 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 280 /* plaintextSize= */ 3086, 281 /* chunkSize= */ 128), 282 new AesGcmHkdfStreamingTestVector( 283 /* keySizeInBytes= */ 32, 284 /* ciphertextSegmentSize= */ 1024, 285 /* firstSegmentOffset= */ 0, 286 HashType.SHA512, 287 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 288 /* plaintextSize= */ 12345, 289 /* chunkSize= */ 128), 290 // During decryption large plaintext chunks are requested. 291 new AesGcmHkdfStreamingTestVector( 292 /* keySizeInBytes= */ 16, 293 /* ciphertextSegmentSize= */ 256, 294 /* firstSegmentOffset= */ 0, 295 HashType.SHA1, 296 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 297 /* plaintextSize= */ 1024, 298 /* chunkSize= */ 4096), 299 new AesGcmHkdfStreamingTestVector( 300 /* keySizeInBytes= */ 16, 301 /* ciphertextSegmentSize= */ 512, 302 /* firstSegmentOffset= */ 0, 303 HashType.SHA256, 304 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 305 /* plaintextSize= */ 3086, 306 /* chunkSize= */ 4096), 307 new AesGcmHkdfStreamingTestVector( 308 /* keySizeInBytes= */ 32, 309 /* ciphertextSegmentSize= */ 1024, 310 /* firstSegmentOffset= */ 0, 311 HashType.SHA512, 312 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 313 /* plaintextSize= */ 12345, 314 /* chunkSize= */ 5000), 315 // Same as above but the offset is non-zero. 316 new AesGcmHkdfStreamingTestVector( 317 /* keySizeInBytes= */ 16, 318 /* ciphertextSegmentSize= */ 256, 319 /* firstSegmentOffset= */ 8, 320 HashType.SHA1, 321 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 322 /* plaintextSize= */ 1024, 323 /* chunkSize= */ 64), 324 new AesGcmHkdfStreamingTestVector( 325 /* keySizeInBytes= */ 16, 326 /* ciphertextSegmentSize= */ 512, 327 /* firstSegmentOffset= */ 20, 328 HashType.SHA256, 329 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 330 /* plaintextSize= */ 3086, 331 /* chunkSize= */ 256), 332 new AesGcmHkdfStreamingTestVector( 333 /* keySizeInBytes= */ 32, 334 /* ciphertextSegmentSize= */ 1024, 335 /* firstSegmentOffset= */ 10, 336 HashType.SHA512, 337 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 338 /* plaintextSize= */ 12345, 339 /* chunkSize= */ 5000), 340 // The ciphertext ends at a segment boundary. 341 new AesGcmHkdfStreamingTestVector( 342 /* keySizeInBytes= */ 16, 343 /* ciphertextSegmentSize= */ 256, 344 /* firstSegmentOffset= */ 0, 345 HashType.SHA1, 346 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 347 /* plaintextSize= */ 216, 348 /* chunkSize= */ 64), 349 new AesGcmHkdfStreamingTestVector( 350 /* keySizeInBytes= */ 16, 351 /* ciphertextSegmentSize= */ 256, 352 /* firstSegmentOffset= */ 16, 353 HashType.SHA256, 354 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 355 /* plaintextSize= */ 200, 356 /* chunkSize= */ 256), 357 new AesGcmHkdfStreamingTestVector( 358 /* keySizeInBytes= */ 16, 359 /* ciphertextSegmentSize= */ 256, 360 /* firstSegmentOffset= */ 16, 361 HashType.SHA512, 362 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 363 /* plaintextSize= */ 440, 364 /* chunkSize= */ 1024), 365 // During decryption single bytes are requested. 366 new AesGcmHkdfStreamingTestVector( 367 /* keySizeInBytes= */ 16, 368 /* ciphertextSegmentSize= */ 256, 369 /* firstSegmentOffset= */ 0, 370 HashType.SHA256, 371 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 372 /* plaintextSize= */ 1024, 373 /* chunkSize= */ 1), 374 new AesGcmHkdfStreamingTestVector( 375 /* keySizeInBytes= */ 16, 376 /* ciphertextSegmentSize= */ 512, 377 /* firstSegmentOffset= */ 0, 378 HashType.SHA512, 379 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 380 /* plaintextSize= */ 5086, 381 /* chunkSize= */ 1) 382 }; 383 // In the following test vectors the chunk sizes are zeroed since they are not needed for the 384 // test. 385 randomAccessTestVectors = 386 new AesGcmHkdfStreamingTestVector[] { 387 // The ciphertext is smaller than 1 segment. 388 new AesGcmHkdfStreamingTestVector( 389 /* keySizeInBytes= */ 16, 390 /* ciphertextSegmentSize= */ 256, 391 /* firstSegmentOffset= */ 0, 392 HashType.SHA256, 393 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 394 /* plaintextSize= */ 100, 395 /* chunkSize= */ 0), 396 new AesGcmHkdfStreamingTestVector( 397 /* keySizeInBytes= */ 16, 398 /* ciphertextSegmentSize= */ 512, 399 /* firstSegmentOffset= */ 0, 400 HashType.SHA256, 401 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 402 /* plaintextSize= */ 400, 403 /* chunkSize= */ 0), 404 // Same as above with an offset. 405 new AesGcmHkdfStreamingTestVector( 406 /* keySizeInBytes= */ 16, 407 /* ciphertextSegmentSize= */ 256, 408 /* firstSegmentOffset= */ 8, 409 HashType.SHA256, 410 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 411 /* plaintextSize= */ 20, 412 /* chunkSize= */ 0), 413 new AesGcmHkdfStreamingTestVector( 414 /* keySizeInBytes= */ 16, 415 /* ciphertextSegmentSize= */ 256, 416 /* firstSegmentOffset= */ 8, 417 HashType.SHA256, 418 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 419 /* plaintextSize= */ 100, 420 /* chunkSize= */ 0), 421 new AesGcmHkdfStreamingTestVector( 422 /* keySizeInBytes= */ 16, 423 /* ciphertextSegmentSize= */ 512, 424 /* firstSegmentOffset= */ 8, 425 HashType.SHA256, 426 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 427 /* plaintextSize= */ 400, 428 /* chunkSize= */ 0), 429 // Empty plaintext. 430 new AesGcmHkdfStreamingTestVector( 431 /* keySizeInBytes= */ 16, 432 /* ciphertextSegmentSize= */ 256, 433 /* firstSegmentOffset= */ 0, 434 HashType.SHA256, 435 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 436 /* plaintextSize= */ 0, 437 /* chunkSize= */ 0), 438 new AesGcmHkdfStreamingTestVector( 439 /* keySizeInBytes= */ 16, 440 /* ciphertextSegmentSize= */ 256, 441 /* firstSegmentOffset= */ 8, 442 HashType.SHA256, 443 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 444 /* plaintextSize= */ 0, 445 /* chunkSize= */ 0), 446 // Ciphertext contains more than one segment. 447 new AesGcmHkdfStreamingTestVector( 448 /* keySizeInBytes= */ 16, 449 /* ciphertextSegmentSize= */ 256, 450 /* firstSegmentOffset= */ 0, 451 HashType.SHA256, 452 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 453 /* plaintextSize= */ 2048, 454 /* chunkSize= */ 0), 455 new AesGcmHkdfStreamingTestVector( 456 /* keySizeInBytes= */ 16, 457 /* ciphertextSegmentSize= */ 256, 458 /* firstSegmentOffset= */ 0, 459 HashType.SHA256, 460 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 461 /* plaintextSize= */ 4096, 462 /* chunkSize= */ 0), 463 new AesGcmHkdfStreamingTestVector( 464 /* keySizeInBytes= */ 32, 465 /* ciphertextSegmentSize= */ 1024, 466 /* firstSegmentOffset= */ 0, 467 HashType.SHA256, 468 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 469 /* plaintextSize= */ 12345, 470 /* chunkSize= */ 0), 471 new AesGcmHkdfStreamingTestVector( 472 /* keySizeInBytes= */ 16, 473 /* ciphertextSegmentSize= */ 4096, 474 /* firstSegmentOffset= */ 0, 475 HashType.SHA256, 476 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 477 /* plaintextSize= */ 123456, 478 /* chunkSize= */ 0), 479 // Same as above but with an offset. 480 new AesGcmHkdfStreamingTestVector( 481 /* keySizeInBytes= */ 16, 482 /* ciphertextSegmentSize= */ 256, 483 /* firstSegmentOffset= */ 8, 484 HashType.SHA256, 485 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 486 /* plaintextSize= */ 2048, 487 /* chunkSize= */ 0), 488 new AesGcmHkdfStreamingTestVector( 489 /* keySizeInBytes= */ 16, 490 /* ciphertextSegmentSize= */ 256, 491 /* firstSegmentOffset= */ 10, 492 HashType.SHA256, 493 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 494 /* plaintextSize= */ 4096, 495 /* chunkSize= */ 0), 496 new AesGcmHkdfStreamingTestVector( 497 /* keySizeInBytes= */ 32, 498 /* ciphertextSegmentSize= */ 1024, 499 /* firstSegmentOffset= */ 20, 500 HashType.SHA256, 501 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 502 /* plaintextSize= */ 12345, 503 /* chunkSize= */ 0), 504 // The ciphertext ends at a segment boundary. 505 new AesGcmHkdfStreamingTestVector( 506 /* keySizeInBytes= */ 16, 507 /* ciphertextSegmentSize= */ 256, 508 /* firstSegmentOffset= */ 0, 509 HashType.SHA256, 510 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 511 /* plaintextSize= */ 216, 512 /* chunkSize= */ 0), 513 new AesGcmHkdfStreamingTestVector( 514 /* keySizeInBytes= */ 16, 515 /* ciphertextSegmentSize= */ 256, 516 /* firstSegmentOffset= */ 16, 517 HashType.SHA256, 518 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 519 /* plaintextSize= */ 200, 520 /* chunkSize= */ 0), 521 new AesGcmHkdfStreamingTestVector( 522 /* keySizeInBytes= */ 16, 523 /* ciphertextSegmentSize= */ 256, 524 /* firstSegmentOffset= */ 16, 525 HashType.SHA256, 526 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 527 /* plaintextSize= */ 440, 528 /* chunkSize= */ 0), 529 }; 530 singleBytesTestVectors = 531 new AesGcmHkdfStreamingTestVector[] { 532 // Encrypting with the stream writing single bytes. Chunk size isn't used for this test. 533 new AesGcmHkdfStreamingTestVector( 534 /* keySizeInBytes= */ 16, 535 /* ciphertextSegmentSize= */ 512, 536 /* firstSegmentOffset= */ 0, 537 HashType.SHA256, 538 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 539 /* plaintextSize= */ 1024, 540 /* chunkSize= */ 0), 541 new AesGcmHkdfStreamingTestVector( 542 /* keySizeInBytes= */ 32, 543 /* ciphertextSegmentSize= */ 512, 544 /* firstSegmentOffset= */ 0, 545 HashType.SHA256, 546 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 547 /* plaintextSize= */ 1024, 548 /* chunkSize= */ 0), 549 new AesGcmHkdfStreamingTestVector( 550 /* keySizeInBytes= */ 16, 551 /* ciphertextSegmentSize= */ 512, 552 /* firstSegmentOffset= */ 0, 553 HashType.SHA256, 554 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 555 /* plaintextSize= */ 12345, 556 /* chunkSize= */ 0), 557 new AesGcmHkdfStreamingTestVector( 558 /* keySizeInBytes= */ 16, 559 /* ciphertextSegmentSize= */ 512, 560 /* firstSegmentOffset= */ 0, 561 HashType.SHA256, 562 /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff", 563 /* plaintextSize= */ 111111, 564 /* chunkSize= */ 0), 565 }; 566 skipWithStreamTestVectors = 567 new AesGcmHkdfStreamingTestVector[] { 568 // Smallest chunk size. 569 new AesGcmHkdfStreamingTestVector( 570 /* keySizeInBytes= */ 16, 571 /* ciphertextSegmentSize= */ 256, 572 /* firstSegmentOffset= */ 8, 573 HashType.SHA256, 574 /* ikm= */ "000102030405060708090a0b0c0d0e0f", 575 /* plaintextSize= */ 4096, 576 /* chunkSize= */ 1), 577 // Chunk size < segmentSize. 578 new AesGcmHkdfStreamingTestVector( 579 /* keySizeInBytes= */ 16, 580 /* ciphertextSegmentSize= */ 256, 581 /* firstSegmentOffset= */ 8, 582 HashType.SHA1, 583 /* ikm= */ "000102030405060708090a0b0c0d0e0f", 584 /* plaintextSize= */ 4096, 585 /* chunkSize= */ 37), 586 // Chunk size > segmentSize. 587 new AesGcmHkdfStreamingTestVector( 588 /* keySizeInBytes= */ 16, 589 /* ciphertextSegmentSize= */ 256, 590 /* firstSegmentOffset= */ 8, 591 HashType.SHA512, 592 /* ikm= */ "000102030405060708090a0b0c0d0e0f", 593 /* plaintextSize= */ 4096, 594 /* chunkSize= */ 384), 595 // Chunk size > 3*segmentSize. 596 new AesGcmHkdfStreamingTestVector( 597 /* keySizeInBytes= */ 16, 598 /* ciphertextSegmentSize= */ 256, 599 /* firstSegmentOffset= */ 8, 600 HashType.SHA256, 601 /* ikm= */ "000102030405060708090a0b0c0d0e0f", 602 /* plaintextSize= */ 4096, 603 /* chunkSize= */ 800), 604 }; 605 defaultAesHkdfStreamingInstance = 606 new AesGcmHkdfStreaming( 607 Hex.decode("000102030405060708090a0b0c0d0e0f"), "HmacSha256", 16, 4096, 0); 608 } 609 610 private static final class AesGcmHkdfStreamingTestVector { 611 final AesGcmHkdfStreaming directConstructorAgs; 612 final AesGcmHkdfStreaming keyObjectAgs; 613 final int plaintextSize; 614 final int chunkSize; 615 AesGcmHkdfStreamingTestVector( int keySizeInBytes, int ciphertextSegmentSize, int firstSegmentOffset, HashType hashType, String ikm, int plaintextSize, int chunkSize)616 private AesGcmHkdfStreamingTestVector( 617 int keySizeInBytes, 618 int ciphertextSegmentSize, 619 int firstSegmentOffset, 620 HashType hashType, 621 String ikm, 622 int plaintextSize, 623 int chunkSize) 624 throws GeneralSecurityException { 625 String hkdfAlgString = ""; 626 if (hashType.equals(HashType.SHA1)) { 627 hkdfAlgString = "HmacSha1"; 628 } else if (hashType.equals(HashType.SHA256)) { 629 hkdfAlgString = "HmacSha256"; 630 } else if (hashType.equals(HashType.SHA512)) { 631 hkdfAlgString = "HmacSha512"; 632 } 633 this.directConstructorAgs = 634 new AesGcmHkdfStreaming( 635 Hex.decode(ikm), 636 hkdfAlgString, 637 keySizeInBytes, 638 ciphertextSegmentSize, 639 firstSegmentOffset); 640 if (firstSegmentOffset != 0) { 641 this.keyObjectAgs = null; 642 } else { 643 AesGcmHkdfStreamingKey aesGcmHkdfStreamingKey = 644 AesGcmHkdfStreamingKey.create( 645 AesGcmHkdfStreamingParameters.builder() 646 .setDerivedAesGcmKeySizeBytes(keySizeInBytes) 647 .setKeySizeBytes(Hex.decode(ikm).length) 648 .setCiphertextSegmentSizeBytes(ciphertextSegmentSize) 649 .setHkdfHashType(hashType) 650 .build(), 651 SecretBytes.copyFrom(Hex.decode(ikm), InsecureSecretKeyAccess.get())); 652 this.keyObjectAgs = 653 (AesGcmHkdfStreaming) AesGcmHkdfStreaming.create(aesGcmHkdfStreamingKey); 654 } 655 this.plaintextSize = plaintextSize; 656 this.chunkSize = chunkSize; 657 } 658 } 659 } 660