Problem decrypting a Java RSA/ECB/PKCS1Padding encrypted string in Swift - java

My iOS app needs to decrypt a string that was encrypted on a Java backend. The backend encrypts the string using these parameters: Cipher.getInstance("RSA/ECB/PKCS1Padding").
As a simple proof of concept, using OpenSSL from the Terminal I extracted the private key from the pfx certificate that they sent me:
$ openssl pkcs12 -in certificate.pfx -nocerts -out key.pem -nodes
$ openssl rsa -in key.pem -out server.key
Then, I hardcoded the private key as a String in my code and tried to decrypt the encrypted message using the SwiftyRSA lib:
import UIKit
import SwiftyRSA
class ViewController: UIViewController {
private let rsaPemPrivateKey = """
-----BEGIN RSA PRIVATE KEY-----
THE ACTUAL PRIVATE KEY...
-----END RSA PRIVATE KEY-----
"""
private let encryptedString = "ciSvTLKRAMqz8d8SEX8epvkyyrfAoiX28Sd1RhYbsz7oOg3/taXZxZkTeCbVeFXB8Mf8eWn2SGMcVIrmFGuxqyRoC5SluJDgrup0wcG/XRg7lrt7oD6esVBAGZT5nmS79mUoAC4CKW5cHclCh66JUysATSIvI9qrrXNUnBApGJc="
override func viewDidLoad() {
super.viewDidLoad()
do {
try decryptWithPrivateKey()
} catch {
print("Exception:")
print(error)
}
}
private func decryptWithPrivateKey() throws {
let privateKey = try PrivateKey(pemEncoded: rsaPemPrivateKey)
let encrypted = try EncryptedMessage(base64Encoded: encryptedString)
let clear = try encrypted.decrypted(with: privateKey, padding: SecPadding.PKCS1)
print("Decrypted string is: \(try clear.string(encoding: .utf8))")
}
}
This results in the following error, when the method encrypted.decrypted is called:
Exception:
chunkDecryptFailed(index: 0)
I also tried with other libraries, but similar errors occurred.
Here's the result with the SwiftRSA lib:
Exception:
decryptionFailed(error: Optional(Error Domain=NSOSStatusErrorDomain Code=-50 "RSAdecrypt wrong input (err -1)" UserInfo={NSDescription=RSAdecrypt wrong input (err -1)}))
And here's the result with the SwCrypt lib:
Exception:
decodeError
I'm not sure what could be wrong here. At first I thought the problem might be with the private key, but none of the libraries throw an exception when I instantiate their corresponding PrivateKey objects with it. Perhaps the problem is with the encrypted string I'm trying to decrypt, but it seems that no base64 decoding is required, as the EncryptedMessage object expects a base 64 encoded string anyway.
Is there anything else I can try to decrypt this RSA/ECB/PKCS1Padding encrypted string in Swift? (although in Java they pass ECB as the mode of operation, it looks like it don't actually use ECB under the hood, so I don't think I need to implement any custom management of the block size of the encrypted string as they say here).
-- Edit --
Here's a few other details as requested by zaitsman:
Dummy certificate's private key:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAt+733lAMe2uhg3pLdhv///wuwYtlJNiRbC3xfz6y/9qkXoDn
3yKleJtw1JI7e1uZIN1h/bY4DUezSDuqio7VpHZ8VpnQ3pm9U87Fozpaqi/62hqM
MzQ7B7lWsrSUrcjgEDZAWehWLdMEZiRlgQL3IeUT8bh4YMMXL9a+3gf+dUHLge5J
FIVJ/3VjyPbRn/05KxPlUwxtkP5TIAMWsJkNbO38i+ymQ9GFhBuaV2rOC2WOV3eo
VMd7LqfIBhPdA/CDpYuo/ZxVPdY2OOdXTPX1JY2qKzoE4sqUrlwzuYaqLbGR6nU+
ZSMUVtivZN+fTCWS6HcmNvEmB14I5DTWJ5BjaQIDAQABAoIBABKS5SDkAH6uHb9D
KD+jEDTvaGFPDEWuQPElqo9o63Z+w75vUfrsar1FJR2yLqOEWnBBKtYOApcEuIwA
ynX3eoeDF4c/PSJdcAr4hGi5SdKJydEggSviiFt9Uc32AlWSRV4dvF3X4mv6NSWD
Y2SlwgMAOQVd1Xof+UVxcBDHyeBZOmFIVkvs+JKDKLAA+Gw6uCmQ+m2kUUtEAh7G
yPQdbqwYdi6vnyVOTRfoyC6J/fmRh0P3ZJtWEctGmlkGVVDt8qYHDwKrtACsbsXh
2dRkVOIUM4JclCK9vh/1xFpn9m+yaAI8c8XXLuN9ZyglDM9nmF6iPrf1n7DRDVRU
lRqO6okCgYEAv0+lTquO1S0RbCSzGCkKJ59JP12PknJQHC9zM6Psa0gd1LN3LYQ3
byEjCmJJhhAnBw95PuTF/B0ESa7nhSvAUazipc123gdTx/7V8raE0WlKZM89X6Vy
H4ZjvNikr/2S2WaNZWwPYNC5b2raOGZP5sEUpGBQz6M9UbZz42SZsN8CgYEA9iCy
DkhX1tzsKQhjRdXU9V/N5daXH65fto+qlpQMOcwIKDAe6DH36lugSR4gaQh+KtmR
nWX/58TM0iQWDIUMs3sbyBeESfCh3LEH42EN1M62BNC6F7A8pnLw8qfGeu+kfu5X
fAvqv0HgBJP4Duqdl30Ux9h4RqtGTyWiQaEnjLcCgYBDB3LR14YZ5sp963XcdzSZ
oVOWof9VvjuXRIDGjR6ekAvzpFWTWwnZI/EVCE7ea/ZgoOlIQfukU75W2rM/k460
jzByC0UkkcinAACSI6TxgkSQgZPtWRhdN0bmubkp+FxlU2sjJ/NTZo4yHWwL6r0A
CpJi7WQi+/zWDmkYOP0oXQKBgQDdC1weK6aH131ZFKljjLlnbZVTN7gdwdM/+CLy
fR/FwJIK1bzMOCQ5G/UF9cKR0gjNnvyB6Zs8oah5ieMrd0qC3quCtmweo7gapfs5
oG51kvgxtuuKXsL5kf0HUNqWiianwJJdW66F+jmgouuDKf5CkRlaqfTLMwNADcJ9
QqhsXQKBgQCJ4hUy3ptM6KUDG0oAT9s+cojVAmsCm5zITHkaFfkjP0W8srGXwrWx
63wLQCy84GOCFH3jecHSKHapq9V0laL+ARnepj6naO8ivMQFSucyAOeX7CfJAc45
BoezzHAqR1cnGn52G57ycqrX7eCHSULfIcYU7VwcqKJzxf1w+A+AVw==
-----END RSA PRIVATE KEY-----
Java code used to encrypt (the minimal reproducible example):
I asked the backend team for an example of the code they use to encript, and they sent me this Kotlin function:
fun String.encryptWithPublicKey(publicKey: String): String {
try {
val base64Decoder = Base64.getDecoder()
val decoded = base64Decoder.decode(publicKey.toByteArray(Charsets.UTF_8))
val key = RSAPublicKey.getInstance(decoded)
val keySpec = RSAPublicKeySpec(key.modulus, key.publicExponent)
val rsaKey = KeyFactory.getInstance("RSA").generatePublic(keySpec)
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.ENCRYPT_MODE, rsaKey)
val encrypted = cipher.doFinal(this.toByteArray(Charsets.UTF_8))
return ByteString.of(encrypted, 0, encrypted.size).base64()
} catch (e: Exception) {
throw e
}
}
Sample encrypted string, b64 encoded:
Here's the base 64 encoded, encrypted string I get from the backend response:
ciSvTLKRAMqz8d8SEX8epvkyyrfAoiX28Sd1RhYbsz7oOg3/taXZxZkTeCbVeFXB8Mf8eWn2SGMcVIrmFGuxqyRoC5SluJDgrup0wcG/XRg7lrt7oD6esVBAGZT5nmS79mUoAC4CKW5cHclCh66JUysATSIvI9qrrXNUnBApGJc=
Sample raw value:
I don't have the exact value right now, but it should be a numeric value similar to this:
1234 5678 9012 3456

Related

RSA Decryption using private key in NodeJs

I am integrating a third-party API service, for security they have asked us to exchange information in an encrypted format. So, they have asked me to create an RSA public/private key and share the public key with them.
This is what they told me to do
Public Key certificate in 4096 bit. For encryption and decryption. (Zip File) OR Public key Self-signed certificate required(In 4096-bit format). Certificate format should be X.509 Certificate should start with “Begin Certificate” and end with “End Certificate”
Encryption Process:-
Asymmetric Encryption(RSA_Encrypt) with RSA 4096 bit Public Key(Certificate), with mode/padding as ECB/PKCS1.
Base64Encode.
In Encryption Process Partner should use our Public Key Certificate.
Decryption Process:-
Base64Decode
Asymmetric Decryption(RSA_Decrypt) by using Partner private Key certificate.
So, I ran the following command and gave them the public key certificate
openssl req -x509 -sha256 -nodes -newkey rsa:4096 -keyout private.key -out public.pem
And, on my end, I have written the following functions to encrypt using their public key and decrypt using my private key
async function RSA_Encrypt(str) {
const publicKey =
fs.readFileSync(path.resolve("./their/UAT_PUBLIC_CERT.txt"), "utf8");
const buffer = Buffer.from(str);
const encrypted = publicEncrypt({ key: publicKey, padding:
constants.RSA_PKCS1_PADDING }, buffer);
return encrypted.toString("base64");
}
async function RSA_Decrypt(str) {
const privateKey = fs.readFileSync(path.resolve("./my/private.key"),
"utf8");
const buffer = Buffer.from(str, "base64");
const decrypted = privateDecrypt({ key: privateKey, padding:
constants.RSA_PKCS1_PADDING }, buffer);
return decrypted.toString("utf8");
}
Now, I am sending the request to them by encrypting the request body with RSA_Encrypt function. They are responding back with an encrypted response, upon decrypting the response using the RSA_Decrypt function I am getting the following error
error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed
Also, I've tested the encryption using my public key and decryption using my private key which is working fine. Here are the functions I've written for test purpose,
function RSA_Encrypt(str) {
const publicKey = fs.readFileSync(path.resolve("./my/public.pem"), "utf8");
const buffer = Buffer.from(str);
const encrypted = crypto.publicEncrypt({ key: publicKey, padding:
crypto.constants.RSA_PKCS1_PADDING }, buffer);
return encrypted.toString("base64");
}
function RSA_Decrypt(str) {
const privateKey = fs.readFileSync(path.resolve("./my/private.key"), "utf8");
const buffer = Buffer.from(str, "base64");
const decrypted = crypto.privateDecrypt({ key: privateKey, padding:
crypto.constants.RSA_PKCS1_PADDING }, buffer);
return decrypted.toString("utf8");
}
I think this is some padding or mode issue, but unable to figure it out on my own. Can I specify ECB mode in privateDecrypt function? The encryption on their side is most probably happening in JAVA, so is there anything I am missing out in NodeJs?

How to verify ECC signature from android/java with python

I write code to sign string android using ECDSA algorithm.
Here is mycode:
String origin = txtChuoi.getText().toString();
try {
byte[] chuoiInput = origin.getBytes("UTF-8");
sig = Signature.getInstance("NONEwithECDSA","SC");
sig.initSign(privateKey);
sig.update(chuoiInput);
signatureBytes = sig.sign();
txtSign.setText(Base64.encodeToString(signatureBytes,Base64.DEFAULT));
} catch (Exception e) {
e.printStackTrace();
}
I can verify this sign string in same code app (using Java/Android). Here is my code:
String origin = txtChuoi.getText().toString();
try {
sig = Signature.getInstance("NONEwithECDSA","SC");
sig.initVerify(publicKey);
byte[] chuoiInput = origin.getBytes("UTF-8");
sig.update(chuoiInput);
txtVerify.setText(sig.verify(signatureBytes)+"");
} catch (Exception e) {
e.printStackTrace();
}
but not I want to verify it on my ubuntu server.
I have a trouble.
How can I implement verify code using python?
I cant write publickey code to pem file like this:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfUnusZsShxFLUuAwwAyFAkGCq3mBy98RXIkTP8YiTO3qmL8w6eMdMadiHfdCG2emktDrUwzNmTr9nMFCFhXdGQ==
-----END PUBLIC KEY-----
But how about the Signature? And I think (but not sure) it verify on bytes[].
How python do this?
Here's a similar question with the answer:
How to sign and verify signature with ecdsa in python
You'll need to prepare the public key for verification. The PEM file you mentioned has it base64 encoded.

PEM to PublicKey in Android

I've seen a number of similar questions, but nothing has quite worked for me. I am simply trying to convert an RSA public key that's in PEM format that I've retrieved from a server into a PublicKeyin Android. Can anyone point me in the right direction?
EDIT:
I've successfully used the following code to convert the PEM into a PublicKey, but upon encoding a message, I get unexpected output...
public PublicKey getFromString(String keystr) throws Exception
{
// Remove the first and last lines
String pubKeyPEM = keystr.replace("-----BEGIN PUBLIC KEY-----\n", "");
pubKeyPEM = pubKeyPEM.replace("-----END PUBLIC KEY-----", "");
// Base64 decode the data
byte [] encoded = Base64.decode(pubKeyPEM);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pubkey = kf.generatePublic(keySpec);
return pubkey;
}
public String RSAEncrypt(final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {
if (pubKey!=null) {
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
encryptedBytes = cipher.doFinal(plain.getBytes());
Log.d("BYTES", new String(encryptedBytes));
return Hex.encodeHexString(encryptedBytes);
}
else
return null;
}
The output looks like this:
b6813f8791d67c0fa82890d005c8ff554b57143b752b34784ad271ec01bfaa9a6a31e7ae08444baef1585a6f78f3f848eecb1706bf7b2868fccefc9d728c30480f3aabc9ac5c3a9b4b3c74c2f7d6f0da235234953ea24b644112e04a2ec619f6bf95306ef30563c4608ec4b53ed7c15736d5f79c7fa1e35f2444beb366ae4c71
when I expect something closer to:
JfoSJGo1qELUbpzH8d4QXtafup+J2F9wLxHCop00BQ4YS0cRdRCKDfHpFPZQYjNeyQj00HwHbz+vj8haTPbpdqT94AHAl+VZ+TPAiUw1U5EXLLyy4tzbmfVI7CwvMm26lwB4REzYUZdedha1caxMEfxQ5duB+x4ol9eRZM/savg=
Is there some formatting or file type that I'm missing?
To answer my own question...The first output is in hex and the second output is in base 64. Just change the return statement to return new String(Base64.encode(encryptedBytes));
and you'll be good!
This doesn't answer the question, but I find the content relevant. Posting as an answer because it doesn't fit as a comment.
PEM vs DER
PEM basically encapsulates a DER-encoded certificate or key.
DER is binary, PEM is text; so PEM can easily be copy-pasted to an email, for example.
What PEM does is:
Encode the DER certificate or key using Base64, and
Delimit the result with -----BEGIN <something>----- and -----END <something>-----.
The key or certificate is the same, just represented in a different format.
Mostly paraphrasing from ASN.1(wiki).
DER to Android/Java public key
The following is an example of how to use a key factory in order to
instantiate a DSA public key from its encoding. Assume Alice has
received a digital signature from Bob. Bob also sent her his public
key (in encoded format) to verify his signature. Alice then performs
the following actions:
X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
...
Note that bobEncodedPubKey is DER-encoded in this sample.
https://developer.android.com/reference/java/security/KeyFactory
PEM to Android/Java public key
Similar to what is done for DER, but do the following beforehand:
Remove the BEGIN/END delimitation, and
Decode the content in Base64 to obtain the original DER.
(The question already shows code on how to do this.)

SHA256withRSA sign from PHP verify from JAVA

For my current project I have to send a signature from PHP to Java application. I am using Crypt/RSA right now for signing my data.
For test I am signing just "abc" with following code :
$rsa = new Crypt_RSA();
$plaintext = 'abc';
$rsa->loadKey("MIICXgIBAAKBgQDjh+hNsqJe566JO0Sg7Iq5H1AdkauACdd8QMLp9YNY0HPslVH0
rXaOFo0zgH0Ktu/Ku3lS1lfxbFQAY8b6ywZKvu4eoxlnEwuBwy09CG+3ZiVLBjCj
TZHA/KOkpVLa+tA6KsoP6zv/xI/ACkSCxPGR0q3SiRuhXV/6tacoKxUYnwIDAQAB
AoGBAIC00GOjONYWmFRoglnFdHNjkx4m2KyE5LAUsi1GBBapU+nwTXvq47VcbGNF
u3XkJaC4i9igBv86GApgZp5XWia86On/Lz9NR4fB2EFP6Ydy84GfCDNNvkism4BR
aA+eYdNiQ3Wfyi98ZpUi+rPsoI6Cid4eSkCC4poTUaqzMkiBAkEA9Gn1oIlUEoVI
q/u5Y9vflXRDt95AA9AokJkQj7XTNjsz8ypU8TO6D6ZykpcbK6zjU0UJsQiC3dKj
AgmAR2VzYwJBAO5RETMAyDnR+5g+MtHpwGqGdY4dq0j4y4CsdtOYKWwSTh3VQy+C
eghJoyPRfIpulw2Mk/l+occEI0ohJl0+UJUCQQDSZtjVLwMZwnUx4EvSw/ewL9sP
0Jpo7evNtoaEQDEncUWiYeGnljDowg/FU6FHMtiq2TajmMEXdflvioBMdfAjAkEA
3TB60SbJr/i4Fo6sJm5ZO8W+eAALiTf50VzBERTqZTb8L+5PZFoqn2SROV5mxClu
o5G1idzBlHC/vD7WV7bNnQJAd0FrxaMBurJ4Uv/B8TDP+eeBdB7d9rKw0+TVlcel
cbpIz6BIP6+nmsgy6dbDRnx0eC/MgF2EU0wrCu1DK0PyWA==");
$rsa->setHash("sha256");
$signature = $rsa->sign($plaintext);
$signature_encoding = mb_convert_encoding($signature, "UTF-8");
error_log("signature encoded in UTF-8 :" . $signature_encoding);
$encoded_sign = base64_encode($signature_encoding);
error_log("encoded sign for abc: " . $encoded_sign);
I can verify the signature from php code. But when it comes to verifying from JAVA, i was not successfull. Here is the java code that does the verify operation :
public boolean verify(String signed, String data, PubKey pubKey) throws Exception{
PublicKey publicKey = jceProvider.generateRSAPublicKeyFromX509(
base64.decode(pubKey.getEncodedKey())
);
byte[] signature = base64.decode(signed);
byte[] verifier = data.getBytes(Charset.forName("UTF-8"));
return jceProvider.verify(signature, verifier, publicKey);
}
public class JCEProvider {
public boolean verify (byte[] signature, byte[] verifier, PublicKey publicKey) throws Exception{
Signature rsaSignature = Signature.getInstance("SHA256withRSA");
rsaSignature.initVerify(publicKey);
rsaSignature.update(verifier);
return rsaSignature.verify(signature);
}
I dont think it is because of keys, I can already verify it from PHP as I told before. There is something that I miss about PHP encoding or byte streams but I am lost for the moment.
Any help would be appreciated.
I'm using openssl like Whity already mentioned. Here is my striped down example. Be aware of any character encoding, line ending, etc. This results in changed binary representation of your text data.
PHP-RSA_SHA256-Sign:
<?php
$data = "For my current project I have to send a signature from PHP to Java application. I am using Crypt/RSA right now for signing my data.";
$private_key = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4Z
RZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQJAL151ZeMKHEU2c1qdRKS9
sTxCcc2pVwoAGVzRccNX16tfmCf8FjxuM3WmLdsPxYoHrwb1LFNxiNk1MXrxjH3R
6QIhAPB7edmcjH4bhMaJBztcbNE1VRCEi/bisAwiPPMq9/2nAiEA3lyc5+f6DEIJ
h1y6BWkdVULDSM+jpi1XiV/DevxuijMCIQCAEPGqHsF+4v7Jj+3HAgh9PU6otj2n
Y79nJtCYmvhoHwIgNDePaS4inApN7omp7WdXyhPZhBmulnGDYvEoGJN66d0CIHra
I2SvDkQ5CmrzkW5qPaE2oO7BSqAhRZxiYpZFb5CI
-----END RSA PRIVATE KEY-----
EOD;
$binary_signature = "";
$algo = "SHA256";
openssl_sign($data, $binary_signature, $private_key, $algo);
print(base64_encode($binary_signature) ."\n");
?>
The output of base64 encoded binary signature is:
OnqiWnFQ2nAjOa1S57Du9jDpVr4Wp2nLdMk2FX+/qX1+SAHpVsW1JvQYqQUDlxvbTOE9vg6dlU6i3omR7KipLw==
JAVA-RSA_SHA256-Verify:
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Base64;
public class RsaVerify {
public static void main(String args[]){
String publicKey =
// "-----BEGIN PUBLIC KEY-----"+
"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6"+
"zxqlVzz0wy2j4kQVUC4ZRZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQ==";
// "-----END PUBLIC KEY-----";
byte[] data = "For my current project I have to send a signature from PHP to Java application. I am using Crypt/RSA right now for signing my data.".getBytes();
byte[] signature = Base64.decodeBase64("OnqiWnFQ2nAjOa1S57Du9jDpVr4Wp2nLdMk2FX+/qX1+SAHpVsW1JvQYqQUDlxvbTOE9vg6dlU6i3omR7KipLw==");
try {
System.out.println(verify(data, signature, publicKey));
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
private static boolean verify(byte[] data, byte[] signature, String publicKey) throws GeneralSecurityException{
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(pubKey);
sig.update(data);
return sig.verify(signature);
}
}
phpseclib uses the more secure PSS padding by default. Java is probably using PKCS#1 padding. So if you were to go the phpseclib route (which I'd recommend doing)... do this:
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
I think u need to improve your PHP solution.
According to http://php.net/manual/en/function.openssl-get-md-methods.php you can use directly [47] => sha256WithRSAEncryption from PHP, probably call openssl from commandline also be possible:
openssl dgst -sha256 -sign my.key -out in.txt.sha256 in.txt

Formatting RSA keys for OpenSSL in Java

Background
RSA key generation with OpenSSL on Linux using the command,
openssl genrsa -out mykey.pem 1024
created the following:
"-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQChs9Fepy5FgeL0gNJ8GHcKRHsYnM2Kkw19zwydDQNyh2hrHWV2
B11wpLFp8d0imcl2Wjb0oV/AxOhb3unQgNzs66LVuXJwS8icp3oIJZtExs6tkxzE
s5mnU68wMeCYtJqHIZOmNblVWvpJMLNAwAVi3oLfnzDDbzjnDapm8M21nQIDAQAB
AoGAZ11P1+acUHgvwMXcRtFIvvp5iYkqZouL00EYOghIjNx75gTbh7A7jbbpZeTi
y6xsuMgAWy4QzGPSeG+tHMhS7+dYQNPuKSv5KtK3V7ubXz/I3ZN1etRVecA56QNw
7HKv6b7srolt08kogGIwpbbfl/mhfJHnv4Jeqd5lNMnK4e0CQQDWFZo4h22OlSaH
ZGd3i4rwLrA0Ux5bkdh7YH0uEeE/nGzpVs1DPhsN8UCyq9LAiKYLlXeeCvwurKwo
OgKlUCkzAkEAwVy2KignoRInFTAaYH8PQRfD835q+oC0Iu21BF68ne06U6wu+wWk
bWiYxTOOb+TGZfA1vA6OAvGVGoXs1bHF7wJBAItGiop0MKYuCl7Sxy1SrxUKir+/
w2Q3QesiHs41+6Byl7hGLEuuv9MWPM0AU5/GRqAKoUNESkPjOi0BcG8z81kCQGGn
OvCreugjzM0skAWv5bpQEExGyixdF5yURFlCpytzBYQAb3Gi9dmze4QMd6EW/wO4
fsrM5vehnlXY0TVTJM0CQQCMPVhub8LSo7T/lCzypvb/cgxJfyITRKcM2asrXud5
r27kbzsXqYum4huHqyFkb3pZammsYA/z89HchylfrD4U
-----END RSA PRIVATE KEY-----"
The following code under Java 6,
KeyPairGenerator keyGen = null;
try {
keyGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
KeyPair pair = keyGen.generateKeyPair();
privateKey = new Base64Encoder().encode(pair.getPrivate().getEncoded());
publicKey = new Base64Encoder().encode(pair.getPublic().getEncoded());`
output the following:
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIsJlqFOP+jPyYvrGwh+dff30a3p
uHysMfHYi1MyNSFCsT/2QbOc/k9U/X28WRCMeFwEEnReLULXA9Ywox8GycI/ApMX+DjKBrrLDbpr
ATLiu9+NMK4VSytKFI87P07HAni3RkiO4rFNEINVQ7t38ZmHavuXHjMkLEAK4dyLQO9NAgMBAAEC
gYBN/jv0EmwBUgYSKflJI39TcT263B+0N/fwXXOSYNiy5rF9WstyUP/LSrbEAJLJmLKvk00y391t
4CVz0ma+sdUdAPlS7Nmx9f3BThGOGcDmpjVo1y4e1afWtyu66ba/XDeuf7q5Y/h/pr20/gXl9Gz2
yefQrzU9xXGKZhE/lxJ2IQJBAMELpeAal+Fa+u0InGrowVmV+lge8RZqKRfCDzPPna465E5Qcekb
J0ShsarP5lnUfrNH5g8GLaDGQwYE/UoIpPkCQQC4YRfck5uMlI1K3F9YC3XvmFAJnf9YexoPfNSu
dznOD4rxlwzW/5daPOR0jjlyIRDH/QuUoPIIEn1mt3dnz7X1AkBZciozgl7pPhySA7FmH96mwcUz
W3LdrebIaVRd707iUctDNibxmXFCbaFCwf27laf3LdM9FuHBYtvfSCSMTyERAkEAlNAQsUAVmKZB
T72D2o0Nd/7oAosaD7DzvLJU+idSaWUUEJ+IhnKuFu/0t7oe1WWopLEwypoIHsnFmsTTQ99ajQJA
Scwh3P3RTN4F6Jz1SxRSe6L729xI8xkbco5EsMq5v5BZeoGynqdPUUZdAPcaO2k5UagaSejvzgna
8xIqR7elVQ=="
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLCZahTj/oz8mL6xsIfnX399Gt6bh8rDHx2ItT
MjUhQrE/9kGznP5PVP19vFkQjHhcBBJ0Xi1C1wPWMKMfBsnCPwKTF/g4yga6yw26awEy4rvfjTCu
FUsrShSPOz9OxwJ4t0ZIjuKxTRCDVUO7d/GZh2r7lx4zJCxACuHci0DvTQIDAQAB"
Questions
How do I put "armor" around the private and public keys created through Java code?
Why is each line of the keys generated through Java code longer than those output by OpenSSL?
Does it make any difference? One of the tools, that other team is using, fails while signing a message using private key generated by Java code mentioned above. However, it works just fine that tool uses the private key generated by OpenSSL.
Is there a way I can export a compatible key with Java?
The OpenSSL private key is in a non-standard format, while the Java code is creating a standard, PKCS-#8–encoded private key.
OpenSSL can convert the standard key format to the non-standard form. You can write Java code to do the same, but it requires some third-party libraries and a good knowledge of ASN.1 helps too.
To convert a PKCS #8 key to OpenSSL format, use OpenSSL's pkcs8 utility.
openssl pkcs8 -nocrypt -inform der < pvt.der > pvt.pem
To convert an RSA key stored as a DER-encoded SubjectPublicKeyInfo to PEM format, use OpenSSL's rsa utility.
openssl rsa -pubin -inform der < pub.der > pub.pem
This assumes that the private key is stored in "binary" (DER) format, not Base-64 encoded. The Java code to create and store keys like this would look something like:
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
KeyPair pair = gen.generateKeyPair();
FileOutputStream ospvt = new FileOutputStream("pvt.der");
try {
ospvt.write(pair.getPrivate().getEncoded());
ospvt.flush();
} finally {
ospvt.close();
}
FileOutputStream ospub = new FileOutputStream("pub.der");
try {
ospub.write(pair.getPublic().getEncoded());
ospub.flush();
} finally {
ospub.close();
}

Categories