changeset 1855:35d504d59c05

Implement server-side support for sk-ecdsa U2F-backed keys (#142) * Implement server-side support for sk-ecdsa U2F-backed keys * Fix out-of-bounds read on normal ecdsa-sha2-[identifier] keys * Fix one more potential out-of-bounds read * Check if nistp256 curve is used in sk-ecdsa-sha2- key It's the only allowed curve per PROTOCOL.u2f specification * Implement server-side support for sk-ed25519 FIDO2-backed keys * Keys with type sk-* make no sense as host keys, so they should be disabled * fix typo * Make sk-ecdsa call buf_ecdsa_verify This reduces code duplication, the SK code just handles the different message format. * Reduce sk specific code The application id can be stored in signkey, then we don't need to call sk-specific functions from svr-authpubkey * Remove debugging output, which causes compilation errors with DEBUG_TRACE disabled * Proper cleanup of sk_app Co-authored-by: Matt Johnston <[email protected]>
author egor-duda <egor-duda@users.noreply.github.com>
date Sat, 22 Jan 2022 16:53:04 +0300
parents cba37fe1ddc8
children 8f28519e34b0
files Makefile.in common-algo.c default_options.h ecdsa.c ed25519.c ed25519.h signkey.c signkey.h sk-ecdsa.c sk-ecdsa.h sk-ed25519.c sk-ed25519.h svr-runopts.c sysoptions.h
diffstat 14 files changed, 271 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.in	Sat Jan 22 12:46:08 2022 +0800
+++ b/Makefile.in	Sat Jan 22 16:53:04 2022 +0300
@@ -35,8 +35,8 @@
 		signkey.o rsa.o dbrandom.o \
 		queue.o \
 		atomicio.o compat.o fake-rfc2553.o \
-		ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
-		curve25519.o ed25519.o \
+		ltc_prng.o ecc.o ecdsa.o sk-ecdsa.o crypto_desc.o \
+		curve25519.o ed25519.o sk-ed25519.o \
 		dbmalloc.o \
 		gensignkey.o gendss.o genrsa.o gened25519.o
 
--- a/common-algo.c	Sat Jan 22 12:46:08 2022 +0800
+++ b/common-algo.c	Sat Jan 22 16:53:04 2022 +0300
@@ -239,6 +239,9 @@
 algo_type sigalgs[] = {
 #if DROPBEAR_ED25519
 	{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
+#if DROPBEAR_SK_ED25519
+	{"[email protected]", DROPBEAR_SIGNATURE_SK_ED25519, NULL, 1, NULL},
+#endif
 #endif
 #if DROPBEAR_ECDSA
 #if DROPBEAR_ECC_256
@@ -250,6 +253,9 @@
 #if DROPBEAR_ECC_521
 	{"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
 #endif
+#if DROPBEAR_SK_ECDSA
+	{"[email protected]", DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256, NULL, 1, NULL},
+#endif
 #endif
 #if DROPBEAR_RSA
 #if DROPBEAR_RSA_SHA256
--- a/default_options.h	Sat Jan 22 12:46:08 2022 +0800
+++ b/default_options.h	Sat Jan 22 16:53:04 2022 +0300
@@ -126,9 +126,11 @@
  * code (either ECDSA or ECDH) increases binary size - around 30kB
  * on x86-64 */
 #define DROPBEAR_ECDSA 1
+#define DROPBEAR_SK_ECDSA 1
 /* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
    binary size - around 7,5kB on x86-64 */
 #define DROPBEAR_ED25519 1
+#define DROPBEAR_SK_ED25519 1
 
 /* RSA must be >=1024 */
 #define DROPBEAR_DEFAULT_RSA_SIZE 2048
--- a/ecdsa.c	Sat Jan 22 12:46:08 2022 +0800
+++ b/ecdsa.c	Sat Jan 22 16:53:04 2022 +0300
@@ -81,18 +81,25 @@
 	struct dropbear_ecc_curve **curve;
 	ecc_key *new_key = NULL;
 
-	/* string   "ecdsa-sha2-[identifier]" */
+	/* string   "ecdsa-sha2-[identifier]" or "[email protected]" */
 	key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
 	/* string   "[identifier]" */
 	identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
 
-	if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
-		TRACE(("Bad identifier lengths"))
-		goto out;
-	}
-	if (memcmp(&key_ident[strlen("ecdsa-sha2-")], identifier, identifier_len) != 0) {
-		TRACE(("mismatching identifiers"))
-		goto out;
+	if (strcmp (key_ident, "[email protected]") == 0) {
+		if (strcmp (identifier, "nistp256") != 0) {
+			TRACE(("mismatching identifiers"))
+			goto out;
+		}
+	} else {
+		if (key_ident_len != identifier_len + strlen ("ecdsa-sha2-")) {
+			TRACE(("Bad identifier lengths"))
+			goto out;
+		}
+		if (memcmp(&key_ident[strlen ("ecdsa-sha2-")], identifier, identifier_len) != 0) {
+			TRACE(("mismatching identifiers"))
+			goto out;
+		}
 	}
 
 	for (curve = dropbear_ecc_curves; *curve; curve++) {
--- a/ed25519.c	Sat Jan 22 12:46:08 2022 +0800
+++ b/ed25519.c	Sat Jan 22 16:53:04 2022 +0300
@@ -38,14 +38,25 @@
  * The key will have the same format as buf_put_ed25519_key.
  * These should be freed with ed25519_key_free.
  * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
-int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key) {
+int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key,
+	enum signkey_type expect_keytype) {
+
 
-	unsigned int len;
+	unsigned int len, typelen;
+	char *keytype = NULL;
+	enum signkey_type buf_keytype;
 
 	TRACE(("enter buf_get_ed25519_pub_key"))
 	dropbear_assert(key != NULL);
 
-	buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
+	/* consume and check the key string */
+	keytype = buf_getstring(buf, &typelen);
+	buf_keytype = signkey_type_from_name(keytype, typelen);
+	m_free(keytype);
+	if (buf_keytype != expect_keytype) {
+		TRACE(("leave buf_get_ed25519_pub_key: mismatch key type"))
+		return DROPBEAR_FAILURE;
+	}
 
 	len = buf_getint(buf);
 	if (len != CURVE25519_LEN || buf->len - buf->pos < len) {
--- a/ed25519.h	Sat Jan 22 12:46:08 2022 +0800
+++ b/ed25519.h	Sat Jan 22 16:53:04 2022 +0300
@@ -27,6 +27,7 @@
 
 #include "includes.h"
 #include "buffer.h"
+#include "signkey.h"
 
 #if DROPBEAR_ED25519 
 
@@ -43,7 +44,8 @@
 #if DROPBEAR_SIGNKEY_VERIFY
 int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf);
 #endif
-int buf_get_ed25519_pub_key(buffer* buf, dropbear_ed25519_key *key);
+int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key,
+        enum signkey_type expect_keytype);
 int buf_get_ed25519_priv_key(buffer* buf, dropbear_ed25519_key *key);
 void buf_put_ed25519_pub_key(buffer* buf, const dropbear_ed25519_key *key);
 void buf_put_ed25519_priv_key(buffer* buf, const dropbear_ed25519_key *key);
--- a/signkey.c	Sat Jan 22 12:46:08 2022 +0800
+++ b/signkey.c	Sat Jan 22 16:53:04 2022 +0300
@@ -28,6 +28,8 @@
 #include "buffer.h"
 #include "ssh.h"
 #include "ecdsa.h"
+#include "sk-ecdsa.h"
+#include "sk-ed25519.h"
 #include "rsa.h"
 #include "dss.h"
 #include "ed25519.h"
@@ -43,9 +45,15 @@
 	"ecdsa-sha2-nistp256",
 	"ecdsa-sha2-nistp384",
 	"ecdsa-sha2-nistp521",
+#if DROPBEAR_SK_ECDSA
+	"[email protected]",
+#endif /* DROPBEAR_SK_ECDSA */
 #endif /* DROPBEAR_ECDSA */
 #if DROPBEAR_ED25519
 	"ssh-ed25519",
+#if DROPBEAR_SK_ED25519
+	"[email protected]",
+#endif /* DROPBEAR_SK_ED25519 */
 #endif /* DROPBEAR_ED25519 */
 	/* "rsa-sha2-256" is special-cased below since it is only a signature name, not key type */
 };
@@ -180,11 +188,17 @@
 	switch (type) {
 #if DROPBEAR_ED25519
 		case DROPBEAR_SIGNKEY_ED25519:
+#if DROPBEAR_SK_ED25519
+		case DROPBEAR_SIGNKEY_SK_ED25519:
+#endif
 			return (void**)&key->ed25519key;
 #endif
 #if DROPBEAR_ECDSA
 #if DROPBEAR_ECC_256
 		case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
+#if DROPBEAR_SK_ECDSA
+		case DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256:
+#endif
 			return (void**)&key->ecckey256;
 #endif
 #if DROPBEAR_ECC_384
@@ -260,7 +274,11 @@
 	}
 #endif
 #if DROPBEAR_ECDSA
-	if (signkey_is_ecdsa(keytype)) {
+	if (signkey_is_ecdsa(keytype)
+#if DROPBEAR_SK_ECDSA
+		|| keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256
+#endif
+	) {
 		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
 		if (eck) {
 			if (*eck) {
@@ -276,10 +294,14 @@
 	}
 #endif
 #if DROPBEAR_ED25519
-	if (keytype == DROPBEAR_SIGNKEY_ED25519) {
+	if (keytype == DROPBEAR_SIGNKEY_ED25519
+#if DROPBEAR_SK_ED25519
+		|| keytype == DROPBEAR_SIGNKEY_SK_ED25519
+#endif
+    ) {
 		ed25519_key_free(key->ed25519key);
 		key->ed25519key = m_malloc(sizeof(*key->ed25519key));
-		ret = buf_get_ed25519_pub_key(buf, key->ed25519key);
+		ret = buf_get_ed25519_pub_key(buf, key->ed25519key, keytype);
 		if (ret == DROPBEAR_FAILURE) {
 			m_free(key->ed25519key);
 			key->ed25519key = NULL;
@@ -287,6 +309,19 @@
 	}
 #endif
 
+#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
+	if (0
+#if DROPBEAR_SK_ED25519
+		|| keytype == DROPBEAR_SIGNKEY_SK_ED25519
+#endif
+#if DROPBEAR_SK_ECDSA
+		|| keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256
+#endif
+	) {
+		key->sk_app = buf_getstring(buf, &key->sk_applen);
+	}
+#endif
+
 	TRACE2(("leave buf_get_pub_key"))
 
 	return ret;
@@ -401,7 +436,11 @@
 	}
 #endif
 #if DROPBEAR_ED25519
-	if (type == DROPBEAR_SIGNKEY_ED25519) {
+	if (type == DROPBEAR_SIGNKEY_ED25519
+#if DROPBEAR_SK_ED25519
+		|| type == DROPBEAR_SIGNKEY_SK_ED25519
+#endif
+	) {
 		buf_put_ed25519_pub_key(pubkeys, key->ed25519key);
 	}
 #endif
@@ -495,6 +534,11 @@
 #endif
 
 	m_free(key->filename);
+#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
+	if (key->sk_app) {
+		m_free(key->sk_app);
+	}
+#endif
 
 	m_free(key);
 	TRACE2(("leave sign_key_free"))
@@ -639,6 +683,7 @@
 }
 
 #if DROPBEAR_SIGNKEY_VERIFY
+
 /* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
  * If FAILURE is returned, the position of
  * buf is undefined. If SUCCESS is returned, buf will be positioned after the
@@ -695,6 +740,22 @@
 		return buf_ed25519_verify(buf, key->ed25519key, data_buf);
 	}
 #endif
+#if DROPBEAR_SK_ECDSA
+	if (keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256) {
+		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
+		if (eck && *eck) {
+			return buf_sk_ecdsa_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen);
+		}
+	}
+#endif
+#if DROPBEAR_SK_ED25519
+	if (keytype == DROPBEAR_SIGNKEY_SK_ED25519) {
+		dropbear_ed25519_key **eck = (dropbear_ed25519_key**)signkey_key_ptr(key, keytype);
+		if (eck && *eck) {
+			return buf_sk_ed25519_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen);
+		}
+	}
+#endif
 
 	dropbear_exit("Non-matching signing type");
 	return DROPBEAR_FAILURE;
--- a/signkey.h	Sat Jan 22 12:46:08 2022 +0800
+++ b/signkey.h	Sat Jan 22 16:53:04 2022 +0300
@@ -44,9 +44,15 @@
 	DROPBEAR_SIGNKEY_ECDSA_NISTP256,
 	DROPBEAR_SIGNKEY_ECDSA_NISTP384,
 	DROPBEAR_SIGNKEY_ECDSA_NISTP521,
+#if DROPBEAR_SK_ECDSA
+	DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256,
+#endif /* DROPBEAR_SK_ECDSA */
 #endif /* DROPBEAR_ECDSA */
 #if DROPBEAR_ED25519
 	DROPBEAR_SIGNKEY_ED25519,
+#if DROPBEAR_SK_ED25519
+	DROPBEAR_SIGNKEY_SK_ED25519,
+#endif
 #endif
 	DROPBEAR_SIGNKEY_NUM_NAMED,
 	DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */
@@ -63,9 +69,15 @@
 	DROPBEAR_SIGNATURE_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_ECDSA_NISTP256,
 	DROPBEAR_SIGNATURE_ECDSA_NISTP384 = DROPBEAR_SIGNKEY_ECDSA_NISTP384,
 	DROPBEAR_SIGNATURE_ECDSA_NISTP521 = DROPBEAR_SIGNKEY_ECDSA_NISTP521,
+#if DROPBEAR_SK_ECDSA
+	DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256,
+#endif /* DROPBEAR_SK_ECDSA */
 #endif /* DROPBEAR_ECDSA */
 #if DROPBEAR_ED25519
 	DROPBEAR_SIGNATURE_ED25519 = DROPBEAR_SIGNKEY_ED25519,
+#if DROPBEAR_SK_ED25519
+	DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519,
+#endif
 #endif
 #if DROPBEAR_RSA_SHA1
 	DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */
@@ -110,6 +122,12 @@
 #if DROPBEAR_ED25519
 	struct dropbear_ED25519_Key * ed25519key;
 #endif
+
+#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
+	/* application ID for U2F/FIDO key types, a malloced string */
+	char * sk_app;
+	unsigned int sk_applen;
+#endif
 };
 
 typedef struct SIGN_key sign_key;
@@ -130,6 +148,7 @@
 void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, const buffer *data_buf);
 #if DROPBEAR_SIGNKEY_VERIFY
 int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf);
+int sk_buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf, char* app, unsigned int applen);
 char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen);
 #endif
 int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sk-ecdsa.c	Sat Jan 22 16:53:04 2022 +0300
@@ -0,0 +1,47 @@
+#include "includes.h"
+
+#if DROPBEAR_SK_ECDSA
+
+#include "dbutil.h"
+#include "ecc.h"
+#include "ecdsa.h"
+#include "sk-ecdsa.h"
+
+int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, const char* app, unsigned int applen) {
+	hash_state hs;
+	unsigned char subhash[SHA256_HASH_SIZE];
+	buffer *sk_buffer = NULL, *sig_buffer = NULL;
+	unsigned char flags;
+	unsigned int counter;
+	int ret;
+
+	TRACE(("buf_sk_ecdsa_verify"))
+
+	/* from https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.u2f */
+	/* ecdsa signature to verify (r, s) */
+	sig_buffer = buf_getbuf(buf);
+
+	flags = buf_getbyte (buf);
+	counter = buf_getint (buf);
+	/* create the message to be signed */
+	sk_buffer = buf_new (2*SHA256_HASH_SIZE+5);
+	sha256_init (&hs);
+	sha256_process (&hs, app, applen);
+	sha256_done (&hs, subhash);
+	buf_putbytes (sk_buffer, subhash, sizeof (subhash));
+	buf_putbyte (sk_buffer, flags);
+	buf_putint (sk_buffer, counter);
+	sha256_init (&hs);
+	sha256_process (&hs, data_buf->data, data_buf->len);
+	sha256_done (&hs, subhash);
+	buf_putbytes (sk_buffer, subhash, sizeof (subhash));
+
+	ret = buf_ecdsa_verify(sig_buffer, key, sk_buffer);
+	buf_free(sk_buffer);
+	buf_free(sig_buffer);
+
+	TRACE(("leave buf_sk_ecdsa_verify, ret=%d", ret))
+	return ret;
+}
+
+#endif /* DROPBEAR_SK_ECDSA */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sk-ecdsa.h	Sat Jan 22 16:53:04 2022 +0300
@@ -0,0 +1,15 @@
+#ifndef DROPBEAR_SK_ECDSA_H_
+#define DROPBEAR_SK_ECDSA_H_
+
+#include "includes.h"
+
+#if DROPBEAR_SK_ECDSA
+
+#include "buffer.h"
+#include "signkey.h"
+
+int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, const char* app, unsigned int applen);
+
+#endif
+
+#endif /* DROPBEAR_SK_ECDSA_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sk-ed25519.c	Sat Jan 22 16:53:04 2022 +0300
@@ -0,0 +1,61 @@
+#include "includes.h"
+
+#if DROPBEAR_SK_ED25519
+
+#include "dbutil.h"
+#include "buffer.h"
+#include "curve25519.h"
+#include "ed25519.h"
+
+int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, const char* app, unsigned int applen) {
+
+	int ret = DROPBEAR_FAILURE;
+	unsigned char *s;
+	unsigned long slen;
+	hash_state hs;
+	unsigned char hash[SHA256_HASH_SIZE];
+	buffer *sk_buffer = NULL;
+	unsigned char flags;
+	unsigned int counter;
+
+	TRACE(("enter buf_sk_ed25519_verify"))
+	dropbear_assert(key != NULL);
+
+	slen = buf_getint(buf);
+	if (slen != 64 || buf->len - buf->pos < slen) {
+		TRACE(("leave buf_sk_ed25519_verify: bad size"))
+		goto out;
+	}
+	s = buf_getptr(buf, slen);
+	buf_incrpos(buf, slen);
+
+	flags = buf_getbyte (buf);
+	counter = buf_getint (buf);
+	sk_buffer = buf_new (2*SHA256_HASH_SIZE+5);
+	sha256_init (&hs);
+	sha256_process (&hs, app, applen);
+	sha256_done (&hs, hash);
+	buf_putbytes (sk_buffer, hash, sizeof (hash));
+	buf_putbyte (sk_buffer, flags);
+	buf_putint (sk_buffer, counter);
+	sha256_init (&hs);
+	sha256_process (&hs, data_buf->data, data_buf->len);
+	sha256_done (&hs, hash);
+	buf_putbytes (sk_buffer, hash, sizeof (hash));
+
+	if (dropbear_ed25519_verify(sk_buffer->data, sk_buffer->len,
+				    s, slen, key->pub) == 0) {
+		/* signature is valid */
+		TRACE(("leave buf_sk_ed25519_verify: success!"))
+		ret = DROPBEAR_SUCCESS;
+	}
+
+out:
+	if (sk_buffer) {
+		buf_free(sk_buffer);
+	}
+	TRACE(("leave buf_sk_ed25519_verify: ret %d", ret))
+	return ret;
+}
+
+#endif /* DROPBEAR_SK_ED25519 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sk-ed25519.h	Sat Jan 22 16:53:04 2022 +0300
@@ -0,0 +1,15 @@
+#ifndef DROPBEAR_SK_ED25519_H_
+#define DROPBEAR_SK_ED25519_H_
+
+#include "includes.h"
+
+#if DROPBEAR_SK_ED25519
+
+#include "buffer.h"
+#include "ed25519.h"
+
+int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, const char* app, unsigned int applen);
+
+#endif
+
+#endif /* DROPBEAR_SK_ED25519_H_ */
--- a/svr-runopts.c	Sat Jan 22 12:46:08 2022 +0800
+++ b/svr-runopts.c	Sat Jan 22 16:53:04 2022 +0300
@@ -668,6 +668,12 @@
 		any_keys = 1;
 	}
 #endif
+#if DROPBEAR_SK_ECDSA
+	disablekey(DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256);
+#endif 
+#if DROPBEAR_SK_ED25519
+	disablekey(DROPBEAR_SIGNKEY_SK_ED25519);
+#endif
 
 	if (!any_keys) {
 		dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
--- a/sysoptions.h	Sat Jan 22 12:46:08 2022 +0800
+++ b/sysoptions.h	Sat Jan 22 16:53:04 2022 +0300
@@ -95,6 +95,7 @@
 #define DROPBEAR_MAX_PASSWORD_LEN 100
 
 #define SHA1_HASH_SIZE 20
+#define SHA256_HASH_SIZE 32
 #define MD5_HASH_SIZE 16
 #define MAX_HASH_SIZE 64 /* sha512 */