Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for BLAKE2 (RFC7693) #313

Open
Jorropo opened this issue May 15, 2022 · 2 comments
Open

Add support for BLAKE2 (RFC7693) #313

Jorropo opened this issue May 15, 2022 · 2 comments

Comments

@Jorropo
Copy link

Jorropo commented May 15, 2022

Description

BLAKE2 is a fast software friendly hash function.
It is also a SHA3 finalist.

I would like to add it to as an optional part of the webcrypto API.

Spec

it can be found here:

Tests

There is an extensive test vector list available here https://github.com/BLAKE2/BLAKE2/tree/master/testvectors (CC0 1.0 Universal license).

Support

It is already supported into many cryptographic libraries, and implementing it is really easy, so it shouldn't be lots of work to implement for vendors.

Reasons BLAKE2 is a usefull hash function

  • It's fast (BLAKE2b is ~2.3x times faster than SHA256 according to www.blake2.net's benchmarks)
  • It's fast on lowpower hardware, making it nice when you need it to work on things like embeded devices, phones, ...
  • It's fast even implemented on software. (in other words, it does not require hardware accelerators like custom CPU extensions to achieve it's great speed)
  • It support an optional key field, allowing for HMAC like patterns without using HMAC (it's builtin in the algorithm).

JS API

Using it would be similar to the current SHA extension.
Consumers would call crypto.subtle.digest with the name, data and optionally the key and get returned a promise, that when resolved would return the digest body.

Name and variants

BLAKE2{s,b}-$SIZE
  • s or b refer to the word size, 32 or 64bits respectively, that also affects the blocksize (which is made of 16 words), keysize, constants used and the number of rounds.
  • $SIZE, even tho internally the hashing will always happen in 64 or 128 bytes blocks, BLAKE2 supports arbitrary sized digests as long it follows 0 < x <= (blocksize/2) bytes, for convinience and following convention it would be expressed in bits.

(note this proposal doesn't include BLAKE2x (arbitrarily sizable digests) or BLAKE2{s,b}p (parallel variant with reduced block depency for increased performance), this proposal stick to RFC7693)

So that allows you to combine them to make the name to pass to digest.
For example:

  • BLAKE2b-256 indicates 64bits words with a 32 bytes digest size.
  • BLAKE2s-16 indicates 32bits words, with a 2 bytes digest size.

Vendors are allowed to only support either of the variant if they wish too.

Normative restriction on variant support

If a vendor support any digest size of a variant, they must also support all other available digest sizes.
So supporting BLAKE2b-512 require you to also supports BLAKE2b-8, BLAKE2b-16, ...

The reason to do this is that the digest size is not actually part of the algorithm, but only a parameter.

Optional key parameter

Unlike SHA, BLAKE2 accepts a key (bytes) that is 0 <= x <= (blocksize/2) big.
This can be passed as an optional third parameter to digest.

If the key is undefined, then assume a 0 sized key.
Else if the type does not match BufferSource throw with TypeError.
Else if the key is bigger than allowed throw with DataError.

Note the optional here, means optional to consumers, not vendors, vendors MUST support the key parameter if they want to support BLAKE2.

Return value

An ArrayBuffer containing the resulting digest, and sized matching the size parameter.

Usage example

function buf2hex(b) { return [...new Uint8Array(b)].map(x => x.toString(16).padStart(2, '0')).join('') }

const body = new TextEncoder("utf-8").encode("hello")
const h1 = crypto.subtle.digest("BLAKE2b-256", body)

const key = new TextEncoder("utf-8").encode("world")
const h2 = crypto.subtle.digest("BLAKE2s-128", body, key)

console.log(buf2hex(await h1)) // 324dcf027dd4a30a932c441f365a25e86b173defa4b8e58948253471b81b72cf
console.log(buf2hex(await h2)) // d956ebc7895f6f2f0d00b5ad04b10749

Implementation interest

I currently have personal interest into getting this added.
I can draft a spec PR and make a W3C's testsuite friendly version of the already existing test cases if reception seems positive.
I'm also interested into implementing this into the major engines.

@twiss
Copy link
Member

twiss commented Jun 9, 2022

Hello 👋 Thanks for the detailed proposal, and apologies for the delayed response.

To me, adding BLAKE2 seems a bit specific: SHA-3 is probably more widely used, and BLAKE3 is probably faster. So perhaps it makes more sense to wait until there's an RFC for BLAKE3 and then add that?

That being said, if you want to propose to add it, the process is outlined here: #280 (comment).

One minor, much more specific comment if you do so: I wouldn't add the digest size in the algorithm name. Algorithms can have parameters, so you could have for example { name: 'BLAKE2b', length: 256 } as the algorithm identifier. And then, you could also add the key as an optional property of that object, rather than adding a new parameter to subtle.digest. See HkdfParams for inspiration, for example.

@Neustradamus
Copy link

To follow it :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants