Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting RSA private key from PEM BASE64 Encoded private key file

I have a private key file (PEM BASE64 encoded). I want to use it else where to decrypt some other data.Using Java i tried to read the file and decode the BASE64 encoded data in it... This is the code snippet which i tried....

import java.io.*; import java.nio.ByteBuffer; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import com.ibm.crypto.fips.provider.RSAPrivateKey; import com.ibm.misc.BASE64Decoder;  public class GetPrivateKey {     public static RSAPrivateKey get() throws Exception {         File privateKeyFile = new File("privatekey.key");         byte[] encodedKey = new byte[(int) privateKeyFile.length()];         new FileInputStream(privateKeyFile).read(encodedKey);         ByteBuffer keyBytes = new BASE64Decoder().decodeBufferToByteBuffer(encodedKey.toString());         PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyBytes.array());         KeyFactory kf = KeyFactory.getInstance("RSA", "IBMJCEFIPS");         RSAPrivateKey pk = (RSAPrivateKey) kf.generatePrivate(privateKeySpec);         return pk;     }      public static void main(String[] args) throws Exception {         PrivateKey privKey = FormatMePlease.get();         System.out.println(privKey.toString());     }  } 

I am getting the following errors

Exception in thread "main" java.security.spec.InvalidKeySpecException: Inappropriate key specification: DerInputStream.getLength(): lengthTag=127, too big. at com.ibm.crypto.fips.provider.RSAKeyFactory.b(Unknown Source) at com.ibm.crypto.fips.provider.RSAKeyFactory.engineGeneratePrivate(Unknown Source) at java.security.KeyFactory.generatePrivate(Unknown Source) at GetPrivateKey.get(GetPrivateKey.java:24) at GetPrivateKey.main(GetPrivateKey.java:29) 

The contents of the file "privatekey.key"

-----BEGIN RSA PRIVATE KEY----- MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAF53wUbKmDHtvfOb8u1HPqEBFNNF csnOMjIcSEhAwIQMbgrOuQ+vH/YgXuuDJaURS85H8P4UTt6lYOJn+SFnXvS82E7LHJpVrWwQzbh2 QKh13/akPe90DlNTUGEYO7rHaPLqTlld0jkLFSytwqfwqn9yrYpM1ncUOpCciK5j8t8MzO71LJoJ g24CFxpjIS0tBrJvKzrRNcxWSRDLmu2kNmtsh7yyJouE6XoizVmBmNVltHhFaDMmqjugMQA2CZfL rxiR1ep8TH8IBvPqysqZI1RIpB/e0engP4/1KLrOt+6gGS0JEDh1kG2fJObl+N4n3sCOtgaz5Uz8 8jpwbmZ3Se8CAwEAAQKCAQAdOsSs2MbavAsIM3qo/GBehO0iqdxooMpbQvECmjZ3JTlvUqNkPPWQ vFdiW8PsHTvtackhdLsqnNUreKxXL5rr8vqi9qm0/0mXpGNi7gP3m/FeaVdYnfpIwgCe6lag5k6M yv7PG/6N8+XrWyBdwlOe96bGohvB4Jp2YFjSTM67QONQ8CdmfqokqJ8/3RyrpDvGN3iX3yzBqXGO jPkoJQv3I4lsYdR0nl4obHHnMSeWCQCYvJoZ7ZOliu/Dd0ksItlodG6s8r/ujkSa8VIhe0fnXTf0 i7lqa55CAByGN4MOR0bAkJwIB7nZzQKurBPcTAYJFFvAc5hgMnWT0XW83TehAoGBALVPGnznScUw O50OXKI5yhxGf/XDT8g28L8Oc4bctRzI+8YfIFfLJ57uDGuojO/BpqtYmXmgORru0jYR8idEkZrx gf62czOiJrCWTkBCEMtrNfFHQJQCQrjfbHofp7ODnEHbHFm7zdlbfNnEBBaKXxd2rVv4UTEhgftv wsHcimbXAoGBAIViWrHWElMeQT0datqlThE/u51mcK4VlV7iRWXVa1/gAP85ZAu44VvvDlkpYVkF zSRR+lHSOzsubDMN45OBQW6UA3RPg4TCvrTOmhQUeF5XPuSdcD0R2At6pdaLwAKnOtILg13Ha6ym Igjv8glodvem3hWLmpHIhNBiaXtf8wqpAoGADH5a8OhvKOtd8EChGXyp9LDW+HRw9vbyN/gi9dQX ltgyoUBb1jDllgoJSRHgRFUvyvbb/ImR5c03JwqtiQ8siWTC9G5WGeS+jcSNt9fVmG7W1L14MbrG Jj8fFns/7xrOlasnlPdgA+5N+CONtI/sZY2D/KZr0drhPhZBcWJlFxkCgYAn+4SOPEo/6hjKNhA6 vER7fSxDEVsDg+rDh3YgAWpvUdlaqBxqOyAqi600YugQZGHK2lv7vNYOdmrunuIx7BPuDqY+bjtR R4Mc9bVQAZbXSLXMl7j2RWwKfNhLSJbk9LX4EoVtTgLjvOUE4tAdq9fFgpqdwLwzqPTO9kECP4++ CQKBgH6tO/xcNxG/uXUideluAn3H2KeyyznZMJ7oCvzf26/XpTAMI243OoeftiKVMgxuZ7hjwqfn /VHXABc4i5gchr9RzSb1hZ/IqFzq2YGmbppg5Ok2cgwalDoDBi21bRf8aDRweL62mO+7aPnCQZ58 j5W72PB8BAr6xg0Oro25O4os -----END RSA PRIVATE KEY----- 

Similar questions have been posted here, but those were of no avail for me. Almost all of them suggested using Bouncycastle provider which am not willing to use as am supposed to use a provider which is FIPS compliant and am not sure if BC provider is FIPS compliant.

A help in gettin me out of this would be highly appreciated... Thanks in advance.

like image 209
v3nM Avatar asked Aug 27 '11 19:08

v3nM


People also ask

Does PEM file contain private key?

The following example PEM file contains the SSL certificate private and public keys, an intermediate certificate, and a root certificate.

Are private keys Base64 encoded?

A private key is an ASN. 1 data structure, serialized to a byte string using DER, and base64 encoded.


2 Answers

This is PKCS#1 format of a private key. Try this code. It doesn't use Bouncy Castle or other third-party crypto providers. Just java.security and sun.security for DER sequece parsing. Also it supports parsing of a private key in PKCS#8 format (PEM file that has a header "-----BEGIN PRIVATE KEY-----").

import sun.security.util.DerInputStream; import sun.security.util.DerValue;  import java.io.File; import java.io.IOException; import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.RSAPrivateCrtKeySpec; import java.util.Base64;  public static PrivateKey pemFileLoadPrivateKeyPkcs1OrPkcs8Encoded(File pemFileName) throws GeneralSecurityException, IOException {         // PKCS#8 format         final String PEM_PRIVATE_START = "-----BEGIN PRIVATE KEY-----";         final String PEM_PRIVATE_END = "-----END PRIVATE KEY-----";          // PKCS#1 format         final String PEM_RSA_PRIVATE_START = "-----BEGIN RSA PRIVATE KEY-----";         final String PEM_RSA_PRIVATE_END = "-----END RSA PRIVATE KEY-----";          Path path = Paths.get(pemFileName.getAbsolutePath());          String privateKeyPem = new String(Files.readAllBytes(path));          if (privateKeyPem.indexOf(PEM_PRIVATE_START) != -1) { // PKCS#8 format             privateKeyPem = privateKeyPem.replace(PEM_PRIVATE_START, "").replace(PEM_PRIVATE_END, "");             privateKeyPem = privateKeyPem.replaceAll("\\s", "");              byte[] pkcs8EncodedKey = Base64.getDecoder().decode(privateKeyPem);              KeyFactory factory = KeyFactory.getInstance("RSA");             return factory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedKey));          } else if (privateKeyPem.indexOf(PEM_RSA_PRIVATE_START) != -1) {  // PKCS#1 format              privateKeyPem = privateKeyPem.replace(PEM_RSA_PRIVATE_START, "").replace(PEM_RSA_PRIVATE_END, "");             privateKeyPem = privateKeyPem.replaceAll("\\s", "");              DerInputStream derReader = new DerInputStream(Base64.getDecoder().decode(privateKeyPem));              DerValue[] seq = derReader.getSequence(0);              if (seq.length < 9) {                 throw new GeneralSecurityException("Could not parse a PKCS1 private key.");             }              // skip version seq[0];             BigInteger modulus = seq[1].getBigInteger();             BigInteger publicExp = seq[2].getBigInteger();             BigInteger privateExp = seq[3].getBigInteger();             BigInteger prime1 = seq[4].getBigInteger();             BigInteger prime2 = seq[5].getBigInteger();             BigInteger exp1 = seq[6].getBigInteger();             BigInteger exp2 = seq[7].getBigInteger();             BigInteger crtCoef = seq[8].getBigInteger();              RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, exp1, exp2, crtCoef);              KeyFactory factory = KeyFactory.getInstance("RSA");              return factory.generatePrivate(keySpec);         }          throw new GeneralSecurityException("Not supported format of a private key");     } 
like image 72
ygalkin Avatar answered Sep 27 '22 02:09

ygalkin


You've just published that private key, so now the whole world knows what it is. Hopefully that was just for testing.

EDIT: Others have noted that the openssl text header of the published key, -----BEGIN RSA PRIVATE KEY-----, indicates that it is PKCS#1. However, the actual Base64 contents of the key in question is PKCS#8. Evidently the OP copy and pasted the header and trailer of a PKCS#1 key onto the PKCS#8 key for some unknown reason. The sample code I've provided below works with PKCS#8 private keys.

Here is some code that will create the private key from that data. You'll have to replace the Base64 decoding with your IBM Base64 decoder.

public class RSAToy {      private static final String BEGIN_RSA_PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----\n"             + "MIIEuwIBADAN ...skipped the rest\n"          // + ...             // + ... skipped the rest          // + ...                + "-----END RSA PRIVATE KEY-----";      public static void main(String[] args) throws Exception {          // Remove the first and last lines          String privKeyPEM = BEGIN_RSA_PRIVATE_KEY.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");         privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");         System.out.println(privKeyPEM);          // Base64 decode the data          byte [] encoded = Base64.decode(privKeyPEM);          // PKCS8 decode the encoded RSA private key          PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);         KeyFactory kf = KeyFactory.getInstance("RSA");         PrivateKey privKey = kf.generatePrivate(keySpec);          // Display the results          System.out.println(privKey);     } } 
like image 33
President James K. Polk Avatar answered Sep 27 '22 02:09

President James K. Polk