pub package codecov GitHub Buy Me A Coffee PayPal Sponsor Support Me on Ko-fi

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 ArgumentError in 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 SecretBoxAuthenticationError from package:cryptography.

Additional information

Contributions and issue reports are welcome on GitHub.

Maintainers: ThaoDoan and DucNguyen.

Libraries

my_salt
Authenticated, passphrase-based encryption for Dart applications.