I'm having a problem in loading RSA public key that was generated by Java in Ruby.
The RSA public key was encoded in X509 format by Java. FYI, here's the Java code for generating the public key
public static void generateKeys() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
System.out.println("keys created");
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey,
RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey,
RSAPrivateKeySpec.class);
saveToFile("public.key", pub.getModulus(), pub.getPublicExponent());
saveToFile("private.key", priv.getModulus(), priv.getPrivateExponent());
System.out.println("keys saved");
}
public static void saveToFile(String fileName, BigInteger mod,
BigInteger exp) throws IOException {
ObjectOutputStream fileOut = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)));
try {
fileOut.writeObject(mod);
fileOut.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error");
} finally {
fileOut.close();
System.out.println("Closed writing file.");
}
}
I've tried using the public.key in my Ruby by using :
public_key = OpenSSL::PKey::RSA.new File.read 'public.key' and
cert = OpenSSL::X509::Certificate.new File.read 'public.key'
But none of them work, instead they printed out error message :
OpenSSL::PKey::RSAError:
Neither PUB key nor PRIV key:: header too long
OpenSSL::X509::CertificateError:
header too long
I'm planning to use the public.key to encrypt some data in Ruby. Can anyone help me out? I really appreciate one, thanks!
Related
I am generating Asymmetric public key and private using the code below.
public static KeyPair generateRSAKkeyPair()
throws Exception {
SecureRandom secureRandom = new SecureRandom();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(
2048, secureRandom);
return keyPairGenerator
.generateKeyPair();
}
public static byte[] do_RSAEncryption(
String plainText,
PublicKey publicKey)
throws Exception {
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(
Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(
plainText.getBytes());
}
public static String do_RSADecryption(
byte[] cipherText,
PrivateKey privateKey)
throws Exception {
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.DECRYPT_MODE,
privateKey);
byte[] result = cipher.doFinal(cipherText);
return new String(result);
}
public static PublicKey getKey(String key) {
try {
byte[] byteKey = Base64.getDecoder().decode(key.getBytes());
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(X509publicKey);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static PrivateKey getPrivateKey(String key) {
try {
byte[] byteKey = Base64.getDecoder().decode(key.getBytes());
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(X509publicKey);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
This works as expected.
String plainText = "This is the PlainText. I want to Encrypt using RSA.";
byte[] cipherText = do_RSAEncryption(plainText, keypair.getPublic());
String decryptedText = do_RSADecryption(cipherText, keypair.getPrivate());
Now, I am storing the generated the generated public key and private key in a string and trying to encrypt and decrypt and it is failing.
String base64EncodedEncryptionKey = DatatypeConverter.printBase64Binary(keypair.getPublic().getEncoded()));
String base64EccodedDecryptionKey = DatatypeConverter.printBase64Binary(keypair.getPrivate().getEncoded()));
PublicKey pubKey = getKey(base64EncodedEncryptionKey);
byte[] cipherText1 = do_RSAEncryption(plainText, pubKey);
System.out.println("Encrypted Text ===> "+ DatatypeConverter.printHexBinary(cipherText1));
PrivateKey privateKey = getPrivateKey(base64EccodedDecryptionKey);
String decryptedText1 = do_RSADecryption(cipherText1,privateKey);
System.out.println("DecryptedText ====>>> "+decryptedText1);
Error:-
java.security.spec.InvalidKeySpecException: Only RSAPrivate(Crt)KeySpec and PKCS8EncodedKeySpec supported for RSA private keys
at java.base/sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:389)
at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:247)
at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.getPrivateKey(Asymmetric.java:96)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.main(Asymmetric.java:135)
Exception in thread "main" java.security.InvalidKeyException: No installed provider supports this key: (null)
at java.base/javax.crypto.Cipher.chooseProvider(Cipher.java:930)
at java.base/javax.crypto.Cipher.init(Cipher.java:1286)
at java.base/javax.crypto.Cipher.init(Cipher.java:1223)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.do_RSADecryption(Asymmetric.java:68)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.main(Asymmetric.java:137)
Private keys are encoded with PKCS8EncodedKeySpec. You should replace X509EncodedKeySpec with that.
Following are the details of the issue along with Code Snippets-
Overview - The purpose of the program is to upload Invoice data to Portal and Receive back the acknowledgement.
Issue - When we run the program and hit API from Windows machines, it is working fine and getting the response code 200 OK.
But when the same is executed from Linux machines, Response code 500 is received , response message - "Internal Sever Error."
Java Version - openjdk version "1.8.0_222"
One Jar Dependency - org.json.jar
Same program is running flawlessly on Windows.
If I generate the AppkKey and Password from windows and use it on linux. It worked.
Methods used for AppKey and Password Generation.
String appkeye = encryptAsymmetricKey(publicKey, new String(appKey));
String password = encryptAsymmetricKey(publicKey, "UserId");
public static String encryptAsymmetricKey(String pubkey, String password) throws Exception {
PublicKey publicKeys = convertPubStringToKey(pubkey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, publicKeys);
byte[] encryptedText = cipher.doFinal(password.getBytes());
String encryptedPassword = Base64.getEncoder().encodeToString(encryptedText);
return encryptedPassword;
}
public static String encryptAsymmetricKey(String pubkey, byte[] appKey) throws Exception {
PublicKey publicKeys = convertPubStringToKey(pubkey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, publicKeys);
byte[] encryptedText = cipher.doFinal(appKey);
return null;
}
private static PublicKey convertPubStringToKey(String publikkey) {
PublicKey pubKey = null;
byte[] publicBytes=Base64.getDecoder().decode(publikkey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
KeyFactory keyFactory;
try {
keyFactory = KeyFactory.getInstance("RSA");
pubKey = keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
}
return pubKey;
}
public static byte[] createAESKey() {
byte[] appKey = null;
try {
KeyGenerator gen = KeyGenerator.getInstance("AES");
gen.init(256);
SecretKey secret = gen.generateKey();
appKey = secret.getEncoded();
} catch (NoSuchAlgorithmException ex) {
}
return appKey;
}
Please suggest
Thanks,
Gaurav
I have been given an RSA public Key and an RSA private key with OAEP SHA-256 padding. I am attempting to simply encrypt a random string and then decrypt it to assert the result is equalt to the original.
This is the public key i have been given:
-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq8tiBtDmkeS/ruY3rrkq
dz6Lc6XWFRbI/GjPtIokrtpM+Ujyv6wX8TBqY8e03gzh+eE7VUyEVPapDnceAqgJ
ZQah2h+N5AEQKqNDM4/1to1V0F+m1ISR7CIUU8dvU+bPk67DU5VkEtLxf+mW8/es
hy0u6oSB04WCDPNnh+9GDF7tN7lOzBH1FxKPWIb5Gqg6GoXS+KgvQhYEk0TajIBk
+mefzTv1D4HJlhFYybgY+/p3k4P2kM5HnbEtoVpz/PL9+94YVp5RBHTQHmk/3SAX
RkPP34IjY6LZqTJGWQGxc64Qci54ZJsq4wSTXvfdHgUWz7eX+v1jA+GLjFExNcYZ
nQIDAQAB
-----END RSA PUBLIC KEY-----
This is the private key I have been given:
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAUQiHdHuMBCnF
P/7RQoRWrp62dGWQLDLP9l+3KUMlSPheN2R5jHDZ/WEGJGF2WYKxaQvv5XCocdnt
uxVZTNM1PVyduokJaJzrSIj+jGWDd4hTWvVoS3vhds8u6W0jD3M4ayrF6c7NYuHc
tE5YLLIgK1DTn+ZZCr3VGbScISDJ/WPx3+1YTNQDvm+T7MfjhetJqqzWIsunMUiw
nQOQvkdjCVWpk+L10SaMrezixtIS5wfpOTjGIZ0w5VunvtsPxg1TkuvGURa9S3rS
7D3uhDPY+V8UDMpBPso3j7TGD5axlBJcpavWeF8qde3sWztmqUFQ3JDypZWGSAe2
d8e4mY65AgMBAAECggEAal8nwYxbHZnb5L892U7aVfuly7Nbzb+0pzRVwsBu5DuV
LL+kslpMvTYZqUUMJ2LhF/HLaXhVtMWsTYLSDx+gHu1+wbtAOtUDHlxzcaAEMhA2
dix0WqiNr6qAdCkmdWMBTu5vrSJigVW1KdcNElY+e+6ZeUQTK6L2Vt0t+cGVGkM4
K5PdHcGLR1BiAf3k4BguHE4TGGnqN9dF5Rn9nPP6C7QihWzGn15efD2dAXn3Kbho
dMIRgyYiO7uXPm2LrIjtldYb8tPus+V9SWT4hcgnJZrtd9atkqZrJ3dhQf9ZetGs
UwTCzHJ169NNbVyrjCbcy4Uht8Na+t/94Im9hI8n0QKBgQDO6tYnwh1hPg3E+4DY
xCiDAp7v3afJIvC9a1sBtif8KkzZTYH31ww+PRcfDPQUlk/MIDie0u6xIawnBYkC
oN1u9erojcvQbBP0GFylP5hNxYZbI7gPA/7AiGRxyezZPOiVMwdd5fCM7Wv4kucr
c1JCcvtPoDQcFFZOfI+wqqdWnQKBgQDt745Pvckt7/XL7wbfv4BV+cwpLNjc4/3k
ajOLtasgpT8mc0gUH2ejHhpkuhjSUpSTrlFB8EN1kAwmBYy0GOoO9967hm6twmqk
Q5L3OHJ96pYkf1rbyXNE1N7inh5Z3M1H5ONIaliAYLHXOzKsZvI5eUdKAJdSqFLo
uvVCwr4PzQKBgG6W3rzDJ9a4Rr24OgYg2RIkTXQgALQko4xpm2tPwxEoPoiJv2QK
ILYHCpuC3dU+/Qk5U2m3jPFI8OyuLask9RSABPwkBQGxMfztJF8BnVI7tvJxJceI
uBiJDT4v0RHOVvSfIFnUMnvvzRw+z6TObvGq6JyHIDK9v98U/etLWkKVAoGAIIxF
lmjqzUrm/8ep1A+5OYmbQQKug8D4aTeR54mpaCTSt6rLcF0/axPiHmdKn/LF+lG9
MdzxDXLwBn952OUTl4qWwGZKW6Cdv+yyfPkOyGS/tyxovGoZR5ArESr6Eebfefc4
lB5gDuerTDr/2o+WkQAjHV9pU9hMxyNUC5biMv0CgYEAiDlw8lBf3cQs6FxNXs9t
whWpfL0yY7WAONvhfFB0Dpsz52gGDCYRvJekGRz6jOlKDuXJ+Mm1AX4BaufMETI5
QseZxtVPIn+BXm0A1x8w/DifmE1JqQZmPCQPOh3eLx5nSn9LKGIbMgd17mfH3HhU
8WX2mzWjmRA3C/CzdGfCKSk=
-----END PRIVATE KEY-----
I am reading this key from a pem file "crypt_pkcs8.pem" but recive the public key as a byte array from a gRPC call.
Here is my Java code:
public class Encryption{
public static void main(String args){
ByteString publicKey = client.getPublicKey(nonce).getRSAEncryptionKey();
String strKeyPEM = "";
BufferedReader br = new BufferedReader(new FileReader("crypt_pkcs8.pem"));
String line;
while ((line = br.readLine()) != null) {
strKeyPEM += line+"\n";
}
br.close();
byte[] pt;
try {
pt = "h".getBytes("UTF-8");
byte[] ct =encrypt(publicKey, pt);
byte[] response= decrypt(strKeyPEM, ct);
assertEquals(pt, response);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static byte[] encrypt(ByteString rawKey ,byte[] message){
String strippedKey=stripKey(rawKey.toStringUtf8());
byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
System.out.println(keyBytes.length);
Cipher cipher_RSA;
try {
cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
PublicKey pk = keyFactory.generatePublic(spec);
System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());
cipher_RSA.init(Cipher.ENCRYPT_MODE, pk);
return cipher_RSA.doFinal(message);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
BadPaddingException | InvalidKeyException | InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static byte[] decrypt(String rawKey ,byte[] message){
String strippedKey=stripPrivateKey(rawKey);
byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
System.out.println(keyBytes.length);
Cipher cipher_RSA;
try {
cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey pk = keyFactory.generatePrivate(spec);
System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());
cipher_RSA.init(Cipher.DECRYPT_MODE, pk);
return cipher_RSA.doFinal(message);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
BadPaddingException | InvalidKeyException | InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static String stripKey(String key){
key = key.replace("-----BEGIN RSA PUBLIC KEY-----\n", "");
key = key.replace("-----END RSA PUBLIC KEY-----", "");
key = key.replace("\n", "");
return key;
}
public static String stripPrivateKey(String key){
key = key.replace("-----BEGIN PRIVATE KEY-----", "");
key = key.replace("-----END PRIVATE KEY-----", "");
key = key.replace("\n", "");
return key;
}
}
I cannot find anything obviously wrong with my actaul code so I believe this is to do with the keys not matching.
I also notice the header/footer is different on the public key and private key. From looking online this is because the public key is in PKCS#8 format.
Will I need to change the public key to pkcs#8 format as well? If so what is the easiest way to do this?
I have also been told I should be able to extract the public key (in pkcs8 format) from the private key given above. Can this be done easily?
If you can get a valid public key then the key is not in PKCS#8 format, it will be in X.509 (SubjectPublicKeyInfo) format as Java expects. However, your public and private keys do indeed not match. You can use the answer here to create the correct public key file from the private key file.
Java doesn't directly contain code to retrieve the public exponent from an RSAPrivateKey without CRT parameters. However, if you want a Java only solution you could cast the PrivateKey even further to RSAPrivateCrtKey which does contain a getPublicExponent method to retrieve the public exponent. Then you can use an RSA KeyFactory to generate a public key using RSAPublicKeySpec.
You could also parse the PEM file to retrieve the public key in Java using e.g. the Bouncy Castle API. But expect a steep learning curve if you do.
I need to sign a String and send both. I have a .pem file as private key, and I'm trying to convert this file into a PrivateKey.
This is my code:
try {
File privateKeyFile = new File("path to .pem file");
//TODO: HOW CAN I CONVERT THAT FILE INTO PRIVATE KEY?
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privateKey);
signature.update(data.getBytes());
byte[] sign = signature.sign();
} catch (NoSuchAlgorithmException | SignatureException e) {
e.printStackTrace();
}
Have you any suggestion to give me about this?
I solved in this way:
Instead used a .pem file I saved directly the String obtained from PrivateKey and then when I need to sign datas, I get that String and the convert it into PrivateKey.
This is my code:
public String signData(final String data, final String privateKeyString) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(privateKeyString.getBytes());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data.getBytes());
byte[] sign = signature.sign();
return new String(sign);
}
im pretty new to android development and i have the following method for encryption data using RSA(2048b):
public byte[] encryptData(String base64) throws GeneralSecurityException {
byte[] dataToEncrypt = base64.getBytes(Charset.forName("UTF-8")); //lenght == 90
try {
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(rsaKeys.getPublicModus(), rsaKeys.getPublicExpo());
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPublicKeySpec);
//default providers
//4.0.3 - BC (BouncyCastleProvider)
//4.4.2 - AndroidOpenSSL
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encryptedData = cipher.doFinal(dataToEncrypt); //this throw exception
return encryptedData;
} catch (GeneralSecurityException e) {
throw e;
}
}
This block of code working on Android 4.4.2 like a magic. Problem comming with Android 4.0.3 where its always end with exception:
com.android.org.bouncycastle.crypto.DataLengthException: input too large for RSA cipher.
at com.android.org.bouncycastle.crypto.engines.RSACoreEngine.convertInput(RSACoreEngine.java:115)
at com.android.org.bouncycastle.crypto.engines.RSABlindedEngine.processBlock(RSABlindedEngine.java:95)
at com.android.org.bouncycastle.crypto.encodings.PKCS1Encoding.encodeBlock(PKCS1Encoding.java:184)
at com.android.org.bouncycastle.crypto.encodings.PKCS1Encoding.processBlock(PKCS1Encoding.java:132)
at com.android.org.bouncycastle.jce.provider.JCERSACipher.engineDoFinal(JCERSACipher.java:467)
at javax.crypto.Cipher.doFinal(Cipher.java:1106)
Im confuse whats wrong (data length and keysize is on both device same). I will be grateful for any clue. Thanks.
My RSAKeys class contains simple constructor and get/set for each field:
private BigInteger publicModus, publicExpo;
private BigInteger privateModus, privateExpo;
Im using this method for RSA key generation:
#SuppressLint("TrulyRandom")
public RSAKeys generateRSAKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// Pullingout parameters which makes up Key
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec rsaPubKeySpec = keyFactory.getKeySpec(publicKey,
RSAPublicKeySpec.class);
RSAPrivateKeySpec rsaPrivKeySpec = keyFactory.getKeySpec(
privateKey, RSAPrivateKeySpec.class);
rsaKeys = new RSAKeys(
rsaPubKeySpec.getModulus(), rsaPubKeySpec.getPublicExponent(),
rsaPrivKeySpec.getModulus(), rsaPrivKeySpec.getPrivateExponent());
return rsaKeys;
} catch (NoSuchAlgorithmException e) {
throw e;
} catch (InvalidKeySpecException e) {
throw e;
}
}
I edited my code for using same message to encrypt base64 = "plain text"; and same RSA keys on both devices. Without any progress. Still getting error on device with Android 4.0.3.
Devices:
HTC Desire 610 - Android 4.4.2
HTC One V - Android 4.0.3
try to specific both algorithm and provider
// example how to generate key pair
class MyKeyPair {
private static final String ALGORITHM = "RSA";
private static final String PROVIDER ="BC";
private static final int STRENGTH = 2048;
private PrivateKey _privateKey;
private PublicKey _publicKey;
public PublicKey getPublicKey {return _publicKey;}
public MyKeyPair() {
generateKeyPair(STRENGTH,RSA,BC);
}
private void generateKeyPair(int keyLength, String algorithm,
String providerName) {
KeyPairGenerator keyPairGen =
KeyPairGenerator.getInstance(algorithm,providerName);
keyPairGen.initialize(keyLength);
KeyPair keyPair = keyPairGen.generateKeyPair();
_privateKey = keyPair.getPrivate();
_publicKey = keyPair.getPublic();
}
}