blob: 7012eaee326d5c6f731f71d612a69f90d4c77078 [file] [log] [blame]
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.security.cryptauth.lib.securegcm;
import com.google.security.cryptauth.lib.securemessage.PublicKeyProtoUtil;
import java.security.Key;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import junit.framework.TestCase;
/**
* Android compatible tests for the {@link KeyEncoding} class.
*/
public class KeyEncodingTest extends TestCase {
private static final byte[] RAW_KEY_BYTES = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2};
private Boolean isLegacy;
private KeyPair userKeyPair;
@Override
protected void setUp() throws Exception {
installSunEcSecurityProviderIfNecessary();
isLegacy = PublicKeyProtoUtil.isLegacyCryptoRequired();
setUserKeyPair();
super.setUp();
}
@Override
protected void tearDown() throws Exception {
KeyEncoding.setSimulateLegacyCrypto(false);
isLegacy = PublicKeyProtoUtil.isLegacyCryptoRequired();
super.tearDown();
}
private void setUserKeyPair() {
userKeyPair = isLegacy ? PublicKeyProtoUtil.generateRSA2048KeyPair()
: PublicKeyProtoUtil.generateEcP256KeyPair();
}
public void testSimulateLegacyCrypto() {
if (isLegacy) {
return; // Nothing to test if we are already stuck in a legacy platform
}
assertFalse(KeyEncoding.isLegacyCryptoRequired());
KeyEncoding.setSimulateLegacyCrypto(true);
assertTrue(KeyEncoding.isLegacyCryptoRequired());
}
public void testMasterKeyEncoding() {
// Require that master keys are encoded/decoded as raw byte arrays
assertTrue(Arrays.equals(
RAW_KEY_BYTES,
KeyEncoding.encodeMasterKey(KeyEncoding.parseMasterKey(RAW_KEY_BYTES))));
}
public void testUserPublicKeyEncoding() throws InvalidKeySpecException {
PublicKey pk = userKeyPair.getPublic();
byte[] encodedPk = KeyEncoding.encodeUserPublicKey(pk);
PublicKey decodedPk = KeyEncoding.parseUserPublicKey(encodedPk);
assertKeysEqual(pk, decodedPk);
}
public void testUserPrivateKeyEncoding() throws InvalidKeySpecException {
PrivateKey sk = userKeyPair.getPrivate();
byte[] encodedSk = KeyEncoding.encodeUserPrivateKey(sk);
PrivateKey decodedSk = KeyEncoding.parseUserPrivateKey(encodedSk, isLegacy);
assertKeysEqual(sk, decodedSk);
}
public void testKeyAgreementPublicKeyEncoding() throws InvalidKeySpecException {
KeyPair clientKeyPair = EnrollmentCryptoOps.generateEnrollmentKeyAgreementKeyPair(isLegacy);
PublicKey pk = clientKeyPair.getPublic();
byte[] encodedPk = KeyEncoding.encodeKeyAgreementPublicKey(pk);
PublicKey decodedPk = KeyEncoding.parseKeyAgreementPublicKey(encodedPk);
assertKeysEqual(pk, decodedPk);
}
public void testKeyAgreementPrivateKeyEncoding() throws InvalidKeySpecException {
KeyPair clientKeyPair = EnrollmentCryptoOps.generateEnrollmentKeyAgreementKeyPair(isLegacy);
PrivateKey sk = clientKeyPair.getPrivate();
byte[] encodedSk = KeyEncoding.encodeKeyAgreementPrivateKey(sk);
PrivateKey decodedSk = KeyEncoding.parseKeyAgreementPrivateKey(encodedSk, isLegacy);
assertKeysEqual(sk, decodedSk);
}
public void testEncodingsWithForcedLegacy() throws InvalidKeySpecException {
if (PublicKeyProtoUtil.isLegacyCryptoRequired()) {
// We already test with legacy in this case
return;
}
KeyEncoding.setSimulateLegacyCrypto(true);
isLegacy = true;
setUserKeyPair();
testUserPublicKeyEncoding();
testUserPrivateKeyEncoding();
testKeyAgreementPublicKeyEncoding();
testKeyAgreementPrivateKeyEncoding();
}
public void testSigningPublicKeyEncoding() throws InvalidKeySpecException {
KeyPair keyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
PublicKey pk = keyPair.getPublic();
byte[] encodedPk = KeyEncoding.encodeSigningPublicKey(pk);
PublicKey decodedPk = KeyEncoding.parseSigningPublicKey(encodedPk);
assertKeysEqual(pk, decodedPk);
}
public void testSigningPrivateKeyEncoding() throws InvalidKeySpecException {
KeyPair keyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
PrivateKey sk = keyPair.getPrivate();
byte[] encodedSk = KeyEncoding.encodeSigningPrivateKey(sk);
PrivateKey decodedSk = KeyEncoding.parseSigningPrivateKey(encodedSk);
assertKeysEqual(sk, decodedSk);
}
public void testDeviceSyncPublicKeyEncoding() throws InvalidKeySpecException {
KeyPair keyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
PublicKey pk = keyPair.getPublic();
byte[] encodedPk = KeyEncoding.encodeDeviceSyncGroupPublicKey(pk);
PublicKey decodedPk = KeyEncoding.parseDeviceSyncGroupPublicKey(encodedPk);
assertKeysEqual(pk, decodedPk);
}
void assertKeysEqual(Key a, Key b) {
if ((a instanceof ECPublicKey)
|| (a instanceof ECPrivateKey)
|| (a instanceof RSAPublicKey)
|| (a instanceof RSAPrivateKey)) {
assertNotNull(a.getEncoded());
assertTrue(Arrays.equals(a.getEncoded(), b.getEncoded()));
}
if (a instanceof DHPublicKey) {
DHPublicKey ya = (DHPublicKey) a;
DHPublicKey yb = (DHPublicKey) b;
assertEquals(ya.getY(), yb.getY());
assertEquals(ya.getParams().getG(), yb.getParams().getG());
assertEquals(ya.getParams().getP(), yb.getParams().getP());
}
if (a instanceof DHPrivateKey) {
DHPrivateKey xa = (DHPrivateKey) a;
DHPrivateKey xb = (DHPrivateKey) b;
assertEquals(xa.getX(), xb.getX());
assertEquals(xa.getParams().getG(), xb.getParams().getG());
assertEquals(xa.getParams().getP(), xb.getParams().getP());
}
}
/**
* Registers the SunEC security provider if no EC security providers are currently registered.
*/
// TODO(shabsi): Remove this method when b/7891565 is fixed
static void installSunEcSecurityProviderIfNecessary() {
if (Security.getProviders("KeyPairGenerator.EC") == null) {
try {
Class<?> providerClass = Class.forName("sun.security.ec.SunEC");
Security.addProvider((Provider) providerClass.newInstance());
} catch (Exception e) {
// SunEC is not available, nothing we can do
}
}
}
}