| // See file LICENSE for more information. |
| |
| library impl.mac.hmac; |
| |
| import 'dart:typed_data'; |
| |
| import 'package:pointycastle/api.dart'; |
| import 'package:pointycastle/src/impl/base_mac.dart'; |
| import 'package:pointycastle/src/registry/registry.dart'; |
| |
| /// HMAC implementation based on RFC2104 |
| /// |
| /// H(K XOR opad, H(K XOR ipad, text)) |
| class HMac extends BaseMac { |
| static final FactoryConfig factoryConfig = DynamicFactoryConfig.suffix( |
| Mac, |
| '/HMAC', |
| (_, Match match) { |
| final digestName = match.group(1); |
| return () { |
| return HMac.withDigest(Digest(digestName!)); |
| }; |
| }, |
| ); |
| |
| //TODO reindent |
| |
| static final _ipad = 0x36; |
| static final _opad = 0x5C; |
| |
| final Digest _digest; |
| late int _digestSize; |
| late int _blockLength; |
| |
| late Uint8List _inputPad; |
| late Uint8List _outputBuf; |
| |
| HMac(this._digest, this._blockLength) { |
| _digestSize = _digest.digestSize; |
| _inputPad = Uint8List(_blockLength); |
| _outputBuf = Uint8List(_blockLength + _digestSize); |
| } |
| |
| HMac.withDigest(this._digest) { |
| _blockLength = _digest.byteLength; |
| |
| _digestSize = _digest.digestSize; |
| _inputPad = Uint8List(_blockLength); |
| _outputBuf = Uint8List(_blockLength + _digestSize); |
| } |
| |
| @override |
| String get algorithmName => '${_digest.algorithmName}/HMAC'; |
| |
| @override |
| int get macSize => _digestSize; |
| |
| @override |
| void reset() { |
| // reset the underlying digest. |
| _digest.reset(); |
| |
| // reinitialize the digest. |
| _digest.update(_inputPad, 0, _inputPad.length); |
| } |
| |
| @override |
| void init(covariant KeyParameter params) { |
| _digest.reset(); |
| |
| var key = params.key; |
| var keyLength = key.length; |
| |
| if (keyLength > _blockLength) { |
| _digest.update(key, 0, keyLength); |
| _digest.doFinal(_inputPad, 0); |
| |
| keyLength = _digestSize; |
| } else { |
| _inputPad.setRange(0, keyLength, key); |
| } |
| |
| _inputPad.fillRange(keyLength, _inputPad.length, 0); |
| |
| _outputBuf.setRange(0, _blockLength, _inputPad); |
| |
| _xorPad(_inputPad, _blockLength, _ipad); |
| _xorPad(_outputBuf, _blockLength, _opad); |
| |
| _digest.update(_inputPad, 0, _inputPad.length); |
| } |
| |
| @override |
| void updateByte(int inp) { |
| _digest.updateByte(inp); |
| } |
| |
| @override |
| void update(Uint8List inp, int inpOff, int len) { |
| _digest.update(inp, inpOff, len); |
| } |
| |
| @override |
| int doFinal(Uint8List out, int outOff) { |
| _digest.doFinal(_outputBuf, _blockLength); |
| _digest.update(_outputBuf, 0, _outputBuf.length); |
| |
| var len = _digest.doFinal(out, outOff); |
| _outputBuf.fillRange(_blockLength, _outputBuf.length, 0); |
| _digest.update(_inputPad, 0, _inputPad.length); |
| |
| return len; |
| } |
| |
| void _xorPad(Uint8List pad, int len, int n) { |
| for (var i = 0; i < len; i++) { |
| pad[i] ^= n; |
| } |
| } |
| } |