MySalt
Authenticated, passphrase-based encryption for Dart and Flutter, with a
migration path for existing OpenSSL/CryptoJS Salted__ ciphertext.
Security defaults
- AES-256-GCM authenticated encryption.
- PBKDF2-HMAC-SHA256 with 600,000 iterations.
- A fresh 128-bit salt and 96-bit nonce for every encryption.
- A versioned Base64 envelope that authenticates its header and ciphertext.
- Strict rejection of malformed, modified, or unsupported envelopes.
MySalt encrypts application data that must later be recovered. Passwords used for login should be hashed with a dedicated password-hashing algorithm instead of being reversibly encrypted.
Getting started
MySalt 1.1.0 requires Dart 3.13.1 or later.
dependencies:
my_salt: ^1.1.0
dart pub get
Flutter applications can also depend on cryptography_flutter to use faster
platform implementations on supported operating systems.
Authenticated encryption
import 'package:my_salt/my_salt.dart';
Future<void> main() async {
const mySalt = MySalt();
const passphrase = 'use-a-long-random-passphrase';
const plainText = 'Hello, this is a secret message!';
final encrypted = await mySalt.encrypt(plainText, passphrase);
final decrypted = await mySalt.decrypt(encrypted, passphrase);
print(encrypted);
print(decrypted);
}
encrypt produces a different value each time, even when plaintext and
passphrase are unchanged. The salt and nonce are stored in the envelope; they
do not need to be stored separately.
Verify values
final matches = await mySalt.verifyAuthenticated(
text: plainText,
encrypted: encrypted,
passphrase: passphrase,
);
final samePlainText = await mySalt.verifyAuthenticatedEncrypted(
encrypted1: encrypted,
encrypted2: anotherEncryptedValue,
passphrase: passphrase,
);
The verification helpers return false for a wrong passphrase, malformed
envelope, or failed authentication. decrypt exposes those failures as
FormatException or SecretBoxAuthenticationError so applications can handle
them explicitly.
Migrating CryptoJS data
Versions before 1.1.0 used AES-CBC with an MD5-based OpenSSL/CryptoJS key derivation scheme. Those methods remain available only for compatibility and are deprecated because the format does not authenticate ciphertext.
final plainText = mySalt.decryptAESCryptoJS(oldCiphertext, passphrase);
final authenticatedCiphertext = await mySalt.encrypt(plainText, passphrase);
Verify the new ciphertext with decrypt before removing the legacy value. Do
not replace decryptAESCryptoJS with decrypt without migrating: the two
methods intentionally use different envelope formats.
Failure behavior
- An empty passphrase throws
ArgumentErrorin the authenticated API. - Invalid Base64, an invalid header, a truncated envelope, or an unsupported
version throws
FormatException. - A wrong passphrase or modified authenticated envelope throws
SecretBoxAuthenticationErrorfrompackage:cryptography.
Additional information
Contributions and issue reports are welcome on GitHub.
Libraries
- my_salt
- Authenticated, passphrase-based encryption for Dart applications.