KeepassX format implementation in pure dart.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

93 lines
2.7 KiB

import 'dart:typed_data';
import 'package:pointycastle/export.dart';
/// https://gist.github.com/proteye/e54eef1713e1fe9123d1eb04c0a5cf9b
class AesHelper {
static const CBC_MODE = 'CBC';
static const CFB_MODE = 'CFB';
// AES key size
static const KEY_SIZE = 32; // 32 byte key for AES-256
static const ITERATION_COUNT = 1000;
static Uint8List deriveKey(
Uint8List password, {
Uint8List salt,
int iterationCount = ITERATION_COUNT,
int derivedKeyLength = KEY_SIZE,
}) {
final Pbkdf2Parameters params =
Pbkdf2Parameters(salt, iterationCount, derivedKeyLength);
final KeyDerivator keyDerivator =
PBKDF2KeyDerivator(HMac(SHA256Digest(), 64));
keyDerivator.init(params);
return keyDerivator.process(password);
}
static String decrypt(Uint8List derivedKey, Uint8List cipherIvBytes,
{String mode = CBC_MODE}) {
// Uint8List derivedKey = deriveKey(password);
final KeyParameter keyParam = KeyParameter(derivedKey);
final BlockCipher aes = AESFastEngine();
// Uint8List cipherIvBytes = base64.decode(ciphertext);
final Uint8List iv = Uint8List(aes.blockSize)
..setRange(0, aes.blockSize, cipherIvBytes);
BlockCipher cipher;
final ParametersWithIV params = ParametersWithIV(keyParam, iv);
switch (mode) {
case CBC_MODE:
cipher = CBCBlockCipher(aes);
break;
case CFB_MODE:
cipher = CFBBlockCipher(aes, aes.blockSize);
break;
default:
throw ArgumentError('incorrect value of the "mode" parameter');
break;
}
cipher.init(false, params);
final int cipherLen = cipherIvBytes.length - aes.blockSize;
final Uint8List cipherBytes = Uint8List(cipherLen)
..setRange(0, cipherLen, cipherIvBytes, aes.blockSize);
final Uint8List paddedText = processBlocks(cipher, cipherBytes);
final Uint8List textBytes = unpad(paddedText);
return String.fromCharCodes(textBytes);
}
static Uint8List unpad(Uint8List src) {
final pad = PKCS7Padding();
pad.init(null);
final int padLength = pad.padCount(src);
final int len = src.length - padLength;
return Uint8List(len)..setRange(0, len, src);
}
static Uint8List pad(Uint8List src, int blockSize) {
final pad = PKCS7Padding();
pad.init(null);
final padLength = blockSize - (src.length % blockSize);
final out = Uint8List(src.length + padLength)..setAll(0, src);
pad.addPadding(out, src.length);
return out;
}
static Uint8List processBlocks(BlockCipher cipher, Uint8List inp) {
final out = Uint8List(inp.lengthInBytes);
for (var offset = 0; offset < inp.lengthInBytes;) {
offset += cipher.processBlock(inp, offset, out, offset);
}
return out;
}
}