Cipher pad block corrupted on Gingerbread - java

I believe this is a snippet from androidsnippets.org - why this isn't funcioning on Android 2.3? How to fix it?
Error
03-05 23:19:17.479: WARN/System.err(3598): javax.crypto.BadPaddingException: pad block corrupted
03-05 23:19:17.518: WARN/System.err(3598): at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:715)
03-05 23:19:17.518: WARN/System.err(3598): at javax.crypto.Cipher.doFinal(Cipher.java:1090)
I found several answers on this topic but I couldn't find a decent way how to fix this, add NoPadding parameter or different algorithm or..?
public static String code(String stringToCode) {
try {
stringToCode = encrypt("somekey",stringToCode);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return stringToCode;
}
public static String decode(String stringToDecode) {
try {
stringToDecode = decrypt("somekey",stringToDecode);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return stringToDecode;
}
public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}

Two points:
1) The toByte() method isn't clear what it's trying to do, but I'll bet it's wrong, as the line
int len = hexString.length()/2;
is going to give the same result of 3 for strings of length 6 and 7 (say)
2) You can't rely on converting stings to byte arrays without specifying the Charset to use. Different locales and different run machines may have different default Charsets. You should probably use str.getBytes("UTF8") in the algorithm.

NickT says: "is going to give the same result of 3 for strings of length 6 and 7 (say)"
I suppose that length of HEX string in that case is always EVEN number (see function appendHex)

It's problem with BouncyCastle (BouncyCastle AES error when upgrading to 1.45).
What I have found is that this
results in two different values for BC
1.34 vs 1.45.
I couldn't find the solution, yet...

Related

javax.crypto.BadPaddingException error during AES encryption

I need to encrypt and decrypt a text using AES. I can call both method locally and it works, however when I run it outside the class I get javax.crypto.BadPaddingException error. I think I am losing data somewhere but U cannot find where.
Here is the code:
public class AES {
public String encryptAES(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public String decryptAES(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
private byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
return result;
}
private String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
String HEX = "0123456789ABCDEF";
for (int i = 0; i < buf.length; i++) {
result.append(HEX.charAt((buf[i] >> 4) & 0x0f)).append(HEX.charAt(buf[i] & 0x0f));
}
return result.toString();
}
the error points to
byte[] decrypted = cipher.doFinal(encrypted);
I see several things that need fixing ..
Firstly the seed to SecureRandom won't make it produce the same output. So if you try to create the same key by specifying the same seed, it wont work.
Secondly .. you should make sure to instantiate your encrypt and decrypt cipher with the same properties .. currently you don't.
Also, when you specify CBC mode you need to handle the initialization vector. If you don't specify one on the encrypt, the cipher makes one for you .. this you need to grab and provide when you decrypt.
Fixing these things don't necessarily fix everything, but should lead you in the right direction. Take a look at some of the related question at the right side .. StackOverflow have numerous working AES examples.

Android javax.crypto.BadPaddingException: pad block corrupted, Is there an alternative or Fix?

I am trying to encrypt data in my android app. I am having following exception.
javax.crypto.BadPaddingException: pad block corrupted
at this line
byte[] decrypted = cipher.doFinal(encrypted);
My code is as follows
private final static String HEX = "0123456789ABCDEF";
public static String encryptString(String str) throws Exception {
return encrypt("KeY123", str);
}
public static String decryptString(String str) throws Exception {
return decrypt("KeY123", str);
}
public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
I am using encryptString and encryptString methods throughout the app to encrypt and decrypt data, I already tried converting
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto"); to
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); and vice versa but nothing helped me.
Are there any other techniques i can use apart from above technique?
Update:-
Added HEX
And if you don't know the solution or answer, there is no need to downvote just mind your own business and move ahead.

How to decrypt a C# encrypted AES string in java

I have a string that encrypted in java by "AES", Now i need decrypt in my C# program (I have the key)
Now i need decrypt in C#.How do I decode it into the C#?
my Encrypte and Decrypt in java :
public class AES {
public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
//ggggg
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG", "Crypto");
secrand.setSeed(seed);
keygen.init(128, secrand);
SecretKey seckey = keygen.generateKey();
byte[] rawKey = seckey.getEncoded();
return rawKey;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
//0000
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
and
try {
String plaintext = "Hello world", key = "111";
String ciphertext = AES.encrypt(key, plaintext);
Log.i("ddddddd",ciphertext);
String plaintext2 = AES.decrypt(key, ciphertext);
Log.i("ddddddd","Encrypting '" + plaintext +
"' yields: (" + ciphertext.length() + ") " + ciphertext);
Log.i("ddddddd","Decrypting it yields: " + plaintext2);
}
catch (Exception ex) {
ex.printStackTrace();
}
Now i need decrypt in C#.How do I decode it into the C#?
the best way would be to use the RijndaelManaged Class to perform your task in C#.
Here you can find an excellent example on encryption/decryption:
https://stackoverflow.com/a/212707/282649
Let me know...

Encryption using AES-128 in Android and IPhone (Different result)

I am trying to encrypt some text using the AES algorithm on both the Android and IPhone platforms. My problem is, even using the same encryption/decryption algorithm (AES-128) and same fixed variables (key, IV, mode), I get different result on both platforms. I am including code samples from both platforms, that I am using to test the encryption/decryption. I would appreciate some help in determining what I am doing wrong.
Key: “123456789abcdefg”
IV: “1111111111111111”
Plain Text: “HelloThere”
Mode: “AES/CBC/NoPadding”
Android Code:
public class Crypto {
private final static String HEX = "0123456789ABCDEF";
public static String encrypt(String seed, String cleartext)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("CBC");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted)
throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
}
IPhone (Objective-C) Code:
- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData {
NSData* secretKey = [Cipher md5:cipherKey];
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
status = CCCryptorCreate(encryptOrDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[secretKey bytes], kCCKeySizeAES128, iv, &cryptor);
if (status != kCCSuccess) {
return nil;
}
size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length], true);
void * buf = malloc(bufsize * sizeof(uint8_t));
memset(buf, 0x0, bufsize);
size_t bufused = 0;
size_t bytesTotal = 0;
status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
buf, bufsize, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
CCCryptorRelease(cryptor);
return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
}
+ (NSData *) md5:(NSString *) stringToHash {
const char *src = [stringToHash UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(src, strlen(src), result);
return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}
Some of my references :
http://code.google.com/p/aes-encryption-samples/wiki/HowToEncryptWithJava
http://automagical.rationalmind.net/2009/02/12/aes-interoperability-between-net-and-iphone/
AES interoperability between .Net and iPhone?
For iPhone I used AESCrypt-ObjC, and for Android use this code:
public class AESCrypt {
private final Cipher cipher;
private final SecretKeySpec key;
private AlgorithmParameterSpec spec;
public AESCrypt(String password) throws Exception
{
// hash password with SHA-256 and crop the output to 128-bit for key
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(password.getBytes("UTF-8"));
byte[] keyBytes = new byte[32];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
key = new SecretKeySpec(keyBytes, "AES");
spec = getIV();
}
public AlgorithmParameterSpec getIV()
{
byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
IvParameterSpec ivParameterSpec;
ivParameterSpec = new IvParameterSpec(iv);
return ivParameterSpec;
}
public String encrypt(String plainText) throws Exception
{
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
String encryptedText = new String(Base64.encode(encrypted, Base64.DEFAULT), "UTF-8");
return encryptedText;
}
public String decrypt(String cryptedText) throws Exception
{
cipher.init(Cipher.DECRYPT_MODE, key, spec);
byte[] bytes = Base64.decode(cryptedText, Base64.DEFAULT);
byte[] decrypted = cipher.doFinal(bytes);
String decryptedText = new String(decrypted, "UTF-8");
return decryptedText;
}
}
It makes me no wonder that you get different results.
Your problem is that you use misuse a SHA1PRNG for key derivation. AFAIK there is no common standard how a SHA1PRNG work internally. AFAIR even the J2SE and Bouncycaste implementation output different results using the same seed.
Hence your implementation of your getRawKey(byte[] seed) will generate you a random key. If you use the key for encryption you are getting an result that depends on that key. As the key is random you will not get the same key on iOS and therefore you are getting a different result.
If you want a key derivation function use a function like PBKDF2 with is nearly fully standardized regarding the key derivation.
On Android, you are using getBytes(). This is an error as it means you are using the default charset rather than a known charset. Use getBytes("UTF-8") instead so you know exactly what bytes you are going to get.
I don't know the equivalent for Objective-C, but don't rely on the default. Explicitly specify UTF-8 when converting strings to bytes. That way you will get the same bytes on both sides.
I also note that you are using MD5 in the Objective-C code but not in the Android code. Is this deliberate?
See my answer for password-based AES encryption, since, you are effectively using your "seed" as a password. (Just change the key length of 256 to 128, if that's what you want.)
Trying to generate the same key by seeding a DRBG with the same value is not reliable.
Next, you are not using CBC or the IV in your Android encryption. My example shows how to do that properly too. By the way, you need to generate a new IV for every message you encrypt, as my example shows, and send it along with the cipher text. Otherwise, there's no point in using CBC.
Note: For android in java
I have written this manager file and its functions are working perfectly fine for me. This is for AES 128 and without any salt.
public class CryptoManager {
private static CryptoManager shared;
private String privateKey = "your_private_key_here";
private String ivString = "your_iv_here";
private CryptoManager(){
}
public static CryptoManager getShared() {
if (shared != null ){
return shared;
}else{
shared = new CryptoManager();
return shared;
}
}
public String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(ivString.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(privateKey.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return android.util.Base64.encodeToString(encrypted, android.util.Base64.DEFAULT);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public String decrypt(String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(ivString.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(privateKey.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = new byte[0];
original = cipher.doFinal(android.util.Base64.decode(encrypted, android.util.Base64.DEFAULT));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
You need to call the functions like this.
String dataToEncrypt = "I need to encrypt myself";
String encryptedData = CryptoManager.getShared().encrypt(data);
And you will get your encrypted string with the following line
String decryptedString = CryptoManager.getShared().decrypt(encryptedData);
If you want an example of compatible code for Android and iPhone, look at the RNCryptor library for iOS and the JNCryptor library for Java/Android.
Both projects are open source and share a common data format. In these libraries, AES 256-bit is used, however it would be trivial to adapt the code if necessary to support 128-bit AES.
As per the accepted answer, both libraries use PBKDF2.

Unable to decrypt the encrypted sms (encrypted in 2.2 os )in Android...(trying to decrypt in 2.3 os)

I am able to encrypt an SMS and send it from one simulator (Android 2.2) to another.
On the receiving end I am able to do the decryption successfully. But the problem is if do the encryption in one OS version (i.e Android 2.2) and trying to decrypt in another OS version ( Android 2.3 ) i am getting 'Bad padding exception'. I checked that i used the same key on both ends.
The code is shown below
public class ED {
private String Key;
public ED() {
Key = "abc12"; // Assigning default key.
}
public ED(String key) {
// TODO Auto-generated constructor stub
Key = key;
}
public String encrypt(String toEncrypt) throws Exception {
byte[] rawKey = getRawKey(Key.getBytes("UTF-8"));
byte[] result = encrypt(rawKey, toEncrypt.getBytes("UTF-8"));
return toHex(result);
}
public byte[] encrypt(byte[] key, byte[] toEncodeString) throws Exception {
SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
byte[] encrypted = cipher.doFinal(toEncodeString);
return encrypted;
}
private byte[] getRawKey(byte[] key) throws Exception {
KeyGenerator kGen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(key);
kGen.init(128, sr);
SecretKey sKey = kGen.generateKey();
byte[] raw = sKey.getEncoded();
return raw;
}
/************************************* Decription *********************************************/
public String decrypt(String encryptedString) throws Exception {
byte[] rawKey = getRawKey(Key.getBytes("UTF-8"));
System.out.println("Decrypted Key in bytes : "+rawKey);
System.out.println("Key in decryption :"+rawKey);
SecretKeySpec sKeySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec);
byte[] decrypted = cipher.doFinal(toByte(encryptedString));
System.out.println("Decrypted mess in bytes---------->" +decrypted);
return new String(decrypted);
}
public String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final String HEX = "0123456789ABCDEF";
private void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
public byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
}
And I am using sendTextMessage() function to send an sms. I read that encryption/decryption doesn't depend on OS but in this case that is not true. Am I missing any important things while configuring the Cipher (in AES) ? Please let me know.
It's setSeed(). It does not do what you think it does: it just adds the entropy of the given seed to the underlying algorithm. You'll probably find out that it returns somehthing different on both platforms. SHA1PRNG is a pseudo random function, but if it is already seeded, it's likely to return different results.
If the problem is in the key length, you could derivate a key from your password, instead of using it directly. You could use a Hash (like SHA-1, MD5, etc) and crop it to the correct size (128, 192 or 256 bits), or use PBEKeySpec instead of SecretKeySpec.
That to remove problems with the key length. If the padding problems were in the plaintext, I suggest you to use CipherInputStream and CipherOutputStream, which are more programmer-friendly to use than Cipher.doFinal.
Don't rely on KeyGenerator to generate the same key just because you seeded the RNG the same way. If you are pre-sharing a key, share the key, not the seed.
You should also specify the encryption transform completely: "AES/ECB/PKCS5Padding"
Finally, ECB mode is not secure for general use.
See another answer of mine for an example to perform encryption correctly with the JCE.
The problem is with SecureRandom generation. It is giving different results on different platforms. It's because of a bug fix on line 320 (in Gingerbread source) of SHA1PRNG_SecureRandomImpl.java in the engineNextBytes() method where
bits = seedLength << 3 + 64;
was changed to
bits = (seedLength << 3) + 64;
Use SecretKeyFactory() to generate a Secure key instead of secure random.
public class Crypto {
Cipher ecipher;
Cipher dcipher;
byte[] salt = { 1, 2, 4, 5, 7, 8, 3, 6 };
int iterationCount = 1979;
Crypto(String passPhase) {
try {
// Create the key
KeySpec keySpec = new PBEKeySpec(passPhase.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance("PBEWITHSHA256AND128BITAES-CBC-BC").generateSecret(keySpec);
ecipher = Cipher.getInstance(key.getAlgorithm());
dcipher = Cipher.getInstance(key.getAlgorithm());
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (Exception e) {
// TODO: handle exception
//Toast.makeText(this, "I cought ", Toast.LENGTH_LONG).show();
}
}
public String encrypt(String str) {
String rVal;
try {
byte[] utf8 = str.getBytes("UTF8");
byte[] enc = ecipher.doFinal(utf8);
rVal = toHex(enc);
} catch (Exception e) {
// TODO: handle exception
rVal = "Exception Caught "+e.getMessage();
}
return rVal;
}
public String decrypt(String str) {
String rVal;
try {
byte[] dec = toByte(str);
byte[] utf8 = dcipher.doFinal(dec);
rVal = new String(utf8, "UTF8");
} catch(Exception e) {
rVal = "Error in decrypting :"+e.getMessage();
}
return rVal;
}
private static byte[] toByte(String hexString ) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for ( int i=0; i<len; i++ ) {
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16 ).byteValue();
}
return result;
}
private static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer( 2*buf.length);
for ( int i=0; i<buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
}

Categories