I am trying to write an encryption class that will allow iPhone to send encrypted text to Android and vice versa. While this is quite straightforward in Android (following code)
private static final String CIPHER_ALGORITHM = "AES";
private static final String RANDOM_GENERATOR_ALGORITHM = "SHA1PRNG";
private static final int RANDOM_KEY_SIZE = 128;
// Encrypts string and encode in Base64
public static String encrypt( String password, String data ) throws Exception
{
byte[] secretKey = generateKey( password.getBytes() );
byte[] clear = data.getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec( secretKey, CIPHER_ALGORITHM );
Cipher cipher = Cipher.getInstance( CIPHER_ALGORITHM );
cipher.init( Cipher.ENCRYPT_MODE, secretKeySpec );
byte[] encrypted = cipher.doFinal( clear );
String encryptedString = Base64.encodeToString( encrypted, Base64.DEFAULT );
return encryptedString;
}
// Decrypts string encoded in Base64
public static String decrypt( String password, String encryptedData ) throws Exception
{
byte[] secretKey = generateKey( password.getBytes() );
SecretKeySpec secretKeySpec = new SecretKeySpec( secretKey, CIPHER_ALGORITHM );
Cipher cipher = Cipher.getInstance( CIPHER_ALGORITHM );
cipher.init( Cipher.DECRYPT_MODE, secretKeySpec );
byte[] encrypted = Base64.decode( encryptedData, Base64.DEFAULT );
byte[] decrypted = cipher.doFinal( encrypted );
return new String( decrypted );
}
public static byte[] generateKey( byte[] seed ) throws Exception
{
KeyGenerator keyGenerator = KeyGenerator.getInstance( CIPHER_ALGORITHM );
SecureRandom secureRandom = SecureRandom.getInstance( RANDOM_GENERATOR_ALGORITHM );
secureRandom.setSeed( seed );
keyGenerator.init( RANDOM_KEY_SIZE, secureRandom );
SecretKey secretKey = keyGenerator.generateKey();
return secretKey.getEncoded();
}
}
I have seen tens of answers on similar topics but did not get a really working piece of code for iOS that gives identical results. Most of the pieces of code don't even compile properly. Does somebody has a real working piece of code for that?
See RNCryptor on iOS, and JNCryptor for Java. They implement the same file format. It correctly handles AES-CBC-256 with a random IV, PBKDF2 generated passwords with random salt, and validated HMAC for data authentication and integrity.
Related
I have done encryption in android with a static password i.e. "encrypt". The encryption works fine and encrypts the data. But when i try to decrypt the encrypted text it does not show. The code to decrypt is as follow.
public String decrypt(String msg, String inputPassword) throws Exception{
SecretKeySpec key= generateKey(inputPassword);
Cipher c = Cipher.getInstance(AES);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decodedValue= Base64.decode(msg, Base64.DEFAULT);
/*If this line is present the encrypted message is not seen*/
byte[] decValue = c.doFinal(Base64.decode(decodedValue,
Base64.DEFAULT));
String decryptedValue = new String(decodedValue);
String decryptedValue = new String(decValue, StandardCharsets.UTF_8);
return decryptedValue;
}
When the code (below the comment) is enabled. The message is not displayed. But when the line is commented. This is shown in the message box
After the code is commented.
This is the encrypt and key generate methods.
public String encrypt(String message, String inputPassword) throws Exception{
SecretKeySpec key = generateKey(inputPassword);
Cipher c = Cipher.getInstance(AES);
c.init(c.ENCRYPT_MODE, key);
byte[] encVal = c.doFinal(message.getBytes());
String encryptedValue = Base64.encodeToString(encVal, Base64.DEFAULT);
return encryptedValue;
}
//For generating key for encryption
public SecretKeySpec generateKey(String inputPassword) throws Exception{
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bytes = inputPassword.getBytes("UTF-8");
digest.update(bytes, 0, bytes.length);
byte[] key = digest.digest();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
return secretKeySpec;
}
The log is follow
enter image description here
Also the API level is not maintained... I don't know where to setup this as well.
enter image description here
Could you try changing this
String decryptedValue = new String(decodedValue)
to this
String decryptedValue = new String(decodedValue, StandardCharsets.UTF_8)
And for your error, try changing to this
c.doFinal(Base64.decode(decodedValue, Base64.DEFAULT))
I have been using the following two methods to encrypt and decrypt sensitive info.
public static String encryptSensitiveInfo(String strToEncrypt,
String saltToEncrypt) throws Exception {
String encryptedString = "";
byte[] encryptedValue;
Key key = new SecretKeySpec(saltToEncrypt.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
encryptedValue = cipher.doFinal(strToEncrypt.getBytes());
encryptedString = new String(Base64.encodeBase64(encryptedValue));
encryptedValue = null;
return encryptedString;
}
public static String decryptSensitiveInfo(String strToDecrypt,
String saltToDecrypt) throws Exception {
String decryptedString = "";
byte[] decryptedValue;
Key key = new SecretKeySpec(saltToDecrypt.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedValue = cipher.doFinal(Base64.decodeBase64(strToDecrypt
.getBytes()));
decryptedString = new String(decryptedValue);
decryptedValue = null;
return decryptedString;
}
At the time of decryption I get "pad block corrupted" execption. Any help to resolve this issue would be very much appreciated. Thanks in advance.
You're correctly performing base 64 on the ciphertext because the ciphertext consists of random looking bytes. However, you forget to do the same with your key (which, inexplicably, is called saltToDecrypt in your code). If the keys do not match or if the ciphertext has become corrupted then you will almost certainly run into a BadPaddingException.
If the amount of ciphertext has changed an IllegalBlockSizeException is more likely and if the key isn't of the right size for AES, an InvalidKeyException.
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);