Java AES Encryption, Python Decryption not working - java

I have tried multiple ways to do this, for three days now and many hours. I have gotten NO WHERE. I am using Java to encrypt certain data using AES/CBC/PKCS7Padding, and trying to decrypt using the same in Python but it just won't work. I am using this Python aes.py library http://anh.cs.luc.edu/331/code/aes.py
I am getting this error:
File "/root/ascend/aes.py", line 384, in decrypt
block[(i+(j*4))] = iput[(i*4)+j]
exceptions.IndexError: list index out of range
Here is the Java Aes code:
public String aesEncrypt(String key, String data) throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
SecretKey secKey = new SecretKeySpec(key.getBytes(), "AES");
KeyGenerator KeyGen = KeyGenerator.getInstance("AES");
KeyGen.init(256);
Cipher AesCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
AesCipher.init(Cipher.ENCRYPT_MODE, secKey, new IvParameterSpec(IV.getBytes("UTF-8")));
byte[] byteCipherText = AesCipher.doFinal(data.getBytes());
return Base64.encodeToString(byteCipherText, 0).trim();
}
Here is the Java key gen which provides the key for python to use as well:
public String genAESKey() {
String uuid = UUID.randomUUID().toString();
return uuid.replace("-","");
}
And here is the python code to decrypt:
self.data = aes.decryptData(user.aes_key, base64.b64decode(self.data))
#Where user.aes_key is the 256bit Aes key generated by java.
Can someone please take a look and explain what is wrong with this? They are both using the same aes 256 key, pkcs7 padding, and CBC. If anyone knows of a better library that works with such java code please do show.
Edit: Just to clarify things, Aes decryption works in Java just not in python and Python encryption using that aes key works and so does python decryption. Just not java -> python. And self.data is the java encrypted aes data.
Edit #2:
Just tried to do this with PyCrypto as well. Same exact error is occuring.
return self._cipher.decrypt(ciphertext)
exceptions.ValueError: Input strings must be a multiple of 16 in length

The problem was that for some reason Java was padding the first byte of the resulting String. Why? I don't have the slightest clue but after stripping it off in Python all was well. Both the PyCrypto code and the Aes.py code work fine.

Related

RSA encrypt in php to RSA decrypt in JAva

at the moment im trying to encrypt with rsa in php with a public key generated in an android app and then decrypt in android app again.
My code to generate the keys in android is:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
With that keys i can en- and decrypt very well. The pub key looks like this:
OpenSSLRSAPublicKey{modulus=9ee9f82dd8429d9fa7f091c1d375b9c289bcf2c39ec57e175a2998b4bdd083465ef0fe6c7955c821b7e883929d017a9164a60290f1622f664a72096f5d2ffda7c7825c3d657c2d13d177445fa6cdd5d68b96346006a96040f5b09baae56d0c3efeaa77d57602f69018f5cefd60cb5c71b6b6f8a4b0472e8740367266917d8c13,publicExponent=10001}
In php im taking the modulus and exponent, creating a encrypted string with phpseclib 1.0
$rsa = new Crypt_RSA();
// $rsa->createKey();
$m = "9ee9f82dd8429d9fa7f091c1d375b9c289bcf2c39ec57e175a2998b4bdd083465ef0fe6c7955c821b7e883929d017a9164a60290f1622f664a72096f5d2ffda7c7825c3d657c2d13d177445fa6cdd5d68b96346006a96040f5b09baae56d0c3efeaa77d57602f69018f5cefd60cb5c71b6b6f8a4b0472e8740367266917d8c13";
$e = "10001";
$data = "hallo";
$modulus = new Math_BigInteger($m, 16);
$exponent = new Math_BigInteger($e, 16);
$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
$messageEncrypt = $rsa->encrypt($data);
In Android again, im loading the key, and decrypting it like this:
Cipher cipher1 = Cipher.getInstance("RSA");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = cipher1.doFinal(encrypted.getBytes());
String decrypted = new String(decryptedBytes);
Im always getting a wrong decrypted plaintext or a " Caused by: java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block" error message from Android.
What i think: The problem is the encoded transfer. That php outputs a different encoded version as java uses. So I tried a lot of different ways. I tried to convert the output to String/bin/hex/byte. Then transfer it, with socket or with copy+paste directly in the Code. Convert it back from hex/bin... to a byte[] and try to decode it. Nothing works...
Anyone has a solution for this?
Since you're not specifying the encryption mode with phpseclib what that means is that you're using the (more secure and less common) OAEP encryption mode. My guess is that Java is using PKCS1 encryption by default ($rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);).
That said, with OAEP mode and the key that you're using (a 1024-bit key; 128 bytes), the limit is 86 bytes. The limit with PKCS1 mode is 117 bytes.
phpseclib 1.0 / 2.0 might not give errors because phpseclib tries to be all user friendly and will split the string up into chunks of the max size and will encrypt each chunk separately. It's unlikely that Java does that.

Java/PHP Encryption CAST-256

I have this legacy Code in PHP that I want to reproduce in Java:
function enCrypt($data = null) {
$key = 'thisismysupersecretkeyglhf1';
$encoded=mcrypt_encrypt(MCRYPT_CAST_256,
$key,
$data,
MCRYPT_MODE_ECB
);
$encoded = base64_encode($encoded);
return $encoded;
}
function deCrypt($data = null) {
$key = 'thisismysupersecretkeyglhf1';
$decrypted= mcrypt_decrypt(
MCRYPT_CAST_256,
$key,
base64_decode($data),
MCRYPT_MODE_ECB
);
return $decrypted;
}
I am using Bouncy Castle CAST-6 Engine in the following way:
public static final String KEY = "thisismysupersecretkeyglhf1";
public static String encrypt(String toDecrypt) throws NoSuchPaddingException,
NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException, DecoderException, UnsupportedEncodingException {
Cipher cipher = Cipher.getInstance("CAST6/ECB/NoPadding");
SecretKeySpec key=new SecretKeySpec(KEY.getBytes(),"CAST6");
cipher.init(Cipher.ENCRYPT_MODE, key);
String decoded=org.apache.commons.codec.binary.Base64.encodeBase64String(cipher.doFinal(toDecrypt.getBytes()));
return decoded;
}
public static String decrypt(String toDecrypt) throws NoSuchPaddingException,
NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException, DecoderException, UnsupportedEncodingException {
Cipher cipher = Cipher.getInstance("CAST6/ECB/NoPadding");
SecretKeySpec key=new SecretKeySpec(KEY.getBytes(),"CAST6");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decoded=org.apache.commons.codec.binary.Base64.decodeBase64(toDecrypt);
return new String(cipher.doFinal(decoded));
}
However, I'm not being able to produce the same encrypted results or decrypt anything encrypted in PHP using JAVA.
What am I lacking?
Is this a Padding Issue? Reading through mcrypt documentation, they seem to be doing a lot of padding to keys and data. My Key (legacy key) is 27chars long, which I believe should be padded to 32 bytes by mcrypt, since mcrypt_get_key_size(MCRYPT_CAST_256,MCRYPT_MODE_ECB) results in 32.
For further info the string I'm trying to encrypt is "1111111111111111". I don't know if this get padded by PHP , but I would think it wouldn't because, mcrypt_get_block_size(MCRYPT_CAST_256,MCRYPT_MODE_ECB) returns 16, which is exactly the length Im using.
I am very inexperienced in cryptography, so I'am a little bit lost. Maybe if I could debug mcrypt internals, I could have a better idea of what's happening.
Any help implementing these functions in Java would be greatly appreciated.
PD. I know this algorithm is not the best, and not using an IV as well as using ECB is somehow alarming, but this is only for legacy code integration.
So I finally figured this out.
Apparently it seems PHP implementation of the Cast6 Algorithm is not standard.
At first I had a nervous breakdown by not being able to even reproduce the same value as the ones in the test vectors for the algorithm. So it was time to look at PHP's source.
I downloaded the PhpCrypt Library by Ryan Gilfether, which produces the exact same result as php's mcrypt lib. And started debugging.
I noticed that php's implementation, after splitting the key and data into 4 bytes blocks, it reverses the contents of these blocks. This is particularly important in the generation of the Masking and Round Keys, because they change a lot because of this.
So, once the problem was spotted , it was a simple matter to recreate the process from the Java side, I created a new Bouncy Castle Engine extending the CAST5Engine and replaced the setKey and encryptBlock method. You can check out this gist to see how it works.
The key is the reverseByteArrayByBlock, which is called multiple times. In the exact same way as PHP does it.
In the Gist you can also check out how to use the class in the PHPCast256Crypter.java file in case you are not too familiar with how Bouncy Castle works (the encrypt/decrypt functions assume your keys are hex encoded).
Good Luck!

Cipher: What is the reason for IllegalBlockSizeException?

I have observed the following when I worked with Cipher.
Encryption code:
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.ENCRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
Decryption code :
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.DECRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
I get IllegalBlockSizeException ( Input length must be multiple of 16 when ...) on running the Decrypt code.
But If I change the decrypt code to
Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding"); //I am passing the padding too
aes.init(Cipher.DECRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
It works fine.
I understand that it is in the pattern algorithm/mode/padding. So I thought it is because I didn't mention the padding. So I tried giving mode and padding during encryption,
Encryption code:
Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");//Gave padding during encryption too
aes.init(Cipher.ENCRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
Decryption code :
Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");
aes.init(Cipher.DECRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
But it fails with IllegalBlockSizeException.
What is the reason, why the exception and what is exactly happening underneath.
If anyone can help? Thanks in advance
UPDATE
Looks like the issue is with the string I am encrypting and decrypting. Because, even the code that I said works, doesn't always work. I am basically encrypting UUIDs (eg : 8e7307a2-ef01-4d7d-b854-e81ce152bbf6). It works with certain strings and doesn't with certain others.
The length of encrypted String is 64 which is divisible by 16. Yes, I am running it on the same machine.
Method for secret key generation:
private Key generateKey() throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA");
String passphrase = "blahbl blahbla blah";
digest.update(passphrase.getBytes());
return new SecretKeySpec(digest.digest(), 0, 16, "AES");
}
During decryption, one can only get an IllegalBlockSizeException if the input data is not a multiple of the block-size (16 bytes for AES).
If the key or the data was invalid (but correct in length), you would get a BadPaddingException because the PKCS #5 padding would be wrong in the plaintext. Very occasionally the padding would appear correct by chance and you would have no exception at all.
N.B. I would recommend you always specify the padding and mode. If you don't, you are liable to be surprised if the provider changes the defaults. AFAIK, the Sun provider converts "AES" to "AES/ECB/PKCS5Padding".
Though I haven't fully understood the internals, I have found what the issue is.
I fetch the encrypted string as a GET request parameter. As the string contains unsafe characters, over the request the string gets corrupted. The solution is, to do URL encoding and decoding.
I am able to do it successfully using the URLEncoder and URLDecoder.
Now the results are consistent. Thanks :)
I would be grateful if anyone can contribute more to this.

Java Android Error "too much data for RSA block" [duplicate]

This question already has answers here:
Too much data for RSA block fail. What is PKCS#7?
(7 answers)
Closed 10 years ago.
A have an error in my Android project (RSA encryption/decryption).
The encryption passes OK, but when I trying to decrypt encrypted text, yhere are an error: "too much data for RSA block".
How to solve this problem?
code:
public String Decrypt(String text) throws Exception
{
try{
Log.i("Crypto.java:Decrypt", text);
RSAPrivateKey privateKey = (RSAPrivateKey)kp.getPrivate();
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] cipherData = cipher.doFinal(text.getBytes());// <----ERROR: too much data for RSA block
byte[] decryptedBytes = cipher.doFinal(cipherData);
String decrypted = new String(decryptedBytes);
Log.i("Decrypted", decrypted);
return decrypted;
}catch(Exception e){
System.out.println(e.getMessage());
}
return null;
}
Your issue is that you need to encode/decode the ciphertext (just text in your code) if you want to transport it using a textual representation (String in your case).
Try and look up base 64 encoding on this site, there should be a lot of information about it. Encode after encryption and decode before decryption. You should also specify a specific character encoding for your plaintext.
Finally, you should probably encrypt with a symmetric cipher, and encrypt the symmetric key using RSA. Otherwise you may run out of space within the RSA calculation, because a public key cannot encrypt data larger than its modulus (key size).

Java RSA Encryption Non-Repeatable?

I've been having trouble encrypting with an RSA public key. Here is a sample JUnit code that reproduces the problem:
public class CryptoTests {
private static KeyPair keys;
#BeforeClass
public static void init() throws NoSuchAlgorithmException{
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = CryptoUtils.getSecureRandom();
keyGen.initialize(2176, random);
keys = keyGen.generateKeyPair();
}
#Test
public void testRepeatabilityPlainRSAPublic() throws EdrmCryptoException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{
byte[] plaintext = new byte [10];
Random r = new Random();
r.nextBytes(plaintext);
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
byte[] encrypted1 = rsa.doFinal(plaintext);
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
byte[] encrypted2 = rsa.doFinal(plaintext);
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
byte[] encrypted3 = rsa.doFinal(plaintext);
assertArrayEquals(encrypted1, encrypted2);
assertArrayEquals(encrypted1, encrypted3);
}
}
The result? The assertion fails.
Why is this behaviour seen here? As far as I remember from my crypto classes, any key can be used for encryption. Yet this is not what happens here.
I've tested the same thing with the private key, and I get a repeatable output.
If, for some reason, RSA encryption with a public key is forbidden, then why am I not getting an exception?
What must I do to get repeatable results?
P.S. My JDK is 1.6.0_22 running on an Ubuntu 10.10 box.
My guess is that it's applying randomized padding, precisely to make it more secure. From the RSA wikipedia page:
Because RSA encryption is a deterministic encryption algorithm – i.e., has no random component – an attacker can successfully launch a chosen plaintext attack against the cryptosystem, by encrypting likely plaintexts under the public key and test if they are equal to the ciphertext. A cryptosystem is called semantically secure if an attacker cannot distinguish two encryptions from each other even if the attacker knows (or has chosen) the corresponding plaintexts. As described above, RSA without padding is not semantically secure.
...
To avoid these problems, practical RSA implementations typically embed some form of structured, randomized padding into the value m before encrypting it. This padding ensures that m does not fall into the range of insecure plaintexts, and that a given message, once padded, will encrypt to one of a large number of different possible ciphertexts.
You can confirm that what is happening is that random padding is being added by initialising your Cipher with the string "RSA/ECB/NoPadding". Now, you should see that the ciphertext is identical in each case (though for reasons stated by another answerer, you shouldn't really do this in practice).
To add extra detail to Jon's answer:
When you do Cipher.getInstance("...") you have a number of options, as you've probably gathered. The Standard Algorithm Names specify what these are.
The one you asked for, RSA is by default RSA under PKCS1, which, to quote the wikipedia article:
There are two schemes for encryption
and decryption:
RSAES-OAEP: improved encryption/decryption scheme; based on
the Optimal Asymmetric Encryption
Padding scheme proposed by Mihir
Bellare and Phillip Rogaway.
RSAES-PKCS1-v1_5: older encryption/decryption scheme as first
standardized in version 1.5 of PKCS#1.
See RSALab's PKCS1 documentation for the detail of said padding schemes.

Categories

Resources