114 lines
2.7 KiB
Dart
114 lines
2.7 KiB
Dart
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;
|
|
}
|
|
}
|
|
}
|