| // See file LICENSE for more information. |
| |
| library impl.secure_random.block_ctr_random; |
| |
| import 'dart:typed_data'; |
| |
| import 'package:pointycastle/api.dart'; |
| import 'package:pointycastle/src/registry/registry.dart'; |
| import 'package:pointycastle/src/ufixnum.dart'; |
| import 'package:pointycastle/src/impl/secure_random_base.dart'; |
| |
| /// An implementation of [SecureRandom] that uses a [BlockCipher] with CTR mode to generate random |
| /// values. |
| class BlockCtrRandom extends SecureRandomBase implements SecureRandom { |
| /// Intended for internal use. |
| static final FactoryConfig factoryConfig = DynamicFactoryConfig.regex( |
| SecureRandom, |
| r'^(.*)/CTR/PRNG$', |
| (_, final Match match) => () { |
| var blockCipherName = match.group(1); |
| var blockCipher = BlockCipher(blockCipherName!); |
| return BlockCtrRandom(blockCipher); |
| }); |
| |
| final BlockCipher cipher; |
| |
| late Uint8List _input; |
| late Uint8List _output; |
| late int _used; |
| |
| BlockCtrRandom(this.cipher) { |
| _input = Uint8List(cipher.blockSize); |
| _output = Uint8List(cipher.blockSize); |
| _used = _output.length; |
| } |
| |
| @override |
| String get algorithmName => '${cipher.algorithmName}/CTR/PRNG'; |
| |
| @override |
| void seed(CipherParameters params) { |
| _used = _output.length; |
| if (params is ParametersWithIV) { |
| _input.setAll(0, params.iv); |
| cipher.init(true, params.parameters!); |
| } else { |
| cipher.init(true, params); |
| } |
| } |
| |
| @override |
| int nextUint8() { |
| if (_used == _output.length) { |
| cipher.processBlock(_input, 0, _output, 0); |
| _used = 0; |
| _incrementInput(); |
| } |
| |
| return clip8(_output[_used++]); |
| } |
| |
| void _incrementInput() { |
| var offset = _input.length; |
| do { |
| offset--; |
| _input[offset] += 1; |
| } while (_input[offset] == 0); |
| } |
| } |