I know that there are several other questions about that topic, but none of them have helped me out. I tried the BouncyCastle lib as well. Could someone please help me here?
The PEM file looks like:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAq2eYtnTsEc/qyqS ...
... zY3WG++SA+amcXiO721hJWNC+uTbZ1bzQ==
-----END RSA PRIVATE KEY-----
I'm using this method
public static PrivateKey getPemPrivateKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
File f = new File(PEMFILES_FOLDER+filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
String temp = new String(keyBytes);
//TODO care about the linefeeds
String privKeyPEM = temp.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");
System.out.println("Private key: \n"+privKeyPEM);
Base64 b64 = new Base64();
byte [] decoded = b64.decode(privKeyPEM);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance(RSA);
return kf.generatePrivate(spec);
}
I am getting this error:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
I hope this can help you. I have copied a working copy of getPemPrivatekey and the way I call it in the main function:
public PrivateKey getPemPrivateKey(String filename, String algorithm) throws Exception {
File f = new File(filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
String temp = new String(keyBytes);
String privKeyPEM = temp.replace("-----BEGIN PRIVATE KEY-----", "");
privKeyPEM = privKeyPEM.replace("-----END PRIVATE KEY-----", "");
//System.out.println("Private key\n"+privKeyPEM);
BASE64Decoder b64=new BASE64Decoder();
byte[] decoded = b64.decodeBuffer(privKeyPEM);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePrivate(spec);
}
The main program looks like this:
....
gcsr = new ...... // instantiate the class here
privateKey= gcsr.getPemPrivateKey("c:\\testdir\\java_private.pem", "RSA");
BASE64Encoder encoder1= new BASE64Encoder();
String s1=encoder1.encodeBuffer(gcsr.getPrivateKey().getEncoded());
System.out.println("Private Key in Base64:"+s1+"\n");
This is currently working (Java 8 on my computer!). "gcsr" is the name of the object I instantiated from the class containing the function.
Regards.
Related
I have a String stored in a variable:
-----BEGIN RSA PUBLIC KEY-----
MIGHAoGBANAahj75ZIz9nXqW2H83nGcUao4wNyYZ9Z1kiNTUYQl7ob/RBmDzs5rY
mUahXAg0qyS7+a55eU/csShf5ATGzAXv+DDPcz8HrSTcHMEFpuyYooX6PrIZ07Ma
XtsJ2J4mhlySI5uOZVRDoaFY53MPQx5gud2quDz759IN/0gnDEEVAgED
-----END RSA PUBLIC KEY-----
I generate public key as:
public static PublicKey getFromString(String keystr) throws Exception
{
//String S1= asciiToHex(keystr);
byte[] keyBytes = new sun.misc.BASE64Decoder().decodeBuffer(keystr);
ASN1InputStream in = new ASN1InputStream(keyBytes);
DERObject obj = in.readObject();
RSAPublicKeyStructure pStruct = RSAPublicKeyStructure.getInstance(obj);
RSAPublicKeySpec spec = new RSAPublicKeySpec(pStrcut.getModulus(), pStruct.getPublicExponent());
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
How to generate the PrivateKey using bouncy castle in android
{Edit}
Without using bouncy castle i am generating private key like this:
public static PrivateKey getKey(String mKey){
try{
// Read in the key into a String
StringBuilder pkcs8Lines = new StringBuilder();
BufferedReader rdr = new BufferedReader(new StringReader(mKey));
String line;
while ((line = rdr.readLine()) != null) {
pkcs8Lines.append(line);
}
// Remove the "BEGIN" and "END" lines, as well as any whitespace
String pkcs8Pem = pkcs8Lines.toString();
pkcs8Pem = pkcs8Pem.replace("-----BEGIN RSA PRIVATE KEY-----", "");
pkcs8Pem = pkcs8Pem.replace("-----END RSA PRIVATE KEY-----", "");
pkcs8Pem = pkcs8Pem.replaceAll("\\s+","");
// Base64 decode the result
byte [] pkcs8EncodedBytes = Base64.decode(pkcs8Pem, Base64.DEFAULT);
// extract the private key
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8EncodedBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privKey = kf.generatePrivate(keySpec);
System.out.println(privKey);
return privKey;
}catch (Exception ex){
ex.printStackTrace();
}
return null;
}
I want to achieve the same using Bouncy Castle
I'm a little confused on why you insist on using bouncycastle, but if you really want to use bouncycastle then the CMS/PKIX library has a nice helper class called PEMParser that will shorten the code needed, e.g:
public static PrivateKey getPemPrivateKey(String mKey) throws Exception {
PEMParser pemParser = new PEMParser(new StringReader(mKey));
final PEMKeyPair pemKeyPair = (PEMKeyPair) pemParser.readObject();
final byte[] encoded = pemKeyPair.getPrivateKeyInfo().getEncoded();
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
}
I have a RSA public key file like this:
-----BEGIN RSA PUBLIC KEY-----
this is content
-----END RSA PUBLIC KEY-----
and i use java to read it:
KeyFactory factory = KeyFactory.getInstance("RSA");
KeySpec spec = new X509EncodedKeySpec(bytesFromThisFile); // bytesFromThisFile is created and filled correctly
PublicKey publicKey = factory.generatePublic(spec);
then i get an exception:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
How to read the file properly? Is there a way to convert this rsa public key file to a java-readable format?
Try this method:
/**
* reads a public key from a file
* #param filename name of the file to read
* #param algorithm is usually RSA
* #return the read public key
* #throws Exception
*/
public PublicKey getPemPublicKey(String filename, String algorithm) throws Exception {
File f = new File(filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
String temp = new String(keyBytes);
String publicKeyPEM = temp.replace("-----BEGIN PUBLIC KEY-----\n", "");
publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
BASE64Decoder b64 = new BASE64Decoder();
byte[] decoded = b64.decodeBuffer(publicKeyPEM);
X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePublic(spec);
}
source: Load RSA public key from file
This is my implementation; can read PEM with key or certificate.
Tested only in java11.
/**
* reads a public key from a file
* #param f file to read
* #return the read public key
* #throws Exception
*/
public static PublicKey getPublicKeyFromPem(File f)
throws Exception
{
byte[] keyBytes = Files.readAllBytes(f.toPath());
String temp = new String(keyBytes);
String publicKeyPEM = temp;
if(temp.contains("-----BEGIN PUBLIC KEY-----"))
{
publicKeyPEM = temp
.replace("-----BEGIN PUBLIC KEY-----\n", "")
.replace("-----END PUBLIC KEY-----", "")
.trim();
}
else if(temp.contains("-----BEGIN RSA PUBLIC KEY-----"))
{
publicKeyPEM = temp
.replace("-----BEGIN RSA PUBLIC KEY-----\n", "")
.replace("-----END RSA PUBLIC KEY-----", "")
.trim();
}
else if(temp.contains("-----BEGIN CERTIFICATE-----"))
{
CertificateFactory fact = CertificateFactory.getInstance("X.509");
try (FileInputStream is = new FileInputStream(f))
{
X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
return cer.getPublicKey();
}
}
Base64.Decoder b64 = Base64.getDecoder();
byte[] decoded = b64.decode(publicKeyPEM);
X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
I'm trying to create a private key object from a given .pem file. The file has this structure:
-----BEGIN EC PRIVATE KEY-----
...............................
...............................
...............................
-----END EC PRIVATE KEY-----
I am attempting to create the private key object with this code:
public static String getKeyFromFile(String filename) throws IOException {
File f = new File(filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
String key = new String(keyBytes);
return key;
}
public static PrivateKey getPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, NoSuchProviderException {
String privateKeyPEM = getKeyFromFile("MY_FILE.pem");
privateKeyPEM = privateKeyPEM.replace("-----BEGIN EC PRIVATE KEY-----\n", "");
privateKeyPEM = privateKeyPEM.replace("-----END EC PRIVATE KEY-----", "");
privateKeyPEM = privateKeyPEM.replaceAll("\n", "");
privateKeyPEM = privateKeyPEM.replaceAll(" ", "");
byte[] privateKeyBytes = privateKeyPEM.getBytes();
String encodedString = Base64.getEncoder().encodeToString(privateKeyBytes);
byte[] decodedString = Base64.getDecoder().decode(encodedString);
EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(decodedString);
KeyFactory kf = KeyFactory.getInstance("EC");
PrivateKey privKey = kf.generatePrivate(privKeySpec);
return privKey;
Upon running this method, I receive this error:
java.security.InvalidKeyException: invalid key format
I am able to parse the text and strip away any unwanted characters just fine, but I'm not able to create the private key object. I am able to generate a public key object from a similar .crt file using very similar methods. I want to be able to do this solely within Java and no openssl. Any help would be greatly appreciated.
Your code does not properly decode the base64 data:
privateKeyPEM contains the String data between the BEGIN and END data (which is base64 encoded).
Your code does the following:
byte[] privateKeyBytes = privateKeyPEM.getBytes();
// privateKeyBytes now contains the base64 encoded key data
String encodedString = Base64.getEncoder().encodeToString(privateKeyBytes);
// encoded String contains now the base64 encoded data of the base64 encoded key data
byte[] decodedString = Base64.getDecoder().decode(encodedString);
// decodedString is not the base64 encoded data of your key data
Why are you encoding the data base64 and then in the next line decoding it - both steps together are just useless.
What you really need is to apply the base64 decode one time onto privateKeyPEM:
byte[] keyData = Base64.getDecoder().decode(privateKeyPEM);
EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(keyData);
If the base64 decode fails then your base64 data is invalid - most likely because of contained spaces or \r.
I'm new to Cryptography.
I would like to generate RSA key in java and write it to a file. Later I would like to read from that file and get the RSA key back.
Code for key generation and writing to file :
public void generate() throws Exception{
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kpair = kpg.genKeyPair();
byte[] publicKeyBytes = kpair.getPublic().getEncoded();
FileOutputStream fos = new FileOutputStream("publicKey");
fos.write(publicKeyBytes);
fos.close();
}
Code for reading and getting back the RSA public key :
public static Key getKeyFromFile(String fileName) throws Exception{
Key pk = null;
File f = new File(fileName);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int)f.length()];
dis.readFully(keyBytes);
dis.close();
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
pk = kf.generatePublic(spec);
return pk;
}
When I run the program I get the following error :
algid parse error, not a sequence
Cannot figure out what's wrong.
I try in this code to verify my code, I have public key , my data and signature.I am read my signature from file and convert my string to public key then get my data and verify to signature.
public static boolean verify () {
String publickey = "MIGfMA0GCSqGSIb3DQE";
byte[] encKey = Base64.decodeBase64(publickey.getBytes());
try {
byte[] MACaddress = GetData();
BufferedReader in = new BufferedReader(new FileReader(
"EndSignatuer.txt"));
FileInputStream keyfis = new FileInputStream("EndSignatuer.txt");
byte[] Signen = new byte[keyfis.available()];
keyfis.read(Signen);
keyfis.close();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pubKey);
byte[] deSignen = Base64.decodeBase64(Signen);
byte[] decrypted_digest = cipher.doFinal(deSignen);
MessageDigest md5_digest = MessageDigest.getInstance("MD5");
md5_digest.update(MACaddress);
byte[] digest = md5_digest.digest();
if (decrypted_digest == digest) {
return true;
}else {
return false;//her why give me false
}
Code encryption:
public static void GenarationKEY(byte[] data) {
try {
File fileEndSignatuer = new File("EndSignatuer.txt");
FileOutputStream fopEndSignatuer = new FileOutputStream(
fileEndSignatuer);
// /Read private key from file
FileInputStream keyfis = new FileInputStream("PiveteKey.txt");
byte[] PrivateKeyB = new byte[keyfis.available()];
keyfis.read(PrivateKeyB);
keyfis.close();
byte[] decodePrivetekey = Base64.decodeBase64(PrivateKeyB);
// /get private key
PKCS8EncodedKeySpec pubKeySpec = new PKCS8EncodedKeySpec(
decodePrivetekey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privKey = keyFactory.generatePrivate(pubKeySpec);
// / make hash
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privKey);
// /make encoding
MessageDigest md5_digest = MessageDigest.getInstance("MD5");
byte[] digest = md5_digest.digest(data);
byte[] cipherText = cipher.doFinal(digest);
byte[] degnatureencode = Base64.encodeBase64(cipherText);
fopEndSignatuer.write(degnatureencode);
fopEndSignatuer.flush();
fopEndSignatuer.close();
}
First of all, what you do is not quite RSA digital signature. Use Signature class instead of combination Cipher and MessageDigest. Or if you insist to do it on low level, then consult specification, particularly section 9.2.
Secondly, string MIGfMA0GCSqGSIb3DQE doesn't represent RSA public key neither it is proper Base64-encoded data.
Also you want to use Arrays.equals(byte[], byte[]) instead of equality operator, as the latter just ensures that array object is the same, while the former compares actual content of the arrays.