Small question regarding a Java code for ECC please.
I am having a very simple piece of Java code. (runnable, just truncating the keys with ...] )
import javax.crypto.Cipher;
import javax.crypto.NullCipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class ECTest {
public static void main(String[] args){
try {
String mySecretMessage = "MySecretMessage";
System.out.println("Step 1: This is the secret message I want to encrypt using ECC -> " + mySecretMessage);
String mySecretMessageEncrypted = encrypt(mySecretMessage.getBytes(StandardCharsets.UTF_8), "MFkwEwYHKoZIzj0CA[...]rBlZtvVpKyQdHxYZ0W6a/IixWc0WjDqqcVAtrwCILmHU7Q==");
System.out.println("Step 2: This is the secret message encrypted, I can share this -> " + mySecretMessageEncrypted);
String mySecretMessageDecrypted = decrypt(mySecretMessageEncrypted.getBytes(StandardCharsets.UTF_8), "MEECAQAwEwYHKoZIzj0[...]RnYMh52QmDg==");
System.out.println("Step 3: This is the secret message decrypted, it should be equal to mySecretMessage, but not mySecretMessageEncrypted -> " + mySecretMessageDecrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static String encrypt(byte[] data, String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
ECPublicKey pubKey = (ECPublicKey) keyFactory.generatePublic(x509KeySpec);
ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(pubKey.getW(), pubKey.getParams());
Cipher cipher = new NullCipher();
cipher.init(Cipher.ENCRYPT_MODE, pubKey, ecPublicKeySpec.getParams());
return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
}
public static String decrypt(byte[] data, String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
ECPrivateKey priKey = (ECPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(priKey.getS(), priKey.getParams());
Cipher cipher = new NullCipher();
cipher.init(Cipher.DECRYPT_MODE, priKey, ecPrivateKeySpec.getParams());
return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
}
}
And here is the output:
Step 1: This is the secret message I want to encrypt using ECC -> MySecretMessage
Step 2: This is the secret message encrypted, I can share this -> MySecretMessage
Step 3: This is the secret message decrypted, it should be equal to mySecretMessage, but not mySecretMessageEncrypted -> MySecretMessage
The issue I am facing is on Step 2: I am surprisingly getting "MySecretMessage", same as the original and decrypted message.
I was hoping to see something encrypted here.
May I ask what is the technical issue please?
Thank you
Related
This question already has an answer here:
RSA encyrption - converting between bytes array and String [duplicate]
(1 answer)
Closed 2 years ago.
we are trying RSA Encryption & Decryption and the issue happens while decrypting. This is our decryption code
Cipher oaepFromInit = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-1", "MGF1", new MGF1ParameterSpec("SHA-1"), PSpecified.DEFAULT);
oaepFromInit.init(Cipher.DECRYPT_MODE, rsaPrivateKey, oaepParams);
byte[] dec = oaepFromInit.doFinal(encrytpedData.getBytes());
The encrytpedData is like this
s11Pyj5rrVOfOiWtxpGq+K5D+pYi16CyyX/EwKfMErBkHJ4aVlTmnhrfeCS7LEeXgTs3gkFp96I/oTedG/rXxF2hTAmMH40k0joKJbRtzO858/0dcaaE1uNzr/rI0Jj3ebXPLGhefCMNNpyFH5V4ukVo6vtev5Z9U8oNkUQolbX/r5jJJomkKCCnzGoHMdQg5dafj9Sw/qakO13501YBrkxS0i9ca0GZ8Ll42NwkOZuInh+MAu+gYW4vAr284eJsqgLgTp0+MS1tmfwR6EXgspk1nYR/U84P3MBZAdpmD3nxsVV3iVOCUeoqVyd4kw7M2pvXev6hMbMN4P1nnomo8g==
An error exception was thrown saying javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
We looked into this link getting a IllegalBlockSizeException: Data must not be longer than 256 bytes when using rsa, but the issue was with the way we were feeding the encrytpedData.
This is a code we got online
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
RSAPublicKey pubkey = (RSAPublicKey) kp.getPublic();
RSAPrivateKey privkey = (RSAPrivateKey) kp.getPrivate();
// --- encrypt given algorithm string
Cipher oaepFromAlgo = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
oaepFromAlgo.init(Cipher.ENCRYPT_MODE, pubkey);
byte[] ct = oaepFromAlgo.doFinal("chakka".getBytes(StandardCharsets.UTF_8));
// --- decrypt given OAEPParameterSpec
Cipher oaepFromInit = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-1", "MGF1", new MGF1ParameterSpec("SHA-1"), PSpecified.DEFAULT);
oaepFromInit.init(Cipher.DECRYPT_MODE, privkey, oaepParams);
byte[] pt = oaepFromInit.doFinal(ct);
System.out.println("Printing decoded string");
System.out.println(new String(pt, StandardCharsets.UTF_8));
Here they are supplying the encrypted array directly and works fine, but in our case we are getting encrytpedData as String. Both the codes are same but the supply of encrypted data differs.
byte[] dec = oaepFromInit.doFinal(encrytpedData.getBytes());
This is where we are getting the exception, so we tried converting the encrytpedData to byte[] in a different way via these two links
RSA encyrption - converting between bytes array and String [duplicate]
IllegalBlockSizeException when trying to encrypt and decrypt a string with AES
So we tried like this
byte[] dec = oaepFromInit.doFinal(Base64.getDecoder().decode(encrytpedData)); which resulted in this javax.crypto.BadPaddingException: Message is larger than modulus.
byte[] dec = oaepFromInit.doFinal(encrytpedData.getBytes(StandardCharsets.UTF_8)); which gave the same old exception javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes.
Any help would be appreciated
The below full example code is taken from my private cross-platform project and should work. It encrypts a string using RSA encryption with a 2048 key pair and uses OAEP padding with SHA-1 as hash.
The encrypted data are in base64 encoding. For demonstration purpose I'm using static (hardcoded) keys in PEM-format - never ever do this in production.
You can run the code online here: https://repl.it/#javacrypto/CpcJavaRsaEncryptionOaepSha1String
this is the output:
RSA 2048 encryption OAEP SHA-1 string
plaintext: The quick brown fox jumps over the lazy dog
* * * encrypt the plaintext with the RSA public key * * *
ciphertextBase64: pSPayOK79NMPLpaQOp8L7dOTdLeS+jVU5cKPF5mDOvuKtnOjf/NYfgsf1JWa5Ud/fzsXrSN8I/8KAs/freagOYflv6PGUHZ7cYk1iX6sO5cmdD0Mfglj39NxczbqCK3FG20hQfa01ZaOu/dV8+QvVx851ph1nEl8arNML5ohhjIdZTxR3olGouGzDJmuJkDlv2fJICP7sdMnvl7t21QI701I2xR01eatD5src5fY//EIOEjSoTesCBZwEUz1S3UpclNqGONAqaYqlscdTyAlY3Hg8smJRqKWk7ZWKSTYsocBbFeTvcNy75LG/xyILM0l4U+NnwGUypkjR2vJRGVQtw==
* * * decrypt the ciphertext with the RSA private key * * *
ciphertextReceivedBase64: pSPayOK79NMPLpaQOp8L7dOTdLeS+jVU5cKPF5mDOvuKtnOjf/NYfgsf1JWa5Ud/fzsXrSN8I/8KAs/freagOYflv6PGUHZ7cYk1iX6sO5cmdD0Mfglj39NxczbqCK3FG20hQfa01ZaOu/dV8+QvVx851ph1nEl8arNML5ohhjIdZTxR3olGouGzDJmuJkDlv2fJICP7sdMnvl7t21QI701I2xR01eatD5src5fY//EIOEjSoTesCBZwEUz1S3UpclNqGONAqaYqlscdTyAlY3Hg8smJRqKWk7ZWKSTYsocBbFeTvcNy75LG/xyILM0l4U+NnwGUypkjR2vJRGVQtw==
decryptedtext: The quick brown fox jumps over the lazy dog
Security warning: the code does not have any exception handling, uses static (hardcoded) keys and is for educational purpose only.
code:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws GeneralSecurityException, IOException {
System.out.println("RSA 2048 encryption OAEP SHA-1 string");
String dataToEncryptString = "The quick brown fox jumps over the lazy dog";
byte[] dataToEncrypt = dataToEncryptString.getBytes(StandardCharsets.UTF_8);
System.out.println("plaintext: " + dataToEncryptString);
// # # # usually we would load the private and public key from a file or keystore # # #
// # # # here we use hardcoded keys for demonstration - don't do this in real programs # # #
String filenamePrivateKeyPem = "privatekey2048.pem";
String filenamePublicKeyPem = "publickey2048.pem";
// encryption
System.out.println("\n* * * encrypt the plaintext with the RSA public key * * *");
PublicKey publicKeyLoad = getPublicKeyFromString(loadRsaPublicKeyPem());
// use this in production
//PublicKey publicKeyLoad = getPublicKeyFromString(loadRsaKeyPemFile(filenamePublicKeyPem));
String ciphertextBase64 = base64Encoding(rsaEncryptionOaepSha1(publicKeyLoad, dataToEncrypt));
System.out.println("ciphertextBase64: " + ciphertextBase64);
// transport the encrypted data to recipient
// receiving the encrypted data, decryption
System.out.println("\n* * * decrypt the ciphertext with the RSA private key * * *");
String ciphertextReceivedBase64 = ciphertextBase64;
//String ciphertextReceivedBase64 = "l4G3O42LtjI9KkzvcF7SQcpqrkOMJw1sWVuI3FCZ1g+Sp/t05E3ZEXyVV/FnadkKVgmpWBifaYPEdKNBTbuts2F1DfrDz1v14lKlMOcqkJB8OmJUAiKJ1ic414R7M5fECKruqkzOdKlTtdb3MI49Ygrzd/cJxOGEvONo3DAOq1kZvZdmyW+K8m807g2qoy833EHyj9NjVZHuDzXi8fMxbIAI5MrN8ykXZBxkFOAGiITEFbGPxu6gBOPJKsPWJ0SVU53CiI1YwGc76/ov4c7FIA1ZeVsJXKo8CEfYuUc7PKIJ3e5Z7CbiNgr4Z5720Xbi0drUBk/LlYq6m8s/zEIMaQ==";
System.out.println("ciphertextReceivedBase64: " + ciphertextReceivedBase64);
PrivateKey privateKeyLoad = getPrivateKeyFromString(loadRsaPrivateKeyPem());
// use this in production
//PrivateKey privateKeyLoad = getPrivateKeyFromString(loadRsaKeyPemFile(filenamePrivateKeyPem));
byte[] ciphertextReceived = base64Decoding(ciphertextReceivedBase64);
byte[] decryptedtextByte = rsaDecryptionOaepSha1(privateKeyLoad, ciphertextReceived);
System.out.println("decryptedtext: " + new String(decryptedtextByte, StandardCharsets.UTF_8));
}
public static byte[] rsaEncryptionOaepSha1 (PublicKey publicKey, byte[] plaintextByte) throws NoSuchAlgorithmException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidAlgorithmParameterException {
byte[] ciphertextByte = null;
Cipher encryptCipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
//OAEPParameterSpec oaepParameterSpecJCE = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
// note: SHA1 is the default for Java
OAEPParameterSpec oaepParameterSpecJCE = new OAEPParameterSpec("SHA1", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParameterSpecJCE);
ciphertextByte = encryptCipher.doFinal(plaintextByte);
return ciphertextByte;
}
public static byte[] rsaDecryptionOaepSha1 (PrivateKey privateKey, byte[] ciphertextByte) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
byte[] decryptedtextByte = null;
Cipher decryptCipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
//OAEPParameterSpec oaepParameterSpecJCE = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
OAEPParameterSpec oaepParameterSpecJCE = new OAEPParameterSpec("SHA1", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParameterSpecJCE);
decryptedtextByte = decryptCipher.doFinal(ciphertextByte);
return decryptedtextByte;
}
private static String base64Encoding(byte[] input) {
return Base64.getEncoder().encodeToString(input);
}
private static byte[] base64Decoding(String input) {
return Base64.getDecoder().decode(input);
}
private static String loadRsaPrivateKeyPem() {
// this is a sample key - don't worry !
return "-----BEGIN PRIVATE KEY-----\n" +
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDwSZYlRn86zPi9\n" +
"e1RTZL7QzgE/36zjbeCMyOhf6o/WIKeVxFwVbG2FAY3YJZIxnBH+9j1XS6f+ewjG\n" +
"FlJY4f2IrOpS1kPiO3fmOo5N4nc8JKvjwmKtUM0t63uFFPfs69+7mKJ4w3tk2mSN\n" +
"4gb8J9P9BCXtH6Q78SdOYvdCMspA1X8eERsdLb/jjHs8+gepKqQ6+XwZbSq0vf2B\n" +
"MtaAB7zTX/Dk+ZxDfwIobShPaB0mYmojE2YAQeRq1gYdwwO1dEGk6E5J2toWPpKY\n" +
"/IcSYsGKyFqrsmbw0880r1BwRDer4RFrkzp4zvY+kX3eDanlyMqDLPN+ghXT1lv8\n" +
"snZpbaBDAgMBAAECggEBAIVxmHzjBc11/73bPB2EGaSEg5UhdzZm0wncmZCLB453\n" +
"XBqEjk8nhDsVfdzIIMSEVEowHijYz1c4pMq9osXR26eHwCp47AI73H5zjowadPVl\n" +
"uEAot/xgn1IdMN/boURmSj44qiI/DcwYrTdOi2qGA+jD4PwrUl4nsxiJRZ/x7PjL\n" +
"hMzRbvDxQ4/Q4ThYXwoEGiIBBK/iB3Z5eR7lFa8E5yAaxM2QP9PENBr/OqkGXLWV\n" +
"qA/YTxs3gAvkUjMhlScOi7PMwRX9HsrAeLKbLuC1KJv1p2THUtZbOHqrAF/uwHaj\n" +
"ygUblFaa/BTckTN7PKSVIhp7OihbD04bSRrh+nOilcECgYEA/8atV5DmNxFrxF1P\n" +
"ODDjdJPNb9pzNrDF03TiFBZWS4Q+2JazyLGjZzhg5Vv9RJ7VcIjPAbMy2Cy5BUff\n" +
"EFE+8ryKVWfdpPxpPYOwHCJSw4Bqqdj0Pmp/xw928ebrnUoCzdkUqYYpRWx0T7YV\n" +
"RoA9RiBfQiVHhuJBSDPYJPoP34kCgYEA8H9wLE5L8raUn4NYYRuUVMa+1k4Q1N3X\n" +
"Bixm5cccc/Ja4LVvrnWqmFOmfFgpVd8BcTGaPSsqfA4j/oEQp7tmjZqggVFqiM2m\n" +
"J2YEv18cY/5kiDUVYR7VWSkpqVOkgiX3lK3UkIngnVMGGFnoIBlfBFF9uo02rZpC\n" +
"5o5zebaDImsCgYAE9d5wv0+nq7/STBj4NwKCRUeLrsnjOqRriG3GA/TifAsX+jw8\n" +
"XS2VF+PRLuqHhSkQiKazGr2Wsa9Y6d7qmxjEbmGkbGJBC+AioEYvFX9TaU8oQhvi\n" +
"hgA6ZRNid58EKuZJBbe/3ek4/nR3A0oAVwZZMNGIH972P7cSZmb/uJXMOQKBgQCs\n" +
"FaQAL+4sN/TUxrkAkylqF+QJmEZ26l2nrzHZjMWROYNJcsn8/XkaEhD4vGSnazCu\n" +
"/B0vU6nMppmezF9Mhc112YSrw8QFK5GOc3NGNBoueqMYy1MG8Xcbm1aSMKVv8xba\n" +
"rh+BZQbxy6x61CpCfaT9hAoA6HaNdeoU6y05lBz1DQKBgAbYiIk56QZHeoZKiZxy\n" +
"4eicQS0sVKKRb24ZUd+04cNSTfeIuuXZrYJ48Jbr0fzjIM3EfHvLgh9rAZ+aHe/L\n" +
"84Ig17KiExe+qyYHjut/SC0wODDtzM/jtrpqyYa5JoEpPIaUSgPuTH/WhO3cDsx6\n" +
"3PIW4/CddNs8mCSBOqTnoaxh\n" +
"-----END PRIVATE KEY-----";
}
private static String loadRsaPublicKeyPem() {
// this is a sample key - don't worry !
return "-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8EmWJUZ/Osz4vXtUU2S+\n" +
"0M4BP9+s423gjMjoX+qP1iCnlcRcFWxthQGN2CWSMZwR/vY9V0un/nsIxhZSWOH9\n" +
"iKzqUtZD4jt35jqOTeJ3PCSr48JirVDNLet7hRT37Ovfu5iieMN7ZNpkjeIG/CfT\n" +
"/QQl7R+kO/EnTmL3QjLKQNV/HhEbHS2/44x7PPoHqSqkOvl8GW0qtL39gTLWgAe8\n" +
"01/w5PmcQ38CKG0oT2gdJmJqIxNmAEHkatYGHcMDtXRBpOhOSdraFj6SmPyHEmLB\n" +
"ishaq7Jm8NPPNK9QcEQ3q+ERa5M6eM72PpF93g2p5cjKgyzzfoIV09Zb/LJ2aW2g\n" +
"QwIDAQAB\n" +
"-----END PUBLIC KEY-----";
}
public static PrivateKey getPrivateKeyFromString(String key) throws GeneralSecurityException {
String privateKeyPEM = key;
privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----", "");
privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", "");
privateKeyPEM = privateKeyPEM.replaceAll("[\\r\\n]+", "");
byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
PrivateKey privKey = (PrivateKey) kf.generatePrivate(keySpec);
return privKey;
}
public static PublicKey getPublicKeyFromString(String key) throws GeneralSecurityException {
String publicKeyPEM = key;
publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----", "");
publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
publicKeyPEM = publicKeyPEM.replaceAll("[\\r\\n]+", "");
byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pubKey = (PublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
return pubKey;
}
private static String loadRsaKeyPemFile(String filename) throws IOException {
return new String(Files.readAllBytes(Paths.get(filename)), StandardCharsets.UTF_8);
}
}
I'm trying to find the similar java code for the below Node JS code,
Node JS Code:
var crypto = require('crypto');
var mykey = crypto.createCipher('aes-128-ecb', 'XXXXXXXX00000000');
var mystr = mykey.update('HelloWorld', 'utf8', 'hex')
mystr += mykey.final('hex');
console.log(mystr);
Encryption Result: ce25d577457cf8113fa4d9eb16379529
Java Code:
public static String toHex(String arg) throws UnsupportedEncodingException {
return String.format("%x", new BigInteger(1, arg.getBytes("UTF-8")));
}
public static void main(String args[]) throws Exception{
byte[] key = "XXXXXXXX".getBytes();
String message = "HelloWorld";
try {
key = Arrays.copyOf(key, 16);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte encstr[] = cipher.update(message.getBytes());
String encData = new String(encstr, "UTF-8");
encData = toHex(encData);
byte encstr2[] = cipher.doFinal();
String encData2 = new String(encstr2);
encData = encData + toHex(encData2);
System.out.println(encData);
} catch (NoSuchAlgorithmException nsae) {
throw new Exception("Invalid Java Version");
} catch (NoSuchPaddingException nse) {
throw new Exception("Invalid Key");
}
}
Encryption Result: 056efbfbdefbfbd7c7760efbfbdefbfbdefbfbd39262cefbfbdefbfbd5166
Taking up the comments of #Robert and #Topaco I wrote a simple decryption program that is working for the given password 'XXXXXXXX00000000'.
Please keep in mind that this progrsm is using UNSECURE AES ECB mode and UNSECURE MD5 hash algorithm.
The program does NOT provide any proper exception handling.
This is the result:
ciphertext Java: ce25d577457cf8113fa4d9eb16379529
ciphertext NodeJS: ce25d577457cf8113fa4d9eb16379529
My code:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MainSo {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
System.out.println("https://stackoverflow.com/questions/63263081/node-js-encryption-code-to-java-encryption-code");
String plaintext = "HelloWorld";
String keyString = "XXXXXXXX00000000"; // 16 chars
byte[] key = keyString.getBytes(StandardCharsets.UTF_8);
// md5 hashing is unsecure !!
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] keyMd5 = md.digest(key);
// aes ecb mode encryption is unsecure
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(keyMd5, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
System.out.println("ciphertext Java: " + bytesToHex(ciphertext));
System.out.println("ciphertext NodeJS: " + "ce25d577457cf8113fa4d9eb16379529");
}
private static String bytesToHex(byte[] bytes) {
// service method for displaying a byte array as hex string
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}
I am trying to generate an encrypted message to send to a remote server and when I do it in Java I succeed but when I try it in PHP, I fail.
I would like your help in pointing out where I am going wrong in the php version. Below is the Java and php version of my code.
private String encryptMessage() {
String msg = "";
String message = "this is the message to send";
String modulus = "xxxxxxxxxxxxxxx";
String exponent = "111";
Security.addProvider(new BouncyCastleProvider());
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger(modulus, 16), new BigInteger(exponent, 16));
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(publicKeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] messageDataBytes = cipher.doFinal(message.getBytes("UTF8"));
msg = Base64.getEncoder().encodeToString(messageDataBytes).replaceAll("\\r|\\n", "");
return msg;
}
The php version that fails
private function encryptMessage()
{
$message = "this is the message to send";
$modulus = "xxxxxxxxxxxxxxx";
$exponent = "111";
$rsa = new RSA();
$exponent = new BigInteger( $exponent, 16);
$modulus = new BigInteger($modulus, 16);
$rsa->loadKey(['n' => $modulus, 'e'=>$exponent]);
$rsa->setPublicKey();
$publicKey = $rsa->getPublicKey();
openssl_public_encrypt($message, $encryptedData, $publicKey);
return base64_encode($encryptedData);
}
For Java,I am using the Bouncy Castle Library while I am using phpseclib version 2 library.
Thanks.
Result from the Java method: VU06XTAFfNfBSjhWz+deqVt/cZw7YBG1nfl0g/c8GwInVTiW1oOwX53z2+Sxp3o65kNztwRSA4ARVKjnrH4M/ygJ+9jrHLvKWt2mmKbcTF9tkmd3Ezdd429s44azulFNRwH0lqQNy80mPTpNzRN4QDkeuRp1mUqDlNHQ70T7BdWwCvjMXZ/kBjXEHocYE+fNmXjgxCQFDCkek1CZQ+IDvxRyW5MtsuQDzAphUO3Kj5epMTJkzUuekV1RzCUErerfUUb83HAo3hh6IGuqhSw3MKjVY7g7AlO0P/0n1pI2+fi/g0EojK7MJt8mzx/WrWxQH2fiMo0GuTb4+YB4+YS9dQ==
Result from PHP:
U1pWl/ohAkP+1+L25vCMwVeQ3bkRJwwWocDn/lWgIkFYM6V8/Wn+LHVbm/ku0ZV0we1tXUkQE784xH7q7Cd9h4P2mGA5XWHdtGHTzQaxHgT31DN/60I5rDsC8A3OJORNbJk/6rBh8PuDEi33vqtayE7v4rqIYXTxAwDWUgjvnBtJOQtZXgfhrnCb/jKiLP5WY2yBfa5/3eHoLCtmButGy2GgrEmg08OnvJlqSTQd/Xtc+1NhWVlha8+vk2e/rZZn/aOzvYAOoUZQbWRUhlonObfom/1HtRJrBJGfJxv2zLFNPP6RrDgoYptMhsNs4r8OVSxj6qiEYFx9tjNqp9c1xA==
My solution consists of 3 files to get a complete testing environment with full working encryption and decryption in Java
and encryption only in PHP.
The test environment I'm working on is on Java-side 11.0.6+8-b520.43 (without any dependencies, e.g. Bouncy Castle)
and on PHP-side php version 7.4.6, openssl version: OpenSSL 1.1.1g 21 Apr 2020 and phpseclib 2.0.27.
GenerateKeysSo.java: generates an RSA private/public keypair in modulus/exponent-presentation. I use the insecure 512 bit keylength just to keep the string length a little bit shorter - in production you should use a minimum of 2048 bit keylength.
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;
public class GenerateKeysSo {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
System.out.println("https://stackoverflow.com/questions/53947613/rsa-public-key-generated-in-java-is-not-valid-in-php");
System.out.println("Generate RSA keys");
System.out.println("java version: " + Runtime.version());
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
//kpGen.initialize(2048, new SecureRandom());
kpGen.initialize(512, new SecureRandom()); // don't use 512 bitlength as it is insecure !
KeyPair keyPair = kpGen.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
byte[] privateKeyEncoded = privateKey.getEncoded();
byte[] publicKeyEncoded = publicKey.getEncoded();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
BigInteger modulus = rsaPublicKey.getModulus();
BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
BigInteger publicKeyExponent = rsaPublicKey.getPublicExponent();
System.out.println("privateKey Base64: " + Base64.getEncoder().encodeToString(privateKeyEncoded));
System.out.println("publicKey Base64: " + Base64.getEncoder().encodeToString(publicKeyEncoded));
System.out.println("modulus : " + modulus);
System.out.println("privateExponent : " + privateExponent);
System.out.println("publicExponent : " + publicKeyExponent);
}
}
The result is short and you need to copy the 3 values of modulus, privateExponent and publicExponent with copy/paste to EncryptSo.java and to
EncryptSo.php:
Generate RSA keys
java version: 11.0.6+8-b520.43
privateKey Base64: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAgKpP+4e9D3r5Mbw4VBaQQG/LRw7nqDOWOU6p+teU2c+mTPE2apPzYUku9AaNf+BiPyjzmkWh/9d7E5jUDWfS9QIDAQABAkA9Ia5y0eFwE3uGt+kDetz64KLylhBXCHudqtR0TC169s4UfGr6EquaqX9YKmQ4ApC5mkO65Rha8V0WzV6PEUlBAiEA6XtDObkbbhAMaDXpLkzqu0I5O2e3cpTMGwCTaK/0GVkCIQCNExoakOZ1+0f5UuiztmGo7UqBpZEieiybL25H/iI2/QIhANPubzcWLy/YoWp2hRLh/q+7jPe/TWVUa3CXNTbxgEEBAiAyA22jsW8isJ0JlQ0OeUASJV3erJXRhUK/GYedWklC+QIgLnxzZVDSNNEGYFpUER0v2bIFWqVXlnm87y5LRbzWn/I=
publicKey Base64: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAICqT/uHvQ96+TG8OFQWkEBvy0cO56gzljlOqfrXlNnPpkzxNmqT82FJLvQGjX/gYj8o85pFof/XexOY1A1n0vUCAwEAAQ==
modulus : 6738747659637003090018178263545882875809887577706500222853194115214616163418986509701683514500084328991941041539147237736316411294805049495944982937719541
privateExponent : 3201720015041533823900789397901821886674218828976379815054133670438877551559197501362784700723343540531608097210070472157677675484894343978127401531033921
publicExponent : 65537
File 2 is the encryption/decryption routine in Java (EncryptSo.java). Paste the 3 values from GenerateSo to the three string variables modulusString,
privateExponentString and publicExponentString. Run the program and it will encrypt a message and decrypt it. After running the PHP-encryption (file 3)
you have an output there - you can paste this output to line 42 (variable ciphertextFromPhp). This string will get decrypted as well.
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
public class EncryptSo {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException, IOException {
System.out.println("https://stackoverflow.com/questions/61966418/converting-a-java-encryption-method-to-php");
System.out.println("encrypt and decrypt with Java with key generation via modulus and exponent");
String modulusString = "7655411376708364139873444642436134423578239360576333940175884244078181837546293928220019721607335417517025652060442851820596480386882812189086919617782503";
String privateExponentString = "6181379361775076881056852519774102589787650800051550108278185489542231510128103539355646657479306697213227070361180012317478947328351699562861534356668225";
String publicExponentString = "65537";
BigInteger modulusBI = new BigInteger(modulusString);
BigInteger publicExponentBI = new BigInteger(publicExponentString,10); // 10 = numeric string
BigInteger privateExponentBI = new BigInteger(privateExponentString,10); // 16 = hex string
// generate private & public keys
KeyFactory factory = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulusBI, privateExponentBI);
PrivateKey privateKeyBI = factory.generatePrivate(rsaPrivateKeySpec);
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulusBI, publicExponentBI);
PublicKey publicKeyBI = factory.generatePublic(rsaPublicKeySpec);
// encryption
String message = "this is the message to send";
System.out.println("message Original : " + message);
String ciphertext = encryptMessageEnc(message, publicKeyBI);
System.out.println("message encrypted: " + ciphertext);
// decryption
String decryptedtext = decryptMessageEnc(ciphertext, privateKeyBI);
System.out.println("message decrypted: " + decryptedtext);
System.out.println("decryption of a encrypted message from PHP");
String ciphertextFromPhp = "B3a1v8oGVYqRpRwRwGP5KRaqaNiiXFRfTdWnz0LsI4Ek63BpXIrWsEXsVNaj1jSu4XIQNrvYHIpwdxwKQrBUUfXXwq6Pix0YfuOmz7mUJMyTerHMcVzcXIpEGAD/L0gGomfCbkahed/CimThPSO527ulazHVirOY173JjMTrWdqyFLS6L7sCD6UHkU49gW94ADkOJtRXOiIWTg==";
System.out.println("message encrypted: " + ciphertextFromPhp);
decryptedtext = decryptMessageEnc(ciphertext, privateKeyBI);
System.out.println("message decrypted: " + decryptedtext);
}
private static String encryptMessageEnc(String message, PublicKey publicKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, BadPaddingException, IllegalBlockSizeException {
String msg = "";
//Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] ciphertextBytes = cipher.doFinal(message.getBytes("UTF8"));
msg = Base64.getEncoder().encodeToString(ciphertextBytes).replaceAll("\\r|\\n", "");
return msg;
}
private static String decryptMessageEnc(String msg, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
//Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] message = Base64.getDecoder().decode(msg);
byte[] messageDataBytes = cipher.doFinal(message);
return new String(messageDataBytes);
}
}
output of EncryptSo:
encrypt and decrypt with Java with key generation via modulus and exponent
java version: 11.0.6+8-b520.43
message Original : this is the message to send
message encrypted: WZs0jp6yMWR71I4g7Oxo54A28yDZRBs5usKYLz9NfoRkMPy7vpe+riLSZzr6mdC8XZFNGveH9HsG2maZWSxhsw==
message decrypted: this is the message to send
decryption of a encrypted message from PHP
message encrypted: B3a1v8oGVYqRpRwRwGP5KRaqaNiiXFRfTdWnz0LsI4Ek63BpXIrWsEXsVNaj1jSu4XIQNrvYHIpwdxwKQrBUUfXXwq6Pix0YfuOmz7mUJMyTerHMcVzcXIpEGAD/L0gGomfCbkahed/CimThPSO527ulazHVirOY173JjMTrWdqyFLS6L7sCD6UHkU49gW94ADkOJtRXOiIWTg==
message decrypted: this is the message to send
File 3 (EncryptSo.php) is simple PHP-application that builds the public key via modulus and exponent and need the external dependency "phpseclib". I included the library without any composer-help just manually. Paste the modulus and exponent to the variables modulusString and publicExponentString and let it run.
<?php
// https://stackoverflow.com/questions/61966418/converting-a-java-encryption-method-to-php
include('phpseclib\Math\BigInteger.php');
include('phpseclib\Crypt\RSA.php');
include('phpseclib\Crypt\HASH.php');
echo 'php version: ' . PHP_VERSION . ' openssl version: ' . OPENSSL_VERSION_TEXT . ' phpseclib 2.0.27' . PHP_EOL;
$message = "this is the message to send";
$modulusString = "7655411376708364139873444642436134423578239360576333940175884244078181837546293928220019721607335417517025652060442851820596480386882812189086919617782503";
$publicExponentString = "65537";
$rsa = new \phpseclib\Crypt\RSA();
//$rsa = new Crypt_RSA();
$exponent = new phpseclib\Math\BigInteger($publicExponentString, 256);
$modulus = new phpseclib\Math\BigInteger($modulusString, 256);
$PUBLICKEY = "";
$rsa->loadKey(['n' => $modulus, 'e'=>$exponent]);
$rsa->setPublicKey();
$publicKey = $rsa->getPublicKey();
openssl_public_encrypt($message, $encryptedData, $publicKey);
$encryptedData = base64_encode($encryptedData);
echo PHP_EOL ."encryptedData base64: " . $encryptedData . PHP_EOL;
// encryptedData base64: K4DCBvi2lWbyQJGiQbZ9cXiZy49sg+Q0KKPvj7+TMObTCyWKtoQce8pmUJlDZ48+K1Fy3vHtTTZFDQzr7fkWKoeYffl171IsxOgFLz2bmjQYhrNiLy5ZI03qUX4i9MI0mtSMlITXhiryDOajHB61Cgs5cfgH+yVCJItV7cM/qMBAGnQVqoMxRAKaSOBEz/zxp3If5X9Jb5zuhA==
?>
Result of PHP encryption:
php version: 7.4.6 openssl version: OpenSSL 1.1.1g 21 Apr 2020 phpseclib 2.0.27
encryptedData base64: M5ys/5JrlleQO5MJDVl6FvRcIUIcxXQhp00y/KLHfB1p0XRNaVaWRwV9t5NKoJmo4wKI1KQI1H9PBd71c6t3i7IWsWcS8QsebOk5iitacvgOTJBW71pjrzWkv4+M7Ge8KZ/jhCl6nQ+e9zNSkJf4HZE1NHmOzFan3pBN1gXDptj19AZPue/MxqdAIgDD538UElvhTzyWMpCJeA==
I make encryption on python and try to decrypt it on Java, but always get decryption error
I have part of code for encrypt and decrypt message in JAVA encoded in RSA
For decrypt:
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class Decrypter
{
public static void main(String[] args)
{
try {
String encoded_data = "PueF1RC5giqmUK9U+X80SwjAjGmgfcHybjjQvWdqHSlua1rv6xr7o6OMutHBU+NRuyCJ3etTQssYOMGiWPITbEC8xr3WG9H9oRRnvel4fYARvQCqsGmf9vO9rXcaczuRKc2zy6jbutt59pKoVKNrbonIBiGN1fx+SaStBPe9Jx+aZE2hymDsa+xdmBSCyjF30R2Ljdt6LrFOiJKaDiYeF/gaej1b7D8G6p0/HBPxiHMWZhx1ZfylSvZ6+zyP0w+MJn55txR2Cln99crGtcdGeBDyBtpm3HV+u0VlW7RhgW5b+DQwjQ/liO+Ib0/ZIPP9M+3sipIwn2DKbC45o0FZHQ==";
byte[] decodeData = Base64.getDecoder().decode(encoded_data);
String publicKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzN2+mrQRXKshq3k0r06" +
"0/FoWafOCl6fCCyuu/7SejNU95SN2LZyopA3ipamY5MeK1G1XHOhEfkPWcYcgUbz" +
"TdD166nqJGi/O+rNK9VYgfhhqD+58BCmLlNidYpV2iDmUZ9B/cvVsQi96GY5XOaK" +
"xuVZfwrDK00xcOq+aCojQEvMh+gry05uvzfSv9xK3ki5/iCMY62ReWlmrY0B19CQ" +
"47FuulmJmrxi0rv2jpKdVsMq1TrOsWDGvDgZ8ieOphOrqZjK0gvN3ktsv63kc/kP" +
"ak78lD9opNmnVKY7zMN1SdnZmloEOcDB+/W2d56+PbfeUhAHBNjgGq2QEatmdQx3" +
"VwIDAQAB";
KeyFactory kf = KeyFactory.getInstance("RSA");
byte[] encodedPb = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpecPb = new X509EncodedKeySpec(encodedPb);
PublicKey pubKey = kf.generatePublic(keySpecPb);
Cipher cipherDecr = Cipher.getInstance("RSA");
cipherDecr.init(Cipher.DECRYPT_MODE, pubKey);
byte[] cipherDataDecr = cipherDecr.doFinal(decodeData);
String result = new String(cipherDataDecr);
System.out.println("result = "+result);
}catch (Exception e){
e.printStackTrace(System.out);
}
}
}
Unfortunately I can't make changes in this code, so all what I can is make changes in python part. This part work correctly. for check I use this code for encrypt:
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class Encrypter
{
public static void main(String[] args)
{
try {
String data = "111111111222";
String privateKeyString = "here is my privat key";
byte [] encoded = Base64.getDecoder().decode(privateKeyString);
System.out.println("encoded = "+encoded);
java.security.Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new PKCS8EncodedKeySpec(encoded);
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(ks);
System.out.println("privKey = "+privKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, privKey);
byte[] cipherData = cipher.doFinal(data.getBytes());
String card = Base64.getEncoder().encodeToString(cipherData);
System.out.println("data = "+card);
}catch (Exception e){
e.printStackTrace(System.out);
}
}
}
And when I use result from Java code for encrypt and put this result to decrypt Java file - all work's great. I need same encryption part, but writing with python.
Part for encrypt with python
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
data = '111111111222'
privat_key = 'here is my privat key'
key = RSA.importKey(privat_key)
cipher = PKCS1_v1_5.new(key)
encrypted_message = str(base64.b64encode(cipher.encrypt(base64.b64decode(data))), 'utf8')
print(encrypted_message)
So, questions is how I should encrypt message for correct decryption with on Java?
I tried different libs (standard rsa, Pycrypto RSA, PKCS1_OAEP, PKCS1_v1_5) and nothing help me
P.S. I know about wrong way for use keys pair, but it is requirements of the external system
UPDATE:
Using new instance fetch me to the some result. I changed format as Maarten Bodewes said
Cipher cipherDecr = Cipher.getInstance("RSA/ECB/NoPadding");
decryption result:
����2����ٰoܬ���(�RM#�/���u*�d�{���w�b+���v�ݏ[�$�#��xJo�s��F1���X��}���1 ���������t%`�YA/��?�
�ɼej�X�T�+6Y4D��!���
I can't read it, but it's not a Exception, it is good. Try to move this way
UPDATE:
I define that Java used RSA/ECB/PKCS1Padding as default. So I should use same in python
First of all I defined that java
Cipher cipher = Cipher.getInstance("RSA");
expanded in
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
or
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1PADDING");
For RSA no different what is defined in second argument (None or ECB). RSA doesn't use it.
So I need add padding to my encryption in python. Unfortunately PyCrypto hasn`t PKCS1PADDING, so i can't encrypt with this padding.
Next step I found M2Crypto lib https://gitlab.com/m2crypto/m2crypto
This fork worked for python3. just download and build it(instruction in repo)
Than I wrote this code and it works:
import M2Crypto
# read privat key
privatKey = M2Crypto.RSA.load_key('privat.key')
# encrypt plaintext using privat key
ciphertext = privatKey.private_encrypt(data.encode('utf-8'), M2Crypto.RSA.pkcs1_padding)
encrypted_message = str(base64.b64encode(ciphertext), 'utf8')
print(encrypted_message)
That's all. It works for me, and I believe, it can help u.
According to my code, Bouncy uses the padding for signature generation, so I presume that is what is different. You can perform a "raw" decrypt (modular exponentiation) and remove the padding yourself.
i got problem Encrypting a string using RSA.
my RSA is in XML format, it looks like that:
<RSAKeyValue><Modulus>lT8ykfyV0R8o3mJZZezLKTKJpYB90Pzvp0moLzh9CTGfgsxLKYiAl+YGaoRfQ7hVQos5UlLIONHWKPNco9kKcmL6EBJvFc8wqBnhX0p4ML2WSv1yDIRsm9XXra82WHIa3+fxK8bNUJHrucxmpr9pDRPdZGZkz+Q9s94FcOyFKbs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
and i'm trying to encrypt a string using this class:
import java.io.BufferedReader;
import java.io.StringReader;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.Security;
import javax.crypto.Cipher;
import org.bouncycastle.openssl.PEMReader;
import android.util.Base64;
import android.util.Log;
public class RsaEncryption {
private String publicKey;
public RsaEncryption(String publicKey)
{
this.publicKey = publicKey;
}
/*
* Function to encrypt the data.
*
*/
public String encrypt( String data ) throws Exception
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
byte[] keyBytes = Base64.decode( this.publicKey, 0 );
PublicKey publickey = strToPublicKey(new String(keyBytes));
cipher.init( Cipher.ENCRYPT_MODE , publickey );
// Base 64 encode the encrypted data
byte[] encryptedBytes = Base64.encode( cipher.doFinal(data.getBytes()), 0 );
return new String(encryptedBytes);
}
public static PublicKey strToPublicKey(String s)
{
PublicKey pbKey = null;
try {
BufferedReader br = new BufferedReader( new StringReader(s) );
PEMReader pr = new PEMReader(br);
Object obj = pr.readObject();
if( obj instanceof PublicKey )
{
pbKey = (PublicKey) pr.readObject();
}
else if( obj instanceof KeyPair )
{
KeyPair kp = (KeyPair) pr.readObject();
pbKey = kp.getPublic();
}
pr.close();
}
catch( Exception e )
{
Log.d("CIPHER", e.getMessage() );
}
return pbKey;
}
}
as you can see i'm using bouncycastle's jar
the error that i get is:
java.security.InvalidKeyException: unknown key type passed to RSA
I'm not sure about this part
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
maybe this is the problem?
if it is, what need to be there instead?
i did hours of research and still didn't find a solution...
Thanks in advance :)
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
maybe this is the problem?
No it's not.
OAEPWith<digest>And<mgf>Padding
Means Optimal Asymmetric Encryption Padding scheme defined in PKCS1, where <digest> should be replaced by the message digest algorithm and <mgf> by the mask generation function. Examples: OAEPWithMD5AndMGF1Padding and OAEPWithSHA-512AndMGF1Padding.
Reference Standard Names and RFC 4055.
The problem is in your Public Key generation. As your key is in XML, and Base64 encoded:
First you need to separate modulus and exponent.
Then Base64 decode both modulus and exponent.
After decoding you will get the byte array of modulus and exponent, so you can easily prepare public key object like the following procedure:
BigInteger modBigInteger = new BigInteger(1, modulus);//modulus must be byte array
BigInteger exBigInteger = new BigInteger(1, exponent);//exp must be byte array
RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(spec);
XML is not PEM.
You need to extract the modulus and the public exponent from the XML and then generate a key using an "RSA" KeyFactory instance and a RSAPublicKeySpec.