121 lines
3.3 KiB
Dart
121 lines
3.3 KiB
Dart
// See file LICENSE for more information.
|
|
|
|
library impl.padded_block_cipher.padded_block_cipher_impl;
|
|
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:pointycastle/api.dart';
|
|
import 'package:pointycastle/src/registry/registry.dart';
|
|
|
|
/// The standard implementation of [PaddedBlockCipher].
|
|
class PaddedBlockCipherImpl implements PaddedBlockCipher {
|
|
/// Intended for internal use.
|
|
static final FactoryConfig factoryConfig = DynamicFactoryConfig.regex(
|
|
PaddedBlockCipher,
|
|
r'^(.+)/([^/]+)$',
|
|
(_, final Match match) => () {
|
|
var padding = Padding(match.group(2)!);
|
|
var underlyingCipher = BlockCipher(match.group(1)!);
|
|
return PaddedBlockCipherImpl(padding, underlyingCipher);
|
|
});
|
|
|
|
@override
|
|
final Padding padding;
|
|
@override
|
|
final BlockCipher cipher;
|
|
|
|
bool? _encrypting;
|
|
|
|
PaddedBlockCipherImpl(this.padding, this.cipher);
|
|
|
|
@override
|
|
String get algorithmName =>
|
|
'${cipher.algorithmName}/${padding.algorithmName}';
|
|
|
|
@override
|
|
int get blockSize => cipher.blockSize;
|
|
|
|
@override
|
|
void reset() {
|
|
_encrypting = null;
|
|
cipher.reset();
|
|
}
|
|
|
|
@override
|
|
void init(bool forEncryption, covariant PaddedBlockCipherParameters params) {
|
|
_encrypting = forEncryption;
|
|
cipher.init(forEncryption, params.underlyingCipherParameters);
|
|
padding.init(params.paddingCipherParameters);
|
|
}
|
|
|
|
@override
|
|
Uint8List process(Uint8List data) {
|
|
var inputBlocks = (data.length + blockSize - 1) ~/ blockSize;
|
|
|
|
int outputBlocks;
|
|
if (_encrypting ?? false) {
|
|
outputBlocks = (data.length + blockSize) ~/ blockSize;
|
|
} else {
|
|
if ((data.length % blockSize) != 0) {
|
|
throw ArgumentError(
|
|
'Input data length must be a multiple of cipher\'s block size');
|
|
}
|
|
outputBlocks = inputBlocks;
|
|
}
|
|
|
|
var out = Uint8List(outputBlocks * blockSize);
|
|
|
|
for (var i = 0; i < (inputBlocks - 1); i++) {
|
|
var offset = i * blockSize;
|
|
processBlock(data, offset, out, offset);
|
|
}
|
|
|
|
var lastBlockOffset = (inputBlocks - 1) * blockSize;
|
|
var lastBlockSize = doFinal(data, lastBlockOffset, out, lastBlockOffset);
|
|
|
|
return out.sublist(0, lastBlockOffset + lastBlockSize);
|
|
}
|
|
|
|
@override
|
|
int processBlock(Uint8List inp, int inpOff, Uint8List out, int outOff) {
|
|
return cipher.processBlock(inp, inpOff, out, outOff);
|
|
}
|
|
|
|
@override
|
|
int doFinal(Uint8List inp, int inpOff, Uint8List out, int outOff) {
|
|
if (_encrypting ?? false) {
|
|
var lastInputBlock = Uint8List(blockSize)..setAll(0, inp.sublist(inpOff));
|
|
|
|
var remainder = inp.length - inpOff;
|
|
|
|
if (remainder < blockSize) {
|
|
// Padding goes embedded in last block of data
|
|
padding.addPadding(lastInputBlock, inp.length - inpOff);
|
|
|
|
processBlock(lastInputBlock, 0, out, outOff);
|
|
|
|
return blockSize;
|
|
} else {
|
|
// Padding goes alone in an additional block
|
|
processBlock(inp, inpOff, out, outOff);
|
|
|
|
padding.addPadding(lastInputBlock, 0);
|
|
|
|
processBlock(lastInputBlock, 0, out, outOff + blockSize);
|
|
|
|
return 2 * blockSize;
|
|
}
|
|
} else {
|
|
// Decrypt last block and remove padding
|
|
processBlock(inp, inpOff, out, outOff);
|
|
|
|
var padCount = padding.padCount(out.sublist(outOff));
|
|
|
|
var padOffsetInBlock = blockSize - padCount;
|
|
|
|
out.fillRange(outOff + padOffsetInBlock, out.length, 0);
|
|
|
|
return padOffsetInBlock;
|
|
}
|
|
}
|
|
}
|