Blowfish on android studio for encryption/decryption

2.4k views Asked by At

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);
}
1

There are 1 answers

11
Luke Joshua Park On

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.