blob: 2bff0c592705a0e40aa7fcb872a914f48710a897 [file] [log] [blame]
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package com.google.crypto.tink.signature;
import static org.junit.Assert.fail;
import com.google.crypto.tink.PublicKeyVerify;
import com.google.crypto.tink.TestUtil;
import com.google.crypto.tink.TestUtil.BytesMutation;
import com.google.crypto.tink.proto.EcdsaPublicKey;
import com.google.crypto.tink.proto.EcdsaSignatureEncoding;
import com.google.crypto.tink.proto.EllipticCurveType;
import com.google.crypto.tink.proto.HashType;
import com.google.crypto.tink.subtle.EllipticCurves;
import com.google.crypto.tink.subtle.Hex;
import com.google.crypto.tink.subtle.Random;
import com.google.crypto.tink.subtle.SubtleUtil;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Unit tests for EcdsaVerifyKeyManager.
*
* <p>TODO(quannguyen): Add more tests.
*/
@RunWith(JUnit4.class)
public class EcdsaVerifyKeyManagerTest {
private static class HashAndCurveType {
public HashType hashType;
public EllipticCurveType curveType;
public HashAndCurveType(HashType hashType, EllipticCurveType curveType) {
this.hashType = hashType;
this.curveType = curveType;
}
}
class RfcTestVector {
byte[] msg;
byte[] pubX;
byte[] pubY;
byte[] sig;
HashType hashType;
EllipticCurveType curveType;
public RfcTestVector(
String msg,
String pubX,
String pubY,
String r,
String s,
HashType hashType,
EllipticCurveType curveType) {
try {
this.msg = msg.getBytes("UTF-8");
} catch (Exception ignored) {
// Ignored
}
this.pubX = TestUtil.hexDecode(pubX.toLowerCase());
this.pubY = TestUtil.hexDecode(pubY.toLowerCase());
this.sig = TestUtil.hexDecode((r + s).toLowerCase());
this.hashType = hashType;
this.curveType = curveType;
}
}
// Test vectors from https://tools.ietf.org/html/rfc6979#appendix-A.2.
final RfcTestVector[] rfcTestVectors = {
new RfcTestVector(
"sample",
"60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6",
"7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
"EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716",
"F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8",
HashType.SHA256,
EllipticCurveType.NIST_P256),
new RfcTestVector(
"sample",
"EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64"
+ "DEF8F0EA9055866064A254515480BC13",
"8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1"
+ "288B231C3AE0D4FE7344FD2533264720",
"ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799C"
+ "FE30F35CC900056D7C99CD7882433709",
"512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112"
+ "DC7CC3EF3446DEFCEB01A45C2667FDD5",
HashType.SHA512,
EllipticCurveType.NIST_P384),
new RfcTestVector(
"test",
"01894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD3"
+ "71123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F502"
+ "3A4",
"00493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A2"
+ "8A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDF"
+ "CF5",
"013E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10"
+ "CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47E"
+ "E6D",
"01FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78"
+ "A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4D"
+ "CE3",
HashType.SHA512,
EllipticCurveType.NIST_P521),
};
@Test
public void testRfcTestVectors() throws Exception {
for (int i = 0; i < rfcTestVectors.length; i++) {
RfcTestVector t = rfcTestVectors[i];
PublicKeyVerify verifier = createVerifier(t);
try {
verifier.verify(t.sig, t.msg);
} catch (GeneralSecurityException e) {
fail("Valid signature, should not throw exception");
}
for (BytesMutation mutation : TestUtil.generateMutations(t.sig)) {
try {
verifier.verify(mutation.value, t.msg);
fail(
String.format(
"Invalid signature, should have thrown exception : sig = %s, msg = %s,"
+ " description = %s",
Hex.encode(mutation.value), Hex.encode(t.msg), mutation.description));
} catch (GeneralSecurityException expected) {
// Expected.
}
}
}
}
@Test
public void testGetPrimitiveWithJCE() throws Exception {
HashAndCurveType[] hashAndCurves = {
new HashAndCurveType(HashType.SHA256, EllipticCurveType.NIST_P256),
new HashAndCurveType(HashType.SHA512, EllipticCurveType.NIST_P384),
new HashAndCurveType(HashType.SHA512, EllipticCurveType.NIST_P521)
};
for (int i = 0; i < hashAndCurves.length; i++) {
HashType hashType = hashAndCurves[i].hashType;
EllipticCurveType curveType = hashAndCurves[i].curveType;
ECParameterSpec ecParams = EllipticCurves.getCurveSpec(SigUtil.toCurveType(curveType));
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(ecParams);
KeyPair keyPair = keyGen.generateKeyPair();
ECPublicKey pubKey = (ECPublicKey) keyPair.getPublic();
ECPrivateKey privKey = (ECPrivateKey) keyPair.getPrivate();
// Sign with JCE's Signature.
Signature signer =
Signature.getInstance(SubtleUtil.toEcdsaAlgo(SigUtil.toHashType(hashType)));
signer.initSign(privKey);
byte[] msg = Random.randBytes(1231);
signer.update(msg);
byte[] signature = signer.sign();
// Create PublicKeyVerify.
ECPoint w = pubKey.getW();
PublicKeyVerify verifier =
createVerifier(
hashType,
curveType,
EcdsaSignatureEncoding.DER,
w.getAffineX().toByteArray(),
w.getAffineY().toByteArray());
try {
verifier.verify(signature, msg);
} catch (GeneralSecurityException e) {
fail("Valid signature, should not throw exception");
}
}
}
@Test
public void testGetPrimitiveWithUnsupportedKey() throws Exception {
HashAndCurveType[] hashAndCurves = {
new HashAndCurveType(HashType.SHA1, EllipticCurveType.NIST_P256),
new HashAndCurveType(HashType.SHA1, EllipticCurveType.NIST_P384),
new HashAndCurveType(HashType.SHA1, EllipticCurveType.NIST_P521),
new HashAndCurveType(HashType.SHA256, EllipticCurveType.NIST_P384),
new HashAndCurveType(HashType.SHA256, EllipticCurveType.NIST_P521),
new HashAndCurveType(HashType.SHA512, EllipticCurveType.NIST_P256),
};
for (int i = 0; i < hashAndCurves.length; i++) {
HashType hashType = hashAndCurves[i].hashType;
EllipticCurveType curveType = hashAndCurves[i].curveType;
ECParameterSpec ecParams = EllipticCurves.getCurveSpec(SigUtil.toCurveType(curveType));
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(ecParams);
KeyPair keyPair = keyGen.generateKeyPair();
ECPublicKey pubKey = (ECPublicKey) keyPair.getPublic();
ECPrivateKey unusedPrivKey = (ECPrivateKey) keyPair.getPrivate();
// Create PublicKeyVerify.
ECPoint w = pubKey.getW();
try {
PublicKeyVerify unusedVerifier =
createVerifier(
hashType,
curveType,
EcdsaSignatureEncoding.DER,
w.getAffineX().toByteArray(),
w.getAffineY().toByteArray());
fail("Unsupported key, should have thrown exception: " + hashType + " " + curveType);
} catch (GeneralSecurityException expected) {
// Expected
}
}
}
private PublicKeyVerify createVerifier(RfcTestVector t) throws Exception {
return createVerifier(
t.hashType, t.curveType, EcdsaSignatureEncoding.IEEE_P1363, t.pubX, t.pubY);
}
private PublicKeyVerify createVerifier(
HashType hashType,
EllipticCurveType curve,
EcdsaSignatureEncoding encoding,
byte[] pubX,
byte[] pubY)
throws Exception {
EcdsaPublicKey ecdsaPubKey = TestUtil.createEcdsaPubKey(hashType, curve, encoding, pubX, pubY);
EcdsaVerifyKeyManager verifyManager = new EcdsaVerifyKeyManager();
return verifyManager.getPrimitive(ecdsaPubKey);
}
}