Now Meet Blake 2 … In Hardware

Ssh! Don’t tell NIST, but there’s a better hashing method than SHA-256 (SHA-2 standard), and it’s Blake 2. Overall, Blake 2b is focused on…

Photo by Markus Spiske on Unsplash

Now Meet Blake 2 … In Hardware

Ssh! Don’t tell NIST, but there’s (possibly) a better hashing method than SHA-256 (SHA-2 standard). And, it’s Blake 2.

So, while Blake 2 has always been faster than most of the existing cryptographic hashes with software methods, a new hardware build has been created that will allow Blake 2s to be implemented in hardware on 32-bit processors:

This build has been created with Verilog and which is a standard hardware description language. Overall, Blake 2b is focused on 64-bit architectures, while Blake 2s focuses on 32-bit ones. The Verilog design implements the Blake 2 methodology defined in RFC 7693 [here] and which was authored by Ed Saarinen and JP Aumasson:

The implementation shows that it uses around the same resources, but is around twice as fast as SHA-256.

Keyed hashing (HMAC) with Blake2

Keyed hashing can be used to apply a secret key onto a hash and can thus be used for authentication of a message and generate a MAC (Message Authentication Code). In this way, we can prove that Bob and Alice have the same secret while authenticating the messages they send. Keyed hashing is used for this, and one of the most popular methods is HMAC (Hash-based message authentication code).

For keyed hashing, we can use BLAKE2 using the indifferentiability property that was defined in the BLAKE hashing method. In this case, Bob and Alice will share a secret key, and then Bob will sign a message with this secret key, and send the signature with the message. Alice then checks the MAC for the message with her shared secret and checks the signature. If it matches the MAC that Bob sent, Alice knows that Bob sent it and that the message has not been changed. In this example, we will check the MAC with a valid secret and with an incorrect one. With indifferentiability, it is not possible for hashes to be distinguishable from each other. Any hash value is thus indistinguishable from a random value, and no additional information can be leaked from the hash.

In the following, we use SHA256 for the hashing method the MAC:

But, we can easily change this to Blake2b with [here]:

from hashlib import blake2b
import hmac, hashlib
from hmac import compare_digest
import sys

m="hello"
no_bytes=64
key="fdf"
if (len(sys.argv)>1):
no_bytes=int(sys.argv[1])
if (len(sys.argv)>2):
key=(sys.argv[2])
if (len(sys.argv)>3):
m=(sys.argv[3])
def sign(msg):
h = blake2b(digest_size=no_bytes, key=key.encode())
h.update(msg.encode())
return h.hexdigest().encode('utf-8')
def verify(msg, sig):
good_sig = sign(msg)
return compare_digest(good_sig, sig)
print ("Message: ",m)
print ("Secret key: ",key)
print ("Size (bytes): ",no_bytes )
sig = sign(m)
print (f"\nSignature: {sig}")
print (f"\nVerified {m}: ",verify(m, sig))
ver=verify(m+"-", sig)
print (f"Verified {m}-: {ver}")
print ("\n== We can also use Blake2 for HMAC ==")
hm = hmac.new(key.encode(), digestmod=hashlib.blake2s)
hm.update(m.encode())
print ("\nHMAC: ",hm.hexdigest())

A sample run is [here]:

Message:  hello
Secret key: fdf
Size: 64
Signature: b'7cb36c835e103f7f4b5a9091074abe1d036d68c62ced9c508e1d409dd2223b54d7b4d9524f2de02559d399301952ec5816362ba8f9fbe8b8d35b64273e51647d'
Verified hello:  True
Verified hello-: False
We can also use Blake for HMAC:
HMAC:  6a9848f2622181412452c2439dcd96dbd5a0231e209750f3ddf6b6a49b3e1dd1

Blake 2 and Rust

One of the best ways to implement Blake 2 is within Rust. The following gives an example of integrating the Blake 2 crate (for Blake 2b and 2s), and in integrating other SHA-2 and SHA-3 methods [here]:

extern crate blake2;
extern crate digest;
extern crate sha2;
extern crate sha1;
extern crate sha3;

use blake2::{Blake2b, Blake2s, Digest};
use sha2::Sha256;
use sha3::{Sha3_224,Sha3_256,Sha3_384,Sha3_512};
use std::env;
 
fn main() {
	let mut string = String::from("Hello world!");
	let args: Vec = env::args().collect();
	if args.len() >1 {
		string = args[1].clone();
}
	println!("Data: {}",string);
let data = string.as_bytes();

	let hash = Blake2b::digest(data);
	println!("\nBlake 2b Hash: {:x}", hash);

	let hash = Blake2s::digest(data);
	println!("\nBlake 2s Hash: {:x}", hash);

	let hash1 = blake3::hash(data).to_hex();
	println!("\nBlake3 Hash: {}", hash1);

	let mut m = sha1::Sha1::new();
m.update(data);
	println!("\nSHA-1 Hash: {}", m.digest().to_string());
	let hash = Sha256::digest(data);
	println!("SHA-256 Hash: {:x}", hash);
	let hash = Sha3_224::digest(data);
	println!("SHA3-244 Hash: {:x}", hash);

	let hash = Sha3_256::digest(data);
	println!("SHA3-256 Hash: {:x}", hash);

	let hash = Sha3_384::digest(data);
	println!("SHA3-384 Hash: {:x}", hash);

	let hash = Sha3_512::digest(data);
	println!("SHA3-512 Hash: {:x}", hash);
}

A sample run shows that the 2s hash version is 32 bytes long, while the 2b version has 64 bytes [here]:

Data: The quick brown fox jumps over the lazy dog
Blake 2b Hash: a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918
Blake 2s Hash: 606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812
Blake3 Hash: 2f1514181aadccd913abd94cfa592701a5686ab23f8df1dff1b74710febc6d4a
SHA-1 Hash: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
SHA-256 Hash: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592
SHA3-244 Hash: d15dadceaa4d5d7bb3b48f446421d542e08ad8887305e28d58335795
SHA3-256 Hash: 69070dda01975c8c120c3aada1b282394e7f032fa9cf32f4cb2259a0897dfc04
SHA3-384 Hash: 7063465e08a93bce31cd89d2e3ca8f602498696e253592ed26f07bf7e703cf328581e1471a7ba7ab119b1a9ebdf8be41
SHA3-512 Hash: 01dedd5de4ef14642445ba5f5b97c15e47b9ad931326e4b0727cd94cefc44fff23f07bf543139939b49128caf436dc1bdee54fcb24023a08d9403f9b4bf0d450

Conclusions

The natural course for the industry is to move towards a standard, but in the case of SHA-256, Blake 2 has proven to have some traction and is faster in production. I now see many software projects adopting it as the standard hashing method, as it provides improved performance levels, and, at scale, we often need our hashing methods to be fast and efficient. What’s great with this project, is that chip designers can now add it to devices.