Added signature key generation to crypto API
parent
ceba09e65c
commit
7e4260b8d5
|
@ -57,7 +57,8 @@ dependencies {
|
||||||
|
|
||||||
// Crypto
|
// Crypto
|
||||||
compile 'org.factcenter.qilin:qilin:1.2.+'
|
compile 'org.factcenter.qilin:qilin:1.2.+'
|
||||||
compile 'org.bouncycastle:bcprov-jdk15on:1.53'
|
compile 'org.bouncycastle:bcprov-jdk15on:1.57'
|
||||||
|
compile 'org.bouncycastle:bcpkix-jdk15on:1.57' // For certificate generation
|
||||||
|
|
||||||
testCompile 'junit:junit:4.+'
|
testCompile 'junit:junit:4.+'
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,11 @@ public class GenericBulletinBoardSignature implements BulletinBoardSignature {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadVerificationCertificate(Crypto.SignatureVerificationKey cert) throws CertificateException {
|
||||||
|
signer.loadVerificationCertificate(cert);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadVerificationCertificates(InputStream certStream) throws CertificateException {
|
public void loadVerificationCertificates(InputStream certStream) throws CertificateException {
|
||||||
signer.loadVerificationCertificates(certStream);
|
signer.loadVerificationCertificates(certStream);
|
||||||
|
@ -98,6 +103,9 @@ public class GenericBulletinBoardSignature implements BulletinBoardSignature {
|
||||||
return signer.getSignerID();
|
return signer.getSignerID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Crypto.SignatureVerificationKey getSignerPublicKey() { return signer.getSignerPublicKey(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearSigningKey() {
|
public void clearSigningKey() {
|
||||||
signer.clearSigningKey();
|
signer.clearSigningKey();
|
||||||
|
|
|
@ -22,6 +22,18 @@ import static meerkat.protobuf.Crypto.*;
|
||||||
public interface DigitalSignature {
|
public interface DigitalSignature {
|
||||||
final public static String CERTIFICATE_ENCODING_X509 = "X.509";
|
final public static String CERTIFICATE_ENCODING_X509 = "X.509";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a verification certificate.
|
||||||
|
* This will be added to the existing set of verification certificates.
|
||||||
|
* @param cert
|
||||||
|
*
|
||||||
|
* @throws CertificateException on parsing errors
|
||||||
|
*/
|
||||||
|
public void loadVerificationCertificate(SignatureVerificationKey cert)
|
||||||
|
throws CertificateException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a set of certificates from an input stream.
|
* Load a set of certificates from an input stream.
|
||||||
* This will consume the entire stream.
|
* This will consume the entire stream.
|
||||||
|
@ -94,6 +106,8 @@ public interface DigitalSignature {
|
||||||
public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password)
|
public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password)
|
||||||
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException;
|
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a private signing key. The keystore must include both the public and private
|
* Loads a private signing key. The keystore must include both the public and private
|
||||||
* key parts.
|
* key parts.
|
||||||
|
@ -111,9 +125,14 @@ public interface DigitalSignature {
|
||||||
*/
|
*/
|
||||||
public ByteString getSignerID();
|
public ByteString getSignerID();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the signer verification key if it exists, null otherwise.
|
||||||
|
*/
|
||||||
|
public SignatureVerificationKey getSignerPublicKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the signing key (will require authentication to use again).
|
* Clear the signing key (will require authentication to use again).
|
||||||
*/
|
*/
|
||||||
public void clearSigningKey();
|
public void clearSigningKey();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package meerkat.crypto;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link DigitalSignature} that supports key generation.
|
||||||
|
*/
|
||||||
|
public interface DigitalSignatureGenerator extends DigitalSignature {
|
||||||
|
/**
|
||||||
|
* Generate a new verification key / signature key pair.
|
||||||
|
* The keypair is loaded as the default signing key.
|
||||||
|
*
|
||||||
|
* @param serial serial number of certificate
|
||||||
|
* @param notBefore earliest valid time
|
||||||
|
* @param notAfter expiration
|
||||||
|
* @param subjectName name corresponding to cert (will be used as "common name" in x509 cert).
|
||||||
|
*/
|
||||||
|
public void generateSigningCertificate(BigInteger serial, Date notBefore, Date notAfter,
|
||||||
|
String subjectName);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a keypair in a given keystore.
|
||||||
|
*
|
||||||
|
* @param store
|
||||||
|
* @param alias
|
||||||
|
* @param password
|
||||||
|
* @throws IOException
|
||||||
|
* @throws KeyStoreException
|
||||||
|
*/
|
||||||
|
public void storeSignatureKeypair(KeyStore store, String alias, char[] password)
|
||||||
|
throws IOException, KeyStoreException;
|
||||||
|
}
|
|
@ -1,28 +1,39 @@
|
||||||
package meerkat.crypto.concrete;
|
package meerkat.crypto.concrete;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.security.*;
|
|
||||||
import java.security.cert.*;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
import com.google.protobuf.Message;
|
||||||
|
import meerkat.crypto.DigitalSignatureGenerator;
|
||||||
import meerkat.protobuf.Crypto;
|
import meerkat.protobuf.Crypto;
|
||||||
|
import meerkat.protobuf.Crypto.Signature;
|
||||||
import meerkat.util.Hex;
|
import meerkat.util.Hex;
|
||||||
|
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||||
|
import org.bouncycastle.asn1.DERSequence;
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
|
import org.bouncycastle.asn1.x509.*;
|
||||||
|
import org.bouncycastle.asn1.x509.Extension;
|
||||||
|
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.operator.ContentSigner;
|
||||||
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.protobuf.Message;
|
|
||||||
|
|
||||||
import meerkat.crypto.DigitalSignature;
|
|
||||||
import meerkat.protobuf.Crypto.Signature;
|
|
||||||
|
|
||||||
import javax.security.auth.callback.Callback;
|
import javax.security.auth.callback.Callback;
|
||||||
import javax.security.auth.callback.CallbackHandler;
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
import javax.security.auth.callback.PasswordCallback;
|
import javax.security.auth.callback.PasswordCallback;
|
||||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.*;
|
||||||
|
import java.security.spec.ECGenParameterSpec;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,7 +41,7 @@ import javax.security.auth.callback.UnsupportedCallbackException;
|
||||||
*
|
*
|
||||||
* This class is not thread-safe (each thread should have its own instance).
|
* This class is not thread-safe (each thread should have its own instance).
|
||||||
*/
|
*/
|
||||||
public class ECDSASignature implements DigitalSignature {
|
public class ECDSASignature implements DigitalSignatureGenerator {
|
||||||
|
|
||||||
private static GlobalCryptoSetup globalCryptoSetup = GlobalCryptoSetup.getInstance();
|
private static GlobalCryptoSetup globalCryptoSetup = GlobalCryptoSetup.getInstance();
|
||||||
|
|
||||||
|
@ -38,6 +49,9 @@ public class ECDSASignature implements DigitalSignature {
|
||||||
|
|
||||||
final public static String KEYSTORE_TYPE = "PKCS12";
|
final public static String KEYSTORE_TYPE = "PKCS12";
|
||||||
final public static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA";
|
final public static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA";
|
||||||
|
final public static String DEFAULT_KEY_ALGORITHM = "ECDSA";
|
||||||
|
final public static String DEFAULT_KEY_CURVE = "secp256k1";
|
||||||
|
|
||||||
|
|
||||||
SHA256Digest certDigest = new SHA256Digest();
|
SHA256Digest certDigest = new SHA256Digest();
|
||||||
|
|
||||||
|
@ -56,6 +70,8 @@ public class ECDSASignature implements DigitalSignature {
|
||||||
|
|
||||||
ByteString loadedSigningKeyId = null;
|
ByteString loadedSigningKeyId = null;
|
||||||
|
|
||||||
|
Certificate loadedSigningCert = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual signing implementation. (used for both signing and verifying)
|
* The actual signing implementation. (used for both signing and verifying)
|
||||||
*/
|
*/
|
||||||
|
@ -100,19 +116,32 @@ public class ECDSASignature implements DigitalSignature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void loadVerificationCertificate(Certificate cert) throws CertificateException {
|
||||||
|
// Just checking
|
||||||
|
if (!(cert instanceof X509Certificate)) {
|
||||||
|
logger.error("Certificate must be in X509 format; got {} instead!", cert.getClass().getCanonicalName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ByteString keyId = computeCertificateFingerprint(cert);
|
||||||
|
loadedCertificates.put(keyId, cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadVerificationCertificate(Crypto.SignatureVerificationKey cert) throws CertificateException {
|
||||||
|
ByteArrayInputStream certStream = new ByteArrayInputStream(cert.getData().toByteArray());
|
||||||
|
loadVerificationCertificates(certStream);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadVerificationCertificates(InputStream certStream)
|
public void loadVerificationCertificates(InputStream certStream)
|
||||||
throws CertificateException {
|
throws CertificateException {
|
||||||
CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_ENCODING_X509);
|
CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_ENCODING_X509);
|
||||||
Collection<? extends Certificate> certs = certificateFactory.generateCertificates(certStream);
|
Collection<? extends Certificate> certs = certificateFactory.generateCertificates(certStream);
|
||||||
for (Certificate cert : certs) {
|
for (Certificate cert : certs) {
|
||||||
// Just checking
|
loadVerificationCertificate(cert);
|
||||||
if (!(cert instanceof X509Certificate)) {
|
|
||||||
logger.error("Certificate must be in X509 format; got {} instead!", cert.getClass().getCanonicalName());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ByteString keyId = computeCertificateFingerprint(cert);
|
|
||||||
loadedCertificates.put(keyId, cert);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +254,15 @@ public class ECDSASignature implements DigitalSignature {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void loadSigningCertificate(Certificate cert, PrivateKey key) throws InvalidKeyException, CertificateException {
|
||||||
|
loadedSigningKey = (PrivateKey) key;
|
||||||
|
loadedSigningKeyId = computeCertificateFingerprint(cert);
|
||||||
|
loadedSigningCert = cert;
|
||||||
|
signer.initSign(loadedSigningKey);
|
||||||
|
logger.debug("Loaded signing key with ID {}", Hex.encode(loadedSigningKeyId));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For now we only support PKCS12.
|
* For now we only support PKCS12.
|
||||||
* TODO: Support for PKCS11 as well.
|
* TODO: Support for PKCS11 as well.
|
||||||
|
@ -283,11 +321,7 @@ public class ECDSASignature implements DigitalSignature {
|
||||||
}
|
}
|
||||||
logger.trace("keystore entry {}, has key type {}", alias, key.getClass());
|
logger.trace("keystore entry {}, has key type {}", alias, key.getClass());
|
||||||
if (key instanceof PrivateKey) {
|
if (key instanceof PrivateKey) {
|
||||||
loadedSigningKey = (PrivateKey) key;
|
loadSigningCertificate(cert, (PrivateKey) key);
|
||||||
loadedSigningKeyId = computeCertificateFingerprint(cert);
|
|
||||||
signer.initSign(loadedSigningKey);
|
|
||||||
logger.debug("Loaded signing key with ID {}", Hex.encode(loadedSigningKeyId));
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
logger.info("Certificate {} in keystore does not have a private key", cert.toString());
|
logger.info("Certificate {} in keystore does not have a private key", cert.toString());
|
||||||
|
@ -314,6 +348,38 @@ public class ECDSASignature implements DigitalSignature {
|
||||||
return loadedSigningKeyId;
|
return loadedSigningKeyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Crypto.SignatureVerificationKey getSignerPublicKey() {
|
||||||
|
Crypto.SignatureType certType;
|
||||||
|
|
||||||
|
if (loadedSigningCert instanceof X509Certificate) {
|
||||||
|
X509Certificate xcert = (X509Certificate) loadedSigningCert;
|
||||||
|
String algName = xcert.getSigAlgName();
|
||||||
|
if (algName.endsWith("ECDSA")) {
|
||||||
|
certType = Crypto.SignatureType.ECDSA;
|
||||||
|
} else if (algName.endsWith("DSA")) {
|
||||||
|
certType = Crypto.SignatureType.DSA;
|
||||||
|
} else if (algName.endsWith("RSA")) {
|
||||||
|
certType = Crypto.SignatureType.RSA;
|
||||||
|
} else {
|
||||||
|
logger.error("Unknown certificate signature algorithm: {}", algName);
|
||||||
|
throw new RuntimeException("Unknown certificate signature algorithm: " + algName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("We don't know how to handle non-X509 certificates");
|
||||||
|
throw new RuntimeException("Unknown Certificate type: " + loadedSigningCert.getClass());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Crypto.SignatureVerificationKey.newBuilder()
|
||||||
|
.setType(certType)
|
||||||
|
.setData(ByteString.copyFrom(loadedSigningCert.getEncoded()))
|
||||||
|
.build();
|
||||||
|
} catch (CertificateEncodingException e) {
|
||||||
|
logger.error("CertificateEncodingException: ", e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void clearSigningKey() {
|
public void clearSigningKey() {
|
||||||
try {
|
try {
|
||||||
// TODO: Check if this really clears the key from memory
|
// TODO: Check if this really clears the key from memory
|
||||||
|
@ -321,6 +387,7 @@ public class ECDSASignature implements DigitalSignature {
|
||||||
signer.initSign(null);
|
signer.initSign(null);
|
||||||
loadedSigningKeyId = null;
|
loadedSigningKeyId = null;
|
||||||
loadedSigningKey = null;
|
loadedSigningKey = null;
|
||||||
|
loadedSigningCert = null;
|
||||||
// Start garbage collection?
|
// Start garbage collection?
|
||||||
} catch (InvalidKeyException e) {
|
} catch (InvalidKeyException e) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
@ -328,4 +395,51 @@ public class ECDSASignature implements DigitalSignature {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateSigningCertificate(BigInteger serial, Date notBefore, Date notAfter,
|
||||||
|
String subjectName) {
|
||||||
|
try {
|
||||||
|
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(DEFAULT_KEY_ALGORITHM);
|
||||||
|
ECGenParameterSpec kpgparams = new ECGenParameterSpec(DEFAULT_KEY_CURVE);
|
||||||
|
keyGen.initialize(kpgparams);
|
||||||
|
KeyPair pair = keyGen.generateKeyPair();
|
||||||
|
|
||||||
|
SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(pair.getPublic().getEncoded());
|
||||||
|
|
||||||
|
// build a certificate generator
|
||||||
|
X500Name subject = new X500Name("cn=" + subjectName);
|
||||||
|
X509v3CertificateBuilder builder = new X509v3CertificateBuilder(subject, serial, notBefore, notAfter,
|
||||||
|
subject, subPubKeyInfo);
|
||||||
|
|
||||||
|
// TODO: Might need to explicitly force SHA256 digest
|
||||||
|
JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
|
||||||
|
|
||||||
|
builder.addExtension(Extension.subjectKeyIdentifier, false, extensionUtils.createSubjectKeyIdentifier(pair.getPublic()));
|
||||||
|
builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
|
||||||
|
KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.digitalSignature | KeyUsage.cRLSign);
|
||||||
|
builder.addExtension(Extension.keyUsage, false, usage);
|
||||||
|
ASN1EncodableVector purposes = new ASN1EncodableVector();
|
||||||
|
purposes.add(KeyPurposeId.id_kp_serverAuth);
|
||||||
|
purposes.add(KeyPurposeId.id_kp_clientAuth);
|
||||||
|
purposes.add(KeyPurposeId.anyExtendedKeyUsage);
|
||||||
|
builder.addExtension(Extension.extendedKeyUsage, false, new DERSequence(purposes));
|
||||||
|
|
||||||
|
String signatureAlgorithm = DEFAULT_SIGNATURE_ALGORITHM;
|
||||||
|
|
||||||
|
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(pair.getPrivate());
|
||||||
|
X509Certificate cert = new JcaX509CertificateConverter().getCertificate(builder.build(contentSigner));
|
||||||
|
|
||||||
|
loadSigningCertificate(cert, pair.getPrivate());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Convert all checked exceptions into runtime exceptions.
|
||||||
|
// TODO: Handle exceptions more elegantly.
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeSignatureKeypair(KeyStore store, String alias, char[] password) throws IOException, KeyStoreException {
|
||||||
|
Certificate chain[] = { loadedSigningCert };
|
||||||
|
store.setKeyEntry(alias, loadedSigningKey, password, chain);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,10 +46,14 @@ public final class GlobalCryptoSetup {
|
||||||
bouncyCastleProvider = new BouncyCastleProvider();
|
bouncyCastleProvider = new BouncyCastleProvider();
|
||||||
// Make bouncycastle our default provider if we're running on a JVM version < 8
|
// Make bouncycastle our default provider if we're running on a JVM version < 8
|
||||||
// (earlier version don't support the EC curve we use for signatures)
|
// (earlier version don't support the EC curve we use for signatures)
|
||||||
if (!hasSecp256k1Curve() && !loadedBouncyCastle) {
|
if (!loadedBouncyCastle) {
|
||||||
loadedBouncyCastle = true;
|
loadedBouncyCastle = true;
|
||||||
Security.insertProviderAt(bouncyCastleProvider, 1);
|
if (!hasSecp256k1Curve()) {
|
||||||
logger.info("Using BouncyCastle instead of native provider to support secp256k1 named curve");
|
Security.insertProviderAt(bouncyCastleProvider, 1);
|
||||||
|
logger.info("Using BouncyCastle as default instead of native provider to support secp256k1 named curve");
|
||||||
|
} else {
|
||||||
|
Security.addProvider(bouncyCastleProvider);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ option java_package = "meerkat.protobuf";
|
||||||
enum SignatureType {
|
enum SignatureType {
|
||||||
ECDSA = 0;
|
ECDSA = 0;
|
||||||
DSA = 1;
|
DSA = 1;
|
||||||
|
RSA = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message BigInteger {
|
message BigInteger {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.junit.Test;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
@ -215,5 +216,24 @@ public class ECDSASignatureTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateKeysSignAndVerify() throws Exception {
|
||||||
|
signer.generateSigningCertificate(BigInteger.ONE, new Date(), new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365), "testing");
|
||||||
|
|
||||||
|
Crypto.SignatureVerificationKey verificationKey = signer.getSignerPublicKey();
|
||||||
|
|
||||||
|
signer.loadVerificationCertificate(verificationKey);
|
||||||
|
|
||||||
|
BigInteger rawMsg = new BigInteger(50, rand);
|
||||||
|
Crypto.BigInteger usMsg = Crypto.BigInteger.newBuilder()
|
||||||
|
.setData(ByteString.copyFrom(rawMsg.toByteArray())).build();
|
||||||
|
|
||||||
|
signer.updateContent(usMsg);
|
||||||
|
Crypto.Signature sig = signer.sign();
|
||||||
|
|
||||||
|
signer.initVerify(sig);
|
||||||
|
signer.updateContent(usMsg);
|
||||||
|
assertTrue("Couldn't verify signature on ", signer.verify());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue