blob: dd72c43516f610834e5237e1fd1f5e3239a01ea6 [file] [log] [blame] [edit]
library impl.stream_cipher.rc4_engine;
import 'dart:typed_data';
import 'package:pointycastle/api.dart';
import 'package:pointycastle/src/impl/base_stream_cipher.dart';
import 'package:pointycastle/src/registry/registry.dart';
class RC4Engine extends BaseStreamCipher {
static final FactoryConfig factoryConfig =
StaticFactoryConfig(StreamCipher, 'RC4', () => RC4Engine());
static int STATE_LENGTH = 256;
Uint8List? _engineState;
int _x = 0;
int _y = 0;
late Uint8List _workingKey;
@override
String get algorithmName => 'RC4';
@override
void init(bool forEncryption, CipherParameters? params) {
if (params != null) {
if (params is KeyParameter) {
_workingKey = params.key;
setKey(params.key);
} else {
throw ArgumentError('Parameters of invalid type');
}
} else {
throw ArgumentError('Missing parameter');
}
}
@override
Uint8List process(Uint8List data) {
var out = Uint8List(data.length);
processBytes(data, 0, data.length, out, 0);
return out;
}
@override
void processBytes(
Uint8List inp, int inpOff, int len, Uint8List out, int outOff) {
if ((inpOff + len) > inp.length) {
throw ArgumentError('input buffer too short');
}
if ((outOff + len) > out.length) {
throw ArgumentError('output buffer too short');
}
for (var i = 0; i < len; i++) {
_x = (_x + 1) & 0xff;
_y = (_engineState![_x] + _y) & 0xff;
// swap
var tmp = _engineState![_x];
_engineState![_x] = _engineState![_y];
_engineState![_y] = tmp;
// xor
out[i + outOff] = inp[i + inpOff] ^
_engineState![(_engineState![_x] + _engineState![_y]) & 0xff];
}
}
@override
void reset() {
setKey(_workingKey);
}
@override
int returnByte(int inp) {
_x = (_x + 1) & 0xff;
_y = (_engineState![_x] + _y) & 0xff;
// swap
var tmp = _engineState![_x];
_engineState![_x] = _engineState![_y];
_engineState![_y] = tmp;
// xor
return inp ^ _engineState![(_engineState![_x] + _engineState![_y]) & 0xff];
}
void setKey(Uint8List keyBytes) {
_workingKey = keyBytes;
_x = 0;
_y = 0;
_engineState ??= Uint8List(STATE_LENGTH);
// reset the state of the engine
for (var i = 0; i < STATE_LENGTH; i++) {
_engineState![i] = i;
}
var i1 = 0;
var i2 = 0;
for (var i = 0; i < STATE_LENGTH; i++) {
i2 = ((keyBytes[i1] & 0xff) + _engineState![i] + i2) & 0xff;
// do the byte-swap inline
var tmp = _engineState![i];
_engineState![i] = _engineState![i2];
_engineState![i2] = tmp;
i1 = (i1 + 1) % keyBytes.length;
}
}
}