shithub: front

Download patch

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");
--