blob: c3ecafcae763d9499cb5b1a66310ba961241733e [file] [log] [blame]
// Digest example 1
import 'dart:convert';
import 'dart:typed_data';
import 'package:pointycastle/pointycastle.dart';
//================================================================
// Demonstrations
//----------------------------------------------------------------
/// Demonstrate the use of `process` to provide the data completely.
Uint8List completeExample(Uint8List dataToDigest) {
var d = Digest('SHA-256');
final hash = d.process(dataToDigest);
return hash;
}
//----------------------------------------------------------------
/// Demonstrates the use of `updateByte`, `update` and `doFinal`
/// to provide the data progressively.
Uint8List progressiveExample() {
var d = Digest('SHA-256');
final chunk1 = utf8.encode('cellophane');
final chunk2 = utf8.encode('world');
d.updateByte(0x48); // 'H'
d.update(Uint8List.fromList(chunk1), 1, 4);
d.updateByte(0x20); // ' '
d.update(Uint8List.fromList(chunk2), 0, chunk2.length);
d.updateByte(0x21); // '!'
final hash = Uint8List(d.digestSize);
d.doFinal(hash, 0); // hash of 'Hello world!'
return hash;
}
//----------------------------------------------------------------
/// Demonstrate the effect of `reset`.
void resetExample() {
final data1 = utf8.encode('Hello ');
final data2 = utf8.encode('world!');
print('\nEffect of `reset`:');
{
print(' Using `process` automatically resets:');
var d = Digest('SHA-256');
final h1 = d.process(Uint8List.fromList(data1));
print(' ${bin2hex(h1)}');
final h2 = d.process(Uint8List.fromList(data2));
print(' ${bin2hex(h2)}');
}
{
print(' Using `doFinal` automatically resets:');
var d = Digest('SHA-256');
final h1 = Uint8List(d.digestSize);
d.update(Uint8List.fromList(data1), 0, data1.length);
d.doFinal(h1, 0);
print(' ${bin2hex(h1)}');
d.reset();
final h2 = Uint8List(d.digestSize);
d.update(Uint8List.fromList(data2), 0, data2.length);
d.doFinal(h2, 0);
print(' ${bin2hex(h2)}');
}
{
final part1 = utf8.encode('Hello ');
final part2 = utf8.encode('world!');
var d = Digest('SHA-256');
final hash = Uint8List(d.digestSize);
// With reset
d.update(Uint8List.fromList(part1), 0, part1.length);
d.reset();
d.update(Uint8List.fromList(part2), 0, part2.length);
d.doFinal(hash, 0); // hash of 'world!'
print(' Using `update` with reset:\n ${bin2hex(hash)}');
// Without rest
d.update(Uint8List.fromList(part1), 0, part1.length);
d.update(Uint8List.fromList(part2), 0, part2.length);
d.doFinal(hash, 0); // hash of 'Hello world!'
print(' Using `update` without reset:\n ${bin2hex(hash)}');
}
}
//----------------------------------------------------------------
/// Shows digest works on arbitrary binary data and not just
/// text converted into bytes as utf8.
///
/// These examples are taken from the text examples from section 8.5 of RFC 6234
/// <https://tools.ietf.org/html/rfc6234#section-8.5>
/// Test inputs are from page 92 and 93 of RFC 6234.
/// Test vectors and results from page 97 and 98 of RFC 6234.
void binaryExample() {
print('\nExamples from RFC 2634:');
var d = Digest('SHA-256');
// TEST1
final test1 = ascii.encode('abc');
assert(test1[0] == 0x61);
assert(test1[1] == 0x62);
assert(test1[2] == 0x63);
assert(test1.length == 3);
final expected1 = 'BA7816BF8F01CFEA4141'
'40DE5DAE2223B00361A396177A9CB410FF61F20015AD';
final hash1 = bin2hex(d.process(test1));
print(' TEST1: $hash1');
if (hash1 != expected1.toLowerCase()) {
print('Error: SHA-256 of TEST1 did not produce the correct hash\n');
}
/* This doesn't work yet. Need to investigate why.
// TEST7_256
final test7_256 = Uint8List.fromList(
'\xbe\x27\x46\xc6\xdb\x52\x76\x5f\xdb\x2f\x88\x70\x0f\x9a\x73'.codeUnits);
assert(test7_256[0] == 0xbe);
assert(test7_256[1] == 0x27);
assert(test7_256[2] == 0x46);
assert(test7_256[3] == 0xc6);
assert(test7_256.last == 0x73);
final repeatCount7 = 1;
final extraBits7 = 0x60;
final numberExtraBits7 = 3;
final expected7 = '77EC1DC8'
'9C821FF2A1279089FA091B35B8CD960BCAF7DE01C6A7680756BEB972';
for (var repeat = 0; repeat < repeatCount7; repeat++) {
d.update(test7_256, 0, test7_256.length);
}
for (var extra = 0; extra < numberExtraBits7; extra++) {
d.updateByte(extraBits7);
}
final hash7bytes = Uint8List(d.digestSize);
d.doFinal(hash7bytes, 0);
final hash7 = bin2hex(hash7bytes);
print(' TEST7_256: $hash7');
if (hash7 != expected7.toLowerCase()) {
print('Error: SHA-256 of TEST7_256 did not produce the correct hash\n');
}
*/
}
//================================================================
// Utility functions
//----------------------------------------------------------------
/// Represent bytes in hexadecimal
///
/// If a [separator] is provided, it is placed the hexadecimal characters
/// representing each byte. Otherwise, all the hexadecimal characters are
/// simply concatenated together.
String bin2hex(Uint8List bytes, {String? separator, int? wrap}) {
var len = 0;
final buf = StringBuffer();
for (final b in bytes) {
final s = b.toRadixString(16);
if (buf.isNotEmpty && separator != null) {
buf.write(separator);
len += separator.length;
}
if (wrap != null && wrap < len + 2) {
buf.write('\n');
len = 0;
}
buf.write('${(s.length == 1) ? '0' : ''}$s');
len += 2;
}
return buf.toString();
}
//----------------------------------------------------------------
void main(List<String> args) {
if (args.contains('-h') || args.contains('--help')) {
print('Usage: digest-demo');
return;
}
// Calculate digest with complete data
//
// Note: the progressive example is hardcoded to produce the digest of
// 'Hello world!', so there is no point in changing the 'data' if you want
// to see they both produce the same result.
const dataForComplete = 'Hello world!';
print('SHA-256 digest of "$dataForComplete":');
final hash1 =
completeExample(Uint8List.fromList(utf8.encode(dataForComplete)));
print(' with complete data: ${bin2hex(hash1)}');
// Calculate digest by providing the data progressively
final hash2 = progressiveExample();
print('with progressive data: ${bin2hex(hash1)}');
// Prove they both produce the same digest value
for (var x = 0; x < hash1.length; x++) {
if (hash1[x] != hash2[x]) {
print('Error: hashes are different');
}
}
// Other examples
resetExample();
binaryExample();
}