Invalid key exception : Algid parse error, not a sequence [duplicate] - java

When trying to read a RSA private key from a file using the method
public PrivateKey getPrivateKey()
throws NoSuchAlgorithmException,
InvalidKeySpecException, IOException {
final InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream("privatekey");
byte[] privKeyBytes = null;
try {
privKeyBytes = IOUtils.toByteArray(inputStream);
} catch (final IOException exception) {
LOGGER.error("", exception);
IOUtils.closeQuietly(inputStream);
}
LOGGER.debug("privKeyBytes: {}", privKeyBytes);
String BEGIN = "-----BEGIN RSA PRIVATE KEY-----";
String END = "-----END RSA PRIVATE KEY-----";
String str = new String(privKeyBytes);
if (str.contains(BEGIN) && str.contains(END)) {
str = str.substring(BEGIN.length(), str.lastIndexOf(END));
}
KeyFactory fac = KeyFactory.getInstance("RSA");
EncodedKeySpec privKeySpec =
new PKCS8EncodedKeySpec(Base64.decode(str.getBytes()));
return fac.generatePrivate(privKeySpec);
}
I get the exception
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:200) ~[na:1.6.0_23]
at java.security.KeyFactory.generatePrivate(KeyFactory.java:342) ~[na:1.6.0_23]
at the fac.generatePrivate(privKeySpec) call.
What does this error mean?
Thanks
Dmitri

I was having this same issue, and the format of the key was NOT the actual problem.
All I had to do to get rid of that exception was to call
java.security.Security.addProvider(
new org.bouncycastle.jce.provider.BouncyCastleProvider()
);
and everything worked

It means your key is not in PKCS#8 format. The easiest thing to do is to use the openssl pkcs8 -topk8 <...other options...> command to convert the key once. Alternatively you can use the PEMReader class of the Bouncycastle lightweight API.

You must make your PCKS8 file from your private key!
private.pem => name of private key file
openssl genrsa -out private.pem 1024
public_key.pem => name of public key file
openssl rsa -in private.pem -pubout -outform PEM -out public_key.pem
‫‪private_key.pem‬‬ => name of private key with PCKS8 format! you can just read this format in java
openssl pkcs8 -topk8 -inform PEM -in private.pem -out private_key.pem -nocrypt

Related

Decrypt File in Java Encrypted via openssl generated (S/Mime) key pair

I am trying to decrypt files that were encrypted using an openssl generated public key. I have the key pair that was generated in openssl and can decrypt files with the private key within openssl. However, I am now tasked with decrypting the files in a Java application, using the same private key that was generated via openssl. I have gotten as far as reading the private key into an java.security.PrivateKey object successfully, using Bouncy Castle libraries. I have written (with the help of code I found in various stack overflow posts) three decryption methods, but get various exceptions with each one. I will provide the openssl commands below and also the Java code I used to read in the private key and one of the decrytion methods I've tried.
Generate key pair with openssl:
openssl genrsa -aes256 -out my-private-key.pem 4096
openssl req -new -x509 -days 730 -key my-private-key.pem -out my-public-key.pem
encrypt file
openssl smime -binary -encrypt -in test.file -out test.file.enc my-public-key.pem
decrypt file
openssl smime -binary -decrypt -inkey ecn-private-key.pem -in test.file.enc -out test.file.dec
(Enter pass phrase for my-private-key.pem)
public key header
-----BEGIN CERTIFICATE-----
private key header
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,4EFFB692F0BEBF75B183DB1371979B97
// read private key - this is successful
private static PrivateKey readPrivateKeyPEM(File file, String password) throws IOException,
GeneralSecurityException, OperatorCreationException, PKCSException {
try (FileReader reader = new FileReader(file)) {
PEMParser parser = new PEMParser(reader);
Object object = parser.readObject();
if (object == null) {
throw new IllegalArgumentException("No key found in " + file);
}
BouncyCastleProvider provider = new BouncyCastleProvider();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(provider);
PEMDecryptorProvider decryptionProvider = new
JcePEMDecryptorProviderBuilder().setProvider(provider).build(password.toCharArray());
PEMKeyPair keypair = ((PEMEncryptedKeyPair) object).decryptKeyPair(decryptionProvider);
return converter.getPrivateKey(keypair.getPrivateKeyInfo());
}
}
// The following method attempts to decrypt file with private key read in above
fails
// this fails
public static void decrypt(PrivateKey privateKey, File encrypted, File decryptedDestination)
throws IOException, CMSException {
byte[] encryptedData = Files.readAllBytes(encrypted.toPath());
CMSEnvelopedDataParser parser = new CMSEnvelopedDataParser(encryptedData);
RecipientInformation recInfo = getSingleRecipient(parser);
Recipient recipient = new JceKeyTransEnvelopedRecipient(privateKey);
try (InputStream decryptedStream = recInfo.getContentStream(recipient).getContentStream()) {
Files.copy(decryptedStream, decryptedDestination.toPath());
}
}
The stack trace is:
Exception in thread "main" org.bouncycastle.cms.CMSException: Unexpected object reading content.
at org.bouncycastle.pkix#1.68/org.bouncycastle.cms.CMSContentInfoParser.(Unknown Source)
at org.bouncycastle.pkix#1.68/org.bouncycastle.cms.CMSEnvelopedDataParser.(Unknown Source)
at org.bouncycastle.pkix#1.68/org.bouncycastle.cms.CMSEnvelopedDataParser.(Unknown Source)
at com.att.floodportal.openssl.EncryptAndDecrypt.decrypt(EncryptAndDecrypt.java:32)
at com.att.floodportal.openssl.JavaSecurityPemUtils.main(JavaSecurityPemUtils.java:77)
Caused by: java.lang.ClassCastException: class org.bouncycastle.asn1.DLApplicationSpecific cannot be cast to class org.bouncycastle.asn1.ASN1SequenceParser (org.bouncycastle.asn1.DLApplicationSpecific and org.bouncycastle.asn1.ASN1SequenceParser are in module org.bouncycastle.provider#1.68 of loader 'app')
Thank You

InvalidKeySpecException: How do I extract a private key from a .der file?

I have a private key file in the .der format. I'm trying to save this private key as a PrivateKey object (with Java) like this:
PrivateKey clientPrivKey = getPrivateKeyFromKeyFile("C:\\Users\\Bob\\Desktop\\Assignments\\Project\\VPN Project\\src\\client-private.der");
This is what the getPrivateKeyFromKeyFile method looks like:
private static PrivateKey getPrivateKeyFromKeyFile(String keyfile) throws Exception
{
Path path = Paths.get(keyfile);
byte[] privKeyByteArray = Files.readAllBytes(path);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyByteArray);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec);
return myPrivKey;
}
But when I try this, I keep getting InvalidKeySpecException because of this line of code:
PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec);
I'm not sure what's the issue here. I opened up the private key file and everything looks fine. It starts with -----BEGIN RSA PRIVATE KEY----- and ends with -----END RSA PRIVATE KEY-----.
And in case it's relevant, I created this private key using this OpenSSL command:
genrsa -out client-private.der 2048
A file generated with
openssl genrsa -out <path to output-file> 2048
is actually not a .der-file, but a .pem-file (see e.g. What are the differences between .pem, .cer and .der?) and the data are not stored in the PKCS8-format, but in the PKCS1-format (see e.g. PKCS#1 and PKCS#8 format for RSA private key).
Keys in the PKCS1-format can not be processed directly using standard Java tools. For this, third-party libraries like BouncyCastle are necessary (see e.g. Read RSA private key of format PKCS1 in JAVA).
Another possibility is to convert the PKCS1-formatted key into a PKCS8-formatted key with OpenSSL first (see e.g. Load a RSA private key in Java (algid parse error, not a sequence)):
openssl pkcs8 -topk8 -inform PEM -outform PEM -in <path to the input-pkcs1-pem-file> -out <path to the output-pkcs8-pem-file> -nocrypt
And then, after (programmatic) deletion of the Beginn-/End-line and after base64-decoding the private key can be generated (see e.g. How to read .pem file to get private and public key) e.g. with
private static PrivateKey getPrivateKeyFromKeyFile(String keyfile) throws Exception
{
Path path = Paths.get(keyfile);
byte[] privKeyByteArray = Files.readAllBytes(path);
// added ----------------------------------------------------------------
String privKeyString = new String(privKeyByteArray);
privKeyString = privKeyString.replace("-----BEGIN PRIVATE KEY-----", "");
privKeyString = privKeyString.replace("-----END PRIVATE KEY-----", "");
privKeyString = privKeyString.replace("\r\n", "");
privKeyByteArray = Base64.getDecoder().decode(privKeyString);
// ----------------------------------------------------------------------
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyByteArray);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec);
return myPrivKey;
}

How to read EC Private key in java which is in .pem file format

How to read EC private key which is in. Pem file using JAVA. While reading I am getting the following exception.
Caused by: java.security.InvalidKeyException: IOException : version mismatch: (supported: 00, parsed: 01
Actually my. Pem file contains private key in the following structure.
----BEGIN EC PRIVATE KEY ------
====+====+===
====+====+===
-----END EC PRIVATE KEY-----
From an EC PRIVATE KEY as requested (ex key.pem), I succeeded to import it in a java.security.KeyStore
transform private key from PEM => PKCS#8 DER
openssl pkcs8 -in key.pem -inform PEM -topk8 -nocrypt -out key-pkcs8.der -outform DER
load it (jvm version java-1.8.0-openjdk-1.8.0.201.b09-2.fc28.x86_64)
void loadPrivateKey(KeyStore ks, X509Certificate cert){
File privKeyFile = new File("key-pkcs8.der");
// read private key DER file
DataInputStream dis = new DataInputStream(new FileInputStream(privKeyFile));
byte[] privKeyBytes = new byte[(int)privKeyFile.length()];
dis.read(privKeyBytes);
dis.close();
KeyFactory kf = KeyFactory.getInstance("EC");
// decode private key
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privKeyBytes);
PrivateKey privKey = kf.generatePrivate(privSpec);
ks.setKeyEntry("key-alias", privKey, "password".toCharArray(), new Certificate[] {cert});
}

How to generate same type of ecdsa keypair in java as generated by openssl?

I am executing the following command to generate ecdsa keypair on my machine:
openssl ecparam -genkey -name secp256k1 -noout -outform DER -out private.key and on executing this next command openssl ec -inform DER -in private.key -noout -text, I get the following output:
read EC key
Private-Key: (256 bit)
priv:
//private key
pub:
04:64:0a:f7:e6:e1:a9:7f:d3:b2:ec:ad:f1:41:96:
ee:c1:c2:e7:02:4a:54:42:ab:e8:da:9f:88:e1:02:
46:aa:32:91:38:b5:9e:37:fc:96:d9:36:02:07:de:
74:59:c4:a8:e0:2b:21:3a:d4:70:7d:5e:92:54:22:
65:80:0f:df:fd
ASN1 OID: secp256k1
Now what I'm interested in is the above public key without colons i.e. 04640af7e6e1a97fd3b2ecadf14196eec1c2e7024a5442abe8da9f88e10246aa329138b59e37fc96d9360207de7459c4a8e02b213ad4707d5e92542265800fdffd. I need to send to this public key to an api call which validates whether the key is valid or not. The key generated by openssl when sent with the api call is accepted by the server as valid.
But the public ecdsa key generated in java when sent with the api call is rejected. I'm using following code to generate keypair
public KeyPair getECDSAKeyPair() throws NoSuchProviderException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "SC");
ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
keyPairGenerator.initialize(spec, new SecureRandom());
return keyPairGenerator.generateKeyPair();
}
public String getHexPublicKeyString(KeyPair keypair) {
PublicKey publicKey = keypair.getPublic();
return Hex.toHexString(publicKey.getEncoded());
}
My question is how can I generate same type of ECDSA keypair as generated by the OpenSSL? And what is the difference between the keys generated by OpenSSL and the code generated by java such that key generated by OpenSSL is accepted whereas key generated by java is rejected?
I was able to generate the required public through following method using SpongyCastle:
public static String getHexEncodedPublicKey(PublicKey publicKey) throws IOException, InvalidKeyException {
ECPublicKeyParameters ecPublicKeyParameters
= (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
byte[] encoded = ecPublicKeyParameters.getQ().getEncoded(false);
return Hex.toHexString(encoded);
}

RSA Encryption: Java to PHP

I'm trying to implement RSA Encryption in both Java and PHP, but I can't seem to get PHP to recognize my Java public/private keys. Here is the java code to Encode/Decode the Public and Private Keys:
public static byte[] EncodePublicKey(PublicKey _publickey) throws Exception
{
return _publickey.getEncoded();
}
public static PublicKey DecodePublicKey(byte[] _encodedkey) throws Exception
{
KeyFactory fac = KeyFactory.getInstance("RSA");
X509EncodedKeySpec encodedKey = new X509EncodedKeySpec(_encodedkey);
return fac.generatePublic(encodedKey);
}
public static byte[] EncodePrivateKey(PrivateKey _privatekey) throws Exception
{
return _privatekey.getEncoded();
}
public static PrivateKey DecodePrivateKey(byte[] _encodedkey) throws Exception
{
KeyFactory fac = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec encodedKey = new PKCS8EncodedKeySpec(_encodedkey);
return fac.generatePrivate(encodedKey);
}
I first tried using the PEAR Crypt_RSA functions, but it doesn't support X.509 or PKCS8 (it just simply base64 encodes the serialized modulus, exponent and key type). I then tried the OpenSSL "openssl_get_publickey" function but it doesn't appear to recognize the format either.
Any help would be greatly appreciated o.O
You need to convert the binary format (DER) from Java to PEM for OpenSSL (and the PHP bindings). You can test your Java key files using the OpenSSL command line by specifying the -inform DER option on the command line.
<?
function pem2der($pem_data) {
$begin = "KEY-----";
$end = "-----END";
$pem_data = substr($pem_data, strpos($pem_data, $begin)+strlen($begin));
$pem_data = substr($pem_data, 0, strpos($pem_data, $end));
$der = base64_decode($pem_data);
return $der;
}
function der2pem($der_data) {
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "-----BEGIN PUBLIC KEY-----\n".$pem."-----END PUBLIC KEY-----\n";
return $pem;
}
// load the public key from a DER-encoded file
$pubkey = der2pem(file_get_contents("pubkey"));
?>
For more information about using OpenSSL keys in Java, check out this link.
The PHP functions require PEM encoded keys. It's trivial to convert DER encoded keys into PEM.
Here is my code to convert PKCS#8 private key to PEM,
function pkcs8_to_pem($der) {
static $BEGIN_MARKER = "-----BEGIN PRIVATE KEY-----";
static $END_MARKER = "-----END PRIVATE KEY-----";
$value = base64_encode($der);
$pem = $BEGIN_MARKER . "\n";
$pem .= chunk_split($value, 64, "\n");
$pem .= $END_MARKER . "\n";
return $pem;
}
For public key in X509, replace PRIVATE with PUBLIC in markers.
http://code.google.com/p/simplersalibrary/ is a simple tool, if you want encrypt something in Java and decrypt in PHP or encrypt in java and decrypt in PHP, simplersa can also generate the pem files for PHP.
You can also try to use CastleCrypt, which allows a easy to use RSA Encryption in JAVA AND PHP: https://github.com/wessnerj/CastleCrypt
For the key generation you may want to try it with openssl:
openssl genrsa -out privateKey.pem 2048
openssl pkcs8 -topk8 -nocrypt -in privateKey.pem -outform der -out privateKey.der
openssl rsa -in privateKey.pem -pubout -outform PEM -out publicKey.pem
openssl rsa -in privateKey.pem -pubout -outform DER -out publicKey.der
This commands gives you private and public key in both DER and PEM Format. For JAVA you have to use the .der keys and for PHP the .pem keys.

Categories