Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Password-based AES CBC encryption? #35

Closed
maplerichie opened this issue May 5, 2020 · 5 comments
Closed

Password-based AES CBC encryption? #35

maplerichie opened this issue May 5, 2020 · 5 comments
Labels
clarification User is having trouble understanding classes

Comments

@maplerichie
Copy link

maplerichie commented May 5, 2020

There are few encryption library available for Flutter but this look more reliable library because of documentation or simpleness.
The key and ivsalt are generate randomly each time, how can I achieve the password-based encryption?
I'm not familiar with crypto, maybe is AES/CBC/PKCS5PADDING?

@AKushWarrior AKushWarrior added the clarification User is having trouble understanding classes label May 6, 2020
@AKushWarrior
Copy link
Owner

AKushWarrior commented May 6, 2020

If you want to handle passwords, you'll need [PassCrypt]. You should use scrypt; that's the securest function we support.

Password hashing should always be one-way, meaning that you can't retrieve the plaintext of the password. Use a key-value store (like https://pub.dev/packages/hive) and map a SHA-hashed username to the scrypt-hashed password + generated salt. Then, you can do password verification off this copy.

I've written a small code sample below to see what this looks like. Keep in mind that this code sample will be outdated when steel_crypt 2.0 comes out!

void map (String key, String value) {
      // Store the key and map it to a value in your database.
}

String getFromMap (String key) {
      // Get the value mapped to 'key' in your database.
}

String createAccount (String username, String password) {
      var salt = CryptKey().genDart();
      var userHash = HashCrypt('SHA-3/256').hash(username);
      var passHash = PassCrypt('scrypt').hashPass(salt, password);
      var passHash += salt;
      map(userHash, passHash);
}

bool isCorrectPassword (String usernameInput, String passInput) {
      var key = HashCrypt('SHA-3/256').hash(usernameInput);
      var correctHash = getFromMap(key);
      var salt = correctHash.sublist(correctHash.length-16, correctHash.length);
      var correctHash = correctHash.sublist(0, correctHash.length-16);
      var inputHash = PassCrypt('scrypt').hashPass(salt, passInput);
      return inputHash == correctHash;
}

@AKushWarrior
Copy link
Owner

Note that both [createAccount] and [isCorrectPassword] will take a while to run; this is necessary for security and impossible to solve.. You might want to make Future wrapper functions so that they can be asynchronous and not block the main thread.

@AKushWarrior
Copy link
Owner

AKushWarrior commented May 6, 2020

Sorry just realized I may have not quite answered your question. This is how you would handle just the username and password. To encrypt/decrypt additional data using AES and password as the key:

String encryptAES (String plain, String username) {
      var dbKey = HashCrypt('SHA-3/256').hash(username);
      var iv = CryptKey().genDart();
      var aesKey = getFromMap(dbKey);
      aesKey = PassCrypt().hashPass(iv, aesKey.substring(0,32));
      var aesEncrypter = AesCrypt(aesKey, 'gcm', 'pkcs7');
      var output = aesEncrypter.encrypt(plain, iv);
      output += iv;
      return output;
}

String decryptAES (String encrypted, String username) {
      var dbKey = HashCrypt('SHA-3/256').hash(username);
      var aesKey = getFromMap(dbKey);
      var iv = encrypted.substring(encrypted.length-16, encrypted.length);
      aesKey = PassCrypt().hashPass(iv, aesKey.substring(0,32));
      var aesEncrypter = AesCrypt(aesKey, 'gcm', 'pkcs7');
      var original = aesEncrypter.decrypt(encrypted.substring(0, encrypted.length-16), iv);
      return original;
}

This integrates with the above example I created.

You really should be using the above example (or something very similar) if you have a username/password system.

Additionally, you really should have a username/password system if you have passwords involved.

@maplerichie
Copy link
Author

maplerichie commented May 6, 2020

Thanks for the prompt replied and answer!
I found better solution for my scenario, RSA encryption. As I need to encrypt data with Javascript frontend to generate QR Code but the AES's key and iv was exposed. So the RSA public key encryption method much more suitable.
Is it? Zero knowledge on cryptography...

@edwin-alvarez
Copy link

what does getFromMap method should do?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clarification User is having trouble understanding classes
Projects
None yet
Development

No branches or pull requests

3 participants