Search code examples
javaangularjsencryptionpasswordscryptojs

Java method to decrypt an AES string from Angular-Cryptography


I'm trying to do a login method that keeps the client password secure and encrypted in my server.

The library I'm using from Angular, is https://github.com/middleout/angular-cryptography

The idea is, to follow these steps:

  1. I set a salt in my module.config:

    app.config(['$cryptoProvider', function($cryptoProvider){
        $cryptoProvider.setCryptographyKey('thisismysalt');
    }]);
    
  2. I encrypt the password with itself:

    user.pw = $crypto.encrypt(user.pw, user.pw);
    
  3. If I'm registering an user, I re-encrypt the password with itself (repeat step 2) and save it in the DB. If I'm logging, I just send the result from the last step, to the server.

  4. When you decypher the double-encrypted string with the single-encrypted one, you get the single encrypted string again. So if your password was correct, you just compare the result with the single-encrypted string, and you validate the user.


Ok, this method should work (I already did it in Node some time ago), works great with SSL to protect user's passwords even in your server!

But I can't find any library or snippet in Java that can do it. I tried many of them, but they are hard to understand and when I adapt them to my procedure, they just won't work. I tried the following method:

static String IV = "AAAAAAAAAAAAAAAA";
static String plaintext = "test text 123\0\0\0"; /*Note null padding*/
static String encryptionKey = "0123456789abcdef";

public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{
    Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "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");
}

I passed it as first argument, the double-encrypted password from the DB, and as second argument, the single-encrypted password from the frontend:

java.security.InvalidKeyException: Invalid AES key length: 44 bytes

Am I doing something wrong? Should I use a different algorithm?


Solution

  • middleout/angular-cryptography uses CryptoJS 3.1.2 under the hood with the least effort possible.

    So

    return $crypto.encrypt(plaintext, password);
    

    is the same as

    $cryptoProvider.setCryptographyKey(password); 
    return $crypto.encrypt(plaintext, password);
    

    and the same as

    return CryptoJS.AES.encrypt(plaintext, password).toString();
    

    I describe in my answer here how to do the same thing in Java.


    If you're using SSL/TLS, there is not much benefit to doing this encryption additionally. The password is already sent in an encrypted way over the internet. Even worse, since the password must be available at the server side, you must store the password in cleartext. That's not how it is done.

    You need to use hashing instead with some strong ones being PBKDF2, bcrypt, scrypt and Argon2. Since hash functions are one-way function, you won't be able to "decrypt" the hashes. In order to authenticate your user, you can run the password through the hash function again in order to compare with the hash that is stored in the database. Since you're already using SSL/TLS, the password is already secured during transmission. See more: How to securely hash passwords?