// See file LICENSE for more information. library impl.digest.sha512t; import 'dart:typed_data'; import 'package:pointycastle/api.dart'; import 'package:pointycastle/src/impl/long_sha2_family_digest.dart'; import 'package:pointycastle/src/registry/registry.dart'; import 'package:pointycastle/src/ufixnum.dart'; /// Implementation of SHA-512/t digest (see FIPS 180-4). class SHA512tDigest extends LongSHA2FamilyDigest implements Digest { static final RegExp _nameRegex = RegExp(r'^SHA-512\/([0-9]+)$'); /// Intended for internal use. static final FactoryConfig factoryConfig = DynamicFactoryConfig( Digest, _nameRegex, (_, final Match match) => () { var bitLength = int.parse(match.group(1)!); if ((bitLength % 8) != 0) { throw RegistryFactoryException( 'Digest length for SHA-512/t is not a multiple of 8: $bitLength'); } return SHA512tDigest(bitLength ~/ 8); }); static final Register64 _hMask = Register64(0xa5a5a5a5, 0xa5a5a5a5); @override final int digestSize; final _h1t = Register64(); final _h2t = Register64(); final _h3t = Register64(); final _h4t = Register64(); final _h5t = Register64(); final _h6t = Register64(); final _h7t = Register64(); final _h8t = Register64(); SHA512tDigest(this.digestSize) { if (digestSize >= 64) { throw ArgumentError('Digest size cannot be >= 64 bytes (512 bits)'); } if (digestSize == 48) { throw ArgumentError( 'Digest size cannot be 48 bytes (384 bits): use SHA-384 instead'); } _generateIVs(digestSize * 8); reset(); } @override String get algorithmName => 'SHA-512/${digestSize * 8}'; @override void reset() { super.reset(); h1.set(_h1t); h2.set(_h2t); h3.set(_h3t); h4.set(_h4t); h5.set(_h5t); h6.set(_h6t); h7.set(_h7t); h8.set(_h8t); } @override int doFinal(Uint8List out, int outOff) { finish(); var tmp = Uint8List(64); var view = ByteData.view(tmp.buffer, tmp.offsetInBytes, tmp.length); h1.pack(view, 0, Endian.big); h2.pack(view, 8, Endian.big); h3.pack(view, 16, Endian.big); h4.pack(view, 24, Endian.big); h5.pack(view, 32, Endian.big); h6.pack(view, 40, Endian.big); h7.pack(view, 48, Endian.big); h8.pack(view, 56, Endian.big); out.setRange(outOff, outOff + digestSize, tmp); reset(); return digestSize; } void _generateIVs(int bitLength) { h1 ..set(0x6a09e667, 0xf3bcc908) ..xor(_hMask); h2 ..set(0xbb67ae85, 0x84caa73b) ..xor(_hMask); h3 ..set(0x3c6ef372, 0xfe94f82b) ..xor(_hMask); h4 ..set(0xa54ff53a, 0x5f1d36f1) ..xor(_hMask); h5 ..set(0x510e527f, 0xade682d1) ..xor(_hMask); h6 ..set(0x9b05688c, 0x2b3e6c1f) ..xor(_hMask); h7 ..set(0x1f83d9ab, 0xfb41bd6b) ..xor(_hMask); h8 ..set(0x5be0cd19, 0x137e2179) ..xor(_hMask); updateByte(0x53); updateByte(0x48); updateByte(0x41); updateByte(0x2D); updateByte(0x35); updateByte(0x31); updateByte(0x32); updateByte(0x2F); if (bitLength > 100) { updateByte(bitLength ~/ 100 + 0x30); bitLength = bitLength % 100; updateByte(bitLength ~/ 10 + 0x30); bitLength = bitLength % 10; updateByte(bitLength + 0x30); } else if (bitLength > 10) { updateByte(bitLength ~/ 10 + 0x30); bitLength = bitLength % 10; updateByte(bitLength + 0x30); } else { updateByte(bitLength + 0x30); } finish(); _h1t.set(h1); _h2t.set(h2); _h3t.set(h3); _h4t.set(h4); _h5t.set(h5); _h6t.set(h6); _h7t.set(h7); _h8t.set(h8); } }