Calculate file crypto hash (sha1, sha256, sha384 and sha512) in Flutter
Introduce crypto and ChunkedStreamReader
crypto
Flutter crypto package provides a set of cryptographic hashing functions implemented in pure Dart.
The following hashing algorithms are supported:
- SHA-1
- SHA-224
- SHA-256
- SHA-384
- SHA-512
- SHA-512/224
- SHA-512/256
- MD5
- HMAC (i.e. HMAC-MD5, HMAC-SHA1, HMAC-SHA256)
crypto package already provide sample code to calculate hash through from bytes.
SHA-1 SHA-256 SHA-512 on bytes
Sample code to calculate SHA-256 hash for a short string. The idea is first convert string
to bytes
,
then invoke the convert()
method on the sha1
, sha256
or sha512
objects:
import 'package:crypto/crypto.dart';
import 'dart:convert'; // for the utf8.encode method
void main() {
final bytes = utf8.encode("Hello, world."); // data being hashed
final digest = sha256.convert(bytes);
print("Digest as bytes: ${digest.bytes}");
print("Digest as hex string: $digest");
}
If the input string is very long, may calculate hash incrementally through chunked input:
import 'dart:convert';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
void main() {
var firstChunk = utf8.encode("foo");
var secondChunk = utf8.encode("bar");
var output = AccumulatorSink<Digest>();
var input = sha1.startChunkedConversion(output);
input.add(firstChunk);
input.add(secondChunk); // call `add` for every chunk of input data
input.close();
final digest = output.events.single;
print("Digest as bytes: ${digest.bytes}");
print("Digest as hex string: $digest");
}
HMAC
Flutter also support calculate HMAC
(Hash-based Message Authentication Codes).
HMAC is a specific type of message authentication code (MAC) involving a cryptographic hash function and a secret cryptographic key. As with any MAC, it may be used to simultaneously verify both the data integrity and authenticity of a message.
There is an example calculate HMAC
in Flutter:
import 'dart:convert';
import 'package:crypto/crypto.dart';
void main() {
final key = utf8.encode('hash password');
final bytes = utf8.encode("some text here...");
final hmacSha256 = Hmac(sha256, key); // HMAC-SHA256
final digest = hmacSha256.convert(bytes);
print("HMAC digest as bytes: ${digest.bytes}");
print("HMAC digest as hex string: $digest");
}
Flutter ChunkedStreamReader
To calculate file hash, we need read file to bytes. To support large file, we should read file by chunk and calculate its hash incrementally.
Flutter async
package contains utility classes in the style of dart:async
to work with asynchronous computations.
Flutter async package provides ChunkedStreamReader
utility class for reading chunks from a file stream.
A chunked stream is a stream where each event is a chunk of elements.
This utility class makes it easy to read a chunked stream using custom chunk sizes and sub-stream sizes, without managing partially read chunks.
Sample code to calculate file sha256 hash
Put crypto
and async
together, an example of calculate file sha256
hash as below.
This code can support large file because it calculate hash chunk by chunk, each chunk is 4KB.
sha1
, sha384
and sha512
is similar, just replace sha256
with sha1
, sha384
or sha512
.
import 'package:async/async.dart';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:convert/convert.dart';
Future<Digest> getFileSha256(String path) async {
final reader = ChunkedStreamReader(File(path).openRead());
const chunkSize = 4096;
var output = AccumulatorSink<Digest>();
var input = sha256.startChunkedConversion(output);
try {
while (true) {
final chunk = await reader.readChunk(chunkSize);
if (chunk.isEmpty) {
// indicate end of file
break;
}
input.add(chunk);
}
} finally {
// We always cancel the ChunkedStreamReader,
// this ensures the underlying stream is cancelled.
reader.cancel();
}
input.close();
return output.events.single;
}
Notes:
- The read-operations
readChunk
must not be invoked until the future from a previous call has completed. - Return
Digest
so we can easily convert tobytes
,hex
orbase64
encoded string.
Example of getFileSha256
Get file hash in hex string
Just use result of Digest.toString()
to get hexadecimal digits.
final hash = await getFileSha256(path);
print("sha256 hash hex in lowercase: ${hash.toString()}");
Get file hash in base64 url safe encode
Hash result Digest.bytes
can be encode with base64Url
to get base64 url safe encoding:
final hash = await getFileSha256(path);
final hashBase64UrlSafe = base64Url.encode(hash.bytes);
print("sha256 hash base64 url safe: $hashBase64UrlSafe");
References
OmniLock - Block / Hide App on iOS
Block distractive apps from appearing on the Home Screen and App Library, enhance your focus and reduce screen time.
DNS Firewall for iOS and Mac OS
Encrypted your DNS to protect your privacy and firewall to block phishing, malicious domains, block ads in all browsers and apps