I'm trying to encrypt data using RC2 algorithm with PKCS7 padding in Android and iOS, but results are different.
I need to get the exact results. The KEY and IV are already provided but I'm not sure what to do with them. I need to get the same result as the codes in ios.
Values for
IV = "11223344"
KEY = "Sample"
IOS Code:
NSString *iv = IV ;
NSData *data = [s dataUsingEncoding:NSASCIIStringEncoding];
//key
NSString *key = KEY;
const char *keyPtr = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cIv = [iv cStringUsingEncoding:NSASCIIStringEncoding];
NSUInteger dataLength = [data length];
size_t bufferSize = dataLength + kCCBlockSizeRC2;
void *buffer = malloc(bufferSize);
//kCCBlockSizeAES128
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmRC2,
kCCOptionPKCS7Padding,keyPtr,
[key length],
cIv,
[data bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
Android Code:
SecretKeySpec skeySpec = new SecretKeySpec(Constant.RC2_KEY.getBytes("US-ASCII"), "PBEWITHSHAAND128BITRC2-CBC");
IvParameterSpec iv = new IvParameterSpec(Constant.RC2_IV.getBytes("US-ASCII"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(data);
return encrypted;
With this code, the cipher.init() does not execute and it results to an error. but when i change "AES/CBC/PKCS7Padding" or "AES/CBC/PKCS5Padding" to "PBEWITHSHAAND128BITRC2-CBC" it doesn't. It encrypts the data but different from the ios code's result.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
Can anyone please help me solve this encryption thingy?
Your Java code looks quite broken - you certainly don't want to be referencing AES as your algorithm.
The following code will use RC2 correctly. I don't have the capability to test your iOS code, so perhaps there are other problems too.
byte[] iv = "87654321".getBytes("US-ASCII");
byte[] key = "SampleKey".getBytes("US-ASCII");
byte[] data = new byte[30]; // for example
SecretKeySpec skeySpec = new SecretKeySpec(key, "RC2");
RC2ParameterSpec ivSpec = new RC2ParameterSpec(key.length * 8, iv);
Cipher cipher = Cipher.getInstance("RC2/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
byte[] encrypted = cipher.doFinal(data);
// ....
Note the use of RC2ParameterSpec, which is required by the algorithm, plus the reference to PKCS5Padding rather than PKCS7Padding.
Related
I am googling and testing solution for a while and so far no success. There is always some problem with it. Following code is "working" (meaning do not show any error while it is running) on Android Kitkat and higher, but decrypted files are not readable. Why?
final static byte[] iv = new byte[16];//ADDED
final static int buffer = 102400;
final static String encryptionType = "AES/CFB8/NoPadding";//CHANGED TO DIFFERENT TYPE
static void encrypt(String password, File fileInput, File fileOutput) throws Exception {
IvParameterSpec ivParams = new IvParameterSpec(iv);//ADDED
FileInputStream fis = new FileInputStream(fileInput);
FileOutputStream fos = new FileOutputStream(fileOutput);
SecretKeySpec sks = new SecretKeySpec(password.getBytes("UTF-8"), encryptionType);
Cipher cipher = Cipher.getInstance(encryptionType);
//cipher.init(Cipher.ENCRYPT_MODE, sks);REPLACED
cipher.init(Cipher.ENCRYPT_MODE, sks, ivParams);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
int b;
byte[] d = new byte[buffer];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
cos.flush();
cos.close();
fis.close();
}
static void decrypt(String password, File fileInput, File fileOutput) throws Exception {
IvParameterSpec ivParams = new IvParameterSpec(iv);//ADDED
FileInputStream fis = new FileInputStream(fileInput);
FileOutputStream fos = new FileOutputStream(fileOutput);
SecretKeySpec sks = new SecretKeySpec(password.getBytes("UTF-8"), encryptionType);
Cipher cipher = Cipher.getInstance(encryptionType);
//cipher.init(Cipher.ENCRYPT_MODE, sks);REPLACED
cipher.init(Cipher.DECRYPT_MODE, sks, ivParams);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[buffer];
while ((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
}
EDIT: After I changed type to "AES/CFB8/NoPadding", it seems to be ok, there is no error in process, but decrypted file is not readable.
The problem in the decrypt method is caused by this line:
cipher.init(Cipher.ENCRYPT_MODE, sks);
the mode needs to Cipher.DECRYPT_MODE, so the line should be
cipher.init(Cipher.DECRYPT_MODE, sks);
Other issues are the use of the long obsolete DESede algorithm, the lack of any IV generation and handling, the absence of a good password-based key derivation algorithm, and the lack of any MAC on the ciphertext. Correctly using AES GCM mode with proper nonce generation and handling, and use of PBKDF2 (which is available on Android and Oracle Java) would represent significant improvements.
You don't supply an IV, so one is generated for you automatically. You must find a way to transmit this IV to the recipient. Typically the IV/Nonce is prepending to the ciphertext and stripped off by the recipient in order to decrypt the data. CipherInputStream/CipherOutputStream does not do this for you, so you must do it on your own.
I finally solve this problem by using shorter password. I am not sure why, but on Android 7 and 8, there is no problem with long password, but same password on Android 4.4 leads to crazy errors and brake encryption.
I just want AES/CBC 128 bit encryption decryption in openSSl c and Android with identical result.
I have to send encrypted data using pre defined 16 bytes key from android to c via bluetooth.
So is there any common mechanism which i can use in both to produce identical result of encryption and decryption.
Any help would be appreciate.
Thank you.
I found a solution which work perfectly for Android.
I am going to post the answer if it would help anyone.
static String IV = "AAAAAAAAAAAAAAAA";
static String encryptionKey = "0123456789ABCDEF";
public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/ZeroBytePadding"/*, "SunJCE"*/);
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return new String(cipher.doFinal(cipherText),"UTF-8");
}
public static byte[] encrypt(String plainText, String encryptionKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/ZeroBytePadding"/*, "SunJCE"*/);
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(plainText.getBytes("UTF-8"));
}
//To Encrypt
byte[] cipher = encrypt(plaintext, encryptionKey);
System.out.print("cipher: ");
//To Decrypt
String decrypted = decrypt(cipher, encryptionKey);
System.out.println("decrypt: " + decrypted);
I currently have an accessory that uses AES/CBC without a random number on the key. Instead, the message itself includes a random number and the key is hard-coded. I'm trying to do the same thing on my Android to exchange with the accessory through BLE. Somehow I can't figure out how generate a Key-class object without using a random number.
Here's an example of what I'd like to be able to do:
public byte[] encrypt(byte[] key, byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding ");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(input);
}
Here's what I've tried:
public byte[] encrypt(byte[] key, byte[] input) throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = new SecureRandom(key);
secureRandom.setSeed(key);
keyGenerator.init(128, secureRandom);
SecretKey secretkey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding ");
cipher.init(Cipher.ENCRYPT_MODE, secretkey);
return cipher.doFinal(input);
}
public byte[] encrypt(byte[] key, byte[] input) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES/CBC/NoPadding ");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding ");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
return cipher.doFinal(input);
}
Unfortunately both of those alter the key before the encryption.
How can I use my key "as is"?
If you want to encrypt with your own key without salt or using any random, you can do as following.
byte[] keyBuf= new byte[32];
byte[] b= key.getBytes("UTF-8");
int len= b.length;
if (len > keyBuf.length) len = keyBuf.length;
System.arraycopy(b, 0, keyBuf, 0, len);
SecretKey keySpec = new SecretKeySpec(keyBuf, "AES");
byte[] ivBuf= new byte[16];
IvParameterSpec ivSpec = new IvParameterSpec(ivBuf);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
Where key is my custom key as a String and b my key as a bytes[]. Initializing the cipher this way avoid the salting and allow you to always use your own key to encrypt anything.
I am working on encrypting (and later decrypting) strings in .Net and Java (on Android), using AES encryption , in the .Net side every thing is OK, in the Android(Java) side the output string of the posted code has unknown symbols.
String stdiv = "1234567890123456";
String txtinput = txtview1.getText().toString();
String mainkey = "0000999988887777";
byte[] key;
key = mainkey.getBytes("UTF8");
byte[] iv = stdiv.getBytes("UTF8");
byte[] input = txtinput.getBytes("UTF8");
Cipher cipher;
cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING");
SecretKeySpec keyspec = new SecretKeySpec(key, "AES" );
IvParameterSpec paramspec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, keyspec, paramspec);
byte[] result = cipher.doFinal(input);
String str=new String(result,"UTF8");
txtview2.setText(str);
I need to encrypt the username and password and encode them and send it via SOAP header.
I used DES algorithm to encrypt the plainText `
String key = "qwer1234qwetr123wqw";
String x = "sadgsagd:%%^%ghsagdh";
byte[] keyBytes = new byte[1024];
byte[] plaintext = x.getBytes();
byte[] tdesKeyData = key.getBytes();
Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
IvParameterSpec ivspec = new IvParameterSpec(keyBytes);
c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
byte[] cipherText = c3des.doFinal(plaintext);
int hash = Base64.encode(cipherText).hashCode();
return Base64.encode(cipherText);`
At runtime i am getting an Exception:
javax.crypto.BadPaddingException: Given
if you are using byte buffer of 64,i probably is too long change it to 32,
or use the length of file like this byte[] buffer = new byte[(int)new File("data").length()];
my problem get solved after doing this..