twonly-app-dependencies/pointycastle/lib/block/modes/ige.dart
2025-12-07 16:10:41 +01:00

117 lines
3.2 KiB
Dart

// See file LICENSE for more information.
library impl.block_cipher.modes.ige;
import 'dart:typed_data';
import 'package:pointycastle/api.dart';
import 'package:pointycastle/src/registry/registry.dart';
import 'package:pointycastle/src/impl/base_block_cipher.dart';
import 'package:pointycastle/src/utils.dart';
/// Implementation of IGE mode on top of a [BlockCipher].
///
/// This mode is not commonly used aside from as a critical building block in
/// the Telegram protocol.
class IGEBlockCipher extends BaseBlockCipher {
static final FactoryConfig factoryConfig = DynamicFactoryConfig.suffix(
BlockCipher,
'/IGE',
(_, final Match match) => () {
var underlying = BlockCipher(match.group(1)!);
return IGEBlockCipher(underlying);
});
final BlockCipher _underlyingCipher;
late Uint8List _x0, _y0, _xPrev, _yPrev;
late bool _encrypting;
/// Instantiates an IGEBlockCipher, using [_underlyingCipher] as the basis
/// for chaining encryption/decryption.
IGEBlockCipher(this._underlyingCipher) {
_x0 = Uint8List(blockSize);
_y0 = Uint8List(blockSize);
_xPrev = Uint8List(blockSize);
_yPrev = Uint8List(blockSize);
}
@override
String get algorithmName => '${_underlyingCipher.algorithmName}/IGE';
@override
int get blockSize => _underlyingCipher.blockSize;
@override
void reset() {
arrayCopy(_x0, 0, _xPrev, 0, blockSize);
arrayCopy(_y0, 0, _yPrev, 0, blockSize);
_underlyingCipher.reset();
}
@override
void init(bool forEncryption, covariant ParametersWithIV params) {
if (params.iv.length != blockSize * 2) {
throw ArgumentError(
'Initialization vector must be the same length as block size');
}
_encrypting = forEncryption;
arrayCopy(params.iv, 0, _x0, 0, blockSize);
arrayCopy(params.iv, blockSize, _y0, 0, blockSize);
reset();
_underlyingCipher.init(forEncryption, params.parameters);
}
@override
int processBlock(Uint8List inp, int inpOff, Uint8List out, int outOff) =>
_encrypting
? _encryptBlock(inp, inpOff, out, outOff)
: _decryptBlock(inp, inpOff, out, outOff);
int _encryptBlock(Uint8List inp, int inpOff, Uint8List out, int outOff) {
if ((inpOff + blockSize) > inp.length) {
throw ArgumentError('Input buffer too short');
}
for (var i = 0; i < blockSize; i++) {
_xPrev[i] ^= inp[inpOff + i];
}
var length = _underlyingCipher.processBlock(_xPrev, 0, out, outOff);
for (var i = 0; i < blockSize; i++) {
out[outOff + i] ^= _yPrev[i];
}
arrayCopy(inp, inpOff, _yPrev, 0, blockSize);
arrayCopy(out, outOff, _xPrev, 0, blockSize);
return length;
}
int _decryptBlock(Uint8List inp, int inpOff, Uint8List out, int outOff) {
if ((inpOff + blockSize) > inp.length) {
throw ArgumentError('Input buffer too short');
}
for (var i = 0; i < blockSize; i++) {
_yPrev[i] ^= inp[inpOff + i];
}
var length = _underlyingCipher.processBlock(_yPrev, 0, out, outOff);
for (var i = 0; i < blockSize; i++) {
out[outOff + i] ^= _xPrev[i];
}
arrayCopy(out, outOff, _yPrev, 0, blockSize);
arrayCopy(inp, inpOff, _xPrev, 0, blockSize);
return length;
}
}