ref: b585b4c034d4725aea6232130c0e71f0d5dca144
parent: a4d95fa815ea52ed8a2c2ee770c83bfa0c834355
author: Jacob Moody <moody@posixcafe.org>
date: Wed Jun 11 21:08:39 EDT 2025
libsec: blake2s_128, mac_blake2s_*
--- a/sys/include/ape/libsec.h
+++ b/sys/include/ape/libsec.h
@@ -240,6 +240,7 @@
MD5dlen= 16, /* MD5 digest length */
RIPEMD160dlen= 20, /* RIPEMD-160 digest length */
Poly1305dlen= 16, /* Poly1305 digest length */
+ BLAKE2S_128dlen= 16, /* Blake2s-128 digest length */
BLAKE2S_256dlen= 32, /* Blake2s-256 digest length */
Hmacblksz = 64, /* in bytes; from rfc2104 */
@@ -275,6 +276,7 @@
DigestState* sha2_256(uchar*, ulong, uchar*, DigestState*);
DigestState* sha2_384(uchar*, ulong, uchar*, DigestState*);
DigestState* sha2_512(uchar*, ulong, uchar*, DigestState*);
+DigestState* blake2s_128(uchar*, ulong, uchar*, DigestState*);
DigestState* blake2s_256(uchar*, ulong, uchar*, DigestState*);
DigestState* hmac_x(uchar *p, ulong len, uchar *key, ulong klen,
uchar *digest, DigestState *s,
@@ -288,6 +290,8 @@
DigestState* hmac_sha2_512(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
DigestState* hmac_blake2s_256(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
DigestState* poly1305(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
+DigestState* mac_blake2s_128(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
+DigestState* mac_blake2s_256(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
/*
* random number generation
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -232,6 +232,7 @@
MD5dlen= 16, /* MD5 digest length */
RIPEMD160dlen= 20, /* RIPEMD-160 digest length */
Poly1305dlen= 16, /* Poly1305 digest length */
+ BLAKE2S_128dlen= 16, /* Blake2s-128 digest length */
BLAKE2S_256dlen= 32, /* Blake2s-256 digest length */
Hmacblksz = 64, /* in bytes; from rfc2104 */
@@ -267,6 +268,7 @@
DigestState* sha2_256(uchar*, ulong, uchar*, DigestState*);
DigestState* sha2_384(uchar*, ulong, uchar*, DigestState*);
DigestState* sha2_512(uchar*, ulong, uchar*, DigestState*);
+DigestState* blake2s_128(uchar*, ulong, uchar*, DigestState*);
DigestState* blake2s_256(uchar*, ulong, uchar*, DigestState*);
DigestState* hmac_x(uchar *p, ulong len, uchar *key, ulong klen,
uchar *digest, DigestState *s,
@@ -280,6 +282,8 @@
DigestState* hmac_sha2_512(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
DigestState* hmac_blake2s_256(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
DigestState* poly1305(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
+DigestState* mac_blake2s_128(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
+DigestState* mac_blake2s_256(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
/*
* random number generation
--- a/sys/man/2/sechash
+++ b/sys/man/2/sechash
@@ -3,6 +3,7 @@
md4, md5, ripemd160,
sha1, sha2_224, sha2_256, sha2_384, sha2_512,
hmac_x, hmac_md5, hmac_sha1, hmac_sha2_224, hmac_sha2_256, hmac_sha2_384, hmac_sha2_512,
+blake2s_128, blake2s_256, mac_blake2s_128, mac_blake2s_256, hmac_blake2s_256,
poly1305 \- cryptographically secure hashes
.SH SYNOPSIS
.nr Wd \w'\fLDS* \fP'u
@@ -43,6 +44,8 @@
.Ti
DS* sha2_512(uchar *data, ulong dlen, uchar *digest, DS *state)
.Ti
+DS* blake2s_128(uchar *data, ulong dlen, uchar *digest, DS *state)
+.Ti
DS* blake2s_256(uchar *data, ulong dlen, uchar *digest, DS *state)
.Ti
DS* hmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DS *s, DS*(*x)(uchar*, ulong, uchar*, DS*), int xlen)
@@ -62,6 +65,10 @@
DS* hmac_blake2s_256(uchar *data, ulong dlen, uchar *key, ulong klen, uchar *digest, DS *state)
.Ti
DS* poly1305(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DS *state)
+.Ti
+DS* mac_blake2s_128(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DS *state)
+.Ti
+DS* mac_blake2s_256(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DS *state)
.SH DESCRIPTION
.DT
The output of a hash is called a
@@ -82,6 +89,7 @@
.IR sha2_256 ,
.IR sha2_384 ,
.IR sha2_512 ,
+.IR blake2s_128 ,
.IR blake2s_256 ,
differ only in the length of the resulting digest
and in the security of the hash.
@@ -113,6 +121,7 @@
.IR SHA2_256dlen ,
.IR SHA2_384dlen ,
.IR SHA2_512dlen ,
+.IR BLAKE2S_128dlen ,
.I BLAKE2S_256dlen
and
.I Poly1305dlen
@@ -143,6 +152,13 @@
is a one-time authenticator designed by D. J. Bernstein is documented in
.IR RFC8439 .
It takes a 32-byte one-time key and a message and produces a 16-byte tag.
+.PP
+.I Mac_blake2s_128
+and
+.I mac_blake2s_256
+provide the keyed variants of their respective blake2s functions.
+Unlike their hmac variants, the key may only be specified on the first call.
+Subsequent calls are free to use the non keyed variants.
.SH EXAMPLES
To hash a single buffer using
.IR md5 :
--- a/sys/src/libsec/port/blake2s.c
+++ b/sys/src/libsec/port/blake2s.c
@@ -4,6 +4,7 @@
extern void _blake2sblock(u32int h[16], uchar *b, u32int blen, u64int offset, u32int f);
static DigestState* blake2s_512(uchar *p, ulong len, uchar *digest, DigestState *s, int dlen);
+static DigestState* mac_blake2s_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s, int dlen);
static void
encode32(uchar *output, u32int *input, ulong len)
@@ -21,8 +22,39 @@
}
DigestState*
+blake2s_128(uchar *p, ulong len, uchar *digest, DigestState *s)
+{
+ return mac_blake2s_128(p, len, nil, 0, digest, s);
+}
+
+DigestState*
+mac_blake2s_128(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
+{
+ return mac_blake2s_x(p, len, key, klen, digest, s, BLAKE2S_128dlen);
+}
+
+DigestState*
blake2s_256(uchar *p, ulong len, uchar *digest, DigestState *s)
{
+ return mac_blake2s_256(p, len, nil, 0, digest, s);
+}
+
+DigestState*
+mac_blake2s_256(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
+{
+ return mac_blake2s_x(p, len, key, klen, digest, s, BLAKE2S_256dlen);
+}
+
+enum{
+ bb = 64,
+
+ fcont = 0,
+ flast = 0xFFFFFFFF,
+};
+
+static DigestState*
+mac_blake2s_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s, int dlen)
+{
if(s == nil) {
s = mallocz(sizeof(*s), 1);
if(s == nil)
@@ -39,18 +71,21 @@
s->state[6] = 0x1F83D9ABUL;
s->state[7] = 0x5BE0CD19UL;
- s->state[0] ^= 0x01010000 ^ BLAKE2S_256dlen;
+ s->state[0] ^= 0x01010000 ^ dlen;
+ if(klen > 0){
+ if(klen > bb){
+ werrstr("key is too large");
+ return nil;
+ }
+ s->state[0] ^= (klen << 8);
+ memcpy(s->buf, key, klen);
+ memset(s->buf+klen, 0, bb-klen);
+ s->blen = bb;
+ }
s->seeded = 1;
}
- return blake2s_512(p, len, digest, s, BLAKE2S_256dlen);
+ return blake2s_512(p, len, digest, s, dlen);
}
-
-enum{
- bb = 64,
-
- fcont = 0,
- flast = 0xFFFFFFFF,
-};
/* 64 byte input blocks */
static DigestState*
--- a/sys/src/libsec/test/blake2s.c
+++ b/sys/src/libsec/test/blake2s.c
@@ -3,36 +3,73 @@
#include <libsec.h>
struct {
- char *in, *exp;
+ char *in, *exp, *key;
} tests[] = {
{ /* empty input */
"",
"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9",
+ "",
},
{ /* reference hash */
"abc",
- "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"
+ "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982",
+ "",
},
{ /* exactly 1 block */
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"f85b88e0ac55872416d202c5f4881e7dbc9c7270542ef75074ff9b0a610b5a0e",
+ "",
},
{ /* exactly 2 blocks */
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"ea263e84e451e17ff77d642cd7a751757765aded33d62b96f1e998af31024e30",
+ "",
},
{ /* 1 block and some change */
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"c4b49a77ee46b6c166d56157131d1ec182153d0004428d6ac011edc942becd93",
+ "",
},
{ /* 2 blocks and some change */
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"cae0fc9b9f296425db4a4af96f83e947649e78954f4081ed72ebdfdfb29cfca4",
+ "",
},
{ /* 3 blocks and some change */
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"1b066f374e7e2d95a64643c5da9e1b89eab1c202cd5c17e27bc061ba3bbdc24a",
+ "",
},
+ { /* empty input with key */
+ "",
+ "b929086ee1f00ca75c05c4deb8eee28b174c6ba98b52b573a6b017db769a125c",
+ "9",
+ },
+ { /* reference input with key */
+ "abc",
+ "e6ee9e3d8b855f2b6a78a072f1a4e14226e7e6b15072681a965236f2b5405aad",
+ "9",
+ },
+ { /* empty input, 16 byte output */
+ "",
+ "64550d6ffe2c0a01a14aba1eade0200c",
+ "",
+ },
+ { /* reference input, 16 byte output */
+ "abc",
+ "aa4938119b1dc7b87cbad0ffd200d0ae",
+ "",
+ },
+ { /* empty input with key, 16 byte output */
+ "",
+ "4487d3ac1ad5879bd10ae24bac221455",
+ "9",
+ },
+ { /* reference input with key, 16 byte output */
+ "abc",
+ "0489aca3bac800d661ac5ba911212150",
+ "9",
+ },
};
void
@@ -43,11 +80,25 @@
char buf[256];
int i;
char *p;
+ DigestState* (*hash)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
+ int len;
fmtinstall('H', encodefmt);
for(i = 0; i < nelem(tests); i++){
- blake2s_256((uchar*)tests[i].in, strlen(tests[i].in), digest, nil);
- snprint(buf, sizeof buf, "%.*lH", BLAKE2S_256dlen, digest);
+ switch(strlen(tests[i].exp)){
+ case 64:
+ hash = mac_blake2s_256;
+ len = BLAKE2S_256dlen;
+ break;
+ case 32:
+ hash = mac_blake2s_128;
+ len = BLAKE2S_128dlen;
+ break;
+ default:
+ sysfatal("invalid test case");
+ }
+ hash((uchar*)tests[i].in, strlen(tests[i].in), (uchar*)tests[i].key, strlen(tests[i].key), digest, nil);
+ snprint(buf, sizeof buf, "%.*lH", len, digest);
if(strcmp(buf, tests[i].exp) != 0){
fprint(2, "Test: %s\nExp: %s\nGot: %s\n\n", tests[i].in, tests[i].exp, buf);
exits("fail");
@@ -56,10 +107,10 @@
s = nil;
memset(digest, 0, BLAKE2S_256dlen);
for(p = tests[i].in; *p != 0; p++)
- s = blake2s_256((uchar*)p, 1, nil, s);
+ s = hash((uchar*)p, 1, (uchar*)tests[i].key, strlen(tests[i].key), nil, s);
- blake2s_256(nil, 0, digest, s);
- snprint(buf, sizeof buf, "%.*lH", BLAKE2S_256dlen, digest);
+ hash(nil, 0, (uchar*)tests[i].key, strlen(tests[i].key), digest, s);
+ snprint(buf, sizeof buf, "%.*lH", len, digest);
if(strcmp(buf, tests[i].exp) != 0){
fprint(2, "Trickle Test: %s\nExp: %s\nGot: %s\n\n", tests[i].in, tests[i].exp, buf);
exits("fail");
--
⑨