Skip to content

Commit

Permalink
Add a Test Vector for AesCtrHmac.
Browse files Browse the repository at this point in the history
This is the same as in C++ and in the cross language tests. It would be good to add more and also do decryption. I want to add more, but I prefer to at least do it for at least C++ and Java at the same time.

PiperOrigin-RevId: 702640386
Change-Id: I27500871df3678871bba91c6caf23183e669ef18
  • Loading branch information
tholenst authored and copybara-github committed Dec 4, 2024
1 parent 9659b06 commit fdaa503
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package com.google.crypto.tink.streamingaead.internal.testing;

import static com.google.common.truth.Truth.assertThat;
import static com.google.crypto.tink.internal.TinkBugException.exceptionIsBug;
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.crypto.tink.AccessesPartialKey;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.streamingaead.AesCtrHmacStreamingKey;
import com.google.crypto.tink.streamingaead.AesCtrHmacStreamingParameters;
import com.google.crypto.tink.subtle.Bytes;
import com.google.crypto.tink.subtle.Hex;
import com.google.crypto.tink.util.SecretBytes;
import java.security.GeneralSecurityException;
import java.util.Arrays;

/** Test vectors for AesCtrHmac StreamingAEAD. */
@AccessesPartialKey
public final class AesCtrHmacStreamingTestUtil {
private static byte[] xor(byte[] b1, byte[] b2) {
assertThat(b1.length).isEqualTo(b2.length);
byte[] result = new byte[b1.length];
for (int i = 0; i < result.length; i++) {
result[i] = (byte) (b1[i] ^ b2[i]);
}
return result;
}

/**
* A test vector which was created by hand for the cross language tests (see
* aes_ctr_hmac_streaming_key_test there, and for more information about the magic values which
* appear in this test.
*/
private static StreamingAeadTestVector createTestVector0() throws GeneralSecurityException {
AesCtrHmacStreamingParameters parameters =
AesCtrHmacStreamingParameters.builder()
.setKeySizeBytes(16)
.setDerivedKeySizeBytes(16)
.setHkdfHashType(AesCtrHmacStreamingParameters.HashType.SHA1)
.setHmacHashType(AesCtrHmacStreamingParameters.HashType.SHA256)
.setHmacTagSizeBytes(32)
.setCiphertextSegmentSizeBytes(64)
.build();
AesCtrHmacStreamingKey key =
AesCtrHmacStreamingKey.create(
parameters,
SecretBytes.copyFrom(
Hex.decode("6eb56cdc726dfbe5d57f2fcdc6e9345b"), InsecureSecretKeyAccess.get()));
byte[] plaintext =
"This is a fairly long plaintext. However, it is not crazy long.".getBytes(UTF_8);
byte[] headerLength = Hex.decode("18");
byte[] salt = Hex.decode("93b3af5e14ab378d065addfc8484da64");
byte[] noncePrefix = Hex.decode("2c0862877baea8");
byte[] header = Bytes.concat(headerLength, salt, noncePrefix);

byte[] msg0 = Arrays.copyOfRange(plaintext, 0, 8);
byte[] msg1 = Arrays.copyOfRange(plaintext, 8, 40);
byte[] msg2 = Arrays.copyOfRange(plaintext, 40, plaintext.length);

byte[] c0 = xor(msg0, Hex.decode("ea8e18301bd57bfd"));
byte[] c1 =
xor(msg1, Hex.decode("2999c8ea5401704243c8cd77929fd52617fec5542a842446251bb2f3a81f6249"));
byte[] c2 = xor(msg2, Hex.decode("70fe58e44835a6602952749e763637d9d973bca8358086"));
byte[] tag0 = Hex.decode("8303ca71c04d8e06e1b01cff7c1178af47dac031517b1f6a2d9be84105677a68");
byte[] tag1 = Hex.decode("834d890839f37f762caddc029cc673300ff107fd51f9a62058fcd00befc362e5");
byte[] tag2 = Hex.decode("5fb0c893903271af38380c2f355cb85e5ec571648513123321bde0c6042f43c7");

byte[] ciphertext = Bytes.concat(header, c0, tag0, c1, tag1, c2, tag2);
byte[] aad = "aad".getBytes(UTF_8);
return new StreamingAeadTestVector(key, plaintext, aad, ciphertext);
}

public static StreamingAeadTestVector[] createAesCtrHmacTestVectors() {
return exceptionIsBug(
() ->
new StreamingAeadTestVector[] {
createTestVector0(),
});
}

private AesCtrHmacStreamingTestUtil() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
licenses(["notice"])

package(default_visibility = ["//:__subpackages__"])

java_library(
name = "aes_ctr_hmac_streaming_test_util",
testonly = 1,
srcs = ["AesCtrHmacStreamingTestUtil.java"],
deps = [
":streaming_aead_test_vector",
"//src/main/java/com/google/crypto/tink:accesses_partial_key",
"//src/main/java/com/google/crypto/tink:insecure_secret_key_access",
"//src/main/java/com/google/crypto/tink/internal:tink_bug_exception",
"//src/main/java/com/google/crypto/tink/streamingaead:aes_ctr_hmac_streaming_key",
"//src/main/java/com/google/crypto/tink/streamingaead:aes_ctr_hmac_streaming_parameters",
"//src/main/java/com/google/crypto/tink/subtle:bytes",
"//src/main/java/com/google/crypto/tink/subtle:hex",
"//src/main/java/com/google/crypto/tink/util:secret_bytes",
"@maven//:com_google_truth_truth",
],
)

java_library(
name = "streaming_aead_test_vector",
testonly = 1,
srcs = ["StreamingAeadTestVector.java"],
deps = [
"//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_key",
"//src/main/java/com/google/crypto/tink/util:bytes",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)

android_library(
name = "aes_ctr_hmac_streaming_test_util-android",
testonly = 1,
srcs = ["AesCtrHmacStreamingTestUtil.java"],
deps = [
":streaming_aead_test_vector-android",
"//src/main/java/com/google/crypto/tink:accesses_partial_key-android",
"//src/main/java/com/google/crypto/tink:insecure_secret_key_access-android",
"//src/main/java/com/google/crypto/tink/internal:tink_bug_exception-android",
"//src/main/java/com/google/crypto/tink/streamingaead:aes_ctr_hmac_streaming_key-android",
"//src/main/java/com/google/crypto/tink/streamingaead:aes_ctr_hmac_streaming_parameters-android",
"//src/main/java/com/google/crypto/tink/subtle:bytes-android",
"//src/main/java/com/google/crypto/tink/subtle:hex-android",
"//src/main/java/com/google/crypto/tink/util:secret_bytes-android",
"@maven//:com_google_truth_truth",
],
)

android_library(
name = "streaming_aead_test_vector-android",
testonly = 1,
srcs = ["StreamingAeadTestVector.java"],
deps = [
"//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_key-android",
"//src/main/java/com/google/crypto/tink/util:bytes-android",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package com.google.crypto.tink.streamingaead.internal.testing;

import com.google.crypto.tink.streamingaead.StreamingAeadKey;
import com.google.crypto.tink.util.Bytes;
import com.google.errorprone.annotations.Immutable;

/** Test vector for StreamingAEAD encryption. */
@Immutable
public final class StreamingAeadTestVector {
public StreamingAeadTestVector(
StreamingAeadKey key, byte[] plaintext, byte[] associatedData, byte[] ciphertext) {
this.key = key;
this.plaintext = Bytes.copyFrom(plaintext);
this.associatedData = Bytes.copyFrom(associatedData);
this.ciphertext = Bytes.copyFrom(ciphertext);
}

private final StreamingAeadKey key;
private final Bytes plaintext;
private final Bytes associatedData;
private final Bytes ciphertext;

public StreamingAeadKey getKey() {
return key;
}

public byte[] getPlaintext() {
return plaintext.toByteArray();
}

public byte[] getAssociatedData() {
return associatedData.toByteArray();
}

public byte[] getCiphertext() {
return ciphertext.toByteArray();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017 Google Inc.
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -27,11 +27,19 @@
import com.google.crypto.tink.StreamingAead;
import com.google.crypto.tink.TinkProtoKeysetFormat;
import com.google.crypto.tink.internal.KeyManagerRegistry;
import com.google.crypto.tink.streamingaead.internal.testing.AesCtrHmacStreamingTestUtil;
import com.google.crypto.tink.streamingaead.internal.testing.StreamingAeadTestVector;
import com.google.crypto.tink.subtle.AesCtrHmacStreaming;
import com.google.crypto.tink.subtle.Hex;
import com.google.crypto.tink.testing.StreamingTestUtil;
import com.google.crypto.tink.testing.StreamingTestUtil.ByteBufferChannel;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.Set;
import java.util.TreeSet;
import javax.annotation.Nullable;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.theories.DataPoints;
Expand Down Expand Up @@ -193,4 +201,50 @@ public void serializeAndParse_works() throws Exception {
TinkProtoKeysetFormat.parseKeyset(serializedHandle, InsecureSecretKeyAccess.get());
assertThat(parsedHandle.equalsKeyset(handle)).isTrue();
}

@DataPoints("testVectors")
public static final StreamingAeadTestVector[] streamingTestVector =
AesCtrHmacStreamingTestUtil.createAesCtrHmacTestVectors();

@Theory
public void decryptCiphertextInputStream_works(
@FromDataPoints("testVectors") StreamingAeadTestVector v) throws Exception {
KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getKey()).makePrimary();
@Nullable Integer id = v.getKey().getIdRequirementOrNull();
if (id == null) {
entry.withRandomId();
} else {
entry.withFixedId(id);
}
KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build();
StreamingAead streamingAead =
handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class);
InputStream plaintextStream =
streamingAead.newDecryptingStream(
new ByteArrayInputStream(v.getCiphertext()), v.getAssociatedData());
byte[] decryption = new byte[v.getPlaintext().length];
plaintextStream.read(decryption);
assertThat(decryption).isEqualTo(v.getPlaintext());
}

@Theory
public void decryptCiphertextChannel_works(
@FromDataPoints("testVectors") StreamingAeadTestVector v) throws Exception {
KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getKey()).makePrimary();
@Nullable Integer id = v.getKey().getIdRequirementOrNull();
if (id == null) {
entry.withRandomId();
} else {
entry.withFixedId(id);
}
KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build();
StreamingAead streamingAead =
handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class);
ReadableByteChannel plaintextChannel =
streamingAead.newDecryptingChannel(
new ByteBufferChannel(v.getCiphertext()), v.getAssociatedData());
ByteBuffer decryption = ByteBuffer.allocate(v.getPlaintext().length);
plaintextChannel.read(decryption);
assertThat(decryption.array()).isEqualTo(v.getPlaintext());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,12 @@ java_test(
"//src/main/java/com/google/crypto/tink/streamingaead:aes_ctr_hmac_streaming_key_manager",
"//src/main/java/com/google/crypto/tink/streamingaead:aes_ctr_hmac_streaming_parameters",
"//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_config",
"//src/main/java/com/google/crypto/tink/streamingaead/internal/testing:aes_ctr_hmac_streaming_test_util",
"//src/main/java/com/google/crypto/tink/streamingaead/internal/testing:streaming_aead_test_vector",
"//src/main/java/com/google/crypto/tink/subtle:aes_ctr_hmac_streaming",
"//src/main/java/com/google/crypto/tink/subtle:hex",
"//src/main/java/com/google/crypto/tink/testing:streaming_test_util",
"@maven//:com_google_code_findbugs_jsr305",
"@maven//:com_google_truth_truth",
"@maven//:junit_junit",
],
Expand Down

0 comments on commit fdaa503

Please sign in to comment.