org.cryptacular.asn.OpenSSLPrivateKeyDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cryptacular Show documentation
Show all versions of cryptacular Show documentation
The spectacular complement to the Bouncy Castle crypto API for Java.
/* See LICENSE for licensing and NOTICE for copyright. */
package org.cryptacular.asn;
import java.math.BigInteger;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.cryptacular.EncodingException;
import org.cryptacular.pbe.OpenSSLAlgorithm;
import org.cryptacular.pbe.OpenSSLEncryptionScheme;
import org.cryptacular.util.ByteUtil;
import org.cryptacular.util.CodecUtil;
import org.cryptacular.util.PemUtil;
/**
* Decrypts PEM-encoded OpenSSL "traditional" format private keys.
*
* @author Middleware Services
*/
public class OpenSSLPrivateKeyDecoder extends AbstractPrivateKeyDecoder
{
@Override
protected byte[] decryptKey(final byte[] encrypted, final char[] password)
{
final String pem = new String(encrypted, ByteUtil.ASCII_CHARSET);
final int start = pem.indexOf(PemUtil.DEK_INFO);
final int eol = pem.indexOf('\n', start);
final String[] dekInfo = pem.substring(start + 10, eol).split(",");
final String alg = dekInfo[0];
final byte[] iv = CodecUtil.hex(dekInfo[1]);
final byte[] bytes = PemUtil.decode(encrypted);
return new OpenSSLEncryptionScheme(OpenSSLAlgorithm.fromAlgorithmId(alg), iv, password).decrypt(bytes);
}
@Override
protected AsymmetricKeyParameter decodeASN1(final byte[] encoded)
{
final ASN1InputStream stream = new ASN1InputStream(encoded);
final ASN1Object o;
try {
o = stream.readObject();
} catch (Exception e) {
throw new EncodingException("Invalid encoded key", e);
}
final AsymmetricKeyParameter key;
if (o instanceof ASN1ObjectIdentifier) {
// EC private key with named curve in the default OpenSSL format emitted
// by openssl ecparam -name xxxx -genkey
try {
key = parseECPrivateKey(ASN1Sequence.getInstance(stream.readObject()));
} catch (Exception e) {
throw new EncodingException("Invalid encoded key", e);
}
} else {
// OpenSSL "traditional" format is an ASN.1 sequence of key parameters
// Detect key type based on number and types of parameters:
// RSA -> {version, mod, pubExp, privExp, prime1, prime2, exp1, exp2, c}
// DSA -> {version, p, q, g, pubExp, privExp}
// EC -> {version, privateKey, parameters, publicKey}
final ASN1Sequence sequence = ASN1Sequence.getInstance(o);
if (sequence.size() == 9) {
// RSA private certificate key
key = new RSAPrivateCrtKeyParameters(
ASN1Integer.getInstance(sequence.getObjectAt(1)).getValue(),
ASN1Integer.getInstance(sequence.getObjectAt(2)).getValue(),
ASN1Integer.getInstance(sequence.getObjectAt(3)).getValue(),
ASN1Integer.getInstance(sequence.getObjectAt(4)).getValue(),
ASN1Integer.getInstance(sequence.getObjectAt(5)).getValue(),
ASN1Integer.getInstance(sequence.getObjectAt(6)).getValue(),
ASN1Integer.getInstance(sequence.getObjectAt(7)).getValue(),
ASN1Integer.getInstance(sequence.getObjectAt(8)).getValue());
} else if (sequence.size() == 6) {
// DSA private key
key = new DSAPrivateKeyParameters(
ASN1Integer.getInstance(sequence.getObjectAt(5)).getValue(),
new DSAParameters(
ASN1Integer.getInstance(sequence.getObjectAt(1)).getValue(),
ASN1Integer.getInstance(sequence.getObjectAt(2)).getValue(),
ASN1Integer.getInstance(sequence.getObjectAt(3)).getValue()));
} else if (sequence.size() == 4) {
// EC private key with explicit curve
key = parseECPrivateKey(sequence);
} else {
throw new EncodingException("Invalid OpenSSL traditional private key format.");
}
}
return key;
}
/**
* Parses an EC private key as defined in RFC 5915.
*
* ECPrivateKey ::= SEQUENCE {
* version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
* privateKey OCTET STRING,
* parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
* publicKey [1] BIT STRING OPTIONAL
* }
*
*
* @param seq ASN1 sequence to parse
*
* @return EC private key
*/
private ECPrivateKeyParameters parseECPrivateKey(final ASN1Sequence seq)
{
final ASN1TaggedObject asn1Params = ASN1TaggedObject.getInstance(seq.getObjectAt(2));
final X9ECParameters params;
if (asn1Params.getObject() instanceof ASN1ObjectIdentifier) {
params = ECUtil.getNamedCurveByOid(ASN1ObjectIdentifier.getInstance(asn1Params.getObject()));
} else {
params = X9ECParameters.getInstance(asn1Params.getObject());
}
return new ECPrivateKeyParameters(
new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets()),
new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH(), params.getSeed()));
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy