I use the following code to encrypt some data and I want to move the decryption code to a server so need to send the cipherData (which is a byte [] array ) to my server over REST
BigInteger modulus = new BigInteger("blah");
BigInteger exponent = new BigInteger("blah");
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory encryptfact = KeyFactory.getInstance("RSA");
PublicKey pubKey = encryptfact.generatePublic(keySpec);
String dataToEncrypt = "Hello World";
/**
* Encrypt data
*/
Cipher encrypt = Cipher.getInstance("RSA");
encrypt.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = encrypt.doFinal(dataToEncrypt.getBytes());
System.out.println("cipherData: " + new String(cipherData));
/**
* Decrypt data
*/
BigInteger privatemodulus = new BigInteger("blah");
BigInteger privateexponent = new BigInteger("blah");
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(privatemodulus, privateexponent);
PrivateKey privateKey = encryptfact.generatePrivate(privateKeySpec);
Cipher decrypt = Cipher.getInstance("RSA");
decrypt.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decData = decrypt.doFinal(cipherData);
System.out.println(new String(decData));
This works fine.
I was hoping I could just create a new String with the cipherData as a parm
When I try this with the above example I get the following error
byte[] decData = decrypt.doFinal(new String(cipherData).getBytes());
javax.crypto.BadPaddingException: Data must start with zero
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:308)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:255)
at com.sun.crypto.provider.RSACipher.a(DashoA13*..)
at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at com.test.EncryptTest.main(EncryptTest.java:52)
Any ideas?
I was hoping I could just create a new String with the cipherData as a parm
No. cipherData is arbitrary binary data. It's not encoded text, which is what the various String constructors expect. (As an aside, you should almost never call the String.getBytes() or new String(byte[]) which don't specify an encoding. Always specify an appropriate encoding, which will depend on the situation.)
Either transmit the data as binary data instead of going through text at all, or use Base64 to safely encode the binary data as text first, then decode it from Base64 to binary again later before decrypting. There's a public domain Base64 encoder which is easy to use.
Related
So I am trying to connect to a website service (Steam) which requires the program to have a Base64 encrypted key which contains the password of the account which I am trying to logon to. I have the RSA key but am having a little difficulty encrypting it with the password. Here is my code:
if(jsonObject.getBoolean("success")){
String timeStamp = jsonObject.getString("timestamp");
String publickey_mod = jsonObject.getString("publickey_mod");
String keyexp = jsonObject.getString("publickey_exp");
String modulus_preHex = new BigInteger(1, publickey_mod.getBytes("UTF-8")).toString(16);
String exponent_preHex = new BigInteger(1, keyexp.getBytes("UTF-8")).toString(16);
BigInteger modulus_post = new BigInteger(modulus_preHex);
BigInteger exponent_post = new BigInteger(exponent_preHex);
PublicKey key = getEncrpytedKey(modulus_post, exponent_post);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] passArray = pass.getBytes("UTF-8");
String encode = Base64.encodeBase64(cipher.doFinal(passArray)).toString();
System.out.println(encode + " - encode");
}
This takes place after a successful POST to the URL where I retrieve the RSAKEY (publickey_mod) and when it expires (keyexp). After ciphering the PublicKey I Base64 encode the string.
public PublicKey getEncrpytedKey(BigInteger m, BigInteger e) throws Exception{
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
}
^^^The method seen being used to get the PublicKey.
When I run this program, the 'encode' String does not change, even when I change the password that is it running with, it is currently:
String encode = [B#32d992b2
When the RSAKey is AB8AA7A6C2513D3CFFCA147F64E7B9C5400CCE5B36D3F881387659A51701D76BB383C1E50F52EF8DE28AD20F6257B8E0013720E4704F6ABDBCC19E477BD58C534A93895408157BE7874152A0153499773BC3AE4E536543A74341D58F7EA9CF74487C9560625BACE2315FB0983BD9E78BD812AE7DDC356427CC7626DCB8D25900658FE5E309D35BF794445F6EF9279882699E1CCBEE2F4193BA2634D0F7B24CFD7EC6A2AA8B35A48969C43DBF759095FCBD087C4D2D8123F598A4F43AECE0CE4E8FA536ECD84782092A329DF96FF88A25677AA386669B4ACAA41D7B6AAD456307357C70E25FD027970F5F0CF952894A065A37BA1BD2222A3AC2CD8FB69632560F
Note that I am not really well versed with encryption, as this is one of my first times trying it out.
Thanks for any help,
Tim
NOTE: I am using org.apache.commons.codec.binary.Base64; for Base64.
Base64.encodeBase64 returns a byte array so what you want is
encode = new String (Base64.encodeBase64(cipher.doFinal(passArray));
I'm developing an android app and getting this public key from the server of the company that I work with:
PFJTQUtleVZhbHVlPjxNb2R1bHVzPnZOcFhkRWVOTU5pZDhuOTlUekRGMVo4MDNvTEdRSzlqWnNFODlDd2tiS29GV0tGZmt2QTZKODBNWHhPZnhqbFZIYU8vYWM4YUpMc1AxWVR1RFNHVis3VExQL0puVVpyNlJQQTdpbFlmMitVWExiS0U2ZW1RYzBKdXlOaVArL0FTMGZmKzYwSnZQekhYeEdQQnVIbWtTcmRqdEtFV0JCZXJzWWNuQVJyT2ZSYz08L01vZHVsdXM+PEV4cG9uZW50PkFRQUI8L0V4cG9uZW50PjwvUlNBS2V5VmFsdWU+
the server is windows with IIS 7.5.
base64decode it give me this XML
<RSAKeyValue><Modulus>vNpXdEeNMNid8n99TzDF1Z803oLGQK9jZsE89CwkbKoFWKFfkvA6J80MXxOfxjlVHaO/ac8aJLsP1YTuDSGV+7TLP/JnUZr6RPA7ilYf2+UXLbKE6emQc0JuyNiP+/AS0ff+60JvPzHXxGPBuHmkSrdjtKEWBBersYcnARrOfRc=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
Extracting the Modulu and the Exponent from this xml, base64decode them and making the spec for the public key object:
PublicKey pbKey = null;
XMLParser parser = new XMLParser();
Document doc = parser.getDomElement(publicKeyString);
Element rsakeyvalue = doc.getDocumentElement();
String modulusBase64 = parser.getValue(rsakeyvalue, "Modulus");
byte[] modulus = Base64.decode(modulusBase64, 0);
String exponentBase64 = parser.getValue(rsakeyvalue, "Exponent");
byte[] exponent = Base64.decode(exponentBase64, 0);
BigInteger modBigInteger = new BigInteger(1,modulus);
BigInteger exBigInteger = new BigInteger(1,exponent);
RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);
try {
KeyFactory factory = KeyFactory.getInstance("RSA");
pbKey = factory.generatePublic(spec);
} catch (Exception e) {
e.printStackTrace();
}
Creating the cipher and adding the plain text to encrypt with:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
byte[] keyBytes = Base64.decode(this.publicKey, 0);
/* the strToPublicKey is the previews code block */
PublicKey publickey = strToPublicKey(new String(keyBytes));
cipher.init( Cipher.ENCRYPT_MODE , publickey );
// Base 64 encode removed.
//byte[] encryptedBytes = Base64.encode( cipher.doFinal(plainText.getBytes()), 0 );
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
everything here is working but the server don't accept it,
I'm base64 encode it and sending it as byte array.
the server admin saying it's too long, supposed to be 128 bit but it's 174 bit...
what I'm doing wrong?
How its called this key? RSA XML is correct? or it's got other name?
I can also get PEM string from the server if someone have an idea how to do it with it.
Edit:
i forgot to put here an important part, i'm sending the data to the server as byte array, this is how i make the string of it:
public static int unsignedToBytes(byte b) {
return b & 0xFF;
}
StringBuilder byteArrayString = new StringBuilder();
int bytesLength = bytes.length;
int bytesCounter = 0;
for (byte aByte : bytes) {
bytesCounter++;
byteArrayString.append(unsignedToBytes(aByte));
if(bytesCounter < bytesLength){
byteArrayString.append(",");
}
}
SOLVED! - the solution:
the bytes that the string builder used are signed so i use this function unsignedToBytes() to make them unsigned and i removed the base64Encription on the encrypt() function.
this was the problem, i hope it will help anyone else.
Your variable naming is bad. encryptedBytes contains not the encrypted bytes but the encrypted bytes in base64 encoding.
This is the reason you do not get the expected result.
The length of the encrypted data before applying Base64 encoding is 128 byte.
Afterwards the length is 172 bytes.
I have RSA Public-Key on server side in below format:
<string xmlns="http://www.cherripik.com/">
<RSAKeyValue><Modulus>abc</Modulus><Exponent>abc</Exponent></RSAKeyValue>
</string>
I have tried almost all possible ways but could not able to encrypt string with this public key on android side. Could anyone give me an example in which i will encrypt any of the string like "abc" with this public key and also decrypt that encrypted key to back to "abc". It will be very helpful to me.
Advance Thanks.
Below are the ways which i have used but no success. It gave some value but it is not correct.
public String encrypt(String message, String Modulus, String Exponent) {
String outputEncrypted = "";
try {
byte[] modulusBytes = Base64Coder.decode(Modulus);
byte[] exponentBytes = Base64Coder.decode(Exponent);
BigInteger modulus = new BigInteger(modulusBytes );
BigInteger exponent = new BigInteger(exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String("abc").getBytes("UTF-8");
byte[] cipherData = cipher.doFinal( plainBytes );
String encryptedString = new String(Base64Coder.encode(cipherData));
Log.i(this.getClass().getSimpleName(), "encryptedString : "+encryptedString);
} catch (Exception e) {
// TODO: handle exception
}
return outputEncrypted;
}
One more thing when I create encrypted string with above method. It will give 346 characters encrypted string. But on my server, I have only encrypt and decrypt method. On server encrypt method, it will producing 344 character. Lastly when I put my encrypted string to server method to verify that my encrypted string is correct. Server throw this error.
<string xmlns="http://www.Myserver.com/">Error occurred while decoding OAEP padding.</string>
public static String encryptByPublicKey(byte[] data, String key)
throws Exception {
byte[] keyBytes = decryptBASE64(key);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return new String(cipher.doFinal(data));
}
I have a public key, like MFWww.........EAAQ==. When I pass the string to that argument, the encrypted message is some unknown characters. Therefore I suspect I should do something on the key before passing it to the function. But I don't how could I make it. So see anyone can help.
Thank you
Never, ever, ever pass arbitrary binary data to the String constructor. You don't have encoded text, you have arbitrary bytes. That's not what the String constructor is for.
Ideally, don't represent the binary data as text at all - but if you have to, do so using base64 or hex, which will encode arbitrary binary data in ASCII.
I'm using RSA encryption for converting simpletext to encrypted form.
my plain text is : hello
encrypted text : [B#d7eed7
Now, how to convert encrypted text into simple plain text
i'm using following code
KeyPairGenerator keygenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keygenerator.initialize(1024, random);
KeyPair keypair = keygenerator.generateKeyPair();
PrivateKey privateKey = keypair.getPrivate();
PublicKey publicKey = keypair.getPublic();
Cipher cipher = Cipher.getInstance("RSA");
String arrayStr = "[b#d7eed7";
byte ciphertext = arrayStr.getBytes();
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] cleartext1 = cipher.doFinal(ciphertext);
System.out.println("the decrypted cleartext is: " + new String(cleartext1));
i'm getting javax.crypto.BadPaddingException: Data must start with zero
need help !!
The problem is that [B#d7eed7 is not the encrypted text. It simply shows the type and the address of the byte array, not its contents.
For more information, see https://stackoverflow.com/a/5500020/367273
I just looked to the "Related" part on the right side of the screen and... Convert Java string to byte array
to convert string to byte array you can use the following:
String source = "0123456789";
byte[] byteArray = source.getBytes("specify encoding alongside endianess");// e.g "UTF-16LE", "UTF-16"..
For more info you can check here, here and here.
Good luck!