I am workin on a Rsa encrypt/decrypt application on android.I create and save my public/private key to sharedpreferences.I am reading them and using for encrypt/decrypt with this code block:
public String RSADecrypt(byte[] encryptedBytes) throws NoSuchAlgorithmException, NoSuchPaddingException,InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException, UnsupportedEncodingException {
privateKey = getPrivateKey();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] cipherData = cipher.doFinal(encryptedBytes);
return new String(cipherData,"UTF-16BE");
}
public String RSAEncrypt(String plain) throws NoSuchAlgorithmException, NoSuchPaddingException,InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException, UnsupportedEncodingException {
publicKey = getPublicKey();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherData = cipher.doFinal(plain.getBytes());
return new String(cipherData,"UTF-16BE");
}
Now, for example i am trying to encrypt "BAHADIR", it writes to EditText meaningless words. I used "UTF-8", "UTF-16", "UTF-16LE", "UTF16BE" and "ISO-8859-1" but everytime i get meaningless words again, not same but all of them meaningless. Where am i wrong, can you help me? Thank you.
You shouldn't convert binary data to a String. You can, for example, encode it with Base64 encoding if you want it as a printable String.
Try the following:
import android.util.Base64
...
byte[] cipherData = cipher.doFinal(encryptedBytes);
String cipherString = Base64.encodeBytes(cipherData);
Related
Trying to use AES-GCM 256 to encrypt "Hello World" in Node.js in such a way that the encrypted string sent ota to an Android phone can be decrypted. The Node.js encryption code is:
const KEY = new Buffer('1bc0d563329d29fc6236f099371e334feb9bbf3e91bba2adb4043feb870b6b21', 'hex');
var iv = Buffer.from("0000000000000000",'base64');
var cipher = crypt.createCipheriv('aes-256-gcm', Buffer.from(KEY, 'utf-8'), iv);
var ciph = cipher.update(Buffer.from("Hello World", 'utf-8'), 'utf8', 'base64');
ciphered += cipher.final('base64');
console.log(cipher.getAuthTag().toString('base64'));
and the Android (Studio) decryption code is:
public static byte[] decrypt(byte[] data)
throws CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableEntryException,
KeyStoreException, NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKey secretKey = null;
byte[] decodedKey = new byte[] {(byte)0x1b,(byte)0xc0,(byte)0xd5,(byte)0x63,(byte)0x32,(byte)0x9d,(byte)0x29,(byte)0xfc,(byte)0x62,(byte)0x36,(byte)0xf0,(byte)0x99,(byte)0x37,(byte)0x1e,(byte)0x33,(byte)0x4f,(byte)0xeb,(byte)0x9b,(byte)0xbf,(byte)0x3e,(byte)0x91,(byte)0xbb,(byte)0xa2,(byte)0xad,(byte)0xb4,(byte)0x04,(byte)0x3f,(byte)0xeb,(byte)0x87,(byte)0x0b,(byte)0x6b,(byte)0x21};
secretKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
byte[] iv = Base64.decode("0000000000000000", Base64.DEFAULT);
GCMParameterSpec gcmspec = new GCMParameterSpec(128, iv);
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmspec);
return cipher.doFinal(data);
}
which fails to decrypt because of authentication tag mismatch. I verified the tags don't match by encrypting the same string in Android with the same key and initialization vector:
public void TEST_ENCRYPT() throws IOException, CertificateException, NoSuchAlgorithmException, InvalidKeyException, UnrecoverableEntryException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, BadPaddingException, KeyStoreException, IllegalBlockSizeException {
String inputString = "Hello World";
byte[] byteArray = inputString.getBytes();
String value = Base64.encodeToString(encrypt(byteArray), Base64.DEFAULT);
Log.d("TEST_ENCRYPT", value);
}
public static byte[] encrypt(byte[] data)
throws CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableEntryException,
KeyStoreException, NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKey secretKey = null;
byte[] decodedKey = new byte[] {(byte)0x1b,(byte)0xc0,(byte)0xd5,(byte)0x63,(byte)0x32,(byte)0x9d,(byte)0x29,(byte)0xfc,(byte)0x62,(byte)0x36,(byte)0xf0,(byte)0x99,(byte)0x37,(byte)0x1e,(byte)0x33,(byte)0x4f,(byte)0xeb,(byte)0x9b,(byte)0xbf,(byte)0x3e,(byte)0x91,(byte)0xbb,(byte)0xa2,(byte)0xad,(byte)0xb4,(byte)0x04,(byte)0x3f,(byte)0xeb,(byte)0x87,(byte)0x0b,(byte)0x6b,(byte)0x21};
secretKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
byte[] iv = Base64.decode("0000000000000000", Base64.DEFAULT);
GCMParameterSpec gcmspec = new GCMParameterSpec(128, iv);
try {
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmspec);
}catch(Exception e)
{
Log.d("error", e.toString());
}
return cipher.doFinal(data);
}
and comparing the appended 16 bytes to the encrypted message (i.e. the Android authentication tag) to the Node.js authentication tag. This authentication tag mismatch occurs despite the fact the encrypted messages are the same, and makes decryption of messages on the Android phone throw errors. How can this problem be solved? I would expect the AES-GCM 256 algorithm to work the same on both client and server.
Look at your Buffer:
new Buffer('1bc0d563329d29fc6236f099371e334feb9bbf3e91bba2adb4043feb870b6b21');
This is not what you expect, this is simply a string.
You need this:
Buffer.from('1bc0d563329d29fc6236f099371e334feb9bbf3e91bba2adb4043feb870b6b21', 'hex');
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 am using the methods below and if I enter the right key everything works fine.
But if I enter a wrong key I am receiving a BadPaddingException:pad block corrupted...
Am I doing something wrong?
public void initKey(String passwd, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException{
byte[] localsalt = salt;
PBEKeySpec password = new PBEKeySpec(passwd.toCharArray(),localsalt, 1024,128);//, localsalt, 1000, 128); //128bit enc aes
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithMD5And128BitAES-CBC-OpenSSL","BC");
PBEKey key = (PBEKey) factory.generateSecret(password);
encKey = new SecretKeySpec(key.getEncoded(), "AES");
}
public String txt2enc(String etxt) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
final Cipher cipher = Cipher.getInstance("AES");//AES
cipher.init(Cipher.ENCRYPT_MODE, encKey);
byte[] encrypted = cipher.doFinal((etxt).getBytes("UTF-8"));
return Base64.encodeToString(encrypted, 0);
}
//decryption
public String txt2dec(String dtxt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
final Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, encKey);
byte[] decrypt = cipher.doFinal(Base64.decode(dtxt, 0));
return new String(decrypt);//return Base64.encodeToString(decrypt, 0);
}
You're not doing anything wrong. It's expected. This is technically a duplicate of Java Encryption issue (which doesn't seem to be easy to find). See this answer for a good explanation. You can consider adding a MAC (Message Authentication Code) to safely accomplish something more like a checksum.
Other than supplying the wrong key, I don't think so :)
A stack trace would help, so we can see which function is throwing the BadPaddingException.
This may well be because the 'bad' key is a different length to the 'good' key - does the 'bad' key come out of initKey() or somewhere else?
Best wishes,
Phil Lello
I have a Java application that runs on desktop computers. It encrypts and decrypts its documents using AES. When I encrypt a file using the desktop version, and decrypt it in the Android emulator, the decryption fails. The cipher.doFinal line throws this exception: javax.crypto.BadPaddingException: pad block corrupted.
When the desktop version runs, it uses the Sun crypto provider. When the Android version runs, it uses the BouncyCastle provider. I realize that the call to Cipher.getInstance is only specifying the algorithm ("AES"). I have tried to specify the algorithm, mode, and padding scheme. For instance, Cipher.GetInstance("AES/ECB/PKCS5Padding"), but, I have yet to determine a mode and padding scheme that is compatible between the Sun crypto provider and BouncyCastle.
I realize that I could simply bundle BouncyCastle with my application, and use it on the desktop and in Android, but I'd prefer not to. I'd also like to avoid any solution to this problem that forces users of the desktop program to convert their encrypted files into a format that works in Android.
My question is: how can I successfully decrypt, on Android, files that were encrypted using the Sun crypto provider?
Sincerely,
Eric Bergman-Terrell
www.EricBT.com
private static byte[] getPasswordMessageDigest(String password) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
byte[] passwordMessageDigest = messageDigest.digest(password.getBytes());
return passwordMessageDigest;
}
public static SecretKey createSecretKey(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] passwordMessageDigest = getPasswordMessageDigest(password);
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(passwordMessageDigest);
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
return secretKey;
}
public static byte[] encrypt(String password, byte[] plainText) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("AES");
SecretKey secretKey = createSecretKey(password);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherText = cipher.doFinal(plainText);
return cipherText;
}
public static byte[] decrypt(String password, byte[] cipherText) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("AES");
SecretKey secretKey = createSecretKey(password);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] plainText = cipher.doFinal(cipherText);
return plainText;
}
I want to encrypt/decrypt some passwords in the SQLite database of my application. To do that I have searched on the internet and I have found the AES algorithm.
I have this code:
public String encript(String dataToEncrypt)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
// I'm using AES encription
if(!dataToEncrypt.equals("")){
String key = "FMVWf8d_sm#fz";
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k;
try {
k = new SecretKeySpec(key.getBytes(), "AES");
c.init(Cipher.ENCRYPT_MODE, k);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return new String(c.doFinal(Base64.decode(dataToEncrypt)));
}
return "";
}
public String decript(String encryptedData)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
if(!encryptedData.equals("")){
String key = "FMVWf8d_sm#fz";
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k = new SecretKeySpec(Base64.decode(key), "AES");
c.init(Cipher.DECRYPT_MODE, k);
return new String(c.doFinal(Base64.decode(encryptedData)));
}
return "";
}
After running this I get this error on encrypt method:
01-27 14:50:51.698: ERROR/ACTIVITY(782):
java.security.InvalidKeyException: Key length not 128/192/256 bits.
I have seen some other cases here on stackoverflow but I want to give the key to the AES not to generate it...
Can somebody help me with this? If there is other encryption method to use but without using another jars or external classes and to let me give the key.
Thank you very much!
The error message makes it perfectly clear: your encryption key must be of certain size: 128, 192 or 256 bits. And your key is 104 bits. Note, that as you want to use only printable characters in your key, the length of the key should be 192 or longer bits, cause your alphabet (set of characters that you use) makes encryption weaker.
Usual practice is such:
Get password (in your case String key = "FMVWf8d_sm#fz";)
Generate using some hash function key with length 128, 192 or 256
Put it into encryption algorithm
Have fun
So you are missing key generation stage. Do smth like:
// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted =
cipher.doFinal((args.length == 0 ?
"This is just an example" : args[0]).getBytes());
System.out.println("encrypted string: " + asHex(encrypted));
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original =
cipher.doFinal(encrypted);
String originalString = new String(original);
System.out.println("Original string: " +
originalString + " " + asHex(original));