I've searched almost all topics here about this subject but I still can't figure out what's wrong. I've created 3 EditText
on my android app:
EditText
where you insert the key/password to encrypt and decrypt;
EditText2
where it is shown the encrypted text;
EditText3
where it is shown the decrypted text.
Since it's still an early test, I've put the message or string to Crypt as variable in the app.
The Problem is that the encryption give something like a blowfish algorithm, so no problem there (it end with 2 == so I think it's working right). I've also tried to decode the string before the decryption or using the raw byte[]
from encryption without any good result. The decryption doesn't give back the original String text, instead give something bigger than the encrypted text. I don't have a preference on the mode of blowfish so I started easy as Blowfish/CFB/NoPadding.
str_key
, str2
and str3
are declared public for now. str2
will set the text for EditText2
field and str3
will set the text for EditText3
field.
An example of output:
Example of output generated from the app
Here's the code :
public void encrypt(){
//encrypt
EditText mEdit = (EditText)findViewById(R.id.editText);
str_key = (String) mEdit.getText().toString();
int iterationCount = 1000;
int keyLength = 256;
int saltLength = keyLength / 8;
SecureRandom random = new SecureRandom();
byte[] salt = new byte[saltLength];
random.nextBytes(salt);
KeySpec keySpec = new PBEKeySpec(str_key.toCharArray(), salt,
iterationCount, keyLength);
SecretKeyFactory keyFactory = null;
try {
keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] keyBytes = new byte[0];
try {
keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
SecretKey key = new SecretKeySpec(keyBytes, "Blowfish");
Cipher cipher = null;
try {
cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
if ( cipher == null || key == null) {
//throw new Exception("Invalid key or cypher");
str2="error";
}
else {
byte[] iv = new byte[cipher.getBlockSize()];
random.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
try {
cipher.init(Cipher.ENCRYPT_MODE, key,ivParams);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
try {
raw = cipher.doFinal(message.getBytes("UTF-8"));
} catch (IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException e) {
e.printStackTrace();
}
str2 = Base64.encodeToString(raw,Base64.DEFAULT);
}
}
Here is the decrypt function:
public void decrypt(){
int iterationCount = 1000;
int keyLength = 256;
int saltLength = keyLength / 8;
SecureRandom random = new SecureRandom();
byte[] salt = new byte[saltLength];
random.nextBytes(salt);
KeySpec keySpec = new PBEKeySpec(str_key.toCharArray(), salt, iterationCount, keyLength);
SecretKeyFactory keyFactory = null;
try {
keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] keyBytes = new byte[0];
try {
keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
SecretKey key = new SecretKeySpec(keyBytes, "Blowfish");
Cipher cipher2 = null;
try {
cipher2 = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
iv = new byte[cipher2.getBlockSize()];
random.nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
try {
cipher2.init(Cipher.DECRYPT_MODE, key, ivSpec );
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
byte[] decryptedBytes = null;
byte[] app= Base64.decode(str2,Base64.DEFAULT);
try {
decryptedBytes = cipher2.doFinal(app);
} catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
str3 = Base64.encodeToString(decryptedBytes,Base64.DEFAULT);
}
You encode the encrypted result to base64 but then when you decrypt, you take the plain bytes of that base64. You should instead base64 decode first to get the actual byte array of ciphertext and then decrypt that.
You are also deriving your key directly from the UTF8 byte array, which is a very poor way to do so. You should instead use a KDF. PBKDF2 is the most commonly used here.
The way you generate an IV (by not generating one at all) is very poor also. It should be randomly generated and prepended to the ciphertext. It doesn't need to be secret, just unpredictable.
Lastly, you don't use a HMAC at all, so anyone could change the ciphertext and you wouldn't know.