Sample code for 30+ languages & platforms
Dart

Duplicate SQL Server ENCRYPTBYPASSPHRASE

See more Encryption Examples

Demonstrates how to duplicate SQL Server's ENCRYPTBYPASSPHRASE.

Chilkat Dart Downloads

Dart
import 'package:chilkat/chilkat.dart';

void main() {
  // This example requires the Chilkat API to have been previously unlocked.
  // See Global Unlock Sample for sample code.

  // For SQL Server 2008 - SQL Server 2016 we must use TripleDES with SHA1
  // For SQL Server 2017 and later, use AES256 / SHA256.

  final password = 'tEst1234';
  final encryptedHexV1 = '0x010000001E8E7DCDBD4061B951999E25D18445D2305474D2D71EEE98A241C755246F58AB';

  // Here's an encrypted string using AES256/SHA256
  final encryptedHexV2 = '0x02000000FFE880C0354780481E64EF25B6197A02E2A854A4BA9D8D9BDDFDAB27EB56537ABDA0B1D9C4D1050C91B313550DECF429';

  final sbEncHex = CkStringBuilder();
  sbEncHex.append(encryptedHexV1);

  // If present, we don't want the leading "0x"
  if (sbEncHex.startsWith('0x', false)) {
    sbEncHex.removeCharsAt(0, 2);
  }

  final crypt = CkCrypt2();
  crypt.encodingMode = 'hex';

  // The encrypted hex string will begin with either 01000000 or 02000000
  // version 1 is produced by SQL Server 2008 to SQL Server 2016, and we must use TripleDES with SHA1
  // version 2 is for SQL Server 2017 and later, and uses AES256 / SHA256.
  final v1 = sbEncHex.startsWith('01', false);

  var ivLen = 0;
  var hashAlg = '';

  if (v1) {
    crypt.cryptAlgorithm = '3des';
    crypt.cipherMode = 'cbc';
    crypt.keyLength = 168;
    ivLen = 8;
    hashAlg = 'sha1';
  } else {
    crypt.cryptAlgorithm = 'aes';
    crypt.cipherMode = 'cbc';
    crypt.keyLength = 256;
    ivLen = 16;
    hashAlg = 'sha256';
  }

  // Remove the SQL Server version info (i.e. the "01000000")
  sbEncHex.removeCharsAt(0, 8);

  // Get the IV part of the sbEncHex, and also remove it from the StringBuilder.
  var ivHex = sbEncHex.getRange(0, ivLen * 2, true);
  print('IV = $ivHex');
  crypt.setEncodedIV(ivHex, 'hex');

  final sbPassword = CkStringBuilder();
  sbPassword.append(password);
  final pwdHash = sbPassword.getHash(hashAlg, 'hex', 'utf-16');
  final sbKey = CkStringBuilder();
  sbKey.append(pwdHash);
  if (v1) {
    // For v1, we only want the 1st 16 bytes of the 20 byte hash.
    // (remember, the hex encoding uses 2 chars per byte, so we remove the last 8 chars)
    sbKey.shorten(8);
  }

  print('crypt key: ${sbKey.getAsString()}');

  crypt.setEncodedKey(sbKey.getAsString(), 'hex');

  // Decrypt
  final bd = CkBinData();
  bd.appendEncoded(sbEncHex.getAsString(), 'hex');
  crypt.decryptBd(bd);

  // The result is composed of a header of 8 bytes which we can discard.
  // The remainder is the decrypted text.

  // The header we are discarding is composed of:
  // Bytes 0-3: Magic number equal to 0DF0ADBA
  // Bytes 4-5: Number of integrity bytes, which is 0 unless an authenticator is used. We're assuming no authenticator is used.
  // Bytes 6-7: Number of plain-text bytes. We really don't need this because the CBC padding takes care of it.

  // Therefore, just return the data after the 1st 8 bytes.
  // Assuming the encrypted string was utf-8 text...
  bd.removeChunk(0, 8);
  var plainText = bd.getString('utf-8');
  print('decrypted plain text: $plainText');

  // The output:

  // IV = 1E8E7DCDBD4061B9
  // crypt key: 710B9C2E61ACCC9570D4112203BD9738
  // decrypted plain text: Hello world.

  // ------------------------------------------------------------------------------------------
  // To encrypt, do the reverse...

  // Let's do v1 with TripleDES with SHA1

  final encryptor = CkCrypt2();
  encryptor.encodingMode = 'hex';

  encryptor.cryptAlgorithm = '3des';
  encryptor.cipherMode = 'cbc';
  encryptor.keyLength = 168;

  // Generate a random 8-byte IV
  final prng = CkPrng();
  ivHex = prng.genRandom(8, 'hex');
  encryptor.setEncodedIV(ivHex, 'hex');

  // The binary password is generated the same as above.
  // We'll use the same password (and same binary password)
  encryptor.setEncodedKey(sbKey.getAsString(), 'hex');

  final plainTextLen = 8;
  plainText = 'ABCD1234';

  // Encrypt the header + the plain-text.
  final bdData = CkBinData();
  bdData.appendEncoded('0DF0ADBA', 'hex');
  bdData.appendEncoded('0000', 'hex');
  bdData.appendInt2(plainTextLen, true);
  print('header: ${bdData.getEncoded('hex')}');
  bdData.appendString(plainText, 'utf-8');
  encryptor.encryptBd(bdData);

  // Compose the result..
  final sbEnc = CkStringBuilder();
  sbEnc.append('0x01000000');
  sbEnc.append(ivHex);
  sbEnc.append(bdData.getEncoded('hex'));

  print('result: ${sbEnc.getAsString()}');
}