aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-12 18:46:34 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-12 18:46:34 +0000
commite734ffdca880518bd54d9e4fcb99e8e43ef0eb68 (patch)
tree11405b03d4824928814f69b1a5c6b9ae35e34a02
parentf1ee9b3f13c695714b9e7f9a502d56c031b5a8aa (diff)
parent31cc0fa7a53b932d3481560a3692cbc24cf8824a (diff)
downloadwycheproof-main-cg-testing-release.tar.gz
Snap for 8580505 from 31cc0fa7a53b932d3481560a3692cbc24cf8824a to main-cg-testing-releasemain-cg-testing-release
Change-Id: Ibb15f645e8e487d4f3b71e7e398f94d595965d7b
-rw-r--r--Android.bp21
-rw-r--r--keystore-cts/java/android/keystore/cts/util/KeyStoreUtil.java (renamed from keystore-cts/java/com/google/security/wycheproof/CertificateUtil.java)50
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/EcUtil.java16
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/AesGcmTest.java96
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java56
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java56
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/EcdhTest.java457
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/EcdsaTest.java185
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/JsonAeadTest.java36
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/JsonCipherTest.java72
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java95
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/JsonSignatureTest.java247
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/MacTest.java73
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java67
-rw-r--r--keystore-cts/java/com/google/security/wycheproof/testcases/RsaSignatureTest.java103
15 files changed, 624 insertions, 1006 deletions
diff --git a/Android.bp b/Android.bp
index 3439961..689e393 100644
--- a/Android.bp
+++ b/Android.bp
@@ -56,21 +56,14 @@ java_library_static {
visibility: [
"//cts/tests/tests/keystore",
],
- srcs: ["keystore-cts/java/**/*.java"],
+ srcs: [
+ "keystore-cts/java/**/*.java",
+ "keystore-cts/android/**/*.java",
+ ],
exclude_srcs: [
- "keystore-cts/java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/EcdhTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/EcdsaTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/JsonCipherTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/JsonEcdhTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/JsonSignatureTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/MacTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/RsaOaepTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/RsaPssTest.java",
- "keystore-cts/java/com/google/security/wycheproof/testcases/RsaSignatureTest.java",
+ "keystore-cts/java/**/JsonEcdhTest.java",
+ "keystore-cts/java/**/RsaOaepTest.java",
+ "keystore-cts/java/**/RsaPssTest.java",
],
java_resource_dirs: ["keystore-cts/testvectors"],
sdk_version: "current",
diff --git a/keystore-cts/java/com/google/security/wycheproof/CertificateUtil.java b/keystore-cts/java/android/keystore/cts/util/KeyStoreUtil.java
index d5d343a..798192d 100644
--- a/keystore-cts/java/com/google/security/wycheproof/CertificateUtil.java
+++ b/keystore-cts/java/android/keystore/cts/util/KeyStoreUtil.java
@@ -11,8 +11,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.security.wycheproof;
+package android.keystore.cts.util;
+import android.security.keystore.KeyProtection;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
@@ -22,16 +23,59 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
+import java.security.GeneralSecurityException;
import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
+import java.util.Enumeration;
+import javax.crypto.spec.SecretKeySpec;
import javax.security.auth.x500.X500Principal;
-/** Certificate utilities */
-public class CertificateUtil {
+/** Keystore utilities */
+public class KeyStoreUtil {
+
+ public static KeyStore saveKeysToKeystore(String alias, PublicKey pubKey, PrivateKey privKey,
+ KeyProtection keyProtection)
+ throws Exception {
+ KeyPair keyPair = new KeyPair(pubKey, privKey);
+ X509Certificate certificate = createCertificate(keyPair,
+ new X500Principal("CN=Test1"),
+ new X500Principal("CN=Test1"));
+ Certificate[] certChain = new Certificate[]{certificate};
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+ keyStore.setEntry(alias,
+ new KeyStore.PrivateKeyEntry(privKey, certChain),
+ keyProtection);
+ return keyStore;
+ }
+
+ public static KeyStore saveSecretKeyToKeystore(String alias, SecretKeySpec keySpec,
+ KeyProtection keyProtection)
+ throws Exception {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+ keyStore.setEntry(alias,
+ new KeyStore.SecretKeyEntry(keySpec),
+ keyProtection);
+ return keyStore;
+ }
+
+ public static void cleanUpKeyStore() throws Exception {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+ for (Enumeration<String> aliases = keyStore.aliases(); aliases.hasMoreElements();) {
+ String alias = aliases.nextElement();
+ keyStore.deleteEntry(alias);
+ }
+ }
public static X509Certificate createCertificate(
KeyPair keyPair, X500Principal subject, X500Principal issuer)
diff --git a/keystore-cts/java/com/google/security/wycheproof/EcUtil.java b/keystore-cts/java/com/google/security/wycheproof/EcUtil.java
index 56c6548..492dd43 100644
--- a/keystore-cts/java/com/google/security/wycheproof/EcUtil.java
+++ b/keystore-cts/java/com/google/security/wycheproof/EcUtil.java
@@ -46,22 +46,6 @@ public class EcUtil {
return parameters.getParameterSpec(ECParameterSpec.class);
}
- public static void printParameters(ECParameterSpec spec) {
- System.out.println("cofactor:" + spec.getCofactor());
- EllipticCurve curve = spec.getCurve();
- System.out.println("A:" + curve.getA());
- System.out.println("B:" + curve.getB());
- ECField field = curve.getField();
- System.out.println("field size:" + field.getFieldSize());
- if (field instanceof ECFieldFp) {
- ECFieldFp fp = (ECFieldFp) field;
- System.out.println("P:" + fp.getP());
- }
- ECPoint generator = spec.getGenerator();
- System.out.println("Gx:" + generator.getAffineX());
- System.out.println("Gy:" + generator.getAffineY());
- System.out.println("order:" + spec.getOrder());
- }
/** Returns the bit size of a given curve. TODO(bleichen): add all curves that are tested. */
public static int getCurveSize(String name) throws NoSuchAlgorithmException {
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/AesGcmTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/AesGcmTest.java
index d02b4f1..8a574f6 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/AesGcmTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/AesGcmTest.java
@@ -37,6 +37,8 @@ import javax.crypto.spec.SecretKeySpec;
import org.junit.Test;
import org.junit.Ignore;
import org.junit.Before;
+import org.junit.After;
+import android.keystore.cts.util.KeyStoreUtil;
import android.security.keystore.KeyProtection;
import android.security.keystore.KeyProperties;
import java.security.KeyStore;
@@ -54,6 +56,15 @@ import java.security.UnrecoverableKeyException;
public class AesGcmTest {
private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
private KeyStore keyStore;
+ private static final String KEY_ALIAS_1 = "Key1";
+ private static final String KEY_ALIAS_2 = "Key2";
+ private static final String KEY_ALIAS_3 = "Key3";
+ private static final String KEY_ALIAS_4 = "Key4";
+ private static final String KEY_ALIAS_5 = "Key5";
+ private static final String KEY_ALIAS_6 = "Key6";
+ private static final String KEY_ALIAS_7 = "Key7";
+ private static final String KEY_ALIAS_8 = "Key8";
+ private static final String KEY_ALIAS_9 = "Key9";
@Before
public void setup() throws Exception {
@@ -64,6 +75,11 @@ public class AesGcmTest {
}
}
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
+
private SecretKey setKeystoreEntry(String alias, SecretKeySpec key)
throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
keyStore.setEntry(
@@ -77,6 +93,10 @@ public class AesGcmTest {
// Key imported, obtain a reference to it.
return (SecretKey) keyStore.getKey(alias, null);
}
+
+ private SecretKey getKey(String alias) throws Exception {
+ return (SecretKey) keyStore.getKey(alias, null);
+ }
/** Test vectors */
public static class GcmTestVector {
@@ -119,35 +139,35 @@ public class AesGcmTest {
"028318abc1824029138141a2",
"",
"26073cc1d851beff176384dc9896d5ff",
- "0a3ea7a5487cb5f7d70fb6c58d038554", "Key1"),
+ "0a3ea7a5487cb5f7d70fb6c58d038554", KEY_ALIAS_1),
new GcmTestVector(
"001d0c231287c1182784554ca3a21908",
"5b9604fe14eadba931b0ccf34843dab9",
"921d2507fa8007b7bd067d34",
"00112233445566778899aabbccddeeff",
"49d8b9783e911913d87094d1f63cc765",
- "1e348ba07cca2cf04c618cb4", "Key2"),
+ "1e348ba07cca2cf04c618cb4", KEY_ALIAS_2),
new GcmTestVector(
"2035af313d1346ab00154fea78322105",
"aa023d0478dcb2b2312498293d9a9129",
"0432bc49ac34412081288127",
"aac39231129872a2",
"eea945f3d0f98cc0fbab472a0cf24e87",
- "4bb9b4812519dadf9e1232016d068133", "Key3"),
+ "4bb9b4812519dadf9e1232016d068133", KEY_ALIAS_3),
new GcmTestVector(
"2035af313d1346ab00154fea78322105",
"aa023d0478dcb2b2312498293d9a9129",
"0432bc49ac344120",
"aac39231129872a2",
"64c36bb3b732034e3a7d04efc5197785",
- "b7d0dd70b00d65b97cfd080ff4b819d1", "Key4"),
+ "b7d0dd70b00d65b97cfd080ff4b819d1", KEY_ALIAS_4),
new GcmTestVector(
"02efd2e5782312827ed5d230189a2a342b277ce048462193",
"2034a82547276c83dd3212a813572bce",
"3254202d854734812398127a3d134421",
"1a0293d8f90219058902139013908190bc490890d3ff12a3",
"64069c2d58690561f27ee199e6b479b6369eec688672bde9",
- "9b7abadd6e69c1d9ec925786534f5075", "Key5"),
+ "9b7abadd6e69c1d9ec925786534f5075", KEY_ALIAS_5),
// GCM uses GHASH to compute the initial counter J0 if the nonce is not 12 bytes long.
// The counter is incremented modulo 2^32 in counter mode. The following test vectors verify
// the behavior of an implementation for initial counter values J0 close to a 2^32 limit.
@@ -158,7 +178,7 @@ public class AesGcmTest {
"7b95b8c356810a84711d68150a1b7750",
"",
"84d4c9c08b4f482861e3a9c6c35bc4d91df927374513bfd49f436bd73f325285daef4ff7e13d46a6",
- "213a3cb93855d18e69337eee66aeec07", "Key6"),
+ "213a3cb93855d18e69337eee66aeec07", KEY_ALIAS_6),
// J0:ffffffffffffffffffffffffffffffff
new GcmTestVector(
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
@@ -166,7 +186,7 @@ public class AesGcmTest {
"1a552e67cdc4dc1a33b824874ebf0bed",
"",
"948ca37a8e6649e88aeffb1c598f3607007702417ea0e0bc3c60ad5a949886de968cf53ea6462aed",
- "99b381bfa2af9751c39d1b6e86d1be6a", "Key6"),
+ "99b381bfa2af9751c39d1b6e86d1be6a", KEY_ALIAS_7),
// J0:000102030405060708090a0bffffffff
new GcmTestVector(
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
@@ -174,7 +194,7 @@ public class AesGcmTest {
"99821c2dd5daecded07300f577f7aff1",
"",
"127af9b39ecdfc57bb11a2847c7c2d3d8f938f40f877e0c4af37d0fe9af033052bd537c4ae978f60",
- "07eb2fe4a958f8434d40684899507c7c", "Key7"),
+ "07eb2fe4a958f8434d40684899507c7c", KEY_ALIAS_8),
// J0:000102030405060708090a0bfffffffe
new GcmTestVector(
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
@@ -182,7 +202,7 @@ public class AesGcmTest {
"5e4a3900142358d1c774d8d124d8d27d",
"",
"0cf6ae47156b14dce03c8a07a2e172b1127af9b39ecdfc57bb11a2847c7c2d3d8f938f40f877e0c4",
- "f145c2dcaf339eede427be934357eac0", "Key8"),
+ "f145c2dcaf339eede427be934357eac0", KEY_ALIAS_9),
};
/**
@@ -203,7 +223,7 @@ public class AesGcmTest {
// Checks whether the parameter size is supported.
// It would be nice if there was a way to check this without trying to encrypt.
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
} catch (InvalidKeyException | InvalidAlgorithmParameterException ex) {
// Not supported
continue;
@@ -218,7 +238,7 @@ public class AesGcmTest {
public void testVectors() throws Exception {
for (GcmTestVector test : getTestVectors()) {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
cipher.updateAAD(test.aad);
byte[] ct = cipher.doFinal(test.pt);
assertEquals(test.ctHex, TestUtil.bytesToHex(ct));
@@ -232,7 +252,7 @@ public class AesGcmTest {
// Encryption
byte[] empty = new byte[0];
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
int outputSize = cipher.getOutputSize(test.pt.length);
ByteBuffer ctBuffer = ByteBuffer.allocate(outputSize);
cipher.updateAAD(empty);
@@ -258,7 +278,7 @@ public class AesGcmTest {
for (GcmTestVector test : getTestVectors()) {
byte[] empty = new byte[0];
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
int outputSize = cipher.getOutputSize(test.ct.length);
ByteBuffer ptBuffer = ByteBuffer.allocate(outputSize);
cipher.updateAAD(empty);
@@ -279,7 +299,7 @@ public class AesGcmTest {
// Simple test that a modified ciphertext fails.
ptBuffer.clear();
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
cipher.updateAAD(empty);
cipher.updateAAD(test.aad);
cipher.updateAAD(new byte[1]);
@@ -315,7 +335,7 @@ public class AesGcmTest {
public void testLateUpdateAAD() throws Exception {
for (GcmTestVector test : getTestVectors()) {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
byte[] c0 = cipher.update(test.pt);
try {
cipher.updateAAD(test.aad);
@@ -348,7 +368,7 @@ public class AesGcmTest {
public void testIvReuse() throws Exception {
for (GcmTestVector test : getTestVectors()) {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
cipher.updateAAD(test.aad);
byte[] ct1 = cipher.doFinal(test.pt);
try {
@@ -375,11 +395,11 @@ public class AesGcmTest {
for (GcmTestVector test : getTestVectors()) {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
// Encryption
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
int outputSize = cipher.getOutputSize(test.pt.length);
assertEquals("plaintext size:" + test.pt.length, test.ct.length, outputSize);
// Decryption
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
outputSize = cipher.getOutputSize(test.ct.length);
assertEquals("ciphertext size:" + test.ct.length, test.pt.length, outputSize);
}
@@ -392,7 +412,7 @@ public class AesGcmTest {
// Encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt);
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
int outputSize = cipher.getOutputSize(test.pt.length);
ByteBuffer ctBuffer = ByteBuffer.allocate(outputSize);
cipher.updateAAD(test.aad);
@@ -401,7 +421,7 @@ public class AesGcmTest {
// Decryption
ctBuffer.flip();
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
outputSize = cipher.getOutputSize(test.ct.length);
ByteBuffer decrypted = ByteBuffer.allocate(outputSize);
cipher.updateAAD(test.aad);
@@ -416,7 +436,7 @@ public class AesGcmTest {
for (GcmTestVector test : getTestVectors()) {
// Encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
int outputSize = cipher.getOutputSize(test.pt.length);
byte[] backingArray = new byte[outputSize];
ByteBuffer ptBuffer = ByteBuffer.wrap(backingArray);
@@ -430,7 +450,7 @@ public class AesGcmTest {
// Decryption
ByteBuffer decrypted = ByteBuffer.wrap(backingArray);
ctBuffer.flip();
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
cipher.updateAAD(test.aad);
cipher.doFinal(ctBuffer, decrypted);
assertEquals(test.ptHex, TestUtil.byteBufferToHex(decrypted));
@@ -640,7 +660,7 @@ public class AesGcmTest {
// Encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt).asReadOnlyBuffer();
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
int outputSize = cipher.getOutputSize(test.pt.length);
ByteBuffer ctBuffer = ByteBuffer.allocate(outputSize);
cipher.updateAAD(test.aad);
@@ -650,7 +670,7 @@ public class AesGcmTest {
// Decryption
ctBuffer.flip();
ctBuffer = ctBuffer.asReadOnlyBuffer();
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
outputSize = cipher.getOutputSize(test.ct.length);
ByteBuffer decrypted = ByteBuffer.allocate(outputSize);
cipher.updateAAD(test.aad);
@@ -678,7 +698,7 @@ public class AesGcmTest {
ByteBuffer ctBuffer = ByteBuffer.wrap(new byte[test.ct.length + 50]);
ctBuffer.position(8);
ctBuffer = ctBuffer.slice();
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
cipher.updateAAD(test.aad);
cipher.doFinal(ptBuffer, ctBuffer);
assertEquals(test.ctHex, TestUtil.byteBufferToHex(ctBuffer));
@@ -688,7 +708,7 @@ public class AesGcmTest {
ByteBuffer decBuffer = ByteBuffer.wrap(new byte[test.pt.length + 50]);
decBuffer.position(6);
decBuffer = decBuffer.slice();
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
cipher.updateAAD(test.aad);
cipher.doFinal(ctBuffer, decBuffer);
assertEquals(test.ptHex, TestUtil.byteBufferToHex(decBuffer));
@@ -702,7 +722,7 @@ public class AesGcmTest {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt);
ByteBuffer ctBuffer = ByteBuffer.allocate(test.ct.length - 1);
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
cipher.updateAAD(test.aad);
try {
cipher.doFinal(ptBuffer, ctBuffer);
@@ -714,7 +734,7 @@ public class AesGcmTest {
// Decryption
ctBuffer = ByteBuffer.wrap(test.ct);
ByteBuffer decrypted = ByteBuffer.allocate(test.pt.length - 1);
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
cipher.updateAAD(test.aad);
try {
cipher.doFinal(ctBuffer, decrypted);
@@ -736,7 +756,7 @@ public class AesGcmTest {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
ByteBuffer empty = ByteBuffer.allocate(0);
ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt);
- cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(test.alias), test.parameters);
int outputSize = cipher.getOutputSize(test.pt.length);
ByteBuffer ctBuffer = ByteBuffer.allocate(outputSize);
cipher.updateAAD(empty);
@@ -754,7 +774,7 @@ public class AesGcmTest {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
ByteBuffer empty = ByteBuffer.allocate(0);
ByteBuffer ctBuffer = ByteBuffer.wrap(test.ct);
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
int outputSize = cipher.getOutputSize(test.ct.length);
ByteBuffer ptBuffer = ByteBuffer.allocate(outputSize);
cipher.updateAAD(empty);
@@ -767,7 +787,7 @@ public class AesGcmTest {
// Simple test that a modified ciphertext fails.
ctBuffer.flip();
ptBuffer.clear();
- cipher.init(Cipher.DECRYPT_MODE, (SecretKey) keyStore.getKey(test.alias, null), test.parameters);
+ cipher.init(Cipher.DECRYPT_MODE, getKey(test.alias), test.parameters);
cipher.updateAAD(empty);
cipher.updateAAD(test.aad);
cipher.updateAAD(new byte[1]);
@@ -807,12 +827,7 @@ public class AesGcmTest {
fail("Failed to set secret key entry in KeyStore.");
}
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
- try {
- cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(counter));
- } catch (InvalidAlgorithmParameterException ex) {
- // OpenJDK8 does not support IvParameterSpec for GCM.
- throw ex;
- }
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(counter));
byte[] output = cipher.doFinal(input);
assertEquals(input.length + 16, output.length);
}
@@ -841,12 +856,7 @@ public class AesGcmTest {
fail("Failed to set secret key entry in KeyStore.");
}
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", EXPECTED_PROVIDER_NAME);
- try {
- AlgorithmParameterGenerator.getInstance("GCM");
- } catch (NoSuchAlgorithmException ex) {
- // Conscrypt does not support AlgorithmParameterGenerator for GCM.
- throw ex;
- }
+ AlgorithmParameterGenerator.getInstance("GCM");
AlgorithmParameters param = AlgorithmParameterGenerator.getInstance("GCM").generateParameters();
cipher.init(Cipher.ENCRYPT_MODE, secretKey, param);
byte[] output = cipher.doFinal(input);
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java
index 3698e4e..d0f85d4 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java
@@ -25,12 +25,17 @@ import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.Ignore;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import java.security.KeyStore;
+import android.keystore.cts.util.KeyStoreUtil;
/**
* CipherInputStream tests
@@ -51,18 +56,31 @@ import org.junit.runners.JUnit4;
* All other tests run under the assumption that returning an empty plaintext is acceptable
* behaviour, so that the tests are able to catch additional problems.
*/
-@RunWith(JUnit4.class)
public class CipherInputStreamTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
static final SecureRandom rand = new SecureRandom();
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
+
static byte[] randomBytes(int size) {
byte[] bytes = new byte[size];
rand.nextBytes(bytes);
return bytes;
}
- static SecretKeySpec randomKey(String algorithm, int keySizeInBytes) {
- return new SecretKeySpec(randomBytes(keySizeInBytes), "AES");
+ static SecretKey randomKey(String algorithm, String alias, int keySizeInBytes) throws Exception {
+ SecretKeySpec keySpec = new SecretKeySpec(randomBytes(keySizeInBytes), "AES");
+ KeyStore keyStore = KeyStoreUtil.saveSecretKeyToKeystore(alias, keySpec,
+ new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setRandomizedEncryptionRequired(false)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ // Key imported, obtain a reference to it.
+ return (SecretKey) keyStore.getKey(alias, null);
}
static AlgorithmParameterSpec randomParameters(
@@ -76,7 +94,7 @@ public class CipherInputStreamTest {
/** Test vectors */
public static class TestVector {
public String algorithm;
- public SecretKeySpec key;
+ public SecretKey key;
public AlgorithmParameterSpec params;
public byte[] pt;
public byte[] aad;
@@ -84,14 +102,14 @@ public class CipherInputStreamTest {
@SuppressWarnings("InsecureCryptoUsage")
public TestVector(
- String algorithm, int keySize, int ivSize, int tagSize, int ptSize, int aadSize)
- throws Exception {
+ String algorithm, String alias, int keySize,
+ int ivSize, int tagSize, int ptSize, int aadSize) throws Exception {
this.algorithm = algorithm;
- this.key = randomKey(algorithm, keySize);
+ this.key = randomKey(algorithm, alias, keySize);
this.params = randomParameters(algorithm, ivSize, tagSize);
this.pt = randomBytes(ptSize);
this.aad = randomBytes(aadSize);
- Cipher cipher = Cipher.getInstance(algorithm);
+ Cipher cipher = Cipher.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, this.key, this.params);
cipher.updateAAD(aad);
this.ct = cipher.doFinal(pt);
@@ -112,7 +130,10 @@ public class CipherInputStreamTest {
for (int tagSize : tagSizes) {
for (int ptSize : ptSizes) {
for (int aadSize : aadSizes) {
- result.add(new TestVector(algorithm, keySize, ivSize, tagSize, ptSize, aadSize));
+ String keyAlias = "Key-" + keySize + "-" + ivSize + "-" + tagSize +
+ "-" + ptSize + "-" + aadSize;
+ result.add(new TestVector(algorithm, keyAlias, keySize,
+ ivSize, tagSize, ptSize, aadSize));
}
}
}
@@ -124,7 +145,7 @@ public class CipherInputStreamTest {
@SuppressWarnings("InsecureCryptoUsage")
public void testEncrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
- Cipher cipher = Cipher.getInstance(t.algorithm);
+ Cipher cipher = Cipher.getInstance(t.algorithm, EXPECTED_PROVIDER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
InputStream is = new ByteArrayInputStream(t.pt);
@@ -148,7 +169,7 @@ public class CipherInputStreamTest {
@SuppressWarnings("InsecureCryptoUsage")
public void testDecrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
- Cipher cipher = Cipher.getInstance(t.algorithm);
+ Cipher cipher = Cipher.getInstance(t.algorithm, EXPECTED_PROVIDER_NAME);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
InputStream is = new ByteArrayInputStream(t.ct);
@@ -184,7 +205,7 @@ public class CipherInputStreamTest {
public void testCorruptDecrypt(Iterable<TestVector> tests, boolean acceptEmptyPlaintext)
throws Exception {
for (TestVector t : tests) {
- Cipher cipher = Cipher.getInstance(t.algorithm);
+ Cipher cipher = Cipher.getInstance(t.algorithm, EXPECTED_PROVIDER_NAME);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
@@ -263,6 +284,7 @@ public class CipherInputStreamTest {
/** Tests CipherOutputStream with AES-EAX if this algorithm is supported by the provider. */
@Test
+ @Ignore // Ignored due to AES/EAX algorithm is not supported in AndroidKeyStore
public void testAesEax() throws Exception {
final String algorithm = "AES/EAX/NoPadding";
final int[] keySizes = {16, 32};
@@ -270,12 +292,6 @@ public class CipherInputStreamTest {
final int[] tagSizes = {12, 16};
final int[] ptSizes = {0, 8, 16, 65, 8100};
final int[] aadSizes = {0, 8, 24};
- try {
- Cipher.getInstance(algorithm);
- } catch (NoSuchAlgorithmException ex) {
- System.out.println("Skipping testAesEax");
- return;
- }
Iterable<TestVector> v =
getTestVectors(algorithm, keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
testEncrypt(v);
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java
index d016941..bf863fe 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java
@@ -24,12 +24,17 @@ import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.Ignore;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import java.security.KeyStore;
+import android.keystore.cts.util.KeyStoreUtil;
/**
* CipherOutputStream tests
@@ -51,18 +56,31 @@ import org.junit.runners.JUnit4;
* behaviour, so that the tests are able to catch additional problems.
*/
-@RunWith(JUnit4.class)
public class CipherOutputStreamTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
static final SecureRandom rand = new SecureRandom();
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
+
static byte[] randomBytes(int size) {
byte[] bytes = new byte[size];
rand.nextBytes(bytes);
return bytes;
}
- static SecretKeySpec randomKey(String algorithm, int keySizeInBytes) {
- return new SecretKeySpec(randomBytes(keySizeInBytes), "AES");
+ static SecretKey randomKey(String algorithm, String alias, int keySizeInBytes) throws Exception{
+ SecretKeySpec keySpec = new SecretKeySpec(randomBytes(keySizeInBytes), "AES");
+ KeyStore keyStore = KeyStoreUtil.saveSecretKeyToKeystore(alias, keySpec,
+ new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setRandomizedEncryptionRequired(false)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ // Key imported, obtain a reference to it.
+ return (SecretKey) keyStore.getKey(alias, null);
}
static AlgorithmParameterSpec randomParameters(
@@ -77,21 +95,21 @@ public class CipherOutputStreamTest {
@SuppressWarnings("InsecureCryptoUsage")
public static class TestVector {
public String algorithm;
- public SecretKeySpec key;
+ public SecretKey key;
public AlgorithmParameterSpec params;
public byte[] pt;
public byte[] aad;
public byte[] ct;
public TestVector(
- String algorithm, int keySize, int ivSize, int tagSize, int ptSize, int aadSize)
- throws Exception {
+ String algorithm, String alias, int keySize,
+ int ivSize, int tagSize, int ptSize, int aadSize) throws Exception {
this.algorithm = algorithm;
- this.key = randomKey(algorithm, keySize);
+ this.key = randomKey(algorithm, alias, keySize);
this.params = randomParameters(algorithm, ivSize, tagSize);
this.pt = randomBytes(ptSize);
this.aad = randomBytes(aadSize);
- Cipher cipher = Cipher.getInstance(algorithm);
+ Cipher cipher = Cipher.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, this.key, this.params);
cipher.updateAAD(aad);
this.ct = cipher.doFinal(pt);
@@ -106,13 +124,16 @@ public class CipherOutputStreamTest {
int[] ptSizes,
int[] aadSizes)
throws Exception {
+ int counter = 0;
ArrayList<TestVector> result = new ArrayList<TestVector>();
for (int keySize : keySizes) {
for (int ivSize : ivSizes) {
for (int tagSize : tagSizes) {
for (int ptSize : ptSizes) {
for (int aadSize : aadSizes) {
- result.add(new TestVector(algorithm, keySize, ivSize, tagSize, ptSize, aadSize));
+ String keyAlias = "Key" + counter++;
+ result.add(new TestVector(algorithm, keyAlias, keySize,
+ ivSize, tagSize, ptSize, aadSize));
}
}
}
@@ -124,7 +145,7 @@ public class CipherOutputStreamTest {
@SuppressWarnings("InsecureCryptoUsage")
public void testEncrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
- Cipher cipher = Cipher.getInstance(t.algorithm);
+ Cipher cipher = Cipher.getInstance(t.algorithm, EXPECTED_PROVIDER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
ByteArrayOutputStream os = new ByteArrayOutputStream();
@@ -138,7 +159,7 @@ public class CipherOutputStreamTest {
@SuppressWarnings("InsecureCryptoUsage")
public void testDecrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
- Cipher cipher = Cipher.getInstance(t.algorithm);
+ Cipher cipher = Cipher.getInstance(t.algorithm, EXPECTED_PROVIDER_NAME);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
ByteArrayOutputStream os = new ByteArrayOutputStream();
@@ -160,7 +181,7 @@ public class CipherOutputStreamTest {
public void testCorruptDecrypt(Iterable<TestVector> tests, boolean acceptEmptyPlaintext)
throws Exception {
for (TestVector t : tests) {
- Cipher cipher = Cipher.getInstance(t.algorithm);
+ Cipher cipher = Cipher.getInstance(t.algorithm, EXPECTED_PROVIDER_NAME);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
@@ -228,6 +249,7 @@ public class CipherOutputStreamTest {
/** Tests CipherOutputStream with AES-EAX if AES-EAS is supported by the provider. */
@SuppressWarnings("InsecureCryptoUsage")
@Test
+ @Ignore // Ignored due to AES/EAX algorithm is not supported in AndroidKeyStore
public void testAesEax() throws Exception {
final String algorithm = "AES/EAX/NoPadding";
final int[] keySizes = {16, 32};
@@ -235,12 +257,6 @@ public class CipherOutputStreamTest {
final int[] tagSizes = {12, 16};
final int[] ptSizes = {8, 16, 65, 8100};
final int[] aadSizes = {0, 8, 24};
- try {
- Cipher.getInstance(algorithm);
- } catch (NoSuchAlgorithmException ex) {
- System.out.println("Skipping testAesEax");
- return;
- }
Iterable<TestVector> v =
getTestVectors(algorithm, keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
testEncrypt(v);
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/EcdhTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/EcdhTest.java
index 517d23b..4f53650 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/EcdhTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/EcdhTest.java
@@ -16,18 +16,13 @@ package com.google.security.wycheproof;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-
-import com.google.security.wycheproof.WycheproofRunner.NoPresubmitTest;
-import com.google.security.wycheproof.WycheproofRunner.ProviderType;
-import com.google.security.wycheproof.WycheproofRunner.SlowTest;
-import java.lang.management.ManagementFactory;
-import java.lang.management.ThreadMXBean;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
@@ -44,10 +39,13 @@ import java.security.spec.EllipticCurve;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.KeyAgreement;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
+import org.junit.Ignore;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyGenParameterSpec;
+import android.keystore.cts.util.KeyStoreUtil;
/**
* Testing ECDH.
*
@@ -89,8 +87,36 @@ import org.junit.runners.JUnit4;
// certificate.
// - CVE-2014-3572: OpenSSL downgrades ECDHE to ECDH
// - CVE-2011-3210: OpenSSL was not thread safe
-@RunWith(JUnit4.class)
public class EcdhTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_PROVIDER_NAME;
+ private static final String KEY_ALIAS_1 = "TestKey";
+ private static final String KEY_ALIAS_2 = "wycheproofkey1";
+ private static final String KEY_ALIAS_3 = "wycheproofkey2";
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
+
+ private static PrivateKey getKeystorePrivateKey(PublicKey pubKey, PrivateKey privKey)
+ throws Exception {
+ return (PrivateKey) KeyStoreUtil.saveKeysToKeystore(
+ KEY_ALIAS_1, pubKey, privKey,
+ new KeyProtection.Builder(KeyProperties.PURPOSE_AGREE_KEY)
+ .build())
+ .getKey(KEY_ALIAS_1, null);
+ }
+
+ private KeyPair generateECKeyPair(String alias, ECGenParameterSpec ecSpec) throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", EXPECTED_PROVIDER_NAME);
+ KeyGenParameterSpec ecKeySpec =
+ new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_AGREE_KEY)
+ .setAlgorithmParameterSpec(ecSpec)
+ .build();
+
+ keyGen.initialize(ecKeySpec);
+ return keyGen.generateKeyPair();
+ }
static final String[] ECDH_VARIANTS = {
// Raw ECDH. The shared secret is the x-coordinate of the ECDH computation.
@@ -161,7 +187,6 @@ public class EcdhTest {
ECPublicKeySpec pub = new ECPublicKeySpec(pubPoint, params);
return pub;
} catch (Exception ex) {
- System.out.println(comment + " throws " + ex.toString());
return null;
}
}
@@ -509,14 +534,11 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
/** Checks that key agreement using ECDH works. */
@Test
public void testBasic() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
- ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
- keyGen.initialize(ecSpec);
- KeyPair keyPairA = keyGen.generateKeyPair();
- KeyPair keyPairB = keyGen.generateKeyPair();
+ KeyPair keyPairA = generateECKeyPair(KEY_ALIAS_2, new ECGenParameterSpec("secp256r1"));
+ KeyPair keyPairB = generateECKeyPair(KEY_ALIAS_3, new ECGenParameterSpec("secp256r1"));
- KeyAgreement kaA = KeyAgreement.getInstance("ECDH");
- KeyAgreement kaB = KeyAgreement.getInstance("ECDH");
+ KeyAgreement kaA = KeyAgreement.getInstance("ECDH", EXPECTED_PROVIDER_NAME);
+ KeyAgreement kaB = KeyAgreement.getInstance("ECDH", EXPECTED_PROVIDER_NAME);
kaA.init(keyPairA.getPrivate());
kaB.init(keyPairB.getPrivate());
kaA.doPhase(keyPairB.getPublic(), true);
@@ -526,10 +548,6 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
assertEquals(TestUtil.bytesToHex(kAB), TestUtil.bytesToHex(kBA));
}
- @NoPresubmitTest(
- providers = {ProviderType.BOUNCY_CASTLE},
- bugs = {"BouncyCastle uses long encoding. Is this a bug?"}
- )
@Test
public void testEncode() throws Exception {
KeyFactory kf = KeyFactory.getInstance("EC");
@@ -559,26 +577,18 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
*/
@SuppressWarnings("InsecureCryptoUsage")
public void testModifiedPublic(String algorithm) throws Exception {
- KeyAgreement ka;
- try {
- ka = KeyAgreement.getInstance(algorithm);
- } catch (NoSuchAlgorithmException ex) {
- System.out.println("testWrongOrder: " + algorithm + " not supported");
- return;
- }
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
- keyGen.initialize(EcUtil.getNistP256Params());
- ECPrivateKey priv = (ECPrivateKey) keyGen.generateKeyPair().getPrivate();
+ KeyAgreement ka = KeyAgreement.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
+ KeyPair pair = generateECKeyPair(KEY_ALIAS_1, new ECGenParameterSpec("secp256r1"));
KeyFactory kf = KeyFactory.getInstance("EC");
ECPublicKey validKey = (ECPublicKey) kf.generatePublic(EC_VALID_PUBLIC_KEY.getSpec());
- ka.init(priv);
+ ka.init(pair.getPrivate());
ka.doPhase(validKey, true);
String expected = TestUtil.bytesToHex(ka.generateSecret());
for (EcPublicKeyTestVector test : EC_MODIFIED_PUBLIC_KEYS) {
try {
X509EncodedKeySpec spec = test.getX509EncodedKeySpec();
ECPublicKey modifiedKey = (ECPublicKey) kf.generatePublic(spec);
- ka.init(priv);
+ ka.init(pair.getPrivate());
ka.doPhase(modifiedKey, true);
String shared = TestUtil.bytesToHex(ka.generateSecret());
// The implementation did not notice that the public key was modified.
@@ -593,7 +603,6 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
assertEquals("algorithm:" + algorithm + " test:" + test.comment, expected, shared);
} catch (GeneralSecurityException ex) {
// OK, since the public keys have been modified.
- System.out.println("testModifiedPublic:" + test.comment + " throws " + ex.toString());
}
}
}
@@ -604,19 +613,11 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
*/
@SuppressWarnings("InsecureCryptoUsage")
public void testModifiedPublicSpec(String algorithm) throws Exception {
- KeyAgreement ka;
- try {
- ka = KeyAgreement.getInstance(algorithm);
- } catch (NoSuchAlgorithmException ex) {
- System.out.println("testWrongOrder: " + algorithm + " not supported");
- return;
- }
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
- keyGen.initialize(EcUtil.getNistP256Params());
- ECPrivateKey priv = (ECPrivateKey) keyGen.generateKeyPair().getPrivate();
+ KeyAgreement ka = KeyAgreement.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
+ KeyPair pair = generateECKeyPair(KEY_ALIAS_1, new ECGenParameterSpec("secp256r1"));
KeyFactory kf = KeyFactory.getInstance("EC");
ECPublicKey validKey = (ECPublicKey) kf.generatePublic(EC_VALID_PUBLIC_KEY.getSpec());
- ka.init(priv);
+ ka.init(pair.getPrivate());
ka.doPhase(validKey, true);
String expected = TestUtil.bytesToHex(ka.generateSecret());
for (EcPublicKeyTestVector test : EC_MODIFIED_PUBLIC_KEYS) {
@@ -628,7 +629,7 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
}
try {
ECPublicKey modifiedKey = (ECPublicKey) kf.generatePublic(spec);
- ka.init(priv);
+ ka.init(pair.getPrivate());
ka.doPhase(modifiedKey, true);
String shared = TestUtil.bytesToHex(ka.generateSecret());
// The implementation did not notice that the public key was modified.
@@ -643,77 +644,30 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
assertEquals("algorithm:" + algorithm + " test:" + test.comment, expected, shared);
} catch (GeneralSecurityException ex) {
// OK, since the public keys have been modified.
- System.out.println("testModifiedPublic:" + test.comment + " throws " + ex.toString());
}
}
}
@Test
- public void testModifiedPublic() throws Exception {
+ public void testEcdhModifiedPublic() throws Exception {
testModifiedPublic("ECDH");
+ }
+
+ @Test
+ @Ignore // ECDHC algorithm is not supported in AndroidKeyStore
+ public void testEcdhcModifiedPublic() throws Exception {
testModifiedPublic("ECDHC");
}
@Test
- public void testModifiedPublicSpec() throws Exception {
+ public void testEcdhModifiedPublicSpec() throws Exception {
testModifiedPublicSpec("ECDH");
- testModifiedPublicSpec("ECDHC");
}
- @SuppressWarnings("InsecureCryptoUsage")
- public void testDistinctCurves(String algorithm, ECPrivateKey priv, ECPublicKey pub)
- throws Exception {
- KeyAgreement kaA;
- try {
- kaA = KeyAgreement.getInstance(algorithm);
- } catch (NoSuchAlgorithmException ex) {
- System.out.println("Algorithm not supported: " + algorithm);
- return;
- }
- byte[] shared;
- try {
- kaA.init(priv);
- kaA.doPhase(pub, true);
- shared = kaA.generateSecret();
- } catch (InvalidKeyException ex) {
- // This is expected.
- return;
- }
- // Printing some information to determine what might have gone wrong:
- // E.g., if the generated secret is the same as the x-coordinate of the public key
- // then it is likely that the ECDH computation was using a fake group with small order.
- // Such a situation is probably exploitable.
- // This probably is exploitable. If the curve of the private key was used for the ECDH
- // then the generated secret and the x-coordinate of the public key are likely
- // distinct.
- EllipticCurve pubCurve = pub.getParams().getCurve();
- EllipticCurve privCurve = priv.getParams().getCurve();
- ECPoint pubW = pub.getW();
- System.out.println("testDistinctCurves: algorithm=" + algorithm);
- System.out.println(
- "Private key: a="
- + privCurve.getA()
- + " b="
- + privCurve.getB()
- + " p"
- + EcUtil.getModulus(privCurve));
- System.out.println(" s =" + priv.getS());
- System.out.println(
- "Public key: a="
- + pubCurve.getA()
- + " b="
- + pubCurve.getB()
- + " p"
- + EcUtil.getModulus(pubCurve));
- System.out.println(" w = (" + pubW.getAffineX() + ", " + pubW.getAffineY() + ")");
- System.out.println(
- " = ("
- + pubW.getAffineX().toString(16)
- + ", "
- + pubW.getAffineY().toString(16)
- + ")");
- System.out.println("generated shared secret:" + TestUtil.bytesToHex(shared));
- fail("Generated secret with distinct Curves using " + algorithm);
+ @Test
+ @Ignore // ECDHC algorithm is not supported in AndroidKeyStore
+ public void testEcdhcModifiedPublicSpec() throws Exception {
+ testModifiedPublicSpec("ECDHC");
}
/**
@@ -725,25 +679,11 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
// TODO(bleichen): This can be merged with testModifiedPublic once this is fixed.
@SuppressWarnings("InsecureCryptoUsage")
public void testWrongOrder(String algorithm, ECParameterSpec spec) throws Exception {
- KeyAgreement ka;
- try {
- ka = KeyAgreement.getInstance(algorithm);
- } catch (NoSuchAlgorithmException ex) {
- System.out.println("testWrongOrder: " + algorithm + " not supported");
- return;
- }
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
- ECPrivateKey priv;
- ECPublicKey pub;
- try {
- keyGen.initialize(spec);
- priv = (ECPrivateKey) keyGen.generateKeyPair().getPrivate();
- pub = (ECPublicKey) keyGen.generateKeyPair().getPublic();
- } catch (GeneralSecurityException ex) {
- // This is OK, since not all provider support Brainpool curves
- System.out.println("testWrongOrder: could not generate keys for curve");
- return;
- }
+ KeyAgreement ka = KeyAgreement.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
+ PrivateKey priv = generateECKeyPair(KEY_ALIAS_2,
+ new ECGenParameterSpec("secp256r1")).getPrivate();
+ ECPublicKey pub = (ECPublicKey) generateECKeyPair(KEY_ALIAS_3,
+ new ECGenParameterSpec("secp256r1")).getPublic();
// Get the shared secret for the unmodified keys.
ka.init(priv);
ka.doPhase(pub, true);
@@ -754,15 +694,7 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
spec.getCurve(), spec.getGenerator(), spec.getOrder().shiftRight(16), 1);
ECPublicKeySpec modifiedPubSpec = new ECPublicKeySpec(pub.getW(), modifiedParams);
KeyFactory kf = KeyFactory.getInstance("EC");
- ECPublicKey modifiedPub;
- try {
- modifiedPub = (ECPublicKey) kf.generatePublic(modifiedPubSpec);
- } catch (GeneralSecurityException ex) {
- // The provider does not support non-standard curves or did a validity check.
- // Both would be correct.
- System.out.println("testWrongOrder: can't modify order.");
- return;
- }
+ ECPublicKey modifiedPub = (ECPublicKey) kf.generatePublic(modifiedPubSpec);
byte[] shared2;
try {
ka.init(priv);
@@ -770,7 +702,6 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
shared2 = ka.generateSecret();
} catch (GeneralSecurityException ex) {
// This is the expected behavior
- System.out.println("testWrongOrder:" + ex.toString());
return;
}
// TODO(bleichen): Getting here is already a bug and we might flag this later.
@@ -782,25 +713,24 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
// of modular reduction, can determine the private key, either by a binary search or by trying
// to guess the private key modulo some small "order".
// BouncyCastle v.1.53 fails this test, and leaks the private key.
- System.out.println(
- "Generated shared secret with a modified order:"
- + algorithm
- + "\n"
- + "expected:"
- + TestUtil.bytesToHex(shared)
- + " computed:"
- + TestUtil.bytesToHex(shared2));
+
assertEquals(
"Algorithm:" + algorithm, TestUtil.bytesToHex(shared), TestUtil.bytesToHex(shared2));
}
@Test
- public void testWrongOrderEcdh() throws Exception {
+ public void testWrongOrderEcdhNist() throws Exception {
testWrongOrder("ECDH", EcUtil.getNistP256Params());
+ }
+
+ @Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore.
+ public void testWrongOrderEcdhBrainpool() throws Exception {
testWrongOrder("ECDH", EcUtil.getBrainpoolP256r1Params());
}
@Test
+ @Ignore // ECDHC algorithm not supported in AndroidKeyStore.
public void testWrongOrderEcdhc() throws Exception {
testWrongOrder("ECDHC", EcUtil.getNistP256Params());
testWrongOrder("ECDHC", EcUtil.getBrainpoolP256r1Params());
@@ -816,24 +746,23 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
private void testLargePrivateKey(ECParameterSpec spec) throws Exception {
BigInteger order = spec.getOrder();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
- ECPublicKey pub;
- try {
- keyGen.initialize(spec);
- pub = (ECPublicKey) keyGen.generateKeyPair().getPublic();
- } catch (GeneralSecurityException ex) {
- // curve is not supported
- return;
- }
+ keyGen.initialize(spec);
+ ECPublicKey pub = (ECPublicKey) keyGen.generateKeyPair().getPublic();
KeyFactory kf = KeyFactory.getInstance("EC");
- KeyAgreement ka = KeyAgreement.getInstance("ECDH");
+ KeyAgreement ka = KeyAgreement.getInstance("ECDH", EXPECTED_PROVIDER_NAME);
for (int i = 1; i <= 64; i++) {
BigInteger p1 = BigInteger.valueOf(i);
ECPrivateKeySpec spec1 = new ECPrivateKeySpec(p1, spec);
ECPrivateKeySpec spec2 = new ECPrivateKeySpec(order.subtract(p1), spec);
- ka.init(kf.generatePrivate(spec1));
+ PrivateKey priv1 = kf.generatePrivate(spec1);
+ // This Public key is not pair of priv1, but it is required to create KeyPair to import into
+ // AndroidKeyStore, So using dummy public key.
+ PublicKey pub1 = kf.generatePublic(EC_VALID_PUBLIC_KEY.getX509EncodedKeySpec());
+ ka.init(getKeystorePrivateKey(pub1, priv1));
ka.doPhase(pub, true);
byte[] shared1 = ka.generateSecret();
- ka.init(kf.generatePrivate(spec2));
+ PrivateKey priv2 = kf.generatePrivate(spec2);
+ ka.init(getKeystorePrivateKey(pub1, priv2));
ka.doPhase(pub, true);
byte[] shared2 = ka.generateSecret();
// The private keys p1 and p2 are equivalent, since only the x-coordinate of the
@@ -843,230 +772,18 @@ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
}
@Test
- public void testLargePrivateKey() throws Exception {
+ public void testNistCurveLargePrivateKey() throws Exception {
testLargePrivateKey(EcUtil.getNistP224Params());
testLargePrivateKey(EcUtil.getNistP256Params());
testLargePrivateKey(EcUtil.getNistP384Params());
// This test failed before CVE-2017-10176 was fixed.
testLargePrivateKey(EcUtil.getNistP521Params());
- testLargePrivateKey(EcUtil.getBrainpoolP256r1Params());
}
- /**
- * This test tries to determine whether point multipliplication using two distinct
- * points leads to distinguishable timings.
- *
- * The main goal here is to determine if the attack by Toru Akishita and Tsuyoshi Takagi
- * in https://www-old.cdc.informatik.tu-darmstadt.de/reports/TR/TI-03-01.zvp.pdf
- * might be applicable. I.e. one of the points contains a zero value when multiplied
- * by mul, the other one does not.
- *
- * In its current form the test here is quite weak for a number of reasons:
- * (1) The timing is often noisy, because the test is run as a unit test.
- * (2) The test is executed with only a small number of input points.
- * (3) The number of samples is rather low. Running this test with a larger sample
- * size would detect more timing differences. Unfortunately
- * (4) The test does not determine if a variable run time is exploitable. For example
- * if the tested provider uses windowed exponentiation and the special point is
- * in the precomputation table then timing differences are easy to spot, but more
- * difficult to exploit and hence additional experiments would be necessary.
- *
- * @param spec the specification of the curve
- * @param p0 This is a special point. I.e. multiplying this point by mul
- * may lead to a zero value that may be observable.
- * @param p1 a random point on the curve
- * @param mul an integer, such that multiplying p0 with this value may lead to a timing
- * difference
- * @param privKeySize the size of the private key in bits
- * @param comment describes the test case
- */
- private void testTiming(ECParameterSpec spec, ECPoint p0, ECPoint p1,
- BigInteger mul, int privKeySize, String comment) throws Exception {
- ThreadMXBean bean = ManagementFactory.getThreadMXBean();
- if (!bean.isCurrentThreadCpuTimeSupported()) {
- System.out.println("getCurrentThreadCpuTime is not supported. Skipping");
- return;
- }
- SecureRandom random = new SecureRandom();
- int fixedSize = mul.bitLength();
- int missingBits = privKeySize - 2 * fixedSize;
- assertTrue(missingBits > 0);
- // possible values for tests, minCount:
- // 1024, 410
- // 2048, 880
- // 4096, 1845
- // 10000, 4682
- // I.e. these are values, such that doing 'tests' coin flips results in <= minCount heads or
- // tails with a probability smaller than 2^-32.
- //
- // def min_count(n, b=33):
- // res, sum, k = 1,1,0
- // bnd = 2**(n-b)
- // while sum < bnd:
- // res *= n - k
- // res //= 1 + k
- // k += 1
- // sum += res
- // return k - 1
- final int tests = 2048;
- final int minCount = 880;
- // the number of measurements done with each point
- final int repetitions = 8;
- // the number of warmup experiments that are ignored
- final int warmup = 8;
- final int sampleSize = warmup + tests;
- KeyFactory kf = KeyFactory.getInstance("EC");
- PublicKey[] publicKeys = new PublicKey[2];
- try {
- publicKeys[0] = kf.generatePublic(new ECPublicKeySpec(p0, spec));
- publicKeys[1] = kf.generatePublic(new ECPublicKeySpec(p1, spec));
- } catch (InvalidKeySpecException ex) {
- // unsupported curve
- return;
- }
- PrivateKey[] privKeys = new PrivateKey[sampleSize];
- for (int i = 0; i < sampleSize; i++) {
- BigInteger m = new BigInteger(missingBits, random);
- m = mul.shiftLeft(missingBits).add(m);
- m = m.shiftLeft(fixedSize).add(mul);
- ECPrivateKeySpec privSpec = new ECPrivateKeySpec(m, spec);
- privKeys[i] = kf.generatePrivate(privSpec);
- }
- KeyAgreement ka = KeyAgreement.getInstance("ECDH");
- long[][] timings = new long[2][sampleSize];
- for (int i = 0; i < sampleSize; i++) {
- for (int j = 0; j < 2 * repetitions; j++) {
- // idx determines which key to use.
- int idx = (j ^ i) & 1;
- ka.init(privKeys[i]);
- long start = bean.getCurrentThreadCpuTime();
- ka.doPhase(publicKeys[idx], true);
- byte[] unused = ka.generateSecret();
- long time = bean.getCurrentThreadCpuTime() - start;
- timings[idx][i] += time;
- }
- }
- for (int i = 0; i < sampleSize; i++) {
- for (int j = 0; j < 2; j++) {
- timings[j][i] /= repetitions;
- }
- }
-
- // Performs some statistics.
- boolean noisy = false; // Set to true, if the timings have a large variance.
- System.out.println("ECDH timing test:" + comment);
- double[] avg = new double[2];
- double[] var = new double[2];
- for (int i = 0; i < 2; i++) {
- double sum = 0.0;
- double sumSqr = 0.0;
- for (int j = warmup; j < sampleSize; j++) {
- double val = (double) timings[i][j];
- sum += val;
- sumSqr += val * val;
- }
- avg[i] = sum / tests;
- var[i] = (sumSqr - avg[i] * sum) / (tests - 1);
- double stdDev = Math.sqrt(var[i]);
- double cv = stdDev / avg[i];
- System.out.println("Timing for point " + i + " avg: " + avg[i] + " std dev: " + stdDev
- + " cv:" + cv);
- // The ratio 0.05 below is a somewhat arbitrary value that tries to determine if the noise
- // is too big to detect even larger timing differences.
- if (cv > 0.05) {
- noisy = true;
- }
- }
- // Paired Z-test:
- // The outcome of this value can be significantly influenced by extreme outliers, such
- // as slow timings because of things like a garbage collection.
- double sigmas = Math.abs(avg[0] - avg[1]) / Math.sqrt((var[0] + var[1]) / tests);
- System.out.println("Sigmas: " + sigmas);
-
- // Pairwise comparison:
- // this comparison has the property that it compares timings done with the same
- // private key, hence timing differences from using different addition chain sizes
- // are ignored. Extreme outliers should not influence the result a lot, as long as the
- // number of outliers is small.
- int point0Faster = 0;
- int equal = 0;
- for (int i = 0; i < sampleSize; i++) {
- if (timings[0][i] < timings[1][i]) {
- point0Faster += 1;
- } else if (timings[0][i] < timings[1][i]) {
- equal += 1;
- }
- }
- point0Faster += equal / 2;
- System.out.println("Point 0 multiplication is faster: " + point0Faster);
- if (point0Faster < minCount || point0Faster > sampleSize - minCount) {
- fail("Timing differences in ECDH computation detected");
- } else if (noisy) {
- System.out.println("Timing was too noisy to expect results.");
- }
- }
-
- @SlowTest(providers =
- {ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE, ProviderType.OPENJDK})
- @Test
- public void testTimingSecp256r1() throws Exception {
- // edge case for projective coordinates
- BigInteger x1 =
- new BigInteger("81bfb55b010b1bdf08b8d9d8590087aa278e28febff3b05632eeff09011c5579", 16);
- BigInteger y1 =
- new BigInteger("732d0e65267ea28b7af8cfcb148936c2af8664cbb4f04e188148a1457400c2a7", 16);
- ECPoint p1 = new ECPoint(x1, y1);
- // random point
- BigInteger x2 =
- new BigInteger("8608e36a91f1fba12e4074972af446176b5608c9c58dc318bd0742754c3dcee7", 16);
- BigInteger y2 =
- new BigInteger("bc2c9ecd44af916ca58d9e3ef1257f698d350ef486eb86137fe69a7375bcc191", 16);
- ECPoint p2 = new ECPoint(x2, y2);
- testTiming(EcUtil.getNistP256Params(), p1, p2, new BigInteger("2"), 256, "secp256r1");
- }
-
- @SlowTest(providers =
- {ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE, ProviderType.OPENJDK})
@Test
- public void testTimingSecp384r1() throws Exception {
- // edge case for projective coordinates
- BigInteger x1 =
- new BigInteger("7a6fadfee03eb09554f2a04fe08300aca88bb3a46e8f6347bace672cfe427698"
- + "8541cef8dc10536a84580215f5f90a3b", 16);
- BigInteger y1 =
- new BigInteger("6d243d5d9de1cdddd04cbeabdc7a0f6c244391f7cb2d5738fe13c334add4b458"
- + "5fef61ffd446db33b39402278713ae78", 16);
- ECPoint p1 = new ECPoint(x1, y1);
- // random point
- BigInteger x2 =
- new BigInteger("71f3c57d6a879889e582af2c7c5444b0eb6ba95d88365b21ca9549475273ecdd"
- + "3930aa0bebbd1cf084e4049667278602", 16);
- BigInteger y2 =
- new BigInteger("9dcbc4d843af8944eb4ba018d369b351a9ea0f7b9e3561df2ee218d54e198f7c"
- + "837a3abaa41dffd2d2cb771a7599ed9e", 16);
- ECPoint p2 = new ECPoint(x2, y2);
- testTiming(EcUtil.getNistP384Params(), p1, p2, new BigInteger("2"), 384, "secp384r1");
- }
-
- @SlowTest(providers =
- {ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE, ProviderType.OPENJDK})
- @Test
- public void testTimingBrainpoolP256r1() throws Exception {
- // edge case for Jacobian and projective coordinates
- BigInteger x1 =
- new BigInteger("79838c22d2b8dc9af2e6cf56f8826dc3dfe10fcb17b6aaaf551ee52bef12f826", 16);
- BigInteger y1 =
- new BigInteger("1e2ed3d453088c8552c6feecf898667bc1e15905002edec6b269feb7bea09d5b", 16);
- ECPoint p1 = new ECPoint(x1, y1);
-
- // random point
- BigInteger x2 =
- new BigInteger("2720b2e821b2ac8209b573bca755a68821e1e09deb580666702570dd527dd4c1", 16);
- BigInteger y2 =
- new BigInteger("25cdd610243c7e693fad7bd69b43ae3e63e94317c4c6b717d9c8bc3be8c996fb", 16);
- ECPoint p2 = new ECPoint(x2, y2);
- testTiming(EcUtil.getBrainpoolP256r1Params(), p1, p2, new BigInteger("2"), 255,
- "brainpoolP256r1");
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore.
+ public void testBrainpoolCurveLargePrivateKey() throws Exception {
+ testLargePrivateKey(EcUtil.getBrainpoolP256r1Params());
}
}
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/EcdsaTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/EcdsaTest.java
index a6ce23a..3da6d83 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/EcdsaTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/EcdsaTest.java
@@ -16,25 +16,27 @@ package com.google.security.wycheproof;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.google.security.wycheproof.WycheproofRunner.ProviderType;
-import com.google.security.wycheproof.WycheproofRunner.SlowTest;
-import java.lang.management.ManagementFactory;
-import java.lang.management.ThreadMXBean;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
+import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.util.Arrays;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.Ignore;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import android.keystore.cts.util.KeyStoreUtil;
/**
* Tests ECDSA signatures.
@@ -44,8 +46,26 @@ import org.junit.runners.JUnit4;
*
* @author bleichen@google.com (Daniel Bleichenbacher)
*/
-@RunWith(JUnit4.class)
public class EcdsaTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+ private static final String KEY_ALIAS_1 = "TestKey";
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
+
+ private static PrivateKey getKeystorePrivateKey(PublicKey pubKey, PrivateKey privKey)
+ throws Exception {
+ KeyProtection keyProtection = new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN)
+ .setDigests(KeyProperties.DIGEST_SHA224,
+ KeyProperties.DIGEST_SHA256,
+ KeyProperties.DIGEST_SHA384,
+ KeyProperties.DIGEST_SHA512)
+ .build();
+ KeyStore keyStore = KeyStoreUtil.saveKeysToKeystore(KEY_ALIAS_1, pubKey, privKey, keyProtection);
+ return (PrivateKey) keyStore.getKey(KEY_ALIAS_1, null);
+ }
/**
* Determines the Hash name from the ECDSA algorithm. There is a small inconsistency in the naming
@@ -149,15 +169,11 @@ public class EcdsaTest {
ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
- // Print the parameters.
- System.out.println("Parameters for curve:" + curve);
- EcUtil.printParameters(pub.getParams());
-
Signature signer;
Signature verifier;
try {
- signer = Signature.getInstance(algorithm);
- verifier = Signature.getInstance(algorithm);
+ signer = Signature.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
+ verifier = Signature.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
} catch (NoSuchAlgorithmException ex) {
// The algorithm is not supported.
return false;
@@ -165,7 +181,7 @@ public class EcdsaTest {
// Both algorithm and curve are supported.
// Hence, we expect that signing and verifying properly works.
byte[] messageBytes = message.getBytes("UTF-8");
- signer.initSign(priv);
+ signer.initSign(getKeystorePrivateKey(pub, priv));
signer.update(messageBytes);
byte[] signature = signer.sign();
verifier.initVerify(pub);
@@ -188,12 +204,7 @@ public class EcdsaTest {
/** Checks whether the one time key k in ECDSA is biased. */
public void testBias(String algorithm, String curve, ECParameterSpec ecParams) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
- try {
- keyGen.initialize(ecParams);
- } catch (InvalidAlgorithmParameterException ex) {
- System.out.println("This provider does not support curve:" + curve);
- return;
- }
+ keyGen.initialize(ecParams);
KeyPair keyPair = keyGen.generateKeyPair();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
// If we throw a fair coin tests times then the probability that
@@ -214,8 +225,8 @@ public class EcdsaTest {
BigInteger q = priv.getParams().getOrder();
BigInteger qHalf = q.shiftRight(1);
- Signature signer = Signature.getInstance(algorithm);
- signer.initSign(priv);
+ Signature signer = Signature.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
+ signer.initSign(getKeystorePrivateKey(keyPair.getPublic(), keyPair.getPrivate()));
BigInteger[] kList = new BigInteger[tests];
for (int i = 0; i < tests; i++) {
signer.update(messageBytes);
@@ -277,141 +288,17 @@ public class EcdsaTest {
}
}
- @SlowTest(
- providers = {
- ProviderType.BOUNCY_CASTLE,
- ProviderType.CONSCRYPT,
- ProviderType.OPENJDK,
- ProviderType.SPONGY_CASTLE
- }
- )
@Test
public void testBiasAll() throws Exception {
testBias("SHA256WithECDSA", "secp256r1", EcUtil.getNistP256Params());
testBias("SHA224WithECDSA", "secp224r1", EcUtil.getNistP224Params());
testBias("SHA384WithECDSA", "secp384r1", EcUtil.getNistP384Params());
testBias("SHA512WithECDSA", "secp521r1", EcUtil.getNistP521Params());
- testBias("SHA256WithECDSA", "brainpoolP256r1", EcUtil.getBrainpoolP256r1Params());
- }
-
- /**
- * Tests for a potential timing attack. This test checks if there is a correlation between the
- * timing of signature generation and the size of the one-time key k. This is for example the case
- * if a double and add method is used for the point multiplication. The test fails if such a
- * correlation can be shown with high confidence. Further analysis will be necessary to determine
- * how easy it is to exploit the bias in a timing attack.
- */
- // TODO(bleichen): Determine if there are exploitable providers.
- //
- // SunEC currently fails this test. Since ECDSA typically is used with EC groups whose order
- // is 224 bits or larger, it is unclear whether the same attacks that apply to DSA are practical.
- //
- // The ECDSA implementation in BouncyCastle leaks information about k through timing too.
- // The test has not been optimized to detect this bias. It would require about 5'000'000 samples,
- // which is too much for a simple unit test.
- //
- // BouncyCastle uses FixedPointCombMultiplier for ECDSA. This is a method using
- // precomputation. The implementation is not constant time, since the precomputation table
- // contains the point at infinity and adding this point is faster than ordinary point additions.
- // The timing leak only has a small correlation to the size of k and at the moment it is is very
- // unclear if the can be exploited. (Randomizing the precomputation table by adding the same
- // random point to each element in the table and precomputing the necessary offset to undo the
- // precomputation seems much easier than analyzing this.)
- public void testTiming(String algorithm, String curve, ECParameterSpec ecParams)
- throws Exception {
- ThreadMXBean bean = ManagementFactory.getThreadMXBean();
- if (!bean.isCurrentThreadCpuTimeSupported()) {
- System.out.println("getCurrentThreadCpuTime is not supported. Skipping");
- return;
- }
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
- try {
- keyGen.initialize(ecParams);
- } catch (InvalidAlgorithmParameterException ex) {
- System.out.println("This provider does not support curve:" + curve);
- return;
- }
- KeyPair keyPair = keyGen.generateKeyPair();
- ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
-
- String message = "Hello";
- String hashAlgorithm = getHashAlgorithm(algorithm);
- byte[] messageBytes = message.getBytes("UTF-8");
- byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
- BigInteger h = new BigInteger(1, digest);
- Signature signer = Signature.getInstance(algorithm);
- signer.initSign(priv);
- // The number of samples used for the test. This number is a bit low.
- // I.e. it just barely detects that SunEC leaks information about the size of k.
- int samples = 50000;
- long[] timing = new long[samples];
- BigInteger[] k = new BigInteger[samples];
- for (int i = 0; i < samples; i++) {
- long start = bean.getCurrentThreadCpuTime();
- signer.update(messageBytes);
- byte[] signature = signer.sign();
- timing[i] = bean.getCurrentThreadCpuTime() - start;
- k[i] = extractK(signature, h, priv);
- }
- long[] sorted = Arrays.copyOf(timing, timing.length);
- Arrays.sort(sorted);
- double n = priv.getParams().getOrder().doubleValue();
- double expectedAverage = n / 2;
- double maxSigma = 0;
- System.out.println("testTiming algorithm:" + algorithm);
- for (int idx = samples - 1; idx > 10; idx /= 2) {
- long cutoff = sorted[idx];
- int count = 0;
- BigInteger total = BigInteger.ZERO;
- for (int i = 0; i < samples; i++) {
- if (timing[i] <= cutoff) {
- total = total.add(k[i]);
- count += 1;
- }
- }
- double expectedStdDev = n / Math.sqrt(12 * count);
- double average = total.doubleValue() / count;
- // Number of standard deviations that the average is away from
- // the expected value:
- double sigmas = Math.abs(expectedAverage - average) / expectedStdDev;
- if (sigmas > maxSigma) {
- maxSigma = sigmas;
- }
- System.out.println(
- "count:"
- + count
- + " cutoff:"
- + cutoff
- + " relative average:"
- + (average / expectedAverage)
- + " sigmas:"
- + sigmas);
- }
- // Checks if the signatures with a small timing have a biased k.
- // We use 7 standard deviations, so that the probability of a false positive is smaller
- // than 10^{-10}.
- if (maxSigma >= 7) {
- fail("Signatures with short timing have a biased k");
- }
}
- @SlowTest(
- providers = {
- ProviderType.BOUNCY_CASTLE,
- ProviderType.CONSCRYPT,
- ProviderType.OPENJDK,
- ProviderType.SPONGY_CASTLE
- }
- )
@Test
- public void testTimingAll() throws Exception {
- testTiming("SHA256WithECDSA", "secp256r1", EcUtil.getNistP256Params());
- // TODO(bleichen): crypto libraries sometimes use optimized code for curves that are frequently
- // used. Hence it would make sense to test distinct curves. But at the moment testing many
- // curves is not practical since one test alone is already quite time consuming.
- // testTiming("SHA224WithECDSA", "secp224r1", EcUtil.getNistP224Params());
- // testTiming("SHA384WithECDSA", "secp384r1", EcUtil.getNistP384Params());
- // testTiming("SHA512WithECDSA", "secp521r1", EcUtil.getNistP521Params());
- // testTiming("SHA256WithECDSA", "brainpoolP256r1", EcUtil.getBrainpoolP256r1Params());
+ @Ignore // Brainpool curve are not supported in AndroidKeyStore
+ public void testBiasBrainpoolCurve() throws Exception {
+ testBias("SHA256WithECDSA", "brainpoolP256r1", EcUtil.getBrainpoolP256r1Params());
}
}
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonAeadTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/JsonAeadTest.java
index c34f3f7..91a0d2c 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonAeadTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/JsonAeadTest.java
@@ -14,12 +14,14 @@
package com.google.security.wycheproof;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
+import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
@@ -28,15 +30,23 @@ import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.junit.Test;
import org.junit.Ignore;
+import org.junit.After;
import android.security.keystore.KeyProtection;
import android.security.keystore.KeyProperties;
-import java.security.KeyStore;
+import android.keystore.cts.util.KeyStoreUtil;
/** This test uses test vectors in JSON format to test AEAD schemes. */
public class JsonAeadTest {
private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_PROVIDER_NAME;
- private static final String EXPECTED_CRYPTO_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+ private static final String EXPECTED_CRYPTO_PROVIDER_NAME =
+ TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+ private static final String KEY_ALIAS_1 = "Key1";
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
/** Joins two bytearrays. */
protected static byte[] join(byte[] head, byte[] tail) {
@@ -84,19 +94,14 @@ public class JsonAeadTest {
Cipher cipher = Cipher.getInstance(algorithm, EXPECTED_CRYPTO_PROVIDER_NAME);
if (algorithm.equalsIgnoreCase("AES/GCM/NoPadding")) {
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
-
- KeyStore keyStore = KeyStore.getInstance(EXPECTED_PROVIDER_NAME);
- keyStore.load(null);
- keyStore.setEntry(
- "key1",
- new KeyStore.SecretKeyEntry(keySpec),
+ KeyStore keyStore = KeyStoreUtil.saveSecretKeyToKeystore(KEY_ALIAS_1, keySpec,
new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setRandomizedEncryptionRequired(false)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
// Key imported, obtain a reference to it.
- SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null);
+ SecretKey keyStoreKey = (SecretKey) keyStore.getKey(KEY_ALIAS_1, null);
AlgorithmParameters params = AlgorithmParameters.getInstance("GCM");
params.init(new GCMParameterSpec(tagSize, iv));
@@ -162,14 +167,17 @@ public class JsonAeadTest {
final String expectedVersion = "0.6";
// Checking preconditions.
- try {
- Cipher.getInstance(algorithm, EXPECTED_CRYPTO_PROVIDER_NAME);
- } catch (NoSuchAlgorithmException ex) {
- throw ex;
- }
+ Cipher.getInstance(algorithm, EXPECTED_CRYPTO_PROVIDER_NAME);
JsonObject test = JsonUtil.getTestVectors(this.getClass(), filename);
String generatorVersion = test.get("generatorVersion").getAsString();
+ assertFalse(
+ algorithm
+ + ": expecting test vectors with version "
+ + expectedVersion
+ + " found vectors with version "
+ + generatorVersion,
+ generatorVersion.equals(expectedVersion));
int numTests = test.get("numberOfTests").getAsInt();
int cntTests = 0;
int errors = 0;
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonCipherTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/JsonCipherTest.java
index a072989..e0c5b27 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonCipherTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/JsonCipherTest.java
@@ -14,6 +14,7 @@
package com.google.security.wycheproof;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
import com.google.gson.JsonElement;
@@ -23,11 +24,15 @@ import java.security.NoSuchAlgorithmException;
import java.util.Set;
import java.util.TreeSet;
import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import java.security.KeyStore;
+import android.keystore.cts.util.KeyStoreUtil;
/**
* This test uses test vectors in JSON format to test symmetric ciphers.
@@ -36,8 +41,14 @@ import org.junit.runners.JUnit4;
* are randomized using an initialization vector as long as the JSON test vectors are represented
* with the type "IndCpaTest".
*/
-@RunWith(JUnit4.class)
public class JsonCipherTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+ private static final String KEY_ALIAS_1 = "Key1";
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
/** Convenience method to get a byte array from a JsonObject. */
protected static byte[] getBytes(JsonObject object, String name) throws Exception {
@@ -73,7 +84,16 @@ public class JsonCipherTest {
fail("Unsupported algorithm:" + algorithm);
}
IvParameterSpec ivSpec = new IvParameterSpec(iv);
- cipher.init(opmode, keySpec, ivSpec);
+ KeyStore keyStore = KeyStoreUtil.saveSecretKeyToKeystore(KEY_ALIAS_1, keySpec,
+ new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ .setRandomizedEncryptionRequired(false)
+ .build());
+ // Key imported, obtain a reference to it.
+ SecretKey keyStoreKey = (SecretKey) keyStore.getKey(KEY_ALIAS_1, null);
+
+ cipher.init(opmode, keyStoreKey, ivSpec);
}
@@ -111,27 +131,20 @@ public class JsonCipherTest {
// the minor number if only the test vectors (but not the format) changes.
// Versions meant for distribution have no status.
final String expectedVersion = "0.4";
- JsonObject test = JsonUtil.getTestVectors(filename);
+ JsonObject test = JsonUtil.getTestVectors(this.getClass(), filename);
Set<String> exceptions = new TreeSet<String>();
String generatorVersion = test.get("generatorVersion").getAsString();
- if (!generatorVersion.equals(expectedVersion)) {
- System.out.println(
+ assertFalse(
algorithm
+ ": expecting test vectors with version "
+ expectedVersion
+ " found vectors with version "
- + generatorVersion);
- }
+ + generatorVersion,
+ generatorVersion.equals(expectedVersion));
int numTests = test.get("numberOfTests").getAsInt();
int cntTests = 0;
int errors = 0;
- Cipher cipher;
- try {
- cipher = Cipher.getInstance(algorithm);
- } catch (NoSuchAlgorithmException ex) {
- System.out.println("Algorithm is not supported. Skipping test for " + algorithm);
- return;
- }
+ Cipher cipher = Cipher.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
for (JsonElement g : test.getAsJsonArray("testGroups")) {
JsonObject group = g.getAsJsonObject();
for (JsonElement t : group.getAsJsonArray("tests")) {
@@ -155,7 +168,6 @@ public class JsonCipherTest {
} catch (GeneralSecurityException ex) {
// Some libraries restrict key size, iv size and tag size.
// Because of the initialization of the cipher might fail.
- System.out.println(ex.toString());
continue;
}
try {
@@ -164,22 +176,15 @@ public class JsonCipherTest {
if (result.equals("invalid")) {
if (eq) {
// Some test vectors use invalid parameters that should be rejected.
- System.out.println("Encrypted " + tc);
errors++;
}
} else {
if (!eq) {
- System.out.println(
- "Incorrect ciphertext for "
- + tc
- + " ciphertext:"
- + TestUtil.bytesToHex(encrypted));
errors++;
}
}
} catch (GeneralSecurityException ex) {
if (result.equals("valid")) {
- System.out.println("Failed to encrypt " + tc);
errors++;
}
}
@@ -192,7 +197,6 @@ public class JsonCipherTest {
try {
initCipher(cipher, algorithm, Cipher.DECRYPT_MODE, key, iv);
} catch (GeneralSecurityException ex) {
- System.out.println("Parameters accepted for encryption but not decryption " + tc);
errors++;
continue;
}
@@ -200,18 +204,15 @@ public class JsonCipherTest {
byte[] decrypted = cipher.doFinal(ciphertext);
boolean eq = arrayEquals(decrypted, msg);
if (result.equals("invalid")) {
- System.out.println("Decrypted invalid ciphertext " + tc + " eq:" + eq);
errors++;
} else {
if (!eq) {
- System.out.println(
- "Incorrect decryption " + tc + " decrypted:" + TestUtil.bytesToHex(decrypted));
+ errors++;
}
}
} catch (GeneralSecurityException ex) {
- exceptions.add(ex.getMessage());
+ exceptions.add(ex.getMessage() == null ? "" : ex.getMessage());
if (result.equals("valid")) {
- System.out.println("Failed to decrypt " + tc);
errors++;
}
}
@@ -228,15 +229,18 @@ public class JsonCipherTest {
// AES/CBC/PKCS5Padding with the tested provider are vulnerable to attacks. Rather it means
// that the provider might simplify attacks if the protocol is using AES/CBC/PKCS5Padding
// incorrectly.
- System.out.println("Number of distinct exceptions:" + exceptions.size());
+ StringBuilder sb = new StringBuilder();
+ sb.append("Exceptions: ");
for (String ex : exceptions) {
- System.out.println(ex);
+ sb.append(ex.toString() + " ");
}
- assertEquals(1, exceptions.size());
+ assertEquals(sb.toString(), 1, exceptions.size());
}
@Test
public void testAesCbcPkcs5() throws Exception {
- testCipher("aes_cbc_pkcs5_test.json", "AES/CBC/PKCS5Padding");
+ // AndroidKeyStore only suuport AES/CBC/PKCS7Padding algorithm,
+ // so it is used instead of PKCS5Padding
+ testCipher("aes_cbc_pkcs5_test.json", "AES/CBC/PKCS7Padding");
}
}
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java
index eeb48ec..c1dddc5 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java
@@ -12,9 +12,12 @@
package com.google.security.wycheproof;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
+import java.security.Key;
+import java.security.KeyStore;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
@@ -23,13 +26,23 @@ import java.util.Locale;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.Ignore;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import java.io.IOException;
+import android.keystore.cts.util.KeyStoreUtil;
/** This test uses test vectors in JSON format to test MAC primitives. */
-@RunWith(JUnit4.class)
public class JsonMacTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+ private static final String KEY_ALIAS_1 = "Key1";
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
/** Convenience method to get a byte array from an JsonObject */
protected static byte[] getBytes(JsonObject obj, String name) throws Exception {
@@ -60,8 +73,8 @@ public class JsonMacTest {
* bits, since the JCE interface does not seem to support such a specification.
*/
protected static byte[] computeMac(String algorithm, byte[] key, byte[] msg, int tagSize)
- throws GeneralSecurityException {
- Mac mac = Mac.getInstance(algorithm);
+ throws Exception {
+ Mac mac = Mac.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
algorithm = algorithm.toUpperCase(Locale.ENGLISH);
if (algorithm.startsWith("HMAC")) {
SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
@@ -77,7 +90,11 @@ public class JsonMacTest {
// But this class is often not supported. Hence the computation here, just computes a
// full length tag and truncates it. The drawback of having to truncate tags is that
// the caller has to compare truncated tags during verification.
- mac.init(keySpec);
+ KeyStore keyStore = KeyStoreUtil.saveSecretKeyToKeystore(KEY_ALIAS_1, keySpec,
+ new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN).build());
+ // Key imported, obtain a reference to it.
+ Key keyStoreKey = keyStore.getKey(KEY_ALIAS_1, null);
+ mac.init(keyStoreKey);
mac.update(msg);
byte[] tag = mac.doFinal();
return Arrays.copyOf(tag, tagSize / 8);
@@ -94,14 +111,9 @@ public class JsonMacTest {
*/
public void testMac(String filename) throws Exception {
// Checking preconditions.
- JsonObject test = JsonUtil.getTestVectors(filename);
+ JsonObject test = JsonUtil.getTestVectors(this.getClass(), filename);
String algorithm = test.get("algorithm").getAsString();
- try {
- Mac.getInstance(algorithm);
- } catch (NoSuchAlgorithmException ex) {
- System.out.println("Algorithm is not supported. Skipping test for " + algorithm);
- return;
- }
+ Mac.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
int numTests = test.get("numberOfTests").getAsInt();
int cntTests = 0;
@@ -125,16 +137,7 @@ public class JsonMacTest {
String result = testcase.get("result").getAsString();
byte[] computedTag = null;
- try {
- computedTag = computeMac(algorithm, key, msg, tagSize);
- } catch (GeneralSecurityException ex) {
- // Some libraries restrict key size or tag size. Hence valid MACs might be
- // rejected.
- continue;
- } catch (IllegalArgumentException ex) {
- // Thrown by javax.crypto.spec.SecretKeySpec (e.g. when the key is empty).
- continue;
- }
+ computedTag = computeMac(algorithm, key, msg, tagSize);
boolean eq = arrayEquals(expectedTag, computedTag);
if (result.equals("invalid")) {
@@ -142,26 +145,17 @@ public class JsonMacTest {
// Some test vectors use invalid parameters that should be rejected.
// E.g. an implementation must not allow AES-GMAC with an IV of length 0,
// since this leaks the authentication key.
- System.out.println("Computed mac for test case " + tc);
errors++;
}
} else {
if (eq) {
passedTests++;
} else {
- System.out.println(
- "Incorrect tag for "
- + tc
- + " expected:"
- + TestUtil.bytesToHex(expectedTag)
- + " computed:"
- + TestUtil.bytesToHex(computedTag));
errors++;
}
}
}
}
- System.out.println("passed Tests for " + algorithm + ":" + passedTests);
assertEquals(0, errors);
assertEquals(numTests, cntTests);
}
@@ -180,7 +174,7 @@ public class JsonMacTest {
*/
protected static Mac getInitializedMacWithIv(String algorithm, byte[] key, byte[] iv, int tagSize)
throws GeneralSecurityException {
- Mac mac = Mac.getInstance(algorithm);
+ Mac mac = Mac.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
algorithm = algorithm.toUpperCase(Locale.ENGLISH);
if (algorithm.equals("AES-GMAC")) {
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
@@ -207,14 +201,9 @@ public class JsonMacTest {
*/
public void testMacWithIv(String filename, String algorithm) throws Exception {
// Checking preconditions.
- try {
- Mac.getInstance(algorithm);
- } catch (NoSuchAlgorithmException ex) {
- System.out.println("Algorithm is not supported. Skipping test for " + algorithm);
- return;
- }
+ Mac.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
- JsonObject test = JsonUtil.getTestVectors(filename);
+ JsonObject test = JsonUtil.getTestVectors(this.getClass(), filename);
int numTests = test.get("numberOfTests").getAsInt();
int cntTests = 0;
int passedTests = 0;
@@ -237,17 +226,7 @@ public class JsonMacTest {
// "acceptable" are test vectors with weak parameters or legacy formats.
String result = testcase.get("result").getAsString();
- Mac mac;
- try {
- mac = getInitializedMacWithIv(algorithm, key, iv, tagSize);
- } catch (GeneralSecurityException ex) {
- // Some libraries restrict key size, iv size and tag size.
- // Because of the initialization of the Mac might fail.
- continue;
- } catch (IllegalArgumentException ex) {
- // Thrown by javax.crypto.spec.SecretKeySpec (e.g. when the key is empty).
- continue;
- }
+ Mac mac = getInitializedMacWithIv(algorithm, key, iv, tagSize);
byte[] computedTag = mac.doFinal(msg);
boolean eq = arrayEquals(expectedTag, computedTag);
@@ -256,26 +235,17 @@ public class JsonMacTest {
// Some test vectors use invalid parameters that should be rejected.
// E.g. an implementation must not allow AES-GMAC with an IV of length 0,
// since this leaks the authentication key.
- System.out.println("Computed mac for test case " + tc);
errors++;
}
} else {
if (eq) {
passedTests++;
} else {
- System.out.println(
- "Incorrect tag for "
- + tc
- + " expected:"
- + TestUtil.bytesToHex(expectedTag)
- + " computed:"
- + TestUtil.bytesToHex(computedTag));
errors++;
}
}
}
}
- System.out.println("passed Tests for " + algorithm + ":" + passedTests);
assertEquals(0, errors);
assertEquals(numTests, cntTests);
}
@@ -306,26 +276,31 @@ public class JsonMacTest {
}
@Test
+ @Ignore // HMAC Sha3 algorithms are not supported in AndroidKeyStore
public void testHmacSha3_224() throws Exception {
testMac("hmac_sha3_224_test.json");
}
@Test
+ @Ignore // HMAC Sha3 algorithms are not supported in AndroidKeyStore
public void testHmacSha3_256() throws Exception {
testMac("hmac_sha3_256_test.json");
}
@Test
+ @Ignore // HMAC Sha3 algorithms are not supported in AndroidKeyStore
public void testHmacSha3_384() throws Exception {
testMac("hmac_sha3_384_test.json");
}
@Test
+ @Ignore // HMAC Sha3 algorithms are not supported in AndroidKeyStore
public void testHmacSha3_512() throws Exception {
testMac("hmac_sha3_512_test.json");
}
@Test
+ @Ignore // Ignored due to AES-GMAC algorithm not supported in AndroidKeyStore
public void testAesGmac() throws Exception {
testMacWithIv("gmac_test.json", "AES-GMAC");
}
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonSignatureTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/JsonSignatureTest.java
index 21bf0d5..58da530 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonSignatureTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/JsonSignatureTest.java
@@ -15,16 +15,16 @@ package com.google.security.wycheproof;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import com.google.security.wycheproof.WycheproofRunner.ExcludedTest;
-import com.google.security.wycheproof.WycheproofRunner.NoPresubmitTest;
-import com.google.security.wycheproof.WycheproofRunner.ProviderType;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
+import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
@@ -33,17 +33,39 @@ import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashSet;
import java.util.Set;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.Ignore;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import android.keystore.cts.util.KeyStoreUtil;
/**
* This test uses test vectors in JSON format to check digital signature schemes. There are still a
* lot of open questions, e.g. the format for the test vectors is not yet finalized. Therefore, we
* are not integrating the tests here into other tests
*/
-@RunWith(JUnit4.class)
public class JsonSignatureTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+ private static final String KEY_ALIAS_1 = "TestKey";
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
+
+ private static PrivateKey getKeystorePrivateKey(PublicKey pubKey, PrivateKey privKey)
+ throws Exception {
+ KeyProtection keyProtection = new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN)
+ .setDigests(KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA224,
+ KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384,
+ KeyProperties.DIGEST_SHA512)
+ .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+ .build();
+ KeyStore keyStore =
+ KeyStoreUtil.saveKeysToKeystore(KEY_ALIAS_1, pubKey, privKey, keyProtection);
+ return (PrivateKey) keyStore.getKey(KEY_ALIAS_1, null);
+ }
/**
* Defines the format of the signatures. RAW is used when the signature scheme already
@@ -105,14 +127,14 @@ public class JsonSignatureTest {
*/
protected static Signature getSignatureInstance(
JsonObject group, String signatureAlgorithm, Format signatureFormat)
- throws NoSuchAlgorithmException {
+ throws NoSuchAlgorithmException, NoSuchProviderException {
String md = "";
if (group.has("sha")) {
md = convertMdName(getString(group, "sha"));
}
if (signatureAlgorithm.equals("ECDSA") || signatureAlgorithm.equals("DSA")) {
if (signatureFormat == Format.ASN) {
- return Signature.getInstance(md + "WITH" + signatureAlgorithm);
+ return Signature.getInstance(md + "WITH" + signatureAlgorithm, EXPECTED_PROVIDER_NAME);
} else if (signatureFormat == Format.P1363) {
// The algorithm names for signature schemes with P1363 format have distinct names
// in distinct providers. This is mainly the case since the P1363 format has only
@@ -120,32 +142,28 @@ public class JsonSignatureTest {
// than that. Hence the code below just tries known algorithm names.
try {
String jdkName = md + "WITH" + signatureAlgorithm + "inP1363Format";
- return Signature.getInstance(jdkName);
+ return Signature.getInstance(jdkName, EXPECTED_PROVIDER_NAME);
} catch (NoSuchAlgorithmException ex) {
// jdkName is not known.
}
- try {
- String bcName = md + "WITHPLAIN-" + signatureAlgorithm;
- return Signature.getInstance(bcName);
- } catch (NoSuchAlgorithmException ex) {
- // bcName is not known.
- }
+ String bcName = md + "WITHPLAIN-" + signatureAlgorithm;
+ return Signature.getInstance(bcName, EXPECTED_PROVIDER_NAME);
}
} else if (signatureAlgorithm.equals("RSA")) {
if (signatureFormat == Format.RAW) {
- return Signature.getInstance(md + "WITH" + signatureAlgorithm);
+ return Signature.getInstance(md + "WITH" + signatureAlgorithm, EXPECTED_PROVIDER_NAME);
}
} else if (signatureAlgorithm.equals("ED25519") || signatureAlgorithm.equals("ED448")) {
if (signatureFormat == Format.RAW) {
// http://openjdk.java.net/jeps/339
try {
- return Signature.getInstance(signatureAlgorithm);
+ return Signature.getInstance(signatureAlgorithm, EXPECTED_PROVIDER_NAME);
} catch (NoSuchAlgorithmException ex) {
// signatureAlgorithm is not known.
}
// An alternative name (e.g. used by BouncyCastle) is "EDDSA".
try {
- return Signature.getInstance("EDDSA");
+ return Signature.getInstance("EDDSA", EXPECTED_PROVIDER_NAME);
} catch (NoSuchAlgorithmException ex) {
// "EDDSA" is not known either.
}
@@ -249,8 +267,12 @@ public class JsonSignatureTest {
if (algorithm.equals("RSA")) {
KeyFactory kf = KeyFactory.getInstance(algorithm);
byte[] encoded = TestUtil.hexToBytes(getString(object, "privateKeyPkcs8"));
+ byte[] pubEncoded = TestUtil.hexToBytes(getString(object, "keyDer"));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
- return kf.generatePrivate(keySpec);
+ PrivateKey intermediateKey = kf.generatePrivate(keySpec);
+ X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(pubEncoded);
+ PublicKey pubKey = kf.generatePublic(x509keySpec);
+ return getKeystorePrivateKey(pubKey, intermediateKey);
} else {
throw new NoSuchAlgorithmException("Algorithm " + algorithm + " is not supported");
}
@@ -298,19 +320,18 @@ public class JsonSignatureTest {
public void testVerification(
String filename, String signatureAlgorithm, Format signatureFormat, boolean allowSkippingKeys)
throws Exception {
- JsonObject test = JsonUtil.getTestVectors(filename);
+ JsonObject test = JsonUtil.getTestVectors(this.getClass(), filename);
// Checks whether the test vectors in the file use the expected algorithm and the expected
// format for the signatures.
String schema = expectedSchema(signatureAlgorithm, signatureFormat, true);
String actualSchema = getString(test, "schema");
- if (!schema.isEmpty() && !schema.equals(actualSchema)) {
- System.out.println(
+ assertFalse(
signatureAlgorithm
+ ": expecting test vectors with schema "
+ schema
+ " found vectors with schema "
- + actualSchema);
- }
+ + actualSchema,
+ !schema.isEmpty() && !schema.equals(actualSchema));
int numTests = test.get("numberOfTests").getAsInt();
int cntTests = 0;
int verifiedSignatures = 0;
@@ -376,49 +397,14 @@ public class JsonSignatureTest {
} catch (Exception ex) {
// Other exceptions (i.e. unchecked exceptions) are considered as error
// since a third party should never be able to cause such exceptions.
- System.out.println(
- signatureAlgorithm
- + " signature throws "
- + ex.toString()
- + " "
- + filename
- + " tcId:"
- + tcid
- + " sig:"
- + sig);
verified = false;
failure = ex;
errors++;
}
if (!verified && result.equals("valid")) {
- String reason = "";
- if (failure != null) {
- reason = " reason:" + failure;
- }
- System.out.println(
- "Valid "
- + signatureAlgorithm
- + " signature not verified."
- + " "
- + filename
- + " tcId:"
- + tcid
- + " sig:"
- + sig
- + reason);
errors++;
} else if (verified) {
if (result.equals("invalid")) {
- System.out.println(
- "Invalid"
- + signatureAlgorithm
- + " signature verified."
- + " "
- + filename
- + " tcId:"
- + tcid
- + " sig:"
- + sig);
errors++;
} else {
verifiedSignatures++;
@@ -426,24 +412,6 @@ public class JsonSignatureTest {
}
}
}
- // Prints some information if tests were skipped. This avoids giving
- // the impression that algorithms are supported.
- if (skippedKeys > 0 || skippedAlgorithms > 0 || verifiedSignatures == 0) {
- System.out.println(
- "File:"
- + filename
- + " number of skipped keys:"
- + skippedKeys
- + " number of skipped algorithms:"
- + skippedAlgorithms
- + " number of supported keys:"
- + supportedKeys
- + " verified signatures:"
- + verifiedSignatures);
- for (String s : skippedGroups) {
- System.out.println("Skipped groups where " + s);
- }
- }
assertEquals(0, errors);
if (skippedKeys == 0 && skippedAlgorithms == 0) {
assertEquals(numTests, cntTests);
@@ -466,19 +434,7 @@ public class JsonSignatureTest {
public void testSigning(
String filename, String signatureAlgorithm, Format signatureFormat,
boolean allowSkippingKeys) throws Exception {
- JsonObject test = JsonUtil.getTestVectors(filename);
- // Checks whether the test vectors in the file use the expected algorithm and the expected
- // format for the signatures.
- String schema = expectedSchema(signatureAlgorithm, signatureFormat, false);
- String actualSchema = getString(test, "schema");
- if (!schema.isEmpty() && !schema.equals(actualSchema)) {
- System.out.println(
- signatureAlgorithm
- + ": expecting test vectors with schema "
- + schema
- + " found vectors with schema "
- + actualSchema);
- }
+ JsonObject test = JsonUtil.getTestVectors(this.getClass(), filename);
int cntTests = 0;
int errors = 0;
int skippedKeys = 0;
@@ -510,29 +466,12 @@ public class JsonSignatureTest {
signer.update(message);
String sig = TestUtil.bytesToHex(signer.sign());
if (!sig.equals(expectedSig)) {
- System.out.println(
- "Incorrect signature generated "
- + filename
- + " tcId:"
- + tcid
- + " expected:"
- + expectedSig
- + " sig:"
- + sig);
errors++;
} else {
cntTests++;
}
} catch (InvalidKeyException | SignatureException ex) {
if (result.equals("valid")) {
- System.out.println(
- "Failed to sign "
- + filename
- + " tcId:"
- + tcid
- + " with exception:"
- + ex);
-
errors++;
}
}
@@ -540,9 +479,6 @@ public class JsonSignatureTest {
}
assertEquals(0, errors);
if (skippedKeys > 0) {
- System.out.println("File:" + filename);
- System.out.println("Number of signatures verified:" + cntTests);
- System.out.println("Number of skipped keys:" + skippedKeys);
assertTrue(allowSkippingKeys);
}
}
@@ -594,171 +530,195 @@ public class JsonSignatureTest {
// Testing curves that may not be supported by a provider.
@Test
+ @Ignore // Secp256k1 curve not supported in AndroidKeystore
public void testSecp256k1Sha256() throws Exception {
testVerification("ecdsa_secp256k1_sha256_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // Secp256k1 curve not supported in AndroidKeystore
public void testSecp256k1Sha512() throws Exception {
testVerification("ecdsa_secp256k1_sha512_test.json", "ECDSA", Format.ASN, true);
}
- @NoPresubmitTest(
- providers = {ProviderType.OPENJDK},
- bugs = {"b/117643131"}
- )
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP224r1Sha224() throws Exception {
testVerification("ecdsa_brainpoolP224r1_sha224_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP256r1Sha256() throws Exception {
testVerification("ecdsa_brainpoolP256r1_sha256_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP320r1Sha384() throws Exception {
testVerification("ecdsa_brainpoolP320r1_sha384_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP384r1Sha384() throws Exception {
testVerification("ecdsa_brainpoolP384r1_sha384_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP512r1Sha512() throws Exception {
testVerification("ecdsa_brainpoolP512r1_sha512_test.json", "ECDSA", Format.ASN, true);
}
// SHA-3 signatures
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testSecp224r1Sha3_224 () throws Exception {
testVerification("ecdsa_secp224r1_sha3_224_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testSecp224r1Sha3_256 () throws Exception {
testVerification("ecdsa_secp224r1_sha3_256_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testSecp224r1Sha3_512 () throws Exception {
testVerification("ecdsa_secp224r1_sha3_512_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testSecp256r1Sha3_256 () throws Exception {
testVerification("ecdsa_secp256r1_sha3_256_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testSecp256r1Sha3_512 () throws Exception {
testVerification("ecdsa_secp256r1_sha3_512_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // Secp256k1 curve and SHA3 algorithms not supported in AndroidKeystore
public void testSecp256k1Sha3_256 () throws Exception {
testVerification("ecdsa_secp256k1_sha3_256_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // Secp256k1 curve and SHA3 algorithms not supported in AndroidKeystore
public void testSecp256k1Sha3_512 () throws Exception {
testVerification("ecdsa_secp256k1_sha3_512_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testSecp384r1Sha3_384 () throws Exception {
testVerification("ecdsa_secp384r1_sha3_384_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testSecp384r1Sha3_512 () throws Exception {
testVerification("ecdsa_secp384r1_sha3_512_test.json", "ECDSA", Format.ASN, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testSecp521r1Sha3_512 () throws Exception {
testVerification("ecdsa_secp521r1_sha3_512_test.json", "ECDSA", Format.ASN, true);
}
// jdk11 adds P1363 encoded signatures.
@Test
+ @Ignore // P1363 encoding not supported in AndroidKeyStore
public void testSecp224r1Sha224inP1363Format() throws Exception {
testVerification("ecdsa_secp224r1_sha224_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // P1363 encoding not supported in AndroidKeyStore
public void testSecp224r1Sha256inP1363Format() throws Exception {
testVerification("ecdsa_secp224r1_sha256_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // P1363 encoding not supported in AndroidKeyStore
public void testSecp224r1Sha512inP1363Format() throws Exception {
testVerification("ecdsa_secp224r1_sha512_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // P1363 encoding not supported in AndroidKeyStore
public void testSecp256r1Sha256inP1363Format() throws Exception {
testVerification("ecdsa_secp256r1_sha256_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // P1363 encoding not supported in AndroidKeyStore
public void testSecp256r1Sha512inP1363Format() throws Exception {
testVerification("ecdsa_secp256r1_sha512_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // P1363 encoding not supported in AndroidKeyStore
public void testSecp384r1Sha384inP1363Format() throws Exception {
testVerification("ecdsa_secp384r1_sha384_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // P1363 encoding not supported in AndroidKeyStore
public void testSecp384r1Sha512inP1363Format() throws Exception {
testVerification("ecdsa_secp384r1_sha512_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // P1363 encoding not supported in AndroidKeyStore
public void testSecp521r1Sha512inP1363Format() throws Exception {
testVerification("ecdsa_secp521r1_sha512_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // Secp256k1 curve not supported in AndroidKeystore
public void testSecp256k1Sha256inP1363Format() throws Exception {
testVerification("ecdsa_secp256k1_sha256_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // Secp256k1 curve not supported in AndroidKeystore
public void testSecp256k1Sha512inP1363Format() throws Exception {
testVerification("ecdsa_secp256k1_sha512_p1363_test.json", "ECDSA", Format.P1363, true);
}
- @NoPresubmitTest(
- providers = {ProviderType.OPENJDK},
- bugs = {"b/117643131"}
- )
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP224r1Sha224inP1363Format() throws Exception {
testVerification("ecdsa_brainpoolP224r1_sha224_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP256r1Sha256inP1363Format() throws Exception {
testVerification("ecdsa_brainpoolP256r1_sha256_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP320r1Sha384inP1363Format() throws Exception {
testVerification("ecdsa_brainpoolP320r1_sha384_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP384r1Sha384inP1363Format() throws Exception {
testVerification("ecdsa_brainpoolP384r1_sha384_p1363_test.json", "ECDSA", Format.P1363, true);
}
@Test
+ @Ignore // Brainpool curves are not supported in AndroidKeyStore
public void testBrainpoolP512r1Sha512inP1363Format() throws Exception {
testVerification("ecdsa_brainpoolP512r1_sha512_p1363_test.json", "ECDSA", Format.P1363, true);
}
@@ -822,21 +782,25 @@ public class JsonSignatureTest {
// RSA signatures with truncated hashes. Tests may be skipped if the provider
// does not support the hash.
@Test
+ @Ignore // SHA-512/224 algorithm not supported in AndrdoiKeyStore
public void testRsaSignatures2048sha512_224() throws Exception {
testVerification("rsa_signature_2048_sha512_224_test.json", "RSA", Format.RAW, true);
}
@Test
+ @Ignore // SHA-512/256 algorithm not supported in AndrdoiKeyStore
public void testRsaSignatures2048sha512_256() throws Exception {
testVerification("rsa_signature_2048_sha512_256_test.json", "RSA", Format.RAW, true);
}
@Test
+ @Ignore // SHA-512/256 algorithm not supported in AndrdoiKeyStore
public void testRsaSignatures3072sha512_256() throws Exception {
testVerification("rsa_signature_3072_sha512_256_test.json", "RSA", Format.RAW, true);
}
@Test
+ @Ignore // SHA-512/256 algorithm not supported in AndrdoiKeyStore
public void testRsaSignatures4096sha512_256() throws Exception {
testVerification("rsa_signature_4096_sha512_256_test.json", "RSA", Format.RAW, true);
}
@@ -844,48 +808,50 @@ public class JsonSignatureTest {
// RSA signatures with SHA-3. Not every provider supports SHA-3. Hence the tests
// may be skipped.
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testRsaSignature2048sha3_224() throws Exception {
testVerification("rsa_signature_2048_sha3_224_test.json", "RSA", Format.RAW, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testRsaSignatures2048sha3_256() throws Exception {
testVerification("rsa_signature_2048_sha3_256_test.json", "RSA", Format.RAW, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testRsaSignatures2048sha3_512() throws Exception {
testVerification("rsa_signature_2048_sha3_512_test.json", "RSA", Format.RAW, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testRsaSignatures3072sha3_256() throws Exception {
testVerification("rsa_signature_3072_sha3_256_test.json", "RSA", Format.RAW, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testRsaSignatures3072sha3_384() throws Exception {
testVerification("rsa_signature_3072_sha3_384_test.json", "RSA", Format.RAW, true);
}
@Test
+ @Ignore // SHA3 algorithms are not supported in AndroidKeyStore
public void testRsaSignatures3072sha3_512() throws Exception {
testVerification("rsa_signature_3072_sha3_512_test.json", "RSA", Format.RAW, true);
}
// EdDSA
- @NoPresubmitTest(
- providers = {ProviderType.BOUNCY_CASTLE},
- bugs = {"https://github.com/bcgit/bc-java/issues/508"})
@Test
+ @Ignore // Ed25519 algorithm not supported in AndroidKeyStore
public void testEd25519Verify() throws Exception {
testVerification("eddsa_test.json", "ED25519", Format.RAW, true);
}
- @NoPresubmitTest(
- providers = {ProviderType.BOUNCY_CASTLE},
- bugs = {"https://github.com/bcgit/bc-java/issues/508"})
@Test
+ @Ignore // Ed448 algorithm not supported in AndroidKeyStore
public void testEd448Verify() throws Exception {
testVerification("ed448_test.json", "ED448", Format.RAW, true);
}
@@ -893,10 +859,8 @@ public class JsonSignatureTest {
// DSA
// Two signature encodings for DSA are tested below: ASN encoded signatures
// and P1363 encoded signatures.
- @ExcludedTest(
- providers = {ProviderType.CONSCRYPT},
- comment = "Conscrypt does not support DSA.")
@Test
+ @Ignore // DSA algorithm not supported in AndroidKeyStore
public void testDsa2048Sha224() throws Exception {
testVerification("dsa_2048_224_sha224_test.json", "DSA", Format.ASN, true);
}
@@ -904,63 +868,48 @@ public class JsonSignatureTest {
// NIST allows 2048-bit DSA keys with either a 224-bit q or a 256-bit q.
// In both cases the security level is 112-bit.
// Jdk generates DSA keys with a 224-bit q (unless specified).
- @ExcludedTest(
- providers = {ProviderType.CONSCRYPT},
- comment = "Conscrypt does not support DSA.")
@Test
+ @Ignore // DSA algorithm not supported in AndroidKeyStore
public void testDsa2048JdkSha256() throws Exception {
testVerification("dsa_2048_224_sha256_test.json", "DSA", Format.ASN, true);
}
// OpenSSL generates DSA keys with a 256-bit q (unless specified).
- @ExcludedTest(
- providers = {ProviderType.CONSCRYPT},
- comment = "Conscrypt does not support DSA.")
@Test
+ @Ignore // DSA algorithm not supported in AndroidKeyStore
public void testDsa2048Sha256() throws Exception {
testVerification("dsa_2048_256_sha256_test.json", "DSA", Format.ASN, true);
}
- @ExcludedTest(
- providers = {ProviderType.CONSCRYPT},
- comment = "Conscrypt does not support DSA.")
@Test
+ @Ignore // DSA algorithm not supported in AndroidKeyStore
public void testDsa3072Sha256() throws Exception {
testVerification("dsa_3072_256_sha256_test.json", "DSA", Format.ASN, true);
}
// DSA tests using P1363 formated signatures.
- @ExcludedTest(
- providers = {ProviderType.CONSCRYPT},
- comment = "Conscrypt does not support DSA.")
@Test
+ @Ignore // DSA algorithm not supported in AndroidKeyStore
public void testDsa2048Sha224inP1363Format() throws Exception {
testVerification("dsa_2048_224_sha224_p1363_test.json", "DSA", Format.P1363, true);
}
- @ExcludedTest(
- providers = {ProviderType.CONSCRYPT},
- comment = "Conscrypt does not support DSA.")
@Test
+ @Ignore // DSA algorithm not supported in AndroidKeyStore
public void testDsa2048JdkSha256inP1363Format() throws Exception {
testVerification("dsa_2048_224_sha256_p1363_test.json", "DSA", Format.P1363, true);
}
- @ExcludedTest(
- providers = {ProviderType.CONSCRYPT},
- comment = "Conscrypt does not support DSA.")
@Test
+ @Ignore // DSA algorithm not supported in AndroidKeyStore
public void testDsa2048Sha256inP1363Format() throws Exception {
testVerification("dsa_2048_256_sha256_p1363_test.json", "DSA", Format.P1363, true);
}
- @ExcludedTest(
- providers = {ProviderType.CONSCRYPT},
- comment = "Conscrypt does not support DSA.")
@Test
+ @Ignore // DSA algorithm not supported in AndroidKeyStore
public void testDsa3072Sha256inP1363Format() throws Exception {
testVerification("dsa_3072_256_sha256_p1363_test.json", "DSA", Format.P1363, true);
}
-
}
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/MacTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/MacTest.java
index 34b6115..171af58 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/MacTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/MacTest.java
@@ -15,18 +15,20 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
-import com.google.security.wycheproof.WycheproofRunner.ProviderType;
-import com.google.security.wycheproof.WycheproofRunner.SlowTest;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.Key;
+import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.Ignore;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import android.keystore.cts.util.KeyStoreUtil;
/**
* Tests for MACs.
@@ -35,8 +37,21 @@ import org.junit.runners.JUnit4;
* with known results are necessary. So far only simple test vectors for long messages are
* available.
*/
-@RunWith(JUnit4.class)
public class MacTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+ private static final String KEY_ALIAS_1 = "TestKey";
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
+
+ private static Key getKeyStoreSecretKey(byte[] keyMaterial, String algorithm) throws Exception {
+ KeyStore keyStore = KeyStoreUtil.saveSecretKeyToKeystore(KEY_ALIAS_1,
+ new SecretKeySpec(keyMaterial, algorithm),
+ new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN).build());
+ return keyStore.getKey(KEY_ALIAS_1, null);
+ }
/**
* Computes the maximum of an array with at least one element.
@@ -79,7 +94,7 @@ public class MacTest {
*/
private void testUpdateWithChunks(String algorithm, Key key, byte[] data, int... chunkSizes)
throws Exception {
- Mac mac = Mac.getInstance(algorithm);
+ Mac mac = Mac.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
// First evaluation: compute MAC in one piece.
int totalLength = 0;
@@ -178,15 +193,14 @@ public class MacTest {
public void testMac(String algorithm, int keySize) throws Exception {
try {
- Mac.getInstance(algorithm);
+ Mac.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
} catch (NoSuchAlgorithmException ex) {
- System.out.println("Algorithm " + algorithm + " is not supported. Skipping test.");
- return;
+ fail("Algorithm " + algorithm + " is not supported.");
}
byte[] key = new byte[keySize];
SecureRandom rand = new SecureRandom();
rand.nextBytes(key);
- testUpdate(algorithm, new SecretKeySpec(key, algorithm));
+ testUpdate(algorithm, getKeyStoreSecretKey(key, algorithm));
}
@Test
@@ -215,21 +229,25 @@ public class MacTest {
}
@Test
+ @Ignore // HmacSha3 algorithms are not supported in AndroidKeyStore
public void testHmacSha3_224() throws Exception {
testMac("HMACSHA3-224", 28);
}
@Test
+ @Ignore // HmacSha3 algorithms are not supported in AndroidKeyStore
public void testHmacSha3_256() throws Exception {
testMac("HMACSHA3-256", 32);
}
@Test
+ @Ignore // HmacSha3 algorithms are not supported in AndroidKeyStore
public void testHmacSha3_384() throws Exception {
testMac("HMACSHA3-384", 48);
}
@Test
+ @Ignore // HmacSha3 algorithms are not supported in AndroidKeyStore
public void testHmacSha3_512() throws Exception {
testMac("HMACSHA3-512", 64);
}
@@ -246,7 +264,7 @@ public class MacTest {
*/
public byte[] macRepeatedMessage(String algorithm, Key key, byte[] message, long repetitions)
throws Exception {
- Mac mac = Mac.getInstance(algorithm);
+ Mac mac = Mac.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
mac.init(key);
// If the message is short then it is more efficient to collect multiple copies
// of the message in one chunk and call update with the larger chunk.
@@ -283,26 +301,18 @@ public class MacTest {
String algorithm, String keyhex, String message, long repetitions, String expected)
throws Exception {
- Key key = new SecretKeySpec(TestUtil.hexToBytes(keyhex), algorithm);
+ Key key = getKeyStoreSecretKey(TestUtil.hexToBytes(keyhex), algorithm);
byte[] bytes = message.getBytes(UTF_8);
byte[] mac = null;
try {
mac = macRepeatedMessage(algorithm, key, bytes, repetitions);
} catch (NoSuchAlgorithmException ex) {
- System.out.println("Algorithm " + algorithm + " is not supported. Skipping test.");
- return;
+ fail("Algorithm " + algorithm + " is not supported.");
}
String hexmac = TestUtil.bytesToHex(mac);
assertEquals(expected, hexmac);
}
- @SlowTest(
- providers = {
- ProviderType.OPENJDK,
- ProviderType.BOUNCY_CASTLE,
- ProviderType.SPONGY_CASTLE,
- ProviderType.CONSCRYPT
- })
@Test
public void testLongMacSha1() throws Exception {
testLongMac(
@@ -319,13 +329,6 @@ public class MacTest {
"d7f4c387f2237ea119fcc27cd7520fc5132b6230");
}
- @SlowTest(
- providers = {
- ProviderType.OPENJDK,
- ProviderType.BOUNCY_CASTLE,
- ProviderType.SPONGY_CASTLE,
- ProviderType.CONSCRYPT
- })
@Test
public void testLongMacSha256() throws Exception {
testLongMac(
@@ -342,13 +345,6 @@ public class MacTest {
"59a75754df7093fa4339aa618b64b104f153a5b42cc85394fdb8735b13ea684a");
}
- @SlowTest(
- providers = {
- ProviderType.OPENJDK,
- ProviderType.BOUNCY_CASTLE,
- ProviderType.SPONGY_CASTLE,
- ProviderType.CONSCRYPT
- })
@Test
public void testLongMacSha384() throws Exception {
testLongMac(
@@ -369,13 +365,6 @@ public class MacTest {
+ "a477e6a84d159d8b7a3daaa89c4f2372");
}
- @SlowTest(
- providers = {
- ProviderType.OPENJDK,
- ProviderType.BOUNCY_CASTLE,
- ProviderType.SPONGY_CASTLE,
- ProviderType.CONSCRYPT
- })
@Test
public void testLongMacSha512() throws Exception {
testLongMac(
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java
index 5f82420..32a78b3 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java
@@ -18,25 +18,39 @@ import static org.junit.Assert.fail;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
+import java.math.BigInteger;
+import java.security.KeyStore;
+import java.security.KeyPair;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.security.spec.RSAPublicKeySpec;
import java.util.Set;
import java.util.TreeSet;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import android.keystore.cts.util.KeyStoreUtil;
/**
* RSA encryption tests
*
* @author bleichen@google.com (Daniel Bleichenbacher)
*/
-@RunWith(JUnit4.class)
public class RsaEncryptionTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+ private static final String KEY_ALIAS_SIG = "SigningKey";
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
/**
* Providers that implement RSA with PKCS1Padding but not OAEP are outdated and should be avoided
@@ -46,15 +60,11 @@ public class RsaEncryptionTest {
*/
@Test
public void testOutdatedProvider() throws Exception {
+ Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", EXPECTED_PROVIDER_NAME);
try {
- Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
- try {
- Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
- } catch (NoSuchPaddingException | NoSuchAlgorithmException ex) {
- fail("Provider " + c.getProvider().getName() + " is outdated and should not be used.");
- }
+ Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING", EXPECTED_PROVIDER_NAME);
} catch (NoSuchPaddingException | NoSuchAlgorithmException ex) {
- System.out.println("RSA/ECB/PKCS1Padding is not implemented");
+ fail("Provider " + c.getProvider().getName() + " is outdated and should not be used.");
}
}
@@ -71,8 +81,17 @@ public class RsaEncryptionTest {
KeyFactory kf;
kf = KeyFactory.getInstance("RSA");
byte[] encoded = TestUtil.hexToBytes(object.get("privateKeyPkcs8").getAsString());
+ BigInteger modulus = new BigInteger(TestUtil.hexToBytes(object.get("n").getAsString()));
+ BigInteger exponent = new BigInteger(TestUtil.hexToBytes(object.get("e").getAsString()));
+
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
- return kf.generatePrivate(keySpec);
+ PrivateKey intermediateKey = kf.generatePrivate(keySpec);
+ PublicKey pubKey = kf.generatePublic(new RSAPublicKeySpec(modulus, exponent));
+ KeyStore keyStore = KeyStoreUtil.saveKeysToKeystore(KEY_ALIAS_SIG, pubKey, intermediateKey,
+ new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
+ .build());
+ return (PrivateKey) keyStore.getKey(KEY_ALIAS_SIG, null);
}
/** Convenience method to get a byte array from a JsonObject */
@@ -124,16 +143,7 @@ public class RsaEncryptionTest {
*/
@SuppressWarnings("InsecureCryptoUsage")
public void testDecryption(String filename) throws Exception {
- final String expectedSchema = "rsaes_pkcs1_decrypt_schema.json";
- JsonObject test = JsonUtil.getTestVectors(filename);
- String schema = test.get("schema").getAsString();
- if (!schema.equals(expectedSchema)) {
- System.out.println(
- "Expecting test vectors with schema "
- + expectedSchema
- + " found vectors with schema "
- + schema);
- }
+ JsonObject test = JsonUtil.getTestVectors(this.getClass(), filename);
// Padding oracle attacks become simpler when the decryption leaks detailed information about
// invalid paddings. Hence implementations are expected to not include such information in the
// exception thrown in the case of an invalid padding.
@@ -144,7 +154,7 @@ public class RsaEncryptionTest {
Set<String> exceptions = new TreeSet<String>();
int errors = 0;
- Cipher decrypter = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ Cipher decrypter = Cipher.getInstance("RSA/ECB/PKCS1Padding", EXPECTED_PROVIDER_NAME);
for (JsonElement g : test.getAsJsonArray("testGroups")) {
JsonObject group = g.getAsJsonObject();
PrivateKey key = getPrivateKey(group);
@@ -178,31 +188,18 @@ public class RsaEncryptionTest {
}
}
if (decrypted == null && result.equals("valid")) {
- System.out.printf(
- "Valid ciphertext not decrypted. filename:%s tcId:%d ct:%s cause:%s\n",
- filename, tcid, ciphertextHex, exception);
errors++;
} else if (decrypted != null) {
String decryptedHex = TestUtil.bytesToHex(decrypted);
if (result.equals("invalid")) {
- System.out.printf(
- "Invalid ciphertext decrypted. filename:%s tcId:%d expected:%s decrypted:%s\n",
- filename, tcid, messageHex, decryptedHex);
errors++;
} else if (!decryptedHex.equals(messageHex)) {
- System.out.printf(
- "Incorrect decryption. filename:%s tcId:%d expected:%s decrypted:%s\n",
- filename, tcid, messageHex, decryptedHex);
errors++;
}
}
}
}
if (exceptions.size() != 1) {
- System.out.println("Exceptions for RSA/ECB/PKCS1Padding");
- for (String s : exceptions) {
- System.out.println(s);
- }
fail("Exceptions leak information about the padding");
}
assertEquals(0, errors);
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/RsaSignatureTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/RsaSignatureTest.java
index 32ea493..57382f6 100644
--- a/keystore-cts/java/com/google/security/wycheproof/testcases/RsaSignatureTest.java
+++ b/keystore-cts/java/com/google/security/wycheproof/testcases/RsaSignatureTest.java
@@ -18,6 +18,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.math.BigInteger;
+import java.security.KeyStore;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
@@ -31,16 +32,42 @@ import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import java.security.cert.X509Certificate;
+import javax.security.auth.x500.X500Principal;
+import java.security.cert.Certificate;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.KeyProperties;
+import android.keystore.cts.util.KeyStoreUtil;
/** Tests PKCS #1 v 1.5 signatures */
// TODO(bleichen):
// - document stuff
// - Join other RSA tests
-@RunWith(JUnit4.class)
public class RsaSignatureTest {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_PROVIDER_NAME;
+ private static final String KEY_ALIAS_1 = "TestKey";
+ private static final String KEY_ALIAS_INVALID = "InvalidSigningKey";
+
+ @After
+ public void tearDown() throws Exception {
+ KeyStoreUtil.cleanUpKeyStore();
+ }
+
+ private static PrivateKey getKeystorePrivateKey(PublicKey pubKey, PrivateKey privKey)
+ throws Exception {
+ KeyStore keyStore = KeyStoreUtil.saveKeysToKeystore(KEY_ALIAS_1, pubKey, privKey,
+ new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN |
+ KeyProperties.PURPOSE_VERIFY)
+ .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
+ .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+ .build());
+ return (PrivateKey) keyStore.getKey(KEY_ALIAS_1, null);
+ }
+
static final RSAPublicKeySpec RSA_KEY1 =
new RSAPublicKeySpec(
new BigInteger(
@@ -1095,29 +1122,15 @@ public class RsaSignatureTest {
RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
byte[] messageBytes = message.getBytes("UTF-8");
- Signature signer = Signature.getInstance(algorithm);
- Signature verifier = Signature.getInstance(algorithm);
- signer.initSign(priv);
+ Signature signer = Signature.getInstance(algorithm, TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME);
+ Signature verifier = Signature.getInstance(algorithm,
+ TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME);
+ signer.initSign(getKeystorePrivateKey(pub, priv));
signer.update(messageBytes);
byte[] signature = signer.sign();
verifier.initVerify(pub);
verifier.update(messageBytes);
assertTrue(verifier.verify(signature));
-
- // Extract some parameters.
- byte[] rawHash = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
-
- // Print keys and signature, so that it can be used to generate new test vectors.
- System.out.println("Message:" + message);
- System.out.println("Hash:" + TestUtil.bytesToHex(rawHash));
- System.out.println("Public key:");
- System.out.println("Modulus:" + pub.getModulus().toString());
- System.out.println("E:" + pub.getPublicExponent().toString());
- System.out.println("encoded:" + TestUtil.bytesToHex(pub.getEncoded()));
- System.out.println("Private key:");
- System.out.println("D:" + priv.getPrivateExponent().toString());
- System.out.println("encoded:" + TestUtil.bytesToHex(priv.getEncoded()));
- System.out.println("Signature:" + TestUtil.bytesToHex(signature));
}
/**
@@ -1135,7 +1148,8 @@ public class RsaSignatureTest {
private void testVectors(RSAPublicKeySpec key, String algorithm, String[] testvectors)
throws Exception {
byte[] message = "Test".getBytes("UTF-8");
- Signature verifier = Signature.getInstance(algorithm);
+ Signature verifier = Signature.getInstance(algorithm,
+ TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pub = kf.generatePublic(key);
int errors = 0;
@@ -1151,10 +1165,8 @@ public class RsaSignatureTest {
// verify can throw SignatureExceptions if the signature is malformed.
}
if (first && !verified) {
- System.out.println("Valid signature not verified:" + signature);
errors++;
} else if (!first && verified) {
- System.out.println("Incorrect signature verified:" + signature);
errors++;
}
first = false;
@@ -1201,9 +1213,11 @@ public class RsaSignatureTest {
RSAPublicKeySpec key = RSA_KEY1;
String algorithm = ALGORITHM_KEY1;
byte[] message = "Test".getBytes("UTF-8");
- Signature verifier = Signature.getInstance(algorithm);
+ Signature verifier = Signature.getInstance(algorithm,
+ TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pub = kf.generatePublic(key);
+ int nonverified = 0;
for (String signature : LEGACY_SIGNATURES_KEY1) {
byte[] signatureBytes = TestUtil.hexToBytes(signature);
verifier.initVerify(pub);
@@ -1213,13 +1227,10 @@ public class RsaSignatureTest {
verified = verifier.verify(signatureBytes);
} catch (SignatureException ex) {
verified = false;
- }
- if (verified) {
- System.out.println("Verfied legacy signature:" + signature);
- } else {
- System.out.println("Rejected legacy signature:" + signature);
+ nonverified++;
}
}
+ assertEquals(0, nonverified);
}
/**
@@ -1280,30 +1291,49 @@ public class RsaSignatureTest {
byte[] message = "Test".getBytes("UTF-8");
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey validPrivKey = kf.generatePrivate(validKey);
- Signature signer = Signature.getInstance("SHA256WithRSA");
- signer.initSign(validPrivKey);
+ Signature signer = Signature.getInstance("SHA256WithRSA",
+ TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME);
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(n, e);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ signer.initSign(getKeystorePrivateKey(pubKey, validPrivKey));
signer.update(message);
byte[] signature = signer.sign();
PrivateKey invalidPrivKey = null;
+ // Here if we use common code to get key from keystore (getKeystorePrivateKey).
+ // It throws run time exception while creating Certificate.
+ // Hence creating certificate using vaid keys.
+ KeyPair keyPair = new KeyPair(pubKey, validPrivKey);
+ X509Certificate certificate = KeyStoreUtil.createCertificate(keyPair,
+ new X500Principal("CN=Test1"),
+ new X500Principal("CN=Test1"));
+ Certificate[] certChain = new Certificate[]{certificate};
+ KeyStore keyStore2 = KeyStore.getInstance("AndroidKeyStore");
+ keyStore2.load(null);
try {
invalidPrivKey = kf.generatePrivate(invalidKey);
- } catch (InvalidKeySpecException ex) {
+ keyStore2.setEntry(
+ KEY_ALIAS_INVALID,
+ new KeyStore.PrivateKeyEntry(invalidPrivKey, certChain),
+ new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN)
+ .setDigests(KeyProperties.DIGEST_SHA256)
+ .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+ .build());
+ } catch (InvalidKeySpecException | java.security.KeyStoreException ex) {
// The provider checks the private key and notices a mismatch.
// This is a good sign, though of course in this case it means that we can't
// check for faults.
- System.out.println("Provider catches invalid RSA key:" + ex);
return;
}
byte[] invalidSignature = null;
try {
- signer.initSign(invalidPrivKey);
+ signer.initSign((PrivateKey)keyStore2.getKey(KEY_ALIAS_INVALID, null));
signer.update(message);
invalidSignature = signer.sign();
} catch (Exception ex) {
// We do not necessarily expect a checked exception here, since generating
// an invalid signature typically indicates a programming error.
// Though RuntimeExceptions are fine here.
- System.out.println("Generating PKCS#1 signature with faulty key throws:" + ex);
return;
}
String signatureHex = TestUtil.bytesToHex(signature);
@@ -1311,7 +1341,6 @@ public class RsaSignatureTest {
if (signatureHex.equals(invalidSignatureHex)) {
// The provider generated a correct signature. This can for example happen if the provider
// does not use the CRT parameters.
- System.out.println("Signature generation did not use faulty parameter");
return;
}
fail("Generated faulty PKCS #1 signature with faulty parameters"