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 com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import com.google.crypto.tink.InsecureSecretKeyAccess; 23 import com.google.crypto.tink.prf.Prf; 24 import com.google.crypto.tink.prf.internal.AesCmacPrfTestUtil; 25 import com.google.crypto.tink.prf.internal.AesCmacPrfWycheproofTestUtil; 26 import java.security.InvalidAlgorithmParameterException; 27 import java.util.Arrays; 28 import java.util.List; 29 import org.junit.experimental.theories.DataPoints; 30 import org.junit.experimental.theories.FromDataPoints; 31 import org.junit.experimental.theories.Theories; 32 import org.junit.experimental.theories.Theory; 33 import org.junit.runner.RunWith; 34 35 /** Unit tests for {@link PrfAesCmac}. */ 36 @RunWith(Theories.class) 37 public class PrfAesCmacTest { 38 39 private static final int KEY_SIZE = 16; 40 41 @DataPoints("AesCmacPrfTestVectors") 42 public static final List<AesCmacPrfTestUtil.TestVector> testVectors = 43 AesCmacPrfTestUtil.creatTestVectors(); 44 45 @DataPoints("WycheproofTestVectors") 46 public static final List<AesCmacPrfTestUtil.TestVector> wycheproofTestVectors = 47 AesCmacPrfWycheproofTestUtil.readTestVectors(); 48 49 @Theory calcN_returnsNumberOfAesBlocks()50 public void calcN_returnsNumberOfAesBlocks() throws Exception { 51 // AES block size is 16 bytes. 52 assertThat(PrfAesCmac.calcN(0)).isEqualTo(1); 53 assertThat(PrfAesCmac.calcN(1)).isEqualTo(1); 54 assertThat(PrfAesCmac.calcN(16)).isEqualTo(1); 55 assertThat(PrfAesCmac.calcN(17)).isEqualTo(2); 56 assertThat(PrfAesCmac.calcN(32)).isEqualTo(2); 57 assertThat(PrfAesCmac.calcN(33)).isEqualTo(3); 58 assertThat(PrfAesCmac.calcN(48)).isEqualTo(3); 59 assertThat(PrfAesCmac.calcN(49)).isEqualTo(4); 60 assertThat(PrfAesCmac.calcN(0x7FFFFFF0)).isEqualTo(0x07FFFFFF); 61 assertThat(PrfAesCmac.calcN(0x7FFFFFF1)).isEqualTo(0x08000000); 62 assertThat(PrfAesCmac.calcN(Integer.MAX_VALUE)).isEqualTo(0x08000000); 63 } 64 65 @Theory compute_isCorrect( @romDataPoints"AesCmacPrfTestVectors") AesCmacPrfTestUtil.TestVector testVector)66 public void compute_isCorrect( 67 @FromDataPoints("AesCmacPrfTestVectors") AesCmacPrfTestUtil.TestVector testVector) 68 throws Exception { 69 Prf prf = 70 new PrfAesCmac(testVector.key().getKeyBytes().toByteArray(InsecureSecretKeyAccess.get())); 71 72 assertThat(prf.compute(testVector.data(), testVector.outputLength())).isEqualTo(testVector.output()); 73 } 74 75 @Theory createWithAesCmacPrfKey_compute_isCorrect( @romDataPoints"AesCmacPrfTestVectors") AesCmacPrfTestUtil.TestVector testVector)76 public void createWithAesCmacPrfKey_compute_isCorrect( 77 @FromDataPoints("AesCmacPrfTestVectors") AesCmacPrfTestUtil.TestVector testVector) 78 throws Exception { 79 Prf prf = PrfAesCmac.create(testVector.key()); 80 81 assertThat(prf.compute(testVector.data(), testVector.outputLength())).isEqualTo(testVector.output()); 82 } 83 84 @Theory wycheproofTestVectors_compute_isCorrect( @romDataPoints"WycheproofTestVectors") AesCmacPrfTestUtil.TestVector testVector)85 public void wycheproofTestVectors_compute_isCorrect( 86 @FromDataPoints("WycheproofTestVectors") AesCmacPrfTestUtil.TestVector testVector) 87 throws Exception { 88 Prf prf = PrfAesCmac.create(testVector.key()); 89 90 assertThat(prf.compute(testVector.data(), testVector.outputLength())) 91 .isEqualTo(testVector.output()); 92 } 93 94 @Theory compute_outputLengthTooLarge_throws()95 public void compute_outputLengthTooLarge_throws() throws Exception { 96 Prf prf = new PrfAesCmac(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c")); 97 byte[] message = new byte[0]; 98 99 assertThrows(InvalidAlgorithmParameterException.class, () -> prf.compute(message, 17)); 100 } 101 102 @Theory compute_bitFlipInMessage_outputIsDifferent()103 public void compute_bitFlipInMessage_outputIsDifferent() throws Exception { 104 byte[] key = Random.randBytes(KEY_SIZE); 105 Prf prf = new PrfAesCmac(key); 106 byte[] message = Random.randBytes(20); 107 int outputLength = 16; 108 109 byte[] output = prf.compute(message, outputLength); 110 111 for (int b = 0; b < message.length; b++) { 112 for (int bit = 0; bit < 8; bit++) { 113 byte[] modifiedMessage = Arrays.copyOf(message, message.length); 114 modifiedMessage[b] = (byte) (modifiedMessage[b] ^ (1 << bit)); 115 116 byte[] outputOfModifiedMessage = prf.compute(modifiedMessage, outputLength); 117 118 assertThat(outputOfModifiedMessage).isNotEqualTo(output); 119 } 120 } 121 } 122 } 123