From fbbc6dcb193cd9c4b6b2fb5ddb378f1a416cc09c Mon Sep 17 00:00:00 2001
From: gpotter2 <10530980+gpotter2@users.noreply.github.com>
Date: Wed, 5 Apr 2023 01:06:28 +0200
Subject: [PATCH 1/3] Try TLS 1.0-1.2, then try TLS 1.3 (and detect it)
This commit updates the TLS banners so that:
- by default masscan tries to use a banner that supports TLS 1.0 to 1.2 (only)
- if this fails, masscan retries using a banner that supports TLS 1.3
This is the less ressource-intensive way of always retrieving the
certificates in case banners are enabled, as TLS 1.3 certificates
are encrypted, while still adding support for TLS 1.3 when it is
enforced.
---
src/proto-banner1.c | 8 +----
src/proto-banout.c | 63 ++++++++++++++++++++++++++++++++++++++
src/proto-banout.h | 8 +++++
src/proto-ssl.c | 73 +++++++++++++++++++++++++++------------------
src/proto-ssl.h | 2 +-
src/stack-tcp-app.c | 2 +-
6 files changed, 118 insertions(+), 38 deletions(-)
diff --git a/src/proto-banner1.c b/src/proto-banner1.c
index ddcd5ae4..fadb3631 100644
--- a/src/proto-banner1.c
+++ b/src/proto-banner1.c
@@ -619,7 +619,7 @@ banner1_create(void)
banner_smtp.init(b);
banner_ssh.init(b);
banner_ssl.init(b);
- banner_ssl_12.init(b);
+ banner_tls_13.init(b);
banner_smb0.init(b);
banner_smb1.init(b);
banner_telnet.init(b);
@@ -797,12 +797,6 @@ banner1_selftest()
return 1;
}
- x = banner_ssl_12.selftest();
- if (x) {
- fprintf(stderr, "SSL banner: selftest failed\n");
- return 1;
- }
-
x = banner_smb1.selftest();
if (x) {
fprintf(stderr, "SMB banner: selftest failed\n");
diff --git a/src/proto-banout.c b/src/proto-banout.c
index 88c1eda3..bb906127 100644
--- a/src/proto-banout.c
+++ b/src/proto-banout.c
@@ -359,6 +359,69 @@ banout_append(struct BannerOutput *banout, unsigned proto,
}
+/***************************************************************************
+ ***************************************************************************/
+unsigned
+banout_replacefirst(struct BannerOutput *banout, unsigned proto,
+ const char *string, const char *replace)
+{
+ struct BannerOutput *p;
+
+ char* first_instance;
+ size_t string_length;
+ size_t replace_length;
+
+ if (string == NULL)
+ return 0;
+
+ string_length = strlen(string);
+
+ if (replace == NULL)
+ return 0;
+
+ replace_length = strlen(replace);
+
+ /*
+ * Get the matching record for the protocol (e.g. HTML, SSL, etc.).
+ */
+ p = banout_find_proto(banout, proto);
+ if (p == NULL) {
+ return 0;
+ }
+
+ /*
+ * Find the string in the banout.
+ */
+ first_instance = strstr((char*) p->banner, string);
+ size_t offset = ((unsigned) (first_instance - (char*) p->banner));
+ if (first_instance == NULL) {
+ return 0;
+ }
+
+ /*
+ * If the current object isn't big enough, expand it
+ */
+ while (p->length + replace_length - string_length >= p->max_length) {
+ p = banout_expand(banout, p);
+ }
+
+ /*
+ * Now that we are assured there is enough space, do the replacement
+ */
+ p->length = (unsigned)(p->length + replace_length - string_length); // can't be <0 because strstr != NULL
+ memcpy(
+ first_instance + replace_length,
+ first_instance + string_length,
+ p->length - offset - string_length
+ );
+ memcpy(
+ first_instance,
+ replace,
+ replace_length
+ );
+ return 1;
+}
+
/*****************************************************************************
*****************************************************************************/
static const char *b64 =
diff --git a/src/proto-banout.h b/src/proto-banout.h
index 6c5361c2..d694fe34 100644
--- a/src/proto-banout.h
+++ b/src/proto-banout.h
@@ -78,6 +78,14 @@ banout_append_hexint(struct BannerOutput *banout, unsigned proto, unsigned long
void
banout_append_unicode(struct BannerOutput *banout, unsigned proto, unsigned c);
+/*
+ * Replace first occurence of string with another string inside the banner.
+ * This function should only be used when banout represents a string,
+ * and not a X.509 certificate.
+ */
+unsigned
+banout_replacefirst(struct BannerOutput *banout, unsigned proto, const char *string, const char *replace);
+
/**
* Select a specific string (of the specified protocol).
* The "banner output" can have multiple protocol objects associated
diff --git a/src/proto-ssl.c b/src/proto-ssl.c
index 5e392c2c..492d527f 100644
--- a/src/proto-ssl.c
+++ b/src/proto-ssl.c
@@ -149,6 +149,7 @@ parse_server_hello(
EXT_LEN0, EXT_LEN1,
EXT_DATA,
EXT_DATA_HEARTBEAT,
+ EXT_DATA_SUPPORTED_VERSIONS,
UNKNOWN,
};
@@ -268,6 +269,8 @@ parse_server_hello(
remaining |= px[i];
DROPDOWN(i,length,state);
+ /* Handling of the various TLS extensions */
+
case EXT_TAG0:
ext_tag:
if (remaining < 4) {
@@ -290,27 +293,20 @@ parse_server_hello(
case EXT_LEN1:
hello->ext_remaining |= px[i];
remaining--;
+ // Next step depends on the tag
switch (hello->ext_tag) {
case 0x000f: /* heartbeat */
state = EXT_DATA_HEARTBEAT;
continue;
+ case 0x002b: /* supported_versions */
+ state = EXT_DATA_SUPPORTED_VERSIONS;
+ continue;
}
DROPDOWN(i,length,state);
-
- case EXT_DATA:
- if (hello->ext_remaining == 0) {
- state = EXT_TAG0;
- goto ext_tag;
- }
- if (remaining == 0) {
- state = UNKNOWN;
- continue;
- }
- remaining--;
- hello->ext_remaining--;
- continue;
+ case EXT_DATA:
case EXT_DATA_HEARTBEAT:
+ case EXT_DATA_SUPPORTED_VERSIONS:
if (hello->ext_remaining == 0) {
state = EXT_TAG0;
goto ext_tag;
@@ -321,10 +317,24 @@ parse_server_hello(
}
remaining--;
hello->ext_remaining--;
- if (px[i]) {
- banout_append( banout, PROTO_VULN, "SSL[heartbeat] ", 15);
+
+ switch (state) {
+ case EXT_DATA_HEARTBEAT:
+ if (px[i]) {
+ banout_append( banout, PROTO_VULN, "SSL[heartbeat] ", 15);
+ }
+ state = EXT_DATA;
+ case EXT_DATA_SUPPORTED_VERSIONS:
+ if (hello->ext_remaining) {
+ hello->version_major = px[i];
+ } else {
+ hello->version_minor = px[i];
+ if ((hello->version_major<<8 | hello->version_minor) == 0x0304) { // TLS 1.3
+ banout_replacefirst(banout, PROTO_SSL3, "TLS/1.2", "TLS/1.3");
+ }
+ }
+ default:
}
- state = EXT_DATA;
continue;
@@ -1073,7 +1083,13 @@ ssl_init(struct Banner1 *banner1)
* TODO: we need to make this dynamically generated, so that users can
* select various options.
*****************************************************************************/
-static const char
+
+/*
+ * By setting the TLS record version to 1.0, and the ClientHello version to 1.2,
+ * this packet support for TLS 1.0, 1.1 and 1.2.
+ */
+
+static const unsigned char
ssl_hello_template[] =
"\x16\x03\x01\x00\xc1" /* TLSv1.0 record layer */
"\x01" /* type = client-hello */
@@ -1104,15 +1120,11 @@ ssl_hello_template[] =
"\x02\x02\x04\x02\x05\x02\x06\x02"
;
-/*****************************************************************************
- * This is the template "Client Hello" packet that is sent to the server
- * to initiate the SSL connection. Right now, it's statically just transmitted
- * on to the wire.
- * TODO: we need to make this dynamically generated, so that users can
- * select various options.
- *****************************************************************************/
-static const char
-ssl_12_hello_template[] =
+/*
+ * If the previous packet didn't work, the server is most likely TLS 1.3 only.
+ */
+static const unsigned char
+tls_13_hello_template[] =
"\x16\x03\x01\x01\x1a"
"\x01"
"\x00\x01\x16"
@@ -1432,13 +1444,16 @@ ssl_selftest(void)
* This is the 'plugin' structure that registers callbacks for this parser in
* the main system.
*****************************************************************************/
-struct ProtocolParserStream banner_ssl_12 = {
- "ssl", 443, ssl_12_hello_template, sizeof(ssl_12_hello_template)-1, 0,
+
+// if TLS 1.0-1.2 didn't work, try TLS 1.3
+struct ProtocolParserStream banner_tls_13 = {
+ "ssl", 443, tls_13_hello_template, sizeof(tls_13_hello_template)-1, 0,
ssl_selftest,
ssl_init,
ssl_parse_record,
};
+// this will be tried first: try TLS 1.0-TLS 1.2
struct ProtocolParserStream banner_ssl = {
"ssl", 443, ssl_hello_template, sizeof(ssl_hello_template)-1,
SF__close, /* send FIN after the hello */
@@ -1447,5 +1462,5 @@ struct ProtocolParserStream banner_ssl = {
ssl_parse_record,
0,
0,
- &banner_ssl_12,
+ &banner_tls_13,
};
diff --git a/src/proto-ssl.h b/src/proto-ssl.h
index 9d726a54..a6f8bdc0 100644
--- a/src/proto-ssl.h
+++ b/src/proto-ssl.h
@@ -3,7 +3,7 @@
#include "proto-banner1.h"
extern struct ProtocolParserStream banner_ssl;
-extern struct ProtocolParserStream banner_ssl_12;
+extern struct ProtocolParserStream banner_tls_13;
extern const char *ssl_hello_heartbeat_template;
extern const char *ssl_hello_ticketbleed_template;
diff --git a/src/stack-tcp-app.c b/src/stack-tcp-app.c
index 4694619a..3606ce7e 100644
--- a/src/stack-tcp-app.c
+++ b/src/stack-tcp-app.c
@@ -154,7 +154,7 @@ application_event(struct stack_handle_t *socket,
case App_SendFirst:
/* This isn't called from the outside, but from one of the
* states internally whhen we transmit for the first time */
- if (stream == &banner_ssl || stream == &banner_ssl_12) {
+ if (stream == &banner_ssl || stream == &banner_tls_13) {
/*
* Kludge, extreme kludge
* I don't even know what this does any longer
From d320eb40e56bffc32f8ebffbe55ad2680ab9d58b Mon Sep 17 00:00:00 2001
From: gpotter2 <10530980+gpotter2@users.noreply.github.com>
Date: Fri, 7 Apr 2023 19:03:27 +0200
Subject: [PATCH 2/3] Add TLS 1.3 certificates decryption support
This commit adds support to retrieve TLS 1.3 certificates (as they are,
unlike TLS 1.2 and below, encrypted). It embeds implementations of
AES256, SHA384 (from rfc6234) and x25519 which are the minimum, most
supported algorithms for TLS 1.3 (ffdhe was only added to openssl in
3.0+). Those implementations are released under compatible licenses.
Also comes with tests.
---
LICENSE | 11 +
README.md | 2 +-
src/crypto-aes256.c | 485 +++++++
src/crypto-aes256.h | 105 ++
src/crypto-curve25519.c | 452 +++++++
src/crypto-curve25519.h | 7 +
src/crypto-rfc6234.c | 2775 +++++++++++++++++++++++++++++++++++++++
src/crypto-rfc6234.h | 357 +++++
src/proto-banner1.h | 34 +-
src/proto-banout.c | 2 +-
src/proto-ssl-test.c | 491 +++++++
src/proto-ssl.c | 676 +++++++++-
12 files changed, 5336 insertions(+), 61 deletions(-)
create mode 100644 src/crypto-aes256.c
create mode 100644 src/crypto-aes256.h
create mode 100644 src/crypto-curve25519.c
create mode 100644 src/crypto-curve25519.h
create mode 100644 src/crypto-rfc6234.c
create mode 100644 src/crypto-rfc6234.h
diff --git a/LICENSE b/LICENSE
index be3f7b28..b5c24884 100644
--- a/LICENSE
+++ b/LICENSE
@@ -659,3 +659,14 @@ specific requirements.
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
.
+
+REDISTRIBUTION NOTE:
+
+A few files listed below are released under different licenses (that are
+compatible with AGPL3), as specified in the files themselves, and are
+redistributed alongside this software:
+
+- crypto-curve25519.c/h: public domain
+- siphash24.c/h: public domain
+- crypto-rfc6234.c/h: simplified BSD license
+- crypto-aes256.c/h: MIT license
diff --git a/README.md b/README.md
index ed61e2f1..f59edad3 100644
--- a/README.md
+++ b/README.md
@@ -95,7 +95,7 @@ Masscan supports banner checking on the following protocols:
* POP3
* SMTP
* SSH
- * SSL
+ * SSL/TLS
* SMBv1
* SMBv2
* Telnet
diff --git a/src/crypto-aes256.c b/src/crypto-aes256.c
new file mode 100644
index 00000000..f5b8d125
--- /dev/null
+++ b/src/crypto-aes256.c
@@ -0,0 +1,485 @@
+// https://github.com/ilvn/aes256
+
+// A compact byte-oriented AES-256 implementation.
+// All lookup tables replaced with 'on the fly' calculations.
+//
+// Copyright (c) 2007-2011 Literatecode, http://www.literatecode.com
+// Copyright (c) 2022 Ilia Levin (ilia@levin.sg)
+//
+// Other contributors: Hal Finney.
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+#include "crypto-aes256.h"
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+// We use the compact version with runtime calculations by default. You may
+// want to define BACK_TO_TABLES for a pre-calculated faster version.
+
+#define BACK_TO_TABLES
+
+#ifdef _MSC_VER
+#define __attribute__(...)
+#endif
+#define GFC_FN_ static uint8_t __attribute__((const))
+#define AES_CORE_FN_ static void __attribute__((nonnull))
+
+// -----------------------------------------------------------------------------
+GFC_FN_
+rj_xtime(uint8_t x)
+{
+ uint8_t y = 0xff & (x << 1);
+ return (x & 0x80) ? (y ^ 0x1b) : y;
+} // rj_xtime
+
+#ifdef BACK_TO_TABLES // use pre-calculated tables
+
+static const uint8_t sbox[256] = {
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+static const uint8_t sboxinv[256] = {
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
+ 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+ 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
+ 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
+ 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
+ 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
+ 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+ 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
+ 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
+ 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+ 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
+ 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
+ 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+ 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
+ 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
+ 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+};
+
+#define rj_sbox(x) sbox[(x)]
+#define rj_sbox_inv(x) sboxinv[(x)]
+
+#else // use tableless subroutines
+
+#define SHL8(x, n) ((0xff & ((x) << (n))) | ((x) >> (8 - (n))))
+
+// -----------------------------------------------------------------------------
+GFC_FN_
+gf_alog(uint8_t x) // calculate anti-logarithm gen 3
+{
+ uint8_t y = 1;
+
+ for (uint8_t i = 0; (x < 0xff) && (i < x); i++) {
+ y ^= rj_xtime(y);
+ }
+
+ return y;
+} // gf_alog
+
+// -----------------------------------------------------------------------------
+GFC_FN_
+gf_log(uint8_t x) // calculate logarithm gen 3
+{
+ uint8_t y = 1, i = 0;
+
+ if (0 != x) {
+ do {
+ y ^= rj_xtime(y);
+ } while ((++i != 0xff) && (y != x));
+ }
+
+ return i;
+} // gf_log
+
+// -----------------------------------------------------------------------------
+GFC_FN_
+gf_mulinv(uint8_t x) // calculate multiplicative inverse
+{
+ return ((x) ? gf_alog(255 - gf_log(x)) : 0);
+} // gf_mulinv
+
+// -----------------------------------------------------------------------------
+GFC_FN_
+rj_sbox(uint8_t x)
+{
+ uint8_t y = gf_mulinv(x), sb = y;
+
+ sb ^= y = SHL8(y, 1);
+ sb ^= y = SHL8(y, 1);
+ sb ^= y = SHL8(y, 1);
+
+ return (sb ^ SHL8(y, 1) ^ 0x63);
+} // rj_sbox
+
+// -----------------------------------------------------------------------------
+GFC_FN_
+rj_sbox_inv(uint8_t x)
+{
+ uint8_t y = (x ^ 0x63), sb = y = SHL8(y, 1);
+
+ sb ^= y = SHL8(y, 2);
+
+ return gf_mulinv(sb ^ SHL8(y, 3));
+} // rj_sbox_inv
+
+#endif // BACK_TO_TABLES
+
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+subBytes(uint8_t *buf)
+{
+ for (uint8_t i = 0; i < 16; i++) {
+ buf[i] = rj_sbox(buf[i]);
+ }
+} // subBytes
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+subBytes_inv(uint8_t *buf)
+{
+ for (uint8_t i = 0; i < 16; i++) {
+ buf[i] = rj_sbox_inv(buf[i]);
+ }
+} // subBytes_inv
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+addRoundKey(uint8_t *buf, uint8_t *key)
+{
+ for (uint8_t i = 0; i < 16; i++) {
+ buf[i] ^= key[i];
+ }
+} // addRoundKey
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+addRoundKey_cpy(uint8_t *buf, uint8_t *key, uint8_t *cpk)
+{
+ for (uint8_t i = 0; i < 16; i++) {
+ buf[i] ^= (cpk[i] = key[i]);
+ cpk[16 + i] = key[16 + i];
+ }
+} // addRoundKey_cpy
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+shiftRows(uint8_t *buf)
+{
+ register uint8_t i, j; // to make it potentially parallelable :)
+
+ i = buf[1];
+ buf[1] = buf[5];
+ buf[5] = buf[9];
+ buf[9] = buf[13];
+ buf[13] = i;
+
+ i = buf[10];
+ buf[10] = buf[2];
+ buf[2] = i;
+
+ j = buf[3];
+ buf[3] = buf[15];
+ buf[15] = buf[11];
+ buf[11] = buf[7];
+ buf[7] = j;
+
+ j = buf[14];
+ buf[14] = buf[6];
+ buf[6] = j;
+} // shiftRows
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+shiftRows_inv(uint8_t *buf)
+{
+ register uint8_t i, j; // similar to shiftRows :)
+
+ i = buf[1];
+ buf[1] = buf[13];
+ buf[13] = buf[9];
+ buf[9] = buf[5];
+ buf[5] = i;
+
+ i = buf[2];
+ buf[2] = buf[10];
+ buf[10] = i;
+
+ j = buf[3];
+ buf[3] = buf[7];
+ buf[7] = buf[11];
+ buf[11] = buf[15];
+ buf[15] = j;
+
+ j = buf[6];
+ buf[6] = buf[14];
+ buf[14] = j;
+} // shiftRows_inv
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+mixColumns(uint8_t *buf)
+{
+ register uint8_t a, b, c, d, e;
+
+ for (uint8_t i = 0; i < 16; i += 4) {
+ a = buf[i];
+ b = buf[i + 1];
+ c = buf[i + 2];
+ d = buf[i + 3];
+ e = a ^ b ^ c ^ d;
+ buf[i] ^= e ^ rj_xtime(a ^ b);
+ buf[i + 1] ^= e ^ rj_xtime(b ^ c);
+ buf[i + 2] ^= e ^ rj_xtime(c ^ d);
+ buf[i + 3] ^= e ^ rj_xtime(d ^ a);
+ }
+} // mixColumns
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+mixColumns_inv(uint8_t *buf)
+{
+ register uint8_t a, b, c, d, e, x, y, z;
+
+ for (uint8_t i = 0; i < 16; i += 4) {
+ a = buf[i];
+ b = buf[i + 1];
+ c = buf[i + 2];
+ d = buf[i + 3];
+ e = a ^ b ^ c ^ d;
+ z = rj_xtime(e);
+ x = e ^ rj_xtime(rj_xtime(z ^ a ^ c));
+ y = e ^ rj_xtime(rj_xtime(z ^ b ^ d));
+ buf[i] ^= x ^ rj_xtime(a ^ b);
+ buf[i + 1] ^= y ^ rj_xtime(b ^ c);
+ buf[i + 2] ^= x ^ rj_xtime(c ^ d);
+ buf[i + 3] ^= y ^ rj_xtime(d ^ a);
+ }
+} // mixColumns_inv
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+expandEncKey(uint8_t *k, uint8_t *rc)
+{
+ k[0] ^= rj_sbox(k[29]) ^ (*rc);
+ k[1] ^= rj_sbox(k[30]);
+ k[2] ^= rj_sbox(k[31]);
+ k[3] ^= rj_sbox(k[28]);
+ *rc = rj_xtime(*rc);
+
+ for (uint8_t i = 4; i < 16; i += 4) {
+ k[i] ^= k[i - 4];
+ k[i + 1] ^= k[i - 3];
+ k[i + 2] ^= k[i - 2];
+ k[i + 3] ^= k[i - 1];
+ }
+
+ k[16] ^= rj_sbox(k[12]);
+ k[17] ^= rj_sbox(k[13]);
+ k[18] ^= rj_sbox(k[14]);
+ k[19] ^= rj_sbox(k[15]);
+
+ for (uint8_t i = 20; i < 32; i += 4) {
+ k[i] ^= k[i - 4];
+ k[i + 1] ^= k[i - 3];
+ k[i + 2] ^= k[i - 2];
+ k[i + 3] ^= k[i - 1];
+ }
+} // expandEncKey
+
+// -----------------------------------------------------------------------------
+AES_CORE_FN_
+expandDecKey(uint8_t *k, uint8_t *rc)
+{
+ for (uint8_t i = 28; i > 16; i -= 4) {
+ k[i + 0] ^= k[i - 4];
+ k[i + 1] ^= k[i - 3];
+ k[i + 2] ^= k[i - 2];
+ k[i + 3] ^= k[i - 1];
+ }
+
+ k[16] ^= rj_sbox(k[12]);
+ k[17] ^= rj_sbox(k[13]);
+ k[18] ^= rj_sbox(k[14]);
+ k[19] ^= rj_sbox(k[15]);
+
+ for (uint8_t i = 12; i > 0; i -= 4) {
+ k[i + 0] ^= k[i - 4];
+ k[i + 1] ^= k[i - 3];
+ k[i + 2] ^= k[i - 2];
+ k[i + 3] ^= k[i - 1];
+ }
+
+ *rc = (((*rc) >> 1) ^ (((*rc) & 1) ? 0x8d : 0));
+ k[0] ^= rj_sbox(k[29]) ^ (*rc);
+ k[1] ^= rj_sbox(k[30]);
+ k[2] ^= rj_sbox(k[31]);
+ k[3] ^= rj_sbox(k[28]);
+} // expandDecKey
+
+// -----------------------------------------------------------------------------
+uint8_t
+aes256_init(aes256_context_t *ctx, aes256_key_t *key)
+{
+ if ((NULL == ctx) || (NULL == key)) {
+ return AES_ERROR;
+ }
+
+ ctx->enckey = ctx->deckey = *key;
+
+ for (uint8_t i = 0, rcon = 1; i < 7; i++) {
+ expandEncKey(ctx->deckey.raw, &rcon);
+ }
+
+ return AES_SUCCESS;
+} // aes256_init
+
+
+// -----------------------------------------------------------------------------
+uint8_t
+aes256_done(aes256_context_t *ctx)
+{
+ const aes256_key_t zero = {0};
+
+ if (NULL != ctx) {
+ ctx->key = ctx->enckey = ctx->deckey = zero;
+ return AES_SUCCESS;
+ }
+
+ return AES_ERROR;
+} // aes256_done
+
+
+// -----------------------------------------------------------------------------
+uint8_t
+aes256_encrypt_ecb(aes256_context_t *ctx, aes256_blk_t *buf)
+{
+ if ((NULL == ctx) || (NULL == buf)) {
+ return AES_ERROR;
+ }
+
+ uint8_t rcon = 1;
+ addRoundKey_cpy(buf->raw, ctx->enckey.raw, ctx->key.raw);
+
+ for (uint8_t i = 1; i < 14; ++i) {
+ subBytes(buf->raw);
+ shiftRows(buf->raw);
+ mixColumns(buf->raw);
+ if (1 == (i & 1)) {
+ addRoundKey(buf->raw, &ctx->key.raw[16]);
+ } else {
+ expandEncKey(ctx->key.raw, &rcon);
+ addRoundKey(buf->raw, ctx->key.raw);
+ }
+ }
+
+ subBytes(buf->raw);
+ shiftRows(buf->raw);
+ expandEncKey(ctx->key.raw, &rcon);
+ addRoundKey(buf->raw, ctx->key.raw);
+
+ return AES_SUCCESS;
+} // aes256_encrypt
+
+// -----------------------------------------------------------------------------
+uint8_t
+aes256_decrypt_ecb(aes256_context_t *ctx, aes256_blk_t *buf)
+{
+ if ((NULL == ctx) || (NULL == buf)) {
+ return AES_ERROR;
+ }
+
+ addRoundKey_cpy(buf->raw, ctx->deckey.raw, ctx->key.raw);
+ shiftRows_inv(buf->raw);
+ subBytes_inv(buf->raw);
+
+ for (uint8_t i = 14, rcon = 0x80; --i;) {
+ if (1 == (i & 1)) {
+ expandDecKey(ctx->key.raw, &rcon);
+ addRoundKey(buf->raw, &ctx->key.raw[16]);
+ } else {
+ addRoundKey(buf->raw, ctx->key.raw);
+ }
+ mixColumns_inv(buf->raw);
+ shiftRows_inv(buf->raw);
+ subBytes_inv(buf->raw);
+ }
+
+ addRoundKey(buf->raw, ctx->key.raw);
+
+ return AES_SUCCESS;
+} // aes256_decrypt
+
+// -----------------------------------------------------------------------------
+uint8_t
+aes256_ctr_inc(uint8_t *p)
+{
+ p += 12;
+ uint32_t val = (uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | (uint32_t)p[3];
+ val++;
+ p[0] = (val >> 24) & 0xFF;
+ p[1] = (val >> 16) & 0xFF;
+ p[2] = (val >> 8) & 0xFF;
+ p[3] = val & 0xFF;
+
+ return AES_SUCCESS;
+} // aes256_ctr_inc
\ No newline at end of file
diff --git a/src/crypto-aes256.h b/src/crypto-aes256.h
new file mode 100644
index 00000000..79e17e76
--- /dev/null
+++ b/src/crypto-aes256.h
@@ -0,0 +1,105 @@
+// https://github.com/ilvn/aes256
+
+// A compact byte-oriented AES-256 implementation.
+// All lookup tables replaced with 'on the fly' calculations.
+//
+// Copyright (c) 2007-2011 Literatecode, http://www.literatecode.com
+// Copyright (c) 2022 Ilia Levin (ilia@levin.sg)
+//
+// Other contributors: Hal Finney.
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef AES256_H__
+#define AES256_H__ 1
+
+#ifndef uint8_t
+#define uint8_t unsigned char
+#endif
+
+#ifndef uint32_t
+#define uint32_t unsigned int
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AES_SUCCESS (0)
+#define AES_ERROR (1)
+
+typedef struct aes256_key_t { uint8_t raw[32]; } aes256_key_t;
+typedef struct aes256_blk_t { uint8_t raw[16]; } aes256_blk_t;
+
+typedef struct aes256_context_t {
+ aes256_key_t key;
+ aes256_key_t enckey;
+ aes256_key_t deckey;
+} aes256_context_t;
+
+
+/// @function aes256_init
+/// @brief Initialize a context structure.
+/// @param[in,out] ctx Pointer to a pre-allocated context structure.
+/// @param[in] key Pointer to a key initialized buffer.
+/// @return AES_SUCCESS on success, AES_ERROR on failure.
+///
+uint8_t aes256_init(
+ aes256_context_t *ctx,
+ aes256_key_t *key
+);
+
+/// @brief Clear the context structure.
+/// @param[in,out] ctx Pointer to a context structure.
+/// @return AES_SUCCESS on success, AES_ERROR on failure.
+///
+uint8_t aes256_done(
+ aes256_context_t *ctx
+);
+
+/// @brief Encrypt a single data block in place.
+/// @param[in] ctx Pointer to an initialized context structure.
+/// @param[in,out] buf Plaintext in, ciphertext out.
+/// @return AES_SUCCESS on success, AES_ERROR on failure.
+///
+uint8_t aes256_encrypt_ecb(
+ aes256_context_t *ctx,
+ aes256_blk_t *buf
+);
+
+/// @brief Decrypt a single data block in place.
+/// @param[in] ctx Pointer to an initialized context structure.
+/// @param[in,out] buf Ciphertext in, plaintext out.
+/// @return AES_SUCCESS on success, AES_ERROR on failure.
+///
+uint8_t aes256_decrypt_ecb(
+ aes256_context_t *ctx,
+ aes256_blk_t *buf
+);
+
+// added by us (masscan):
+
+/// @brief Increment the CTR pointer by 1 in-place.
+/// @param[in,out] p Pointer to the CTR pointer.
+/// @return AES_SUCCESS on success, AES_ERROR on failure.
+///
+uint8_t aes256_ctr_inc(
+ uint8_t *p
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // AES256_H__
+
diff --git a/src/crypto-curve25519.c b/src/crypto-curve25519.c
new file mode 100644
index 00000000..bbd61d1e
--- /dev/null
+++ b/src/crypto-curve25519.c
@@ -0,0 +1,452 @@
+// https://github.com/agl/curve25519-donna/blob/master/curve25519-donna-c64.c
+
+/* Copyright 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Code released into the public domain.
+ *
+ * curve25519-donna: Curve25519 elliptic curve, public key function
+ *
+ * http://code.google.com/p/curve25519-donna/
+ *
+ * Adam Langley
+ *
+ * Derived from public domain C code by Daniel J. Bernstein
+ *
+ * More information about curve25519 can be found here
+ * http://cr.yp.to/ecdh.html
+ *
+ * djb's sample implementation of curve25519 is written in a special assembly
+ * language called qhasm and uses the floating point registers.
+ *
+ * This is, almost, a clean room reimplementation from the curve25519 paper. It
+ * uses many of the tricks described therein. Only the crecip function is taken
+ * from the sample implementation.
+ */
+
+#include "crypto-curve25519.h"
+#include
+#include
+
+typedef uint8_t u8;
+typedef uint64_t limb;
+typedef limb felem[5];
+// This is a special gcc mode for 128-bit integers. It's implemented on 64-bit
+// platforms only as far as I know.
+typedef unsigned uint128_t __attribute__((mode(TI)));
+
+#undef force_inline
+#define force_inline __attribute__((always_inline))
+
+/* Sum two numbers: output += in */
+static inline void force_inline
+fsum(limb *output, const limb *in) {
+ output[0] += in[0];
+ output[1] += in[1];
+ output[2] += in[2];
+ output[3] += in[3];
+ output[4] += in[4];
+}
+
+/* Find the difference of two numbers: output = in - output
+ * (note the order of the arguments!)
+ *
+ * Assumes that out[i] < 2**52
+ * On return, out[i] < 2**55
+ */
+static inline void force_inline
+fdifference_backwards(felem out, const felem in) {
+ /* 152 is 19 << 3 */
+ static const limb two54m152 = (((limb)1) << 54) - 152;
+ static const limb two54m8 = (((limb)1) << 54) - 8;
+
+ out[0] = in[0] + two54m152 - out[0];
+ out[1] = in[1] + two54m8 - out[1];
+ out[2] = in[2] + two54m8 - out[2];
+ out[3] = in[3] + two54m8 - out[3];
+ out[4] = in[4] + two54m8 - out[4];
+}
+
+/* Multiply a number by a scalar: output = in * scalar */
+static inline void force_inline
+fscalar_product(felem output, const felem in, const limb scalar) {
+ uint128_t a;
+
+ a = ((uint128_t) in[0]) * scalar;
+ output[0] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[1]) * scalar + ((limb) (a >> 51));
+ output[1] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[2]) * scalar + ((limb) (a >> 51));
+ output[2] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[3]) * scalar + ((limb) (a >> 51));
+ output[3] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[4]) * scalar + ((limb) (a >> 51));
+ output[4] = ((limb)a) & 0x7ffffffffffff;
+
+ output[0] += (a >> 51) * 19;
+}
+
+/* Multiply two numbers: output = in2 * in
+ *
+ * output must be distinct to both inputs. The inputs are reduced coefficient
+ * form, the output is not.
+ *
+ * Assumes that in[i] < 2**55 and likewise for in2.
+ * On return, output[i] < 2**52
+ */
+static inline void force_inline
+fmul(felem output, const felem in2, const felem in) {
+ uint128_t t[5];
+ limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c;
+
+ r0 = in[0];
+ r1 = in[1];
+ r2 = in[2];
+ r3 = in[3];
+ r4 = in[4];
+
+ s0 = in2[0];
+ s1 = in2[1];
+ s2 = in2[2];
+ s3 = in2[3];
+ s4 = in2[4];
+
+ t[0] = ((uint128_t) r0) * s0;
+ t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0;
+ t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1;
+ t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1;
+ t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2;
+
+ r4 *= 19;
+ r1 *= 19;
+ r2 *= 19;
+ r3 *= 19;
+
+ t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2;
+ t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3;
+ t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4;
+ t[3] += ((uint128_t) r4) * s4;
+
+ r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51);
+ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51);
+ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51);
+ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51);
+ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51);
+ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff;
+ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff;
+ r2 += c;
+
+ output[0] = r0;
+ output[1] = r1;
+ output[2] = r2;
+ output[3] = r3;
+ output[4] = r4;
+}
+
+static inline void force_inline
+fsquare_times(felem output, const felem in, limb count) {
+ uint128_t t[5];
+ limb r0,r1,r2,r3,r4,c;
+ limb d0,d1,d2,d4,d419;
+
+ r0 = in[0];
+ r1 = in[1];
+ r2 = in[2];
+ r3 = in[3];
+ r4 = in[4];
+
+ do {
+ d0 = r0 * 2;
+ d1 = r1 * 2;
+ d2 = r2 * 2 * 19;
+ d419 = r4 * 19;
+ d4 = d419 * 2;
+
+ t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 ));
+ t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19));
+ t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 ));
+ t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 ));
+ t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 ));
+
+ r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51);
+ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51);
+ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51);
+ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51);
+ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51);
+ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff;
+ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff;
+ r2 += c;
+ } while(--count);
+
+ output[0] = r0;
+ output[1] = r1;
+ output[2] = r2;
+ output[3] = r3;
+ output[4] = r4;
+}
+
+/* Load a little-endian 64-bit number */
+static limb
+load_limb(const u8 *in) {
+ return
+ ((limb)in[0]) |
+ (((limb)in[1]) << 8) |
+ (((limb)in[2]) << 16) |
+ (((limb)in[3]) << 24) |
+ (((limb)in[4]) << 32) |
+ (((limb)in[5]) << 40) |
+ (((limb)in[6]) << 48) |
+ (((limb)in[7]) << 56);
+}
+
+static void
+store_limb(u8 *out, limb in) {
+ out[0] = in & 0xff;
+ out[1] = (in >> 8) & 0xff;
+ out[2] = (in >> 16) & 0xff;
+ out[3] = (in >> 24) & 0xff;
+ out[4] = (in >> 32) & 0xff;
+ out[5] = (in >> 40) & 0xff;
+ out[6] = (in >> 48) & 0xff;
+ out[7] = (in >> 56) & 0xff;
+}
+
+/* Take a little-endian, 32-byte number and expand it into polynomial form */
+static void
+fexpand(limb *output, const u8 *in) {
+ output[0] = load_limb(in) & 0x7ffffffffffff;
+ output[1] = (load_limb(in+6) >> 3) & 0x7ffffffffffff;
+ output[2] = (load_limb(in+12) >> 6) & 0x7ffffffffffff;
+ output[3] = (load_limb(in+19) >> 1) & 0x7ffffffffffff;
+ output[4] = (load_limb(in+24) >> 12) & 0x7ffffffffffff;
+}
+
+/* Take a fully reduced polynomial form number and contract it into a
+ * little-endian, 32-byte array
+ */
+static void
+fcontract(u8 *output, const felem input) {
+ uint128_t t[5];
+
+ t[0] = input[0];
+ t[1] = input[1];
+ t[2] = input[2];
+ t[3] = input[3];
+ t[4] = input[4];
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
+
+ /* now t is between 0 and 2^255-1, properly carried. */
+ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */
+
+ t[0] += 19;
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
+
+ /* now between 19 and 2^255-1 in both cases, and offset by 19. */
+
+ t[0] += 0x8000000000000 - 19;
+ t[1] += 0x8000000000000 - 1;
+ t[2] += 0x8000000000000 - 1;
+ t[3] += 0x8000000000000 - 1;
+ t[4] += 0x8000000000000 - 1;
+
+ /* now between 2^255 and 2^256-20, and offset by 2^255. */
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[4] &= 0x7ffffffffffff;
+
+ store_limb(output, t[0] | (t[1] << 51));
+ store_limb(output+8, (t[1] >> 13) | (t[2] << 38));
+ store_limb(output+16, (t[2] >> 26) | (t[3] << 25));
+ store_limb(output+24, (t[3] >> 39) | (t[4] << 12));
+}
+
+/* Input: Q, Q', Q-Q'
+ * Output: 2Q, Q+Q'
+ *
+ * x2 z3: long form
+ * x3 z3: long form
+ * x z: short form, destroyed
+ * xprime zprime: short form, destroyed
+ * qmqp: short form, preserved
+ */
+static void
+fmonty(limb *x2, limb *z2, /* output 2Q */
+ limb *x3, limb *z3, /* output Q + Q' */
+ limb *x, limb *z, /* input Q */
+ limb *xprime, limb *zprime, /* input Q' */
+ const limb *qmqp /* input Q - Q' */) {
+ limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5],
+ zzprime[5], zzzprime[5];
+
+ memcpy(origx, x, 5 * sizeof(limb));
+ fsum(x, z);
+ fdifference_backwards(z, origx); // does x - z
+
+ memcpy(origxprime, xprime, sizeof(limb) * 5);
+ fsum(xprime, zprime);
+ fdifference_backwards(zprime, origxprime);
+ fmul(xxprime, xprime, z);
+ fmul(zzprime, x, zprime);
+ memcpy(origxprime, xxprime, sizeof(limb) * 5);
+ fsum(xxprime, zzprime);
+ fdifference_backwards(zzprime, origxprime);
+ fsquare_times(x3, xxprime, 1);
+ fsquare_times(zzzprime, zzprime, 1);
+ fmul(z3, zzzprime, qmqp);
+
+ fsquare_times(xx, x, 1);
+ fsquare_times(zz, z, 1);
+ fmul(x2, xx, zz);
+ fdifference_backwards(zz, xx); // does zz = xx - zz
+ fscalar_product(zzz, zz, 121665);
+ fsum(zzz, xx);
+ fmul(z2, zz, zzz);
+}
+
+// -----------------------------------------------------------------------------
+// Maybe swap the contents of two limb arrays (@a and @b), each @len elements
+// long. Perform the swap iff @swap is non-zero.
+//
+// This function performs the swap without leaking any side-channel
+// information.
+// -----------------------------------------------------------------------------
+static void
+swap_conditional(limb a[5], limb b[5], limb iswap) {
+ unsigned i;
+ const limb swap = -iswap;
+
+ for (i = 0; i < 5; ++i) {
+ const limb x = swap & (a[i] ^ b[i]);
+ a[i] ^= x;
+ b[i] ^= x;
+ }
+}
+
+/* Calculates nQ where Q is the x-coordinate of a point on the curve
+ *
+ * resultx/resultz: the x coordinate of the resulting curve point (short form)
+ * n: a little endian, 32-byte number
+ * q: a point of the curve (short form)
+ */
+static void
+cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
+ limb a[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0};
+ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
+ limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1};
+ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
+
+ unsigned i, j;
+
+ memcpy(nqpqx, q, sizeof(limb) * 5);
+
+ for (i = 0; i < 32; ++i) {
+ u8 byte = n[31 - i];
+ for (j = 0; j < 8; ++j) {
+ const limb bit = byte >> 7;
+
+ swap_conditional(nqx, nqpqx, bit);
+ swap_conditional(nqz, nqpqz, bit);
+ fmonty(nqx2, nqz2,
+ nqpqx2, nqpqz2,
+ nqx, nqz,
+ nqpqx, nqpqz,
+ q);
+ swap_conditional(nqx2, nqpqx2, bit);
+ swap_conditional(nqz2, nqpqz2, bit);
+
+ t = nqx;
+ nqx = nqx2;
+ nqx2 = t;
+ t = nqz;
+ nqz = nqz2;
+ nqz2 = t;
+ t = nqpqx;
+ nqpqx = nqpqx2;
+ nqpqx2 = t;
+ t = nqpqz;
+ nqpqz = nqpqz2;
+ nqpqz2 = t;
+
+ byte <<= 1;
+ }
+ }
+
+ memcpy(resultx, nqx, sizeof(limb) * 5);
+ memcpy(resultz, nqz, sizeof(limb) * 5);
+}
+
+
+// -----------------------------------------------------------------------------
+// Shamelessly copied from djb's code, tightened a little
+// -----------------------------------------------------------------------------
+static void
+crecip(felem out, const felem z) {
+ felem a,t0,b,c;
+
+ /* 2 */ fsquare_times(a, z, 1); // a = 2
+ /* 8 */ fsquare_times(t0, a, 2);
+ /* 9 */ fmul(b, t0, z); // b = 9
+ /* 11 */ fmul(a, b, a); // a = 11
+ /* 22 */ fsquare_times(t0, a, 1);
+ /* 2^5 - 2^0 = 31 */ fmul(b, t0, b);
+ /* 2^10 - 2^5 */ fsquare_times(t0, b, 5);
+ /* 2^10 - 2^0 */ fmul(b, t0, b);
+ /* 2^20 - 2^10 */ fsquare_times(t0, b, 10);
+ /* 2^20 - 2^0 */ fmul(c, t0, b);
+ /* 2^40 - 2^20 */ fsquare_times(t0, c, 20);
+ /* 2^40 - 2^0 */ fmul(t0, t0, c);
+ /* 2^50 - 2^10 */ fsquare_times(t0, t0, 10);
+ /* 2^50 - 2^0 */ fmul(b, t0, b);
+ /* 2^100 - 2^50 */ fsquare_times(t0, b, 50);
+ /* 2^100 - 2^0 */ fmul(c, t0, b);
+ /* 2^200 - 2^100 */ fsquare_times(t0, c, 100);
+ /* 2^200 - 2^0 */ fmul(t0, t0, c);
+ /* 2^250 - 2^50 */ fsquare_times(t0, t0, 50);
+ /* 2^250 - 2^0 */ fmul(t0, t0, b);
+ /* 2^255 - 2^5 */ fsquare_times(t0, t0, 5);
+ /* 2^255 - 21 */ fmul(out, t0, a);
+}
+
+int curve25519_donna(u8 *, const u8 *, const u8 *);
+
+int
+curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
+ limb bp[5], x[5], z[5], zmone[5];
+ uint8_t e[32];
+ int i;
+
+ for (i = 0;i < 32;++i) e[i] = secret[i];
+ e[0] &= 248;
+ e[31] &= 127;
+ e[31] |= 64;
+
+ fexpand(bp, basepoint);
+ cmult(x, z, e, bp);
+ crecip(zmone, z);
+ fmul(z, x, zmone);
+ fcontract(mypublic, z);
+ return 0;
+}
diff --git a/src/crypto-curve25519.h b/src/crypto-curve25519.h
new file mode 100644
index 00000000..7f72b8a6
--- /dev/null
+++ b/src/crypto-curve25519.h
@@ -0,0 +1,7 @@
+#ifndef CRYPTO_X25519_H
+#define CRYPTO_X25519_H
+#include
+
+int curve25519_donna(unsigned char *mypublic, const unsigned char *secret, const unsigned char *basepoint);
+
+#endif
diff --git a/src/crypto-rfc6234.c b/src/crypto-rfc6234.c
new file mode 100644
index 00000000..cff046f8
--- /dev/null
+++ b/src/crypto-rfc6234.c
@@ -0,0 +1,2775 @@
+/***************** See RFC 6234 for details. *******************/
+/* Copyright (c) 2011 IETF Trust and the persons identified as */
+/* authors of the code. All rights reserved. */
+/* See crypto-rfc2634.h for terms of use and redistribution. */
+
+/*
+ * This is a concatenation of all the .c files included in
+ * RFC6234: https://www.rfc-editor.org/rfc/rfc6234
+ *
+ * This implements most of the crypto required to compute the
+ * various keys in TLS:
+ * - TLS 1.1: SHA-1
+ * - TLS 1.2: SHA-256/SHA-384
+ * - TLS 1.3: SHA-384 + HKDF
+ */
+
+#include "crypto-rfc6234.h"
+#include
+#include
+
+/*****************************************************************/
+/*****************************************************************/
+/*****************************************************************/
+
+#ifdef USE_32BIT_ONLY
+/*
+ * Define 64-bit arithmetic in terms of 32-bit arithmetic.
+ * Each 64-bit number is represented in a 2-word array.
+ * All macros are defined such that the result is the last parameter.
+ */
+
+/*
+ * Define shift, rotate left, and rotate right functions
+ */
+#define SHA512_SHR(bits, word, ret) ( \
+ /* (((uint64_t)((word))) >> (bits)) */ \
+ (ret)[0] = (((bits) < 32) && ((bits) >= 0)) ? \
+ ((word)[0] >> (bits)) : 0, \
+ (ret)[1] = ((bits) > 32) ? ((word)[0] >> ((bits) - 32)) : \
+ ((bits) == 32) ? (word)[0] : \
+ ((bits) >= 0) ? \
+ (((word)[0] << (32 - (bits))) | \
+ ((word)[1] >> (bits))) : 0 )
+
+#define SHA512_SHL(bits, word, ret) ( \
+ /* (((uint64_t)(word)) << (bits)) */ \
+ (ret)[0] = ((bits) > 32) ? ((word)[1] << ((bits) - 32)) : \
+ ((bits) == 32) ? (word)[1] : \
+ ((bits) >= 0) ? \
+ (((word)[0] << (bits)) | \
+ ((word)[1] >> (32 - (bits)))) : \
+ 0, \
+ (ret)[1] = (((bits) < 32) && ((bits) >= 0)) ? \
+ ((word)[1] << (bits)) : 0 )
+
+/*
+ * Define 64-bit OR
+ */
+#define SHA512_OR(word1, word2, ret) ( \
+ (ret)[0] = (word1)[0] | (word2)[0], \
+ (ret)[1] = (word1)[1] | (word2)[1] )
+
+/*
+ * Define 64-bit XOR
+ */
+#define SHA512_XOR(word1, word2, ret) ( \
+ (ret)[0] = (word1)[0] ^ (word2)[0], \
+ (ret)[1] = (word1)[1] ^ (word2)[1] )
+
+/*
+ * Define 64-bit AND
+ */
+#define SHA512_AND(word1, word2, ret) ( \
+ (ret)[0] = (word1)[0] & (word2)[0], \
+ (ret)[1] = (word1)[1] & (word2)[1] )
+
+/*
+ * Define 64-bit TILDA
+ */
+#define SHA512_TILDA(word, ret) \
+ ( (ret)[0] = ~(word)[0], (ret)[1] = ~(word)[1] )
+
+/*
+ * Define 64-bit ADD
+ */
+#define SHA512_ADD(word1, word2, ret) ( \
+ (ret)[1] = (word1)[1], (ret)[1] += (word2)[1], \
+ (ret)[0] = (word1)[0] + (word2)[0] + ((ret)[1] < (word1)[1]) )
+
+/*
+ * Add the 4word value in word2 to word1.
+ */
+static uint32_t ADDTO4_temp, ADDTO4_temp2;
+#define SHA512_ADDTO4(word1, word2) ( \
+ ADDTO4_temp = (word1)[3], \
+ (word1)[3] += (word2)[3], \
+ ADDTO4_temp2 = (word1)[2], \
+ (word1)[2] += (word2)[2] + ((word1)[3] < ADDTO4_temp), \
+ ADDTO4_temp = (word1)[1], \
+ (word1)[1] += (word2)[1] + ((word1)[2] < ADDTO4_temp2), \
+ (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO4_temp) )
+
+/*
+ * Add the 2word value in word2 to word1.
+ */
+static uint32_t ADDTO2_temp;
+#define SHA512_ADDTO2(word1, word2) ( \
+ ADDTO2_temp = (word1)[1], \
+ (word1)[1] += (word2)[1], \
+ (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO2_temp) )
+
+/*
+ * SHA rotate ((word >> bits) | (word << (64-bits)))
+ */
+static uint32_t ROTR_temp1[2], ROTR_temp2[2];
+#define SHA512_ROTR(bits, word, ret) ( \
+ SHA512_SHR((bits), (word), ROTR_temp1), \
+ SHA512_SHL(64-(bits), (word), ROTR_temp2), \
+ SHA512_OR(ROTR_temp1, ROTR_temp2, (ret)) )
+
+/*
+ * Define the SHA SIGMA and sigma macros
+ *
+ * SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word)
+ */
+static uint32_t SIGMA0_temp1[2], SIGMA0_temp2[2],
+ SIGMA0_temp3[2], SIGMA0_temp4[2];
+#define SHA512_SIGMA0(word, ret) ( \
+ SHA512_ROTR(28, (word), SIGMA0_temp1), \
+ SHA512_ROTR(34, (word), SIGMA0_temp2), \
+ SHA512_ROTR(39, (word), SIGMA0_temp3), \
+ SHA512_XOR(SIGMA0_temp2, SIGMA0_temp3, SIGMA0_temp4), \
+ SHA512_XOR(SIGMA0_temp1, SIGMA0_temp4, (ret)) )
+
+/*
+ * SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word)
+ */
+static uint32_t SIGMA1_temp1[2], SIGMA1_temp2[2],
+ SIGMA1_temp3[2], SIGMA1_temp4[2];
+#define SHA512_SIGMA1(word, ret) ( \
+ SHA512_ROTR(14, (word), SIGMA1_temp1), \
+ SHA512_ROTR(18, (word), SIGMA1_temp2), \
+ SHA512_ROTR(41, (word), SIGMA1_temp3), \
+ SHA512_XOR(SIGMA1_temp2, SIGMA1_temp3, SIGMA1_temp4), \
+ SHA512_XOR(SIGMA1_temp1, SIGMA1_temp4, (ret)) )
+
+/*
+ * (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word))
+ */
+static uint32_t sigma0_temp1[2], sigma0_temp2[2],
+ sigma0_temp3[2], sigma0_temp4[2];
+#define SHA512_sigma0(word, ret) ( \
+ SHA512_ROTR( 1, (word), sigma0_temp1), \
+ SHA512_ROTR( 8, (word), sigma0_temp2), \
+ SHA512_SHR( 7, (word), sigma0_temp3), \
+ SHA512_XOR(sigma0_temp2, sigma0_temp3, sigma0_temp4), \
+ SHA512_XOR(sigma0_temp1, sigma0_temp4, (ret)) )
+
+/*
+ * (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word))
+ */
+static uint32_t sigma1_temp1[2], sigma1_temp2[2],
+ sigma1_temp3[2], sigma1_temp4[2];
+#define SHA512_sigma1(word, ret) ( \
+ SHA512_ROTR(19, (word), sigma1_temp1), \
+ SHA512_ROTR(61, (word), sigma1_temp2), \
+ SHA512_SHR( 6, (word), sigma1_temp3), \
+ SHA512_XOR(sigma1_temp2, sigma1_temp3, sigma1_temp4), \
+ SHA512_XOR(sigma1_temp1, sigma1_temp4, (ret)) )
+
+#ifndef USE_MODIFIED_MACROS
+/*
+ * These definitions are the ones used in FIPS 180-3, section 4.1.3
+ * Ch(x,y,z) ((x & y) ^ (~x & z))
+ */
+static uint32_t Ch_temp1[2], Ch_temp2[2], Ch_temp3[2];
+#define SHA_Ch(x, y, z, ret) ( \
+ SHA512_AND(x, y, Ch_temp1), \
+ SHA512_TILDA(x, Ch_temp2), \
+ SHA512_AND(Ch_temp2, z, Ch_temp3), \
+ SHA512_XOR(Ch_temp1, Ch_temp3, (ret)) )
+
+/*
+ * Maj(x,y,z) (((x)&(y)) ^ ((x)&(z)) ^ ((y)&(z)))
+ */
+static uint32_t Maj_temp1[2], Maj_temp2[2],
+ Maj_temp3[2], Maj_temp4[2];
+#define SHA_Maj(x, y, z, ret) ( \
+ SHA512_AND(x, y, Maj_temp1), \
+ SHA512_AND(x, z, Maj_temp2), \
+ SHA512_AND(y, z, Maj_temp3), \
+ SHA512_XOR(Maj_temp2, Maj_temp3, Maj_temp4), \
+ SHA512_XOR(Maj_temp1, Maj_temp4, (ret)) )
+#else /* !USE_MODIFIED_MACROS */
+/*
+ * These definitions are potentially faster equivalents for the ones
+ * used in FIPS 180-3, section 4.1.3.
+ * ((x & y) ^ (~x & z)) becomes
+ * ((x & (y ^ z)) ^ z)
+ */
+#define SHA_Ch(x, y, z, ret) ( \
+ (ret)[0] = (((x)[0] & ((y)[0] ^ (z)[0])) ^ (z)[0]), \
+ (ret)[1] = (((x)[1] & ((y)[1] ^ (z)[1])) ^ (z)[1]) )
+
+/*
+ * ((x & y) ^ (x & z) ^ (y & z)) becomes
+ * ((x & (y | z)) | (y & z))
+ */
+#define SHA_Maj(x, y, z, ret) ( \
+ ret[0] = (((x)[0] & ((y)[0] | (z)[0])) | ((y)[0] & (z)[0])), \
+ ret[1] = (((x)[1] & ((y)[1] | (z)[1])) | ((y)[1] & (z)[1])) )
+#endif /* USE_MODIFIED_MACROS */
+
+/*
+ * Add "length" to the length.
+ * Set Corrupted when overflow has occurred.
+ */
+static uint32_t addTemp[4] = { 0, 0, 0, 0 };
+#define SHA384_512AddLength(context, length) ( \
+ addTemp[3] = (length), SHA512_ADDTO4((context)->Length, addTemp), \
+ (context)->Corrupted = (((context)->Length[3] < (length)) && \
+ ((context)->Length[2] == 0) && ((context)->Length[1] == 0) && \
+ ((context)->Length[0] == 0)) ? shaInputTooLong : \
+ (context)->Corrupted )
+
+/* Local Function Prototypes */
+static int SHA384_512Reset(SHA512Context *context,
+ uint32_t H0[SHA512HashSize/4]);
+static void SHA384_512ProcessMessageBlock(SHA512Context *context);
+static void SHA384_512Finalize(SHA512Context *context,
+ uint8_t Pad_Byte);
+static void SHA384_512PadMessage(SHA512Context *context,
+ uint8_t Pad_Byte);
+static int SHA384_512ResultN( SHA512Context *context,
+ uint8_t Message_Digest[ ], int HashSize);
+
+/* Initial Hash Values: FIPS 180-3 sections 5.3.4 and 5.3.5 */
+static uint32_t SHA384_H0[SHA512HashSize/4] = {
+ 0xCBBB9D5D, 0xC1059ED8, 0x629A292A, 0x367CD507, 0x9159015A,
+ 0x3070DD17, 0x152FECD8, 0xF70E5939, 0x67332667, 0xFFC00B31,
+ 0x8EB44A87, 0x68581511, 0xDB0C2E0D, 0x64F98FA7, 0x47B5481D,
+ 0xBEFA4FA4
+};
+static uint32_t SHA512_H0[SHA512HashSize/4] = {
+ 0x6A09E667, 0xF3BCC908, 0xBB67AE85, 0x84CAA73B, 0x3C6EF372,
+ 0xFE94F82B, 0xA54FF53A, 0x5F1D36F1, 0x510E527F, 0xADE682D1,
+ 0x9B05688C, 0x2B3E6C1F, 0x1F83D9AB, 0xFB41BD6B, 0x5BE0CD19,
+ 0x137E2179
+};
+
+#else /* !USE_32BIT_ONLY */
+
+/*
+ * These definitions are defined in FIPS 180-3, section 4.1.
+ * Ch() and Maj() are defined identically in sections 4.1.1,
+ * 4.1.2, and 4.1.3.
+ *
+ * The definitions used in FIPS 180-3 are as follows:
+ */
+
+#ifndef USE_MODIFIED_MACROS
+#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#else /* USE_MODIFIED_MACROS */
+/*
+ * The following definitions are equivalent and potentially faster.
+ */
+
+#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
+#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
+
+#endif /* USE_MODIFIED_MACROS */
+
+#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z))
+
+/* Define the SHA shift, rotate left and rotate right macros */
+#define SHA512_SHR(bits,word) (((uint64_t)(word)) >> (bits))
+#define SHA512_ROTR(bits,word) ((((uint64_t)(word)) >> (bits)) | \
+ (((uint64_t)(word)) << (64-(bits))))
+
+/*
+ * Define the SHA SIGMA and sigma macros
+ *
+ * SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word)
+ */
+#define SHA512_SIGMA0(word) \
+ (SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word))
+#define SHA512_SIGMA1(word) \
+ (SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word))
+#define SHA512_sigma0(word) \
+ (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word))
+#define SHA512_sigma1(word) \
+ (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word))
+
+/*
+ * Add "length" to the length.
+ * Set Corrupted when overflow has occurred.
+ */
+static unsigned int addTemp;
+#define SHA384_512AddLength(context, length) \
+ (addTemp = context->Length_Low, context->Corrupted = \
+ ((context->Length_Low += length) < addTemp) && \
+ (++context->Length_High == 0) ? shaInputTooLong : \
+ (context)->Corrupted)
+
+/* Local Function Prototypes */
+static int SHA384_512Reset(SHA512Context *context,
+ uint64_t H0[SHA512HashSize/8]);
+static void SHA384_512ProcessMessageBlock(SHA512Context *context);
+static void SHA384_512Finalize(SHA512Context *context,
+ uint8_t Pad_Byte);
+static void SHA384_512PadMessage(SHA512Context *context,
+ uint8_t Pad_Byte);
+static int SHA384_512ResultN(SHA512Context *context,
+ uint8_t Message_Digest[ ], int HashSize);
+
+/* Initial Hash Values: FIPS 180-3 sections 5.3.4 and 5.3.5 */
+static uint64_t SHA384_H0[ ] = {
+ 0xCBBB9D5DC1059ED8ll, 0x629A292A367CD507ll, 0x9159015A3070DD17ll,
+ 0x152FECD8F70E5939ll, 0x67332667FFC00B31ll, 0x8EB44A8768581511ll,
+ 0xDB0C2E0D64F98FA7ll, 0x47B5481DBEFA4FA4ll
+};
+static uint64_t SHA512_H0[ ] = {
+ 0x6A09E667F3BCC908ll, 0xBB67AE8584CAA73Bll, 0x3C6EF372FE94F82Bll,
+ 0xA54FF53A5F1D36F1ll, 0x510E527FADE682D1ll, 0x9B05688C2B3E6C1Fll,
+ 0x1F83D9ABFB41BD6Bll, 0x5BE0CD19137E2179ll
+};
+
+#endif /* USE_32BIT_ONLY */
+
+/*
+ * SHA384Reset
+ *
+ * Description:
+ * This function will initialize the SHA384Context in preparation
+ * for computing a new SHA384 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA384Reset(SHA384Context *context)
+{
+ return SHA384_512Reset(context, SHA384_H0);
+}
+
+/*
+ * SHA384Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_array[ ]: [in]
+ * An array of octets representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA384Input(SHA384Context *context,
+ const uint8_t *message_array, unsigned int length)
+{
+ return SHA512Input(context, message_array, length);
+}
+
+/*
+ * SHA384FinalBits
+ *
+ * Description:
+ * This function will add in any final bits of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_bits: [in]
+ * The final bits of the message, in the upper portion of the
+ * byte. (Use 0b###00000 instead of 0b00000### to input the
+ * three bits ###.)
+ * length: [in]
+ * The number of bits in message_bits, between 1 and 7.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA384FinalBits(SHA384Context *context,
+ uint8_t message_bits, unsigned int length)
+{
+ return SHA512FinalBits(context, message_bits, length);
+}
+
+/*
+ * SHA384Result
+ *
+ * Description:
+ * This function will return the 384-bit message digest
+ * into the Message_Digest array provided by the caller.
+ * NOTE:
+ * The first octet of hash is stored in the element with index 0,
+ * the last octet of hash in the element with index 47.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA hash.
+ * Message_Digest[ ]: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA384Result(SHA384Context *context,
+ uint8_t Message_Digest[SHA384HashSize])
+{
+ return SHA384_512ResultN(context, Message_Digest, SHA384HashSize);
+}
+
+/*
+ * SHA512Reset
+ *
+ * Description:
+ * This function will initialize the SHA512Context in preparation
+ * for computing a new SHA512 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA512Reset(SHA512Context *context)
+{
+ return SHA384_512Reset(context, SHA512_H0);
+}
+
+/*
+ * SHA512Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_array[ ]: [in]
+ * An array of octets representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA512Input(SHA512Context *context,
+ const uint8_t *message_array,
+ unsigned int length)
+{
+ if (!context) return shaNull;
+ if (!length) return shaSuccess;
+ if (!message_array) return shaNull;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ if (context->Corrupted) return context->Corrupted;
+
+ while (length--) {
+ context->Message_Block[context->Message_Block_Index++] =
+ *message_array;
+
+ if ((SHA384_512AddLength(context, 8) == shaSuccess) &&
+ (context->Message_Block_Index == SHA512_Message_Block_Size))
+ SHA384_512ProcessMessageBlock(context);
+
+ message_array++;
+ }
+
+ return context->Corrupted;
+}
+
+/*
+ * SHA512FinalBits
+ *
+ * Description:
+ * This function will add in any final bits of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_bits: [in]
+ * The final bits of the message, in the upper portion of the
+ * byte. (Use 0b###00000 instead of 0b00000### to input the
+ * three bits ###.)
+ * length: [in]
+ * The number of bits in message_bits, between 1 and 7.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA512FinalBits(SHA512Context *context,
+ uint8_t message_bits, unsigned int length)
+{
+ static uint8_t masks[8] = {
+ /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80,
+ /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0,
+ /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8,
+ /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE
+ };
+ static uint8_t markbit[8] = {
+ /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40,
+ /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10,
+ /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04,
+ /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01
+ };
+
+ if (!context) return shaNull;
+ if (!length) return shaSuccess;
+ if (context->Corrupted) return context->Corrupted;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ if (length >= 8) return context->Corrupted = shaBadParam;
+
+ SHA384_512AddLength(context, length);
+ SHA384_512Finalize(context, (uint8_t)
+ ((message_bits & masks[length]) | markbit[length]));
+
+ return context->Corrupted;
+}
+
+/*
+ * SHA512Result
+ *
+ * Description:
+ * This function will return the 512-bit message digest
+ * into the Message_Digest array provided by the caller.
+ * NOTE:
+ * The first octet of hash is stored in the element with index 0,
+ * the last octet of hash in the element with index 63.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA hash.
+ * Message_Digest[ ]: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA512Result(SHA512Context *context,
+ uint8_t Message_Digest[SHA512HashSize])
+{
+ return SHA384_512ResultN(context, Message_Digest, SHA512HashSize);
+}
+
+/*
+ * SHA384_512Reset
+ *
+ * Description:
+ * This helper function will initialize the SHA512Context in
+ * preparation for computing a new SHA384 or SHA512 message
+ * digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ * H0[ ]: [in]
+ * The initial hash value array to use.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+#ifdef USE_32BIT_ONLY
+static int SHA384_512Reset(SHA512Context *context,
+ uint32_t H0[SHA512HashSize/4])
+#else /* !USE_32BIT_ONLY */
+static int SHA384_512Reset(SHA512Context *context,
+ uint64_t H0[SHA512HashSize/8])
+#endif /* USE_32BIT_ONLY */
+{
+ int i;
+ if (!context) return shaNull;
+ context->Message_Block_Index = 0;
+
+#ifdef USE_32BIT_ONLY
+ context->Length[0] = context->Length[1] =
+ context->Length[2] = context->Length[3] = 0;
+
+ for (i = 0; i < SHA512HashSize/4; i++)
+ context->Intermediate_Hash[i] = H0[i];
+#else /* !USE_32BIT_ONLY */
+ context->Length_High = context->Length_Low = 0;
+
+ for (i = 0; i < SHA512HashSize/8; i++)
+ context->Intermediate_Hash[i] = H0[i];
+#endif /* USE_32BIT_ONLY */
+
+ context->Computed = 0;
+ context->Corrupted = shaSuccess;
+
+ return shaSuccess;
+}
+
+/*
+ * SHA384_512ProcessMessageBlock
+ *
+ * Description:
+ * This helper function will process the next 1024 bits of the
+ * message stored in the Message_Block array.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the
+ * names used in the Secure Hash Standard.
+ *
+ *
+ */
+static void SHA384_512ProcessMessageBlock(SHA512Context *context)
+{
+#ifdef USE_32BIT_ONLY
+ /* Constants defined in FIPS 180-3, section 4.2.3 */
+ static const uint32_t K[80*2] = {
+ 0x428A2F98, 0xD728AE22, 0x71374491, 0x23EF65CD, 0xB5C0FBCF,
+ 0xEC4D3B2F, 0xE9B5DBA5, 0x8189DBBC, 0x3956C25B, 0xF348B538,
+ 0x59F111F1, 0xB605D019, 0x923F82A4, 0xAF194F9B, 0xAB1C5ED5,
+ 0xDA6D8118, 0xD807AA98, 0xA3030242, 0x12835B01, 0x45706FBE,
+ 0x243185BE, 0x4EE4B28C, 0x550C7DC3, 0xD5FFB4E2, 0x72BE5D74,
+ 0xF27B896F, 0x80DEB1FE, 0x3B1696B1, 0x9BDC06A7, 0x25C71235,
+ 0xC19BF174, 0xCF692694, 0xE49B69C1, 0x9EF14AD2, 0xEFBE4786,
+ 0x384F25E3, 0x0FC19DC6, 0x8B8CD5B5, 0x240CA1CC, 0x77AC9C65,
+ 0x2DE92C6F, 0x592B0275, 0x4A7484AA, 0x6EA6E483, 0x5CB0A9DC,
+ 0xBD41FBD4, 0x76F988DA, 0x831153B5, 0x983E5152, 0xEE66DFAB,
+ 0xA831C66D, 0x2DB43210, 0xB00327C8, 0x98FB213F, 0xBF597FC7,
+ 0xBEEF0EE4, 0xC6E00BF3, 0x3DA88FC2, 0xD5A79147, 0x930AA725,
+ 0x06CA6351, 0xE003826F, 0x14292967, 0x0A0E6E70, 0x27B70A85,
+ 0x46D22FFC, 0x2E1B2138, 0x5C26C926, 0x4D2C6DFC, 0x5AC42AED,
+ 0x53380D13, 0x9D95B3DF, 0x650A7354, 0x8BAF63DE, 0x766A0ABB,
+ 0x3C77B2A8, 0x81C2C92E, 0x47EDAEE6, 0x92722C85, 0x1482353B,
+ 0xA2BFE8A1, 0x4CF10364, 0xA81A664B, 0xBC423001, 0xC24B8B70,
+ 0xD0F89791, 0xC76C51A3, 0x0654BE30, 0xD192E819, 0xD6EF5218,
+ 0xD6990624, 0x5565A910, 0xF40E3585, 0x5771202A, 0x106AA070,
+ 0x32BBD1B8, 0x19A4C116, 0xB8D2D0C8, 0x1E376C08, 0x5141AB53,
+ 0x2748774C, 0xDF8EEB99, 0x34B0BCB5, 0xE19B48A8, 0x391C0CB3,
+ 0xC5C95A63, 0x4ED8AA4A, 0xE3418ACB, 0x5B9CCA4F, 0x7763E373,
+ 0x682E6FF3, 0xD6B2B8A3, 0x748F82EE, 0x5DEFB2FC, 0x78A5636F,
+ 0x43172F60, 0x84C87814, 0xA1F0AB72, 0x8CC70208, 0x1A6439EC,
+ 0x90BEFFFA, 0x23631E28, 0xA4506CEB, 0xDE82BDE9, 0xBEF9A3F7,
+ 0xB2C67915, 0xC67178F2, 0xE372532B, 0xCA273ECE, 0xEA26619C,
+ 0xD186B8C7, 0x21C0C207, 0xEADA7DD6, 0xCDE0EB1E, 0xF57D4F7F,
+ 0xEE6ED178, 0x06F067AA, 0x72176FBA, 0x0A637DC5, 0xA2C898A6,
+ 0x113F9804, 0xBEF90DAE, 0x1B710B35, 0x131C471B, 0x28DB77F5,
+ 0x23047D84, 0x32CAAB7B, 0x40C72493, 0x3C9EBE0A, 0x15C9BEBC,
+ 0x431D67C4, 0x9C100D4C, 0x4CC5D4BE, 0xCB3E42B6, 0x597F299C,
+ 0xFC657E2A, 0x5FCB6FAB, 0x3AD6FAEC, 0x6C44198C, 0x4A475817
+ };
+ int t, t2, t8; /* Loop counter */
+ uint32_t temp1[2], temp2[2], /* Temporary word values */
+ temp3[2], temp4[2], temp5[2];
+ uint32_t W[2*80]; /* Word sequence */
+ uint32_t A[2], B[2], C[2], D[2], /* Word buffers */
+ E[2], F[2], G[2], H[2];
+
+ /* Initialize the first 16 words in the array W */
+ for (t = t2 = t8 = 0; t < 16; t++, t8 += 8) {
+ W[t2++] = ((((uint32_t)context->Message_Block[t8 ])) << 24) |
+ ((((uint32_t)context->Message_Block[t8 + 1])) << 16) |
+ ((((uint32_t)context->Message_Block[t8 + 2])) << 8) |
+ ((((uint32_t)context->Message_Block[t8 + 3])));
+ W[t2++] = ((((uint32_t)context->Message_Block[t8 + 4])) << 24) |
+ ((((uint32_t)context->Message_Block[t8 + 5])) << 16) |
+ ((((uint32_t)context->Message_Block[t8 + 6])) << 8) |
+ ((((uint32_t)context->Message_Block[t8 + 7])));
+ }
+
+ for (t = 16; t < 80; t++, t2 += 2) {
+ /* W[t] = SHA512_sigma1(W[t-2]) + W[t-7] +
+ SHA512_sigma0(W[t-15]) + W[t-16]; */
+ uint32_t *Wt2 = &W[t2-2*2];
+ uint32_t *Wt7 = &W[t2-7*2];
+ uint32_t *Wt15 = &W[t2-15*2];
+ uint32_t *Wt16 = &W[t2-16*2];
+ SHA512_sigma1(Wt2, temp1);
+ SHA512_ADD(temp1, Wt7, temp2);
+ SHA512_sigma0(Wt15, temp1);
+ SHA512_ADD(temp1, Wt16, temp3);
+ SHA512_ADD(temp2, temp3, &W[t2]);
+ }
+
+ A[0] = context->Intermediate_Hash[0];
+ A[1] = context->Intermediate_Hash[1];
+ B[0] = context->Intermediate_Hash[2];
+ B[1] = context->Intermediate_Hash[3];
+ C[0] = context->Intermediate_Hash[4];
+ C[1] = context->Intermediate_Hash[5];
+ D[0] = context->Intermediate_Hash[6];
+ D[1] = context->Intermediate_Hash[7];
+ E[0] = context->Intermediate_Hash[8];
+ E[1] = context->Intermediate_Hash[9];
+ F[0] = context->Intermediate_Hash[10];
+ F[1] = context->Intermediate_Hash[11];
+ G[0] = context->Intermediate_Hash[12];
+ G[1] = context->Intermediate_Hash[13];
+ H[0] = context->Intermediate_Hash[14];
+ H[1] = context->Intermediate_Hash[15];
+
+ for (t = t2 = 0; t < 80; t++, t2 += 2) {
+ /*
+ * temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t];
+ */
+ SHA512_SIGMA1(E,temp1);
+ SHA512_ADD(H, temp1, temp2);
+ SHA_Ch(E,F,G,temp3);
+ SHA512_ADD(temp2, temp3, temp4);
+ SHA512_ADD(&K[t2], &W[t2], temp5);
+ SHA512_ADD(temp4, temp5, temp1);
+ /*
+ * temp2 = SHA512_SIGMA0(A) + SHA_Maj(A,B,C);
+ */
+ SHA512_SIGMA0(A,temp3);
+ SHA_Maj(A,B,C,temp4);
+ SHA512_ADD(temp3, temp4, temp2);
+ H[0] = G[0]; H[1] = G[1];
+ G[0] = F[0]; G[1] = F[1];
+ F[0] = E[0]; F[1] = E[1];
+ SHA512_ADD(D, temp1, E);
+ D[0] = C[0]; D[1] = C[1];
+ C[0] = B[0]; C[1] = B[1];
+ B[0] = A[0]; B[1] = A[1];
+ SHA512_ADD(temp1, temp2, A);
+ }
+
+ SHA512_ADDTO2(&context->Intermediate_Hash[0], A);
+ SHA512_ADDTO2(&context->Intermediate_Hash[2], B);
+ SHA512_ADDTO2(&context->Intermediate_Hash[4], C);
+ SHA512_ADDTO2(&context->Intermediate_Hash[6], D);
+ SHA512_ADDTO2(&context->Intermediate_Hash[8], E);
+ SHA512_ADDTO2(&context->Intermediate_Hash[10], F);
+ SHA512_ADDTO2(&context->Intermediate_Hash[12], G);
+ SHA512_ADDTO2(&context->Intermediate_Hash[14], H);
+
+#else /* !USE_32BIT_ONLY */
+ /* Constants defined in FIPS 180-3, section 4.2.3 */
+ static const uint64_t K[80] = {
+ 0x428A2F98D728AE22ll, 0x7137449123EF65CDll, 0xB5C0FBCFEC4D3B2Fll,
+ 0xE9B5DBA58189DBBCll, 0x3956C25BF348B538ll, 0x59F111F1B605D019ll,
+ 0x923F82A4AF194F9Bll, 0xAB1C5ED5DA6D8118ll, 0xD807AA98A3030242ll,
+ 0x12835B0145706FBEll, 0x243185BE4EE4B28Cll, 0x550C7DC3D5FFB4E2ll,
+ 0x72BE5D74F27B896Fll, 0x80DEB1FE3B1696B1ll, 0x9BDC06A725C71235ll,
+ 0xC19BF174CF692694ll, 0xE49B69C19EF14AD2ll, 0xEFBE4786384F25E3ll,
+ 0x0FC19DC68B8CD5B5ll, 0x240CA1CC77AC9C65ll, 0x2DE92C6F592B0275ll,
+ 0x4A7484AA6EA6E483ll, 0x5CB0A9DCBD41FBD4ll, 0x76F988DA831153B5ll,
+ 0x983E5152EE66DFABll, 0xA831C66D2DB43210ll, 0xB00327C898FB213Fll,
+ 0xBF597FC7BEEF0EE4ll, 0xC6E00BF33DA88FC2ll, 0xD5A79147930AA725ll,
+ 0x06CA6351E003826Fll, 0x142929670A0E6E70ll, 0x27B70A8546D22FFCll,
+ 0x2E1B21385C26C926ll, 0x4D2C6DFC5AC42AEDll, 0x53380D139D95B3DFll,
+ 0x650A73548BAF63DEll, 0x766A0ABB3C77B2A8ll, 0x81C2C92E47EDAEE6ll,
+ 0x92722C851482353Bll, 0xA2BFE8A14CF10364ll, 0xA81A664BBC423001ll,
+ 0xC24B8B70D0F89791ll, 0xC76C51A30654BE30ll, 0xD192E819D6EF5218ll,
+ 0xD69906245565A910ll, 0xF40E35855771202All, 0x106AA07032BBD1B8ll,
+ 0x19A4C116B8D2D0C8ll, 0x1E376C085141AB53ll, 0x2748774CDF8EEB99ll,
+ 0x34B0BCB5E19B48A8ll, 0x391C0CB3C5C95A63ll, 0x4ED8AA4AE3418ACBll,
+ 0x5B9CCA4F7763E373ll, 0x682E6FF3D6B2B8A3ll, 0x748F82EE5DEFB2FCll,
+ 0x78A5636F43172F60ll, 0x84C87814A1F0AB72ll, 0x8CC702081A6439ECll,
+ 0x90BEFFFA23631E28ll, 0xA4506CEBDE82BDE9ll, 0xBEF9A3F7B2C67915ll,
+ 0xC67178F2E372532Bll, 0xCA273ECEEA26619Cll, 0xD186B8C721C0C207ll,
+ 0xEADA7DD6CDE0EB1Ell, 0xF57D4F7FEE6ED178ll, 0x06F067AA72176FBAll,
+ 0x0A637DC5A2C898A6ll, 0x113F9804BEF90DAEll, 0x1B710B35131C471Bll,
+ 0x28DB77F523047D84ll, 0x32CAAB7B40C72493ll, 0x3C9EBE0A15C9BEBCll,
+ 0x431D67C49C100D4Cll, 0x4CC5D4BECB3E42B6ll, 0x597F299CFC657E2All,
+ 0x5FCB6FAB3AD6FAECll, 0x6C44198C4A475817ll
+ };
+ int t, t8; /* Loop counter */
+ uint64_t temp1, temp2; /* Temporary word value */
+ uint64_t W[80]; /* Word sequence */
+ uint64_t A, B, C, D, E, F, G, H; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for (t = t8 = 0; t < 16; t++, t8 += 8)
+ W[t] = ((uint64_t)(context->Message_Block[t8 ]) << 56) |
+ ((uint64_t)(context->Message_Block[t8 + 1]) << 48) |
+ ((uint64_t)(context->Message_Block[t8 + 2]) << 40) |
+ ((uint64_t)(context->Message_Block[t8 + 3]) << 32) |
+ ((uint64_t)(context->Message_Block[t8 + 4]) << 24) |
+ ((uint64_t)(context->Message_Block[t8 + 5]) << 16) |
+ ((uint64_t)(context->Message_Block[t8 + 6]) << 8) |
+ ((uint64_t)(context->Message_Block[t8 + 7]));
+
+ for (t = 16; t < 80; t++)
+ W[t] = SHA512_sigma1(W[t-2]) + W[t-7] +
+ SHA512_sigma0(W[t-15]) + W[t-16];
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+ F = context->Intermediate_Hash[5];
+ G = context->Intermediate_Hash[6];
+ H = context->Intermediate_Hash[7];
+
+ for (t = 0; t < 80; t++) {
+ temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t];
+ temp2 = SHA512_SIGMA0(A) + SHA_Maj(A,B,C);
+ H = G;
+ G = F;
+ F = E;
+ E = D + temp1;
+ D = C;
+ C = B;
+ B = A;
+ A = temp1 + temp2;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+ context->Intermediate_Hash[5] += F;
+ context->Intermediate_Hash[6] += G;
+ context->Intermediate_Hash[7] += H;
+#endif /* USE_32BIT_ONLY */
+
+ context->Message_Block_Index = 0;
+}
+
+/*
+ * SHA384_512Finalize
+ *
+ * Description:
+ * This helper function finishes off the digest calculations.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * Pad_Byte: [in]
+ * The last byte to add to the message block before the 0-padding
+ * and length. This will contain the last bits of the message
+ * followed by another single bit. If the message was an
+ * exact multiple of 8-bits long, Pad_Byte will be 0x80.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+static void SHA384_512Finalize(SHA512Context *context,
+ uint8_t Pad_Byte)
+{
+ int_least16_t i;
+ SHA384_512PadMessage(context, Pad_Byte);
+ /* message may be sensitive, clear it out */
+ for (i = 0; i < SHA512_Message_Block_Size; ++i)
+ context->Message_Block[i] = 0;
+#ifdef USE_32BIT_ONLY /* and clear length */
+ context->Length[0] = context->Length[1] = 0;
+ context->Length[2] = context->Length[3] = 0;
+#else /* !USE_32BIT_ONLY */
+ context->Length_High = context->Length_Low = 0;
+#endif /* USE_32BIT_ONLY */
+ context->Computed = 1;
+}
+
+/*
+ * SHA384_512PadMessage
+ *
+ * Description:
+ * According to the standard, the message must be padded to the next
+ * even multiple of 1024 bits. The first padding bit must be a '1'.
+ * The last 128 bits represent the length of the original message.
+ * All bits in between should be 0. This helper function will
+ * pad the message according to those rules by filling the
+ * Message_Block array accordingly. When it returns, it can be
+ * assumed that the message digest has been computed.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to pad.
+ * Pad_Byte: [in]
+ * The last byte to add to the message block before the 0-padding
+ * and length. This will contain the last bits of the message
+ * followed by another single bit. If the message was an
+ * exact multiple of 8-bits long, Pad_Byte will be 0x80.
+ *
+ * Returns:
+ * Nothing.
+ *
+ */
+static void SHA384_512PadMessage(SHA512Context *context,
+ uint8_t Pad_Byte)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (context->Message_Block_Index >= (SHA512_Message_Block_Size-16)) {
+ context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
+ while (context->Message_Block_Index < SHA512_Message_Block_Size)
+ context->Message_Block[context->Message_Block_Index++] = 0;
+
+ SHA384_512ProcessMessageBlock(context);
+ } else
+ context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
+
+ while (context->Message_Block_Index < (SHA512_Message_Block_Size-16))
+ context->Message_Block[context->Message_Block_Index++] = 0;
+
+ /*
+ * Store the message length as the last 16 octets
+ */
+#ifdef USE_32BIT_ONLY
+ context->Message_Block[112] = (uint8_t)(context->Length[0] >> 24);
+ context->Message_Block[113] = (uint8_t)(context->Length[0] >> 16);
+ context->Message_Block[114] = (uint8_t)(context->Length[0] >> 8);
+ context->Message_Block[115] = (uint8_t)(context->Length[0]);
+ context->Message_Block[116] = (uint8_t)(context->Length[1] >> 24);
+ context->Message_Block[117] = (uint8_t)(context->Length[1] >> 16);
+ context->Message_Block[118] = (uint8_t)(context->Length[1] >> 8);
+ context->Message_Block[119] = (uint8_t)(context->Length[1]);
+
+ context->Message_Block[120] = (uint8_t)(context->Length[2] >> 24);
+ context->Message_Block[121] = (uint8_t)(context->Length[2] >> 16);
+ context->Message_Block[122] = (uint8_t)(context->Length[2] >> 8);
+ context->Message_Block[123] = (uint8_t)(context->Length[2]);
+ context->Message_Block[124] = (uint8_t)(context->Length[3] >> 24);
+ context->Message_Block[125] = (uint8_t)(context->Length[3] >> 16);
+ context->Message_Block[126] = (uint8_t)(context->Length[3] >> 8);
+ context->Message_Block[127] = (uint8_t)(context->Length[3]);
+#else /* !USE_32BIT_ONLY */
+ context->Message_Block[112] = (uint8_t)(context->Length_High >> 56);
+ context->Message_Block[113] = (uint8_t)(context->Length_High >> 48);
+ context->Message_Block[114] = (uint8_t)(context->Length_High >> 40);
+ context->Message_Block[115] = (uint8_t)(context->Length_High >> 32);
+ context->Message_Block[116] = (uint8_t)(context->Length_High >> 24);
+ context->Message_Block[117] = (uint8_t)(context->Length_High >> 16);
+ context->Message_Block[118] = (uint8_t)(context->Length_High >> 8);
+ context->Message_Block[119] = (uint8_t)(context->Length_High);
+
+ context->Message_Block[120] = (uint8_t)(context->Length_Low >> 56);
+ context->Message_Block[121] = (uint8_t)(context->Length_Low >> 48);
+ context->Message_Block[122] = (uint8_t)(context->Length_Low >> 40);
+ context->Message_Block[123] = (uint8_t)(context->Length_Low >> 32);
+ context->Message_Block[124] = (uint8_t)(context->Length_Low >> 24);
+ context->Message_Block[125] = (uint8_t)(context->Length_Low >> 16);
+ context->Message_Block[126] = (uint8_t)(context->Length_Low >> 8);
+ context->Message_Block[127] = (uint8_t)(context->Length_Low);
+#endif /* USE_32BIT_ONLY */
+
+ SHA384_512ProcessMessageBlock(context);
+}
+
+/*
+ * SHA384_512ResultN
+ *
+ * Description:
+ * This helper function will return the 384-bit or 512-bit message
+ * digest into the Message_Digest array provided by the caller.
+ * NOTE:
+ * The first octet of hash is stored in the element with index 0,
+ * the last octet of hash in the element with index 47/63.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA hash.
+ * Message_Digest[ ]: [out]
+ * Where the digest is returned.
+ * HashSize: [in]
+ * The size of the hash, either 48 or 64.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+static int SHA384_512ResultN(SHA512Context *context,
+ uint8_t Message_Digest[ ], int HashSize)
+{
+ int i;
+#ifdef USE_32BIT_ONLY
+ int i2;
+#endif /* USE_32BIT_ONLY */
+
+ if (!context) return shaNull;
+ if (!Message_Digest) return shaNull;
+ if (context->Corrupted) return context->Corrupted;
+
+ if (!context->Computed)
+ SHA384_512Finalize(context, 0x80);
+
+#ifdef USE_32BIT_ONLY
+ for (i = i2 = 0; i < HashSize; ) {
+ Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>24);
+ Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>16);
+ Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>8);
+ Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2++]);
+ Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>24);
+ Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>16);
+ Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>8);
+ Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2++]);
+ }
+#else /* !USE_32BIT_ONLY */
+ for (i = 0; i < HashSize; ++i)
+ Message_Digest[i] = (uint8_t)
+ (context->Intermediate_Hash[i>>3] >> 8 * ( 7 - ( i % 8 ) ));
+#endif /* USE_32BIT_ONLY */
+
+ return shaSuccess;
+}
+
+/*****************************************************************/
+/*****************************************************************/
+/*****************************************************************/
+
+/* Define the SHA shift, rotate left, and rotate right macros */
+#define SHA256_SHR(bits,word) ((word) >> (bits))
+#define SHA256_ROTL(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+#define SHA256_ROTR(bits,word) \
+ (((word) >> (bits)) | ((word) << (32-(bits))))
+
+/* Define the SHA SIGMA and sigma macros */
+#define SHA256_SIGMA0(word) \
+ (SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word))
+#define SHA256_SIGMA1(word) \
+ (SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word))
+#define SHA256_sigma0(word) \
+ (SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word))
+#define SHA256_sigma1(word) \
+ (SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word))
+
+/*
+ * Add "length" to the length.
+ * Set Corrupted when overflow has occurred.
+ */
+static unsigned int addTemp;
+#define SHA224_256AddLength(context, length) \
+ (addTemp = (context)->Length_Low, (context)->Corrupted = \
+ (((context)->Length_Low += (length)) < addTemp) && \
+ (++(context)->Length_High == 0) ? shaInputTooLong : \
+ (context)->Corrupted )
+
+/* Local Function Prototypes */
+static int SHA224_256Reset(SHA256Context *context, uint32_t *H0);
+static void SHA224_256ProcessMessageBlock(SHA256Context *context);
+static void SHA224_256Finalize(SHA256Context *context,
+ uint8_t Pad_Byte);
+static void SHA224_256PadMessage(SHA256Context *context,
+ uint8_t Pad_Byte);
+static int SHA224_256ResultN(SHA256Context *context,
+ uint8_t Message_Digest[ ], int HashSize);
+
+/* Initial Hash Values: FIPS 180-3 section 5.3.2 */
+static uint32_t SHA224_H0[SHA256HashSize/4] = {
+ 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939,
+ 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4
+};
+
+/* Initial Hash Values: FIPS 180-3 section 5.3.3 */
+static uint32_t SHA256_H0[SHA256HashSize/4] = {
+ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+ 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
+};
+
+/*
+ * SHA224Reset
+ *
+ * Description:
+ * This function will initialize the SHA224Context in preparation
+ * for computing a new SHA224 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int SHA224Reset(SHA224Context *context)
+{
+ return SHA224_256Reset(context, SHA224_H0);
+}
+
+/*
+ * SHA224Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_array[ ]: [in]
+ * An array of octets representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA224Input(SHA224Context *context, const uint8_t *message_array,
+ unsigned int length)
+{
+ return SHA256Input(context, message_array, length);
+}
+
+/*
+ * SHA224FinalBits
+ *
+ * Description:
+ * This function will add in any final bits of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_bits: [in]
+ * The final bits of the message, in the upper portion of the
+ * byte. (Use 0b###00000 instead of 0b00000### to input the
+ * three bits ###.)
+ * length: [in]
+ * The number of bits in message_bits, between 1 and 7.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int SHA224FinalBits(SHA224Context *context,
+ uint8_t message_bits, unsigned int length)
+{
+ return SHA256FinalBits(context, message_bits, length);
+}
+
+/*
+ * SHA224Result
+ *
+ * Description:
+ * This function will return the 224-bit message digest
+ * into the Message_Digest array provided by the caller.
+ * NOTE:
+ * The first octet of hash is stored in the element with index 0,
+ * the last octet of hash in the element with index 27.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA hash.
+ * Message_Digest[ ]: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int SHA224Result(SHA224Context *context,
+ uint8_t Message_Digest[SHA224HashSize])
+{
+ return SHA224_256ResultN(context, Message_Digest, SHA224HashSize);
+}
+
+/*
+ * SHA256Reset
+ *
+ * Description:
+ * This function will initialize the SHA256Context in preparation
+ * for computing a new SHA256 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int SHA256Reset(SHA256Context *context)
+{
+ return SHA224_256Reset(context, SHA256_H0);
+}
+
+/*
+ * SHA256Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_array[ ]: [in]
+ * An array of octets representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int SHA256Input(SHA256Context *context, const uint8_t *message_array,
+ unsigned int length)
+{
+ if (!context) return shaNull;
+ if (!length) return shaSuccess;
+ if (!message_array) return shaNull;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ if (context->Corrupted) return context->Corrupted;
+
+ while (length--) {
+ context->Message_Block[context->Message_Block_Index++] =
+ *message_array;
+
+ if ((SHA224_256AddLength(context, 8) == shaSuccess) &&
+ (context->Message_Block_Index == SHA256_Message_Block_Size))
+ SHA224_256ProcessMessageBlock(context);
+
+ message_array++;
+ }
+
+ return context->Corrupted;
+
+}
+
+/*
+ * SHA256FinalBits
+ *
+ * Description:
+ * This function will add in any final bits of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_bits: [in]
+ * The final bits of the message, in the upper portion of the
+ * byte. (Use 0b###00000 instead of 0b00000### to input the
+ * three bits ###.)
+ * length: [in]
+ * The number of bits in message_bits, between 1 and 7.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int SHA256FinalBits(SHA256Context *context,
+ uint8_t message_bits, unsigned int length)
+{
+ static uint8_t masks[8] = {
+ /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80,
+ /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0,
+ /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8,
+ /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE
+ };
+ static uint8_t markbit[8] = {
+ /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40,
+ /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10,
+ /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04,
+ /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01
+ };
+
+ if (!context) return shaNull;
+ if (!length) return shaSuccess;
+ if (context->Corrupted) return context->Corrupted;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ if (length >= 8) return context->Corrupted = shaBadParam;
+
+ SHA224_256AddLength(context, length);
+ SHA224_256Finalize(context, (uint8_t)
+ ((message_bits & masks[length]) | markbit[length]));
+
+ return context->Corrupted;
+}
+
+/*
+ * SHA256Result
+ *
+ * Description:
+ * This function will return the 256-bit message digest
+ * into the Message_Digest array provided by the caller.
+ * NOTE:
+ * The first octet of hash is stored in the element with index 0,
+ * the last octet of hash in the element with index 31.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA hash.
+ * Message_Digest[ ]: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int SHA256Result(SHA256Context *context,
+ uint8_t Message_Digest[SHA256HashSize])
+{
+ return SHA224_256ResultN(context, Message_Digest, SHA256HashSize);
+}
+
+/*
+ * SHA224_256Reset
+ *
+ * Description:
+ * This helper function will initialize the SHA256Context in
+ * preparation for computing a new SHA-224 or SHA-256 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ * H0[ ]: [in]
+ * The initial hash value array to use.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+static int SHA224_256Reset(SHA256Context *context, uint32_t *H0)
+{
+ if (!context) return shaNull;
+
+ context->Length_High = context->Length_Low = 0;
+ context->Message_Block_Index = 0;
+
+ context->Intermediate_Hash[0] = H0[0];
+ context->Intermediate_Hash[1] = H0[1];
+ context->Intermediate_Hash[2] = H0[2];
+ context->Intermediate_Hash[3] = H0[3];
+ context->Intermediate_Hash[4] = H0[4];
+ context->Intermediate_Hash[5] = H0[5];
+ context->Intermediate_Hash[6] = H0[6];
+ context->Intermediate_Hash[7] = H0[7];
+
+ context->Computed = 0;
+ context->Corrupted = shaSuccess;
+
+ return shaSuccess;
+}
+
+/*
+ * SHA224_256ProcessMessageBlock
+ *
+ * Description:
+ * This helper function will process the next 512 bits of the
+ * message stored in the Message_Block array.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the
+ * names used in the Secure Hash Standard.
+ */
+static void SHA224_256ProcessMessageBlock(SHA256Context *context)
+{
+ /* Constants defined in FIPS 180-3, section 4.2.2 */
+ static const uint32_t K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,
+ 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,
+ 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
+ 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
+ 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
+ 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
+ 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
+ 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
+ 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+ };
+ int t, t4; /* Loop counter */
+ uint32_t temp1, temp2; /* Temporary word value */
+ uint32_t W[64]; /* Word sequence */
+ uint32_t A, B, C, D, E, F, G, H; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for (t = t4 = 0; t < 16; t++, t4 += 4)
+ W[t] = (((uint32_t)context->Message_Block[t4]) << 24) |
+ (((uint32_t)context->Message_Block[t4 + 1]) << 16) |
+ (((uint32_t)context->Message_Block[t4 + 2]) << 8) |
+ (((uint32_t)context->Message_Block[t4 + 3]));
+ for (t = 16; t < 64; t++)
+ W[t] = SHA256_sigma1(W[t-2]) + W[t-7] +
+ SHA256_sigma0(W[t-15]) + W[t-16];
+
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+ F = context->Intermediate_Hash[5];
+ G = context->Intermediate_Hash[6];
+ H = context->Intermediate_Hash[7];
+
+ for (t = 0; t < 64; t++) {
+ temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t];
+ temp2 = SHA256_SIGMA0(A) + SHA_Maj(A,B,C);
+ H = G;
+ G = F;
+ F = E;
+ E = D + temp1;
+ D = C;
+ C = B;
+ B = A;
+ A = temp1 + temp2;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+ context->Intermediate_Hash[5] += F;
+ context->Intermediate_Hash[6] += G;
+ context->Intermediate_Hash[7] += H;
+
+ context->Message_Block_Index = 0;
+}
+
+/*
+ * SHA224_256Finalize
+ *
+ * Description:
+ * This helper function finishes off the digest calculations.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * Pad_Byte: [in]
+ * The last byte to add to the message block before the 0-padding
+ * and length. This will contain the last bits of the message
+ * followed by another single bit. If the message was an
+ * exact multiple of 8-bits long, Pad_Byte will be 0x80.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+static void SHA224_256Finalize(SHA256Context *context,
+ uint8_t Pad_Byte)
+{
+ int i;
+ SHA224_256PadMessage(context, Pad_Byte);
+ /* message may be sensitive, so clear it out */
+ for (i = 0; i < SHA256_Message_Block_Size; ++i)
+ context->Message_Block[i] = 0;
+ context->Length_High = 0; /* and clear length */
+ context->Length_Low = 0;
+ context->Computed = 1;
+}
+
+/*
+ * SHA224_256PadMessage
+ *
+ * Description:
+ * According to the standard, the message must be padded to the next
+ * even multiple of 512 bits. The first padding bit must be a '1'.
+ * The last 64 bits represent the length of the original message.
+ * All bits in between should be 0. This helper function will pad
+ * the message according to those rules by filling the
+ * Message_Block array accordingly. When it returns, it can be
+ * assumed that the message digest has been computed.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to pad.
+ * Pad_Byte: [in]
+ * The last byte to add to the message block before the 0-padding
+ * and length. This will contain the last bits of the message
+ * followed by another single bit. If the message was an
+ * exact multiple of 8-bits long, Pad_Byte will be 0x80.
+ *
+ * Returns:
+ * Nothing.
+ */
+static void SHA224_256PadMessage(SHA256Context *context,
+ uint8_t Pad_Byte)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (context->Message_Block_Index >= (SHA256_Message_Block_Size-8)) {
+ context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
+ while (context->Message_Block_Index < SHA256_Message_Block_Size)
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ SHA224_256ProcessMessageBlock(context);
+ } else
+ context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
+
+ while (context->Message_Block_Index < (SHA256_Message_Block_Size-8))
+ context->Message_Block[context->Message_Block_Index++] = 0;
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ context->Message_Block[56] = (uint8_t)(context->Length_High >> 24);
+ context->Message_Block[57] = (uint8_t)(context->Length_High >> 16);
+ context->Message_Block[58] = (uint8_t)(context->Length_High >> 8);
+ context->Message_Block[59] = (uint8_t)(context->Length_High);
+ context->Message_Block[60] = (uint8_t)(context->Length_Low >> 24);
+ context->Message_Block[61] = (uint8_t)(context->Length_Low >> 16);
+ context->Message_Block[62] = (uint8_t)(context->Length_Low >> 8);
+ context->Message_Block[63] = (uint8_t)(context->Length_Low);
+
+ SHA224_256ProcessMessageBlock(context);
+}
+
+/*
+ * SHA224_256ResultN
+ *
+ * Description:
+ * This helper function will return the 224-bit or 256-bit message
+ * digest into the Message_Digest array provided by the caller.
+ * NOTE:
+ * The first octet of hash is stored in the element with index 0,
+ * the last octet of hash in the element with index 27/31.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA hash.
+ * Message_Digest[ ]: [out]
+ * Where the digest is returned.
+ * HashSize: [in]
+ * The size of the hash, either 28 or 32.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+static int SHA224_256ResultN(SHA256Context *context,
+ uint8_t Message_Digest[ ], int HashSize)
+{
+ int i;
+
+ if (!context) return shaNull;
+ if (!Message_Digest) return shaNull;
+ if (context->Corrupted) return context->Corrupted;
+
+ if (!context->Computed)
+ SHA224_256Finalize(context, 0x80);
+
+ for (i = 0; i < HashSize; ++i)
+ Message_Digest[i] = (uint8_t)
+ (context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ));
+
+ return shaSuccess;
+}
+
+/*****************************************************************/
+/*****************************************************************/
+/*****************************************************************/
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1_ROTL(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/*
+ * Add "length" to the length.
+ * Set Corrupted when overflow has occurred.
+ */
+static unsigned int addTemp;
+#define SHA1AddLength(context, length) \
+ (addTemp = (context)->Length_Low, \
+ (context)->Corrupted = \
+ (((context)->Length_Low += (length)) < addTemp) && \
+ (++(context)->Length_High == 0) ? shaInputTooLong \
+ : (context)->Corrupted )
+
+/* Local Function Prototypes */
+static void SHA1ProcessMessageBlock(SHA1Context *context);
+static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte);
+static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte);
+
+/*
+ * SHA1Reset
+ *
+ * Description:
+ * This function will initialize the SHA1Context in preparation
+ * for computing a new SHA1 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Reset(SHA1Context *context)
+{
+ if (!context) return shaNull;
+
+ context->Length_High = context->Length_Low = 0;
+ context->Message_Block_Index = 0;
+
+ /* Initial Hash Values: FIPS 180-3 section 5.3.1 */
+ context->Intermediate_Hash[0] = 0x67452301;
+ context->Intermediate_Hash[1] = 0xEFCDAB89;
+ context->Intermediate_Hash[2] = 0x98BADCFE;
+ context->Intermediate_Hash[3] = 0x10325476;
+ context->Intermediate_Hash[4] = 0xC3D2E1F0;
+
+ context->Computed = 0;
+ context->Corrupted = shaSuccess;
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_array[ ]: [in]
+ * An array of octets representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Input(SHA1Context *context,
+ const uint8_t *message_array, unsigned length)
+{
+ if (!context) return shaNull;
+ if (!length) return shaSuccess;
+ if (!message_array) return shaNull;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ if (context->Corrupted) return context->Corrupted;
+
+ while (length--) {
+ context->Message_Block[context->Message_Block_Index++] =
+ *message_array;
+
+ if ((SHA1AddLength(context, 8) == shaSuccess) &&
+ (context->Message_Block_Index == SHA1_Message_Block_Size))
+ SHA1ProcessMessageBlock(context);
+
+ message_array++;
+ }
+
+ return context->Corrupted;
+}
+
+/*
+ * SHA1FinalBits
+ *
+ * Description:
+ * This function will add in any final bits of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_bits: [in]
+ * The final bits of the message, in the upper portion of the
+ * byte. (Use 0b###00000 instead of 0b00000### to input the
+ * three bits ###.)
+ * length: [in]
+ * The number of bits in message_bits, between 1 and 7.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int SHA1FinalBits(SHA1Context *context, uint8_t message_bits,
+ unsigned int length)
+{
+ static uint8_t masks[8] = {
+ /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80,
+ /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0,
+ /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8,
+ /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE
+ };
+
+ static uint8_t markbit[8] = {
+ /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40,
+ /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10,
+ /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04,
+ /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01
+ };
+
+ if (!context) return shaNull;
+ if (!length) return shaSuccess;
+ if (context->Corrupted) return context->Corrupted;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ if (length >= 8) return context->Corrupted = shaBadParam;
+
+ SHA1AddLength(context, length);
+ SHA1Finalize(context,
+ (uint8_t) ((message_bits & masks[length]) | markbit[length]));
+
+ return context->Corrupted;
+}
+
+/*
+ * SHA1Result
+ *
+ * Description:
+ * This function will return the 160-bit message digest
+ * into the Message_Digest array provided by the caller.
+ * NOTE:
+ * The first octet of hash is stored in the element with index 0,
+ * the last octet of hash in the element with index 19.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA-1 hash.
+ * Message_Digest[ ]: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Result(SHA1Context *context,
+ uint8_t Message_Digest[SHA1HashSize])
+{
+ int i;
+
+ if (!context) return shaNull;
+ if (!Message_Digest) return shaNull;
+ if (context->Corrupted) return context->Corrupted;
+
+ if (!context->Computed)
+ SHA1Finalize(context, 0x80);
+
+ for (i = 0; i < SHA1HashSize; ++i)
+ Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i>>2]
+ >> (8 * ( 3 - ( i & 0x03 ) )));
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1ProcessMessageBlock
+ *
+ * Description:
+ * This helper function will process the next 512 bits of the
+ * message stored in the Message_Block array.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the
+ * names used in the Secure Hash Standard.
+ */
+static void SHA1ProcessMessageBlock(SHA1Context *context)
+{
+ /* Constants defined in FIPS 180-3, section 4.2.1 */
+ const uint32_t K[4] = {
+ 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6
+ };
+
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for (t = 0; t < 16; t++) {
+ W[t] = ((uint32_t)context->Message_Block[t * 4]) << 24;
+ W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16;
+ W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8;
+ W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]);
+ }
+
+ for (t = 16; t < 80; t++)
+ W[t] = SHA1_ROTL(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+
+ for (t = 0; t < 20; t++) {
+ temp = SHA1_ROTL(5,A) + SHA_Ch(B, C, D) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1_ROTL(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 20; t < 40; t++) {
+ temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1_ROTL(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 40; t < 60; t++) {
+ temp = SHA1_ROTL(5,A) + SHA_Maj(B, C, D) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1_ROTL(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 60; t < 80; t++) {
+ temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1_ROTL(30,B);
+ B = A;
+ A = temp;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+ context->Message_Block_Index = 0;
+}
+
+/*
+ * SHA1Finalize
+ *
+ * Description:
+ * This helper function finishes off the digest calculations.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * Pad_Byte: [in]
+ * The last byte to add to the message block before the 0-padding
+ * and length. This will contain the last bits of the message
+ * followed by another single bit. If the message was an
+ * exact multiple of 8-bits long, Pad_Byte will be 0x80.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte)
+{
+ int i;
+ SHA1PadMessage(context, Pad_Byte);
+ /* message may be sensitive, clear it out */
+ for (i = 0; i < SHA1_Message_Block_Size; ++i)
+ context->Message_Block[i] = 0;
+ context->Length_High = 0; /* and clear length */
+ context->Length_Low = 0;
+ context->Computed = 1;
+}
+
+/*
+ * SHA1PadMessage
+ *
+ * Description:
+ * According to the standard, the message must be padded to the next
+ * even multiple of 512 bits. The first padding bit must be a '1'.
+ * The last 64 bits represent the length of the original message.
+ * All bits in between should be 0. This helper function will pad
+ * the message according to those rules by filling the Message_Block
+ * array accordingly. When it returns, it can be assumed that the
+ * message digest has been computed.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to pad.
+ * Pad_Byte: [in]
+ * The last byte to add to the message block before the 0-padding
+ * and length. This will contain the last bits of the message
+ * followed by another single bit. If the message was an
+ * exact multiple of 8-bits long, Pad_Byte will be 0x80.
+ *
+ * Returns:
+ * Nothing.
+ */
+static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (context->Message_Block_Index >= (SHA1_Message_Block_Size - 8)) {
+ context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
+ while (context->Message_Block_Index < SHA1_Message_Block_Size)
+ context->Message_Block[context->Message_Block_Index++] = 0;
+
+ SHA1ProcessMessageBlock(context);
+ } else
+ context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
+
+ while (context->Message_Block_Index < (SHA1_Message_Block_Size - 8))
+ context->Message_Block[context->Message_Block_Index++] = 0;
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ context->Message_Block[56] = (uint8_t) (context->Length_High >> 24);
+ context->Message_Block[57] = (uint8_t) (context->Length_High >> 16);
+ context->Message_Block[58] = (uint8_t) (context->Length_High >> 8);
+ context->Message_Block[59] = (uint8_t) (context->Length_High);
+ context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24);
+ context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16);
+ context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8);
+ context->Message_Block[63] = (uint8_t) (context->Length_Low);
+
+ SHA1ProcessMessageBlock(context);
+}
+
+/*****************************************************************/
+/*****************************************************************/
+/*****************************************************************/
+
+/*
+ * USHAReset
+ *
+ * Description:
+ * This function will initialize the SHA Context in preparation
+ * for computing a new SHA message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ * whichSha: [in]
+ * Selects which SHA reset to call
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int USHAReset(USHAContext *context, enum SHAversion whichSha)
+{
+ if (!context) return shaNull;
+ context->whichSha = whichSha;
+ switch (whichSha) {
+ case SHA1: return SHA1Reset((SHA1Context*)&context->ctx);
+ case SHA224: return SHA224Reset((SHA224Context*)&context->ctx);
+ case SHA256: return SHA256Reset((SHA256Context*)&context->ctx);
+ case SHA384: return SHA384Reset((SHA384Context*)&context->ctx);
+ case SHA512: return SHA512Reset((SHA512Context*)&context->ctx);
+ default: return shaBadParam;
+ }
+}
+
+/*
+ * USHAInput
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_array: [in]
+ * An array of octets representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int USHAInput(USHAContext *context,
+ const uint8_t *bytes, unsigned int bytecount)
+{
+ if (!context) return shaNull;
+ switch (context->whichSha) {
+ case SHA1:
+ return SHA1Input((SHA1Context*)&context->ctx, bytes,
+ bytecount);
+ case SHA224:
+ return SHA224Input((SHA224Context*)&context->ctx, bytes,
+ bytecount);
+ case SHA256:
+ return SHA256Input((SHA256Context*)&context->ctx, bytes,
+ bytecount);
+ case SHA384:
+ return SHA384Input((SHA384Context*)&context->ctx, bytes,
+ bytecount);
+ case SHA512:
+ return SHA512Input((SHA512Context*)&context->ctx, bytes,
+ bytecount);
+ default: return shaBadParam;
+ }
+}
+
+/*
+ * USHAFinalBits
+ *
+ * Description:
+ * This function will add in any final bits of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update.
+ * message_bits: [in]
+ * The final bits of the message, in the upper portion of the
+ * byte. (Use 0b###00000 instead of 0b00000### to input the
+ * three bits ###.)
+ * length: [in]
+ * The number of bits in message_bits, between 1 and 7.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int USHAFinalBits(USHAContext *context,
+ uint8_t bits, unsigned int bit_count)
+{
+ if (!context) return shaNull;
+ switch (context->whichSha) {
+ case SHA1:
+ return SHA1FinalBits((SHA1Context*)&context->ctx, bits,
+ bit_count);
+ case SHA224:
+ return SHA224FinalBits((SHA224Context*)&context->ctx, bits,
+ bit_count);
+ case SHA256:
+ return SHA256FinalBits((SHA256Context*)&context->ctx, bits,
+ bit_count);
+ case SHA384:
+ return SHA384FinalBits((SHA384Context*)&context->ctx, bits,
+ bit_count);
+ case SHA512:
+ return SHA512FinalBits((SHA512Context*)&context->ctx, bits,
+ bit_count);
+ default: return shaBadParam;
+ }
+}
+
+/*
+ * USHAResult
+ *
+ * Description:
+ * This function will return the message digest of the appropriate
+ * bit size, as returned by USHAHashSizeBits(whichSHA) for the
+ * 'whichSHA' value used in the preceeding call to USHAReset,
+ * into the Message_Digest array provided by the caller.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA-1 hash.
+ * Message_Digest: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int USHAResult(USHAContext *context,
+ uint8_t Message_Digest[USHAMaxHashSize])
+{
+ if (!context) return shaNull;
+ switch (context->whichSha) {
+ case SHA1:
+ return SHA1Result((SHA1Context*)&context->ctx, Message_Digest);
+ case SHA224:
+ return SHA224Result((SHA224Context*)&context->ctx,
+ Message_Digest);
+ case SHA256:
+ return SHA256Result((SHA256Context*)&context->ctx,
+ Message_Digest);
+ case SHA384:
+ return SHA384Result((SHA384Context*)&context->ctx,
+ Message_Digest);
+ case SHA512:
+ return SHA512Result((SHA512Context*)&context->ctx,
+ Message_Digest);
+ default: return shaBadParam;
+ }
+}
+
+/*
+ * USHABlockSize
+ *
+ * Description:
+ * This function will return the blocksize for the given SHA
+ * algorithm.
+ *
+ * Parameters:
+ * whichSha:
+ * which SHA algorithm to query
+ *
+ * Returns:
+ * block size
+ *
+ */
+int USHABlockSize(enum SHAversion whichSha)
+{
+ switch (whichSha) {
+ case SHA1: return SHA1_Message_Block_Size;
+ case SHA224: return SHA224_Message_Block_Size;
+ case SHA256: return SHA256_Message_Block_Size;
+ case SHA384: return SHA384_Message_Block_Size;
+ default:
+ case SHA512: return SHA512_Message_Block_Size;
+ }
+}
+
+/*
+ * USHAHashSize
+ *
+ * Description:
+ * This function will return the hashsize for the given SHA
+ * algorithm.
+ *
+ * Parameters:
+ * whichSha:
+ * which SHA algorithm to query
+ *
+ * Returns:
+ * hash size
+ *
+ */
+int USHAHashSize(enum SHAversion whichSha)
+{
+ switch (whichSha) {
+ case SHA1: return SHA1HashSize;
+ case SHA224: return SHA224HashSize;
+ case SHA256: return SHA256HashSize;
+ case SHA384: return SHA384HashSize;
+ default:
+ case SHA512: return SHA512HashSize;
+ }
+}
+
+/*
+ * USHAHashSizeBits
+ *
+ * Description:
+ * This function will return the hashsize for the given SHA
+ * algorithm, expressed in bits.
+ *
+ * Parameters:
+ * whichSha:
+ * which SHA algorithm to query
+ *
+ * Returns:
+ * hash size in bits
+ *
+ */
+int USHAHashSizeBits(enum SHAversion whichSha)
+{
+ switch (whichSha) {
+ case SHA1: return SHA1HashSizeBits;
+ case SHA224: return SHA224HashSizeBits;
+ case SHA256: return SHA256HashSizeBits;
+ case SHA384: return SHA384HashSizeBits;
+ default:
+ case SHA512: return SHA512HashSizeBits;
+ }
+}
+
+/*
+ * USHAHashName
+ *
+ * Description:
+ * This function will return the name of the given SHA algorithm
+ * as a string.
+ *
+ * Parameters:
+ * whichSha:
+ * which SHA algorithm to query
+ *
+ * Returns:
+ * character string with the name in it
+ *
+ */
+const char *USHAHashName(enum SHAversion whichSha)
+{
+ switch (whichSha) {
+ case SHA1: return "SHA1";
+ case SHA224: return "SHA224";
+ case SHA256: return "SHA256";
+ case SHA384: return "SHA384";
+ default:
+ case SHA512: return "SHA512";
+ }
+}
+
+/*****************************************************************/
+/*****************************************************************/
+/*****************************************************************/
+
+/*
+ * hmac
+ *
+ * Description:
+ * This function will compute an HMAC message digest.
+ *
+ * Parameters:
+ * whichSha: [in]
+ * One of SHA1, SHA224, SHA256, SHA384, SHA512
+ * message_array[ ]: [in]
+ * An array of octets representing the message.
+ * Note: in RFC 2104, this parameter is known
+ * as 'text'.
+ * length: [in]
+ * The length of the message in message_array.
+ * key[ ]: [in]
+ * The secret shared key.
+ * key_len: [in]
+ * The length of the secret shared key.
+ * digest[ ]: [out]
+ * Where the digest is to be returned.
+ * NOTE: The length of the digest is determined by
+ * the value of whichSha.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+
+int hmac(SHAversion whichSha,
+ const unsigned char *message_array, int length,
+ const unsigned char *key, int key_len,
+ uint8_t digest[USHAMaxHashSize])
+{
+ HMACContext context;
+ return hmacReset(&context, whichSha, key, key_len) ||
+ hmacInput(&context, message_array, length) ||
+ hmacResult(&context, digest);
+}
+
+/*
+ * hmacReset
+ *
+ * Description:
+ * This function will initialize the hmacContext in preparation
+ * for computing a new HMAC message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ * whichSha: [in]
+ * One of SHA1, SHA224, SHA256, SHA384, SHA512
+ * key[ ]: [in]
+ * The secret shared key.
+ * key_len: [in]
+ * The length of the secret shared key.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int hmacReset(HMACContext *context, enum SHAversion whichSha,
+ const unsigned char *key, int key_len)
+{
+ int i, blocksize, hashsize, ret;
+
+ /* inner padding - key XORd with ipad */
+ unsigned char k_ipad[USHA_Max_Message_Block_Size];
+
+ /* temporary buffer when keylen > blocksize */
+ unsigned char tempkey[USHAMaxHashSize];
+
+ if (!context) return shaNull;
+ context->Computed = 0;
+ context->Corrupted = shaSuccess;
+
+ blocksize = context->blockSize = USHABlockSize(whichSha);
+ hashsize = context->hashSize = USHAHashSize(whichSha);
+ context->whichSha = whichSha;
+
+ /*
+ * If key is longer than the hash blocksize,
+ * reset it to key = HASH(key).
+ */
+ if (key_len > blocksize) {
+ USHAContext tcontext;
+ int err = USHAReset(&tcontext, whichSha) ||
+ USHAInput(&tcontext, key, key_len) ||
+ USHAResult(&tcontext, tempkey);
+ if (err != shaSuccess) return err;
+
+ key = tempkey;
+ key_len = hashsize;
+ }
+
+ /*
+ * The HMAC transform looks like:
+ *
+ * SHA(K XOR opad, SHA(K XOR ipad, text))
+ *
+ * where K is an n byte key, 0-padded to a total of blocksize bytes,
+ * ipad is the byte 0x36 repeated blocksize times,
+ * opad is the byte 0x5c repeated blocksize times,
+ * and text is the data being protected.
+ */
+
+ /* store key into the pads, XOR'd with ipad and opad values */
+ for (i = 0; i < key_len; i++) {
+ k_ipad[i] = key[i] ^ 0x36;
+ context->k_opad[i] = key[i] ^ 0x5c;
+ }
+ /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
+ for ( ; i < blocksize; i++) {
+ k_ipad[i] = 0x36;
+ context->k_opad[i] = 0x5c;
+ }
+
+ /* perform inner hash */
+ /* init context for 1st pass */
+ ret = USHAReset(&context->shaContext, whichSha) ||
+ /* and start with inner pad */
+ USHAInput(&context->shaContext, k_ipad, blocksize);
+ return context->Corrupted = ret;
+}
+
+/*
+ * hmacInput
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message. It may be called multiple times.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The HMAC context to update.
+ * text[ ]: [in]
+ * An array of octets representing the next portion of
+ * the message.
+ * text_len: [in]
+ * The length of the message in text.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int hmacInput(HMACContext *context, const unsigned char *text,
+ int text_len)
+{
+ if (!context) return shaNull;
+ if (context->Corrupted) return context->Corrupted;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ /* then text of datagram */
+ return context->Corrupted =
+ USHAInput(&context->shaContext, text, text_len);
+}
+
+/*
+ * hmacFinalBits
+ *
+ * Description:
+ * This function will add in any final bits of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The HMAC context to update.
+ * message_bits: [in]
+ * The final bits of the message, in the upper portion of the
+ * byte. (Use 0b###00000 instead of 0b00000### to input the
+ * three bits ###.)
+ * length: [in]
+ * The number of bits in message_bits, between 1 and 7.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int hmacFinalBits(HMACContext *context,
+ uint8_t bits, unsigned int bit_count)
+{
+ if (!context) return shaNull;
+ if (context->Corrupted) return context->Corrupted;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ /* then final bits of datagram */
+ return context->Corrupted =
+ USHAFinalBits(&context->shaContext, bits, bit_count);
+}
+
+/*
+ * hmacResult
+ *
+ * Description:
+ * This function will return the N-byte message digest into the
+ * Message_Digest array provided by the caller.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the HMAC hash.
+ * digest[ ]: [out]
+ * Where the digest is returned.
+ * NOTE 2: The length of the hash is determined by the value of
+ * whichSha that was passed to hmacReset().
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int hmacResult(HMACContext *context, uint8_t digest[USHAMaxHashSize])
+{
+ int ret;
+ if (!context) return shaNull;
+ if (context->Corrupted) return context->Corrupted;
+ if (context->Computed) return context->Corrupted = shaStateError;
+
+ /* finish up 1st pass */
+ /* (Use digest here as a temporary buffer.) */
+ ret =
+ USHAResult(&context->shaContext, digest) ||
+
+ /* perform outer SHA */
+ /* init context for 2nd pass */
+ USHAReset(&context->shaContext, context->whichSha) ||
+
+ /* start with outer pad */
+ USHAInput(&context->shaContext, context->k_opad,
+ context->blockSize) ||
+
+ /* then results of 1st hash */
+ USHAInput(&context->shaContext, digest, context->hashSize) ||
+ /* finish up 2nd pass */
+ USHAResult(&context->shaContext, digest);
+
+ context->Computed = 1;
+ return context->Corrupted = ret;
+}
+
+/*
+ * hkdf
+ *
+ * Description:
+ * This function will generate keying material using HKDF.
+ *
+ * Parameters:
+ * whichSha: [in]
+ * One of SHA1, SHA224, SHA256, SHA384, SHA512
+ * salt[ ]: [in]
+ * The optional salt value (a non-secret random value);
+ * if not provided (salt == NULL), it is set internally
+ * to a string of HashLen(whichSha) zeros.
+ * salt_len: [in]
+ * The length of the salt value. (Ignored if salt == NULL.)
+ * ikm[ ]: [in]
+ * Input keying material.
+ * ikm_len: [in]
+ * The length of the input keying material.
+ * info[ ]: [in]
+ * The optional context and application specific information.
+ * If info == NULL or a zero-length string, it is ignored.
+ * info_len: [in]
+ * The length of the optional context and application specific
+ * information. (Ignored if info == NULL.)
+ * okm[ ]: [out]
+ * Where the HKDF is to be stored.
+ * okm_len: [in]
+ * The length of the buffer to hold okm.
+ * okm_len must be <= 255 * USHABlockSize(whichSha)
+ *
+ * Notes:
+ * Calls hkdfExtract() and hkdfExpand().
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int hkdf(SHAversion whichSha,
+ const unsigned char *salt, int salt_len,
+ const unsigned char *ikm, int ikm_len,
+ const unsigned char *info, int info_len,
+ uint8_t okm[ ], int okm_len)
+{
+ uint8_t prk[USHAMaxHashSize];
+ return hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) ||
+ hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
+ info_len, okm, okm_len);
+}
+
+/*
+ * hkdfExtract
+ *
+ * Description:
+ * This function will perform HKDF extraction.
+ *
+ * Parameters:
+ * whichSha: [in]
+ * One of SHA1, SHA224, SHA256, SHA384, SHA512
+ * salt[ ]: [in]
+ * The optional salt value (a non-secret random value);
+ * if not provided (salt == NULL), it is set internally
+ * to a string of HashLen(whichSha) zeros.
+ * salt_len: [in]
+ * The length of the salt value. (Ignored if salt == NULL.)
+ * ikm[ ]: [in]
+ * Input keying material.
+ * ikm_len: [in]
+ * The length of the input keying material.
+ * prk[ ]: [out]
+ * Array where the HKDF extraction is to be stored.
+ * Must be larger than USHAHashSize(whichSha);
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int hkdfExtract(SHAversion whichSha,
+ const unsigned char *salt, int salt_len,
+ const unsigned char *ikm, int ikm_len,
+ uint8_t prk[USHAMaxHashSize])
+{
+ unsigned char nullSalt[USHAMaxHashSize];
+ if (salt == 0) {
+ salt = nullSalt;
+ salt_len = USHAHashSize(whichSha);
+ memset(nullSalt, '\0', salt_len);
+ } else if (salt_len < 0) {
+ return shaBadParam;
+ }
+ return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
+}
+
+/*
+ * hkdfExpand
+ *
+ * Description:
+ * This function will perform HKDF expansion.
+ *
+ * Parameters:
+ * whichSha: [in]
+ * One of SHA1, SHA224, SHA256, SHA384, SHA512
+ * prk[ ]: [in]
+ * The pseudo-random key to be expanded; either obtained
+ * directly from a cryptographically strong, uniformly
+ * distributed pseudo-random number generator, or as the
+ * output from hkdfExtract().
+ * prk_len: [in]
+ * The length of the pseudo-random key in prk;
+ * should at least be equal to USHAHashSize(whichSHA).
+ * info[ ]: [in]
+ * The optional context and application specific information.
+ * If info == NULL or a zero-length string, it is ignored.
+ * info_len: [in]
+ * The length of the optional context and application specific
+ * information. (Ignored if info == NULL.)
+ * okm[ ]: [out]
+ * Where the HKDF is to be stored.
+ * okm_len: [in]
+ * The length of the buffer to hold okm.
+ * okm_len must be <= 255 * USHABlockSize(whichSha)
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], int prk_len,
+ const unsigned char *info, int info_len,
+ uint8_t okm[ ], int okm_len)
+{
+ int hash_len, N;
+ unsigned char T[USHAMaxHashSize];
+ int Tlen, where, i;
+
+ if (info == 0) {
+ info = (const unsigned char *)"";
+ info_len = 0;
+ } else if (info_len < 0) {
+ return shaBadParam;
+ }
+ if (okm_len <= 0) return shaBadParam;
+ if (!okm) return shaBadParam;
+
+ hash_len = USHAHashSize(whichSha);
+ if (prk_len < hash_len) return shaBadParam;
+ N = okm_len / hash_len;
+ if ((okm_len % hash_len) != 0) N++;
+ if (N > 255) return shaBadParam;
+
+ Tlen = 0;
+ where = 0;
+ for (i = 1; i <= N; i++) {
+ HMACContext context;
+ unsigned char c = i;
+ int ret = hmacReset(&context, whichSha, prk, prk_len) ||
+ hmacInput(&context, T, Tlen) ||
+ hmacInput(&context, info, info_len) ||
+ hmacInput(&context, &c, 1) ||
+ hmacResult(&context, T);
+ if (ret != shaSuccess) return ret;
+ memcpy(okm + where, T,
+ (i != N) ? hash_len : (okm_len - where));
+ where += hash_len;
+ Tlen = hash_len;
+ }
+ return shaSuccess;
+}
+
+/*
+ * hkdfReset
+ *
+ * Description:
+ * This function will initialize the hkdfContext in preparation
+ * for key derivation using the modular HKDF interface for
+ * arbitrary length inputs.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ * whichSha: [in]
+ * One of SHA1, SHA224, SHA256, SHA384, SHA512
+ * salt[ ]: [in]
+ * The optional salt value (a non-secret random value);
+ * if not provided (salt == NULL), it is set internally
+ * to a string of HashLen(whichSha) zeros.
+ * salt_len: [in]
+ * The length of the salt value. (Ignored if salt == NULL.)
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
+ const unsigned char *salt, int salt_len)
+{
+ unsigned char nullSalt[USHAMaxHashSize];
+ if (!context) return shaNull;
+
+ context->whichSha = whichSha;
+ context->hashSize = USHAHashSize(whichSha);
+ if (salt == 0) {
+ salt = nullSalt;
+ salt_len = context->hashSize;
+ memset(nullSalt, '\0', salt_len);
+ }
+
+ return hmacReset(&context->hmacContext, whichSha, salt, salt_len);
+}
+
+/*
+ * hkdfInput
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the input keying material. It may be called multiple times.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The HKDF context to update.
+ * ikm[ ]: [in]
+ * An array of octets representing the next portion of
+ * the input keying material.
+ * ikm_len: [in]
+ * The length of ikm.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int hkdfInput(HKDFContext *context, const unsigned char *ikm,
+ int ikm_len)
+{
+ if (!context) return shaNull;
+ if (context->Corrupted) return context->Corrupted;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ return hmacInput(&context->hmacContext, ikm, ikm_len);
+}
+
+/*
+ * hkdfFinalBits
+ *
+ * Description:
+ * This function will add in any final bits of the
+ * input keying material.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The HKDF context to update
+ * ikm_bits: [in]
+ * The final bits of the input keying material, in the upper
+ * portion of the byte. (Use 0b###00000 instead of 0b00000###
+ * to input the three bits ###.)
+ * ikm_bit_count: [in]
+ * The number of bits in message_bits, between 1 and 7.
+ *
+ * Returns:
+ * sha Error Code.
+ */
+int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
+ unsigned int ikm_bit_count)
+{
+ if (!context) return shaNull;
+ if (context->Corrupted) return context->Corrupted;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count);
+}
+
+/*
+ * hkdfResult
+ *
+ * Description:
+ * This function will finish the HKDF extraction and perform the
+ * final HKDF expansion.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The HKDF context to use to calculate the HKDF hash.
+ * prk[ ]: [out]
+ * An optional location to store the HKDF extraction.
+ * Either NULL, or pointer to a buffer that must be
+ * larger than USHAHashSize(whichSha);
+ * info[ ]: [in]
+ * The optional context and application specific information.
+ * If info == NULL or a zero-length string, it is ignored.
+ * info_len: [in]
+ * The length of the optional context and application specific
+ * information. (Ignored if info == NULL.)
+ * okm[ ]: [out]
+ * Where the HKDF is to be stored.
+ * okm_len: [in]
+ * The length of the buffer to hold okm.
+ * okm_len must be <= 255 * USHABlockSize(whichSha)
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int hkdfResult(HKDFContext *context,
+ uint8_t prk[USHAMaxHashSize],
+ const unsigned char *info, int info_len,
+ uint8_t okm[USHAMaxHashSize], int okm_len)
+{
+ uint8_t prkbuf[USHAMaxHashSize];
+ int ret;
+
+ if (!context) return shaNull;
+ if (context->Corrupted) return context->Corrupted;
+ if (context->Computed) return context->Corrupted = shaStateError;
+ if (!okm) return context->Corrupted = shaBadParam;
+ if (!prk) prk = prkbuf;
+
+ ret = hmacResult(&context->hmacContext, prk) ||
+ hkdfExpand(context->whichSha, prk, context->hashSize, info,
+ info_len, okm, okm_len);
+ context->Computed = 1;
+ return context->Corrupted = ret;
+}
+
diff --git a/src/crypto-rfc6234.h b/src/crypto-rfc6234.h
new file mode 100644
index 00000000..777bb00d
--- /dev/null
+++ b/src/crypto-rfc6234.h
@@ -0,0 +1,357 @@
+/***************** See RFC 6234 for details. *******************/
+/*
+ Copyright (c) 2011 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, are permitted provided that the following
+ conditions are met:
+
+ - Redistributions of source code must retain the above
+ copyright notice, this list of conditions and
+ the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ - Neither the name of Internet Society, IETF or IETF Trust, nor
+ the names of specific contributors, may be used to endorse or
+ promote products derived from this software without specific
+ prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef _SHA_H_
+#define _SHA_H_
+
+/*
+ * Description:
+ * This file implements the Secure Hash Algorithms
+ * as defined in the U.S. National Institute of Standards
+ * and Technology Federal Information Processing Standards
+ * Publication (FIPS PUB) 180-3 published in October 2008
+ * and formerly defined in its predecessors, FIPS PUB 180-1
+ * and FIP PUB 180-2.
+ *
+ * A combined document showing all algorithms is available at
+ * http://csrc.nist.gov/publications/fips/
+ * fips180-3/fips180-3_final.pdf
+ *
+ * The five hashes are defined in these sizes:
+ * SHA-1 20 byte / 160 bit
+ * SHA-224 28 byte / 224 bit
+ * SHA-256 32 byte / 256 bit
+ * SHA-384 48 byte / 384 bit
+ * SHA-512 64 byte / 512 bit
+ *
+ * Compilation Note:
+ * These files may be compiled with two options:
+ * USE_32BIT_ONLY - use 32-bit arithmetic only, for systems
+ * without 64-bit integers
+ *
+ * USE_MODIFIED_MACROS - use alternate form of the SHA_Ch()
+ * and SHA_Maj() macros that are equivalent
+ * and potentially faster on many systems
+ *
+ */
+
+#include
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typedef the following:
+ * name meaning
+ * uint64_t unsigned 64-bit integer
+ * uint32_t unsigned 32-bit integer
+ * uint8_t unsigned 8-bit integer (i.e., unsigned char)
+ * int_least16_t integer of >= 16 bits
+ *
+ * See stdint-example.h
+ */
+
+#ifndef _SHA_enum_
+#define _SHA_enum_
+/*
+ * All SHA functions return one of these values.
+ */
+enum {
+ shaSuccess = 0,
+ shaNull, /* Null pointer parameter */
+ shaInputTooLong, /* input data too long */
+ shaStateError, /* called Input after FinalBits or Result */
+ shaBadParam /* passed a bad parameter */
+};
+#endif /* _SHA_enum_ */
+
+/*
+ * These constants hold size information for each of the SHA
+ * hashing operations
+ */
+enum {
+ SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64,
+ SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128,
+ SHA512_Message_Block_Size = 128,
+ USHA_Max_Message_Block_Size = SHA512_Message_Block_Size,
+
+ SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32,
+ SHA384HashSize = 48, SHA512HashSize = 64,
+ USHAMaxHashSize = SHA512HashSize,
+
+ SHA1HashSizeBits = 160, SHA224HashSizeBits = 224,
+ SHA256HashSizeBits = 256, SHA384HashSizeBits = 384,
+ SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits
+};
+
+/*
+ * These constants are used in the USHA (Unified SHA) functions.
+ */
+typedef enum SHAversion {
+ SHA1, SHA224, SHA256, SHA384, SHA512
+} SHAversion;
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation.
+ */
+typedef struct SHA1Context {
+ uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
+
+ uint32_t Length_High; /* Message length in bits */
+ uint32_t Length_Low; /* Message length in bits */
+
+ int_least16_t Message_Block_Index; /* Message_Block array index */
+ /* 512-bit message blocks */
+ uint8_t Message_Block[SHA1_Message_Block_Size];
+
+ int Computed; /* Is the hash computed? */
+ int Corrupted; /* Cumulative corruption code */
+} SHA1Context;
+
+/*
+ * This structure will hold context information for the SHA-256
+ * hashing operation.
+ */
+typedef struct SHA256Context {
+ uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */
+
+ uint32_t Length_High; /* Message length in bits */
+ uint32_t Length_Low; /* Message length in bits */
+
+ int_least16_t Message_Block_Index; /* Message_Block array index */
+ /* 512-bit message blocks */
+ uint8_t Message_Block[SHA256_Message_Block_Size];
+
+ int Computed; /* Is the hash computed? */
+ int Corrupted; /* Cumulative corruption code */
+} SHA256Context;
+
+/*
+ * This structure will hold context information for the SHA-512
+ * hashing operation.
+ */
+typedef struct SHA512Context {
+#ifdef USE_32BIT_ONLY
+ uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */
+ uint32_t Length[4]; /* Message length in bits */
+#else /* !USE_32BIT_ONLY */
+ uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */
+ uint64_t Length_High, Length_Low; /* Message length in bits */
+#endif /* USE_32BIT_ONLY */
+
+ int_least16_t Message_Block_Index; /* Message_Block array index */
+ /* 1024-bit message blocks */
+ uint8_t Message_Block[SHA512_Message_Block_Size];
+
+ int Computed; /* Is the hash computed?*/
+ int Corrupted; /* Cumulative corruption code */
+} SHA512Context;
+
+/*
+ * This structure will hold context information for the SHA-224
+ * hashing operation. It uses the SHA-256 structure for computation.
+ */
+typedef struct SHA256Context SHA224Context;
+
+/*
+ * This structure will hold context information for the SHA-384
+ * hashing operation. It uses the SHA-512 structure for computation.
+ */
+typedef struct SHA512Context SHA384Context;
+
+/*
+ * This structure holds context information for all SHA
+ * hashing operations.
+ */
+typedef struct USHAContext {
+ int whichSha; /* which SHA is being used */
+ union {
+ SHA1Context sha1Context;
+ SHA224Context sha224Context; SHA256Context sha256Context;
+ SHA384Context sha384Context; SHA512Context sha512Context;
+ } ctx;
+
+} USHAContext;
+
+/*
+ * This structure will hold context information for the HMAC
+ * keyed-hashing operation.
+ */
+typedef struct HMACContext {
+ int whichSha; /* which SHA is being used */
+ int hashSize; /* hash size of SHA being used */
+ int blockSize; /* block size of SHA being used */
+ USHAContext shaContext; /* SHA context */
+ unsigned char k_opad[USHA_Max_Message_Block_Size];
+ /* outer padding - key XORd with opad */
+ int Computed; /* Is the MAC computed? */
+ int Corrupted; /* Cumulative corruption code */
+
+} HMACContext;
+
+/*
+ * This structure will hold context information for the HKDF
+ * extract-and-expand Key Derivation Functions.
+ */
+typedef struct HKDFContext {
+ int whichSha; /* which SHA is being used */
+ HMACContext hmacContext;
+ int hashSize; /* hash size of SHA being used */
+ unsigned char prk[USHAMaxHashSize];
+ /* pseudo-random key - output of hkdfInput */
+ int Computed; /* Is the key material computed? */
+ int Corrupted; /* Cumulative corruption code */
+} HKDFContext;
+
+/*
+ * Function Prototypes
+ */
+
+/* SHA-1 */
+extern int SHA1Reset(SHA1Context *);
+extern int SHA1Input(SHA1Context *, const uint8_t *bytes,
+ unsigned int bytecount);
+extern int SHA1FinalBits(SHA1Context *, uint8_t bits,
+ unsigned int bit_count);
+extern int SHA1Result(SHA1Context *,
+ uint8_t Message_Digest[SHA1HashSize]);
+
+/* SHA-224 */
+extern int SHA224Reset(SHA224Context *);
+extern int SHA224Input(SHA224Context *, const uint8_t *bytes,
+ unsigned int bytecount);
+extern int SHA224FinalBits(SHA224Context *, uint8_t bits,
+ unsigned int bit_count);
+extern int SHA224Result(SHA224Context *,
+ uint8_t Message_Digest[SHA224HashSize]);
+
+/* SHA-256 */
+extern int SHA256Reset(SHA256Context *);
+extern int SHA256Input(SHA256Context *, const uint8_t *bytes,
+ unsigned int bytecount);
+extern int SHA256FinalBits(SHA256Context *, uint8_t bits,
+ unsigned int bit_count);
+extern int SHA256Result(SHA256Context *,
+ uint8_t Message_Digest[SHA256HashSize]);
+
+/* SHA-384 */
+extern int SHA384Reset(SHA384Context *);
+extern int SHA384Input(SHA384Context *, const uint8_t *bytes,
+ unsigned int bytecount);
+extern int SHA384FinalBits(SHA384Context *, uint8_t bits,
+ unsigned int bit_count);
+extern int SHA384Result(SHA384Context *,
+ uint8_t Message_Digest[SHA384HashSize]);
+
+/* SHA-512 */
+extern int SHA512Reset(SHA512Context *);
+extern int SHA512Input(SHA512Context *, const uint8_t *bytes,
+ unsigned int bytecount);
+extern int SHA512FinalBits(SHA512Context *, uint8_t bits,
+ unsigned int bit_count);
+extern int SHA512Result(SHA512Context *,
+ uint8_t Message_Digest[SHA512HashSize]);
+
+/* Unified SHA functions, chosen by whichSha */
+extern int USHAReset(USHAContext *context, SHAversion whichSha);
+extern int USHAInput(USHAContext *context,
+ const uint8_t *bytes, unsigned int bytecount);
+extern int USHAFinalBits(USHAContext *context,
+ uint8_t bits, unsigned int bit_count);
+extern int USHAResult(USHAContext *context,
+ uint8_t Message_Digest[USHAMaxHashSize]);
+extern int USHABlockSize(enum SHAversion whichSha);
+extern int USHAHashSize(enum SHAversion whichSha);
+extern int USHAHashSizeBits(enum SHAversion whichSha);
+extern const char *USHAHashName(enum SHAversion whichSha);
+
+/*
+ * HMAC Keyed-Hashing for Message Authentication, RFC 2104,
+ * for all SHAs.
+ * This interface allows a fixed-length text input to be used.
+ */
+extern int hmac(SHAversion whichSha, /* which SHA algorithm to use */
+ const unsigned char *text, /* pointer to data stream */
+ int text_len, /* length of data stream */
+ const unsigned char *key, /* pointer to authentication key */
+ int key_len, /* length of authentication key */
+ uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */
+
+/*
+ * HMAC Keyed-Hashing for Message Authentication, RFC 2104,
+ * for all SHAs.
+ * This interface allows any length of text input to be used.
+ */
+extern int hmacReset(HMACContext *context, enum SHAversion whichSha,
+ const unsigned char *key, int key_len);
+extern int hmacInput(HMACContext *context, const unsigned char *text,
+ int text_len);
+extern int hmacFinalBits(HMACContext *context, uint8_t bits,
+ unsigned int bit_count);
+extern int hmacResult(HMACContext *context,
+ uint8_t digest[USHAMaxHashSize]);
+
+/*
+ * HKDF HMAC-based Extract-and-Expand Key Derivation Function,
+ * RFC 5869, for all SHAs.
+ */
+extern int hkdf(SHAversion whichSha, const unsigned char *salt,
+ int salt_len, const unsigned char *ikm, int ikm_len,
+ const unsigned char *info, int info_len,
+ uint8_t okm[ ], int okm_len);
+extern int hkdfExtract(SHAversion whichSha, const unsigned char *salt,
+ int salt_len, const unsigned char *ikm,
+ int ikm_len, uint8_t prk[USHAMaxHashSize]);
+extern int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ],
+ int prk_len, const unsigned char *info,
+ int info_len, uint8_t okm[ ], int okm_len);
+
+/*
+ * HKDF HMAC-based Extract-and-Expand Key Derivation Function,
+ * RFC 5869, for all SHAs.
+ * This interface allows any length of text input to be used.
+ */
+extern int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
+ const unsigned char *salt, int salt_len);
+extern int hkdfInput(HKDFContext *context, const unsigned char *ikm,
+ int ikm_len);
+extern int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
+ unsigned int ikm_bit_count);
+extern int hkdfResult(HKDFContext *context,
+ uint8_t prk[USHAMaxHashSize],
+ const unsigned char *info, int info_len,
+ uint8_t okm[USHAMaxHashSize], int okm_len);
+#endif /* _SHA_H_ */
+
diff --git a/src/proto-banner1.h b/src/proto-banner1.h
index 5056532b..e7f0eb2b 100644
--- a/src/proto-banner1.h
+++ b/src/proto-banner1.h
@@ -8,6 +8,9 @@
#include "proto-x509.h"
#include "proto-spnego.h"
+#include "crypto-aes256.h"
+#include "crypto-rfc6234.h"
+
struct stack_handle_t;
struct Banner1;
struct StreamState;
@@ -50,16 +53,27 @@ struct BannerBase64
unsigned temp:24;
};
+struct AES_CTR_STATE {
+ unsigned char counter[16]; // 128 bits
+ struct aes256_context_t key;
+ unsigned char buf[16];
+ unsigned char offset; // how much the buf is filled
+};
+
struct SSL_SERVER_HELLO {
unsigned state;
unsigned remaining;
unsigned timestamp;
unsigned short cipher_suite;
- unsigned short ext_tag;
- unsigned short ext_remaining;
+ struct {
+ unsigned short tag;
+ unsigned short len;
+ unsigned short i;
+ } ext;
unsigned char compression_method;
unsigned char version_major;
unsigned char version_minor;
+ unsigned char kx_data[32]; // x25519 server pubkey
};
struct SSL_SERVER_CERT {
unsigned state;
@@ -73,18 +87,34 @@ struct SSL_SERVER_ALERT {
unsigned char level;
unsigned char description;
};
+struct SSL_APPLICATION_DATA {
+ unsigned state;
+ struct AES_CTR_STATE aes;
+};
struct SSLRECORD {
unsigned char type;
unsigned char version_major;
unsigned char version_minor;
+ /* "sequence number is set to zero at the beginning of a
+ * connection and whenever the key is changed" */
+ unsigned long seqnum;
struct {
unsigned state;
unsigned char type;
unsigned remaining;
+ unsigned negotiation_state;
+ // For TLS 1.3, one must do the SHA384 of clienthello + serverhello
+ SHA384Context sha384ctx;
+ aes256_key_t client_handshake_key;
+ aes256_key_t server_handshake_key;
+ unsigned char client_handshake_iv[12];
+ unsigned char server_handshake_iv[12];
} handshake;
+ struct SSL_APPLICATION_DATA application_data;
+
union {
struct {
/* all these structs should start with state */
diff --git a/src/proto-banout.c b/src/proto-banout.c
index bb906127..1a1fb43c 100644
--- a/src/proto-banout.c
+++ b/src/proto-banout.c
@@ -135,7 +135,7 @@ banout_is_contains(const struct BannerOutput *banout, unsigned proto,
unsigned
banout_string_length(const struct BannerOutput *banout, unsigned proto)
{
- while (banout && banout->protocol != proto)
+ while (banout && (banout->protocol&0xFFFF) != proto)
banout = banout->next;
if (banout)
diff --git a/src/proto-ssl-test.c b/src/proto-ssl-test.c
index 89e03a2f..ad423ce8 100644
--- a/src/proto-ssl-test.c
+++ b/src/proto-ssl-test.c
@@ -2430,3 +2430,494 @@ const char yahoo_cert[] =
"\xbe\xbd\x25\x4f\x24\x9b\x26\x98\x2c\x04\x1c\x51\x2b";
size_t yahoo_cert_size = sizeof(yahoo_cert) - 1;
+const char tls13_test_case_1_clienthello[] =
+"\x16\x03\x01\x00\xf8\x01\x00\x00\xf4\x03\x03\x00\x01\x02\x03\x04"
+"\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+"\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\xe0\xe1\xe2\xe3"
+"\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3"
+"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x00\x08\x13\x02"
+"\x13\x03\x13\x01\x00\xff\x01\x00\x00\xa3\x00\x00\x00\x18\x00\x16"
+"\x00\x00\x13\x65\x78\x61\x6d\x70\x6c\x65\x2e\x75\x6c\x66\x68\x65"
+"\x69\x6d\x2e\x6e\x65\x74\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a"
+"\x00\x16\x00\x14\x00\x1d\x00\x17\x00\x1e\x00\x19\x00\x18\x01\x00"
+"\x01\x01\x01\x02\x01\x03\x01\x04\x00\x23\x00\x00\x00\x16\x00\x00"
+"\x00\x17\x00\x00\x00\x0d\x00\x1e\x00\x1c\x04\x03\x05\x03\x06\x03"
+"\x08\x07\x08\x08\x08\x09\x08\x0a\x08\x0b\x08\x04\x08\x05\x08\x06"
+"\x04\x01\x05\x01\x06\x01\x00\x2b\x00\x03\x02\x03\x04\x00\x2d\x00"
+"\x02\x01\x01\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20\x35\x80\x72"
+"\xd6\x36\x58\x80\xd1\xae\xea\x32\x9a\xdf\x91\x21\x38\x38\x51\xed"
+"\x21\xa2\x8e\x3b\x75\xe9\x65\xd0\xd2\xcd\x16\x62\x54";
+size_t tls13_test_case_1_clienthello_size = sizeof(tls13_test_case_1_clienthello) - 1;
+
+const char tls13_test_case_1_kxdata[32] =
+"\x9f\xd7\xad\x6d\xcf\xf4\x29\x8d\xd3\xf9\x6d\x5b\x1b\x2a\xf9\x10"
+"\xa0\x53\x5b\x14\x88\xd7\xf8\xfa\xbb\x34\x9a\x98\x28\x80\xb6\x15";
+
+const char tls13_test_case_1_serverhello[] =
+"\x16\x03\x03\x00\x7a\x02\x00\x00\x76\x03\x03\x70\x71\x72\x73\x74"
+"\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84"
+"\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x20\xe0\xe1\xe2\xe3"
+"\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3"
+"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x13\x02\x00\x00"
+"\x2e\x00\x2b\x00\x02\x03\x04\x00\x33\x00\x24\x00\x1d\x00\x20\x9f"
+"\xd7\xad\x6d\xcf\xf4\x29\x8d\xd3\xf9\x6d\x5b\x1b\x2a\xf9\x10\xa0"
+"\x53\x5b\x14\x88\xd7\xf8\xfa\xbb\x34\x9a\x98\x28\x80\xb6\x15\x14"
+"\x03\x03\x00\x01\x01\x17\x03\x03\x00\x17\x6b\xe0\x2f\x9d\xa7\xc2"
+"\xdc\x9d\xde\xf5\x6f\x24\x68\xb9\x0a\xdf\xa2\x51\x01\xab\x03\x44"
+"\xae\x17\x03\x03\x03\x43\xba\xf0\x0a\x9b\xe5\x0f\x3f\x23\x07\xe7"
+"\x26\xed\xcb\xda\xcb\xe4\xb1\x86\x16\x44\x9d\x46\xc6\x20\x7a\xf6"
+"\xe9\x95\x3e\xe5\xd2\x41\x1b\xa6\x5d\x31\xfe\xaf\x4f\x78\x76\x4f"
+"\x2d\x69\x39\x87\x18\x6c\xc0\x13\x29\xc1\x87\xa5\xe4\x60\x8e\x8d"
+"\x27\xb3\x18\xe9\x8d\xd9\x47\x69\xf7\x73\x9c\xe6\x76\x83\x92\xca"
+"\xca\x8d\xcc\x59\x7d\x77\xec\x0d\x12\x72\x23\x37\x85\xf6\xe6\x9d"
+"\x6f\x43\xef\xfa\x8e\x79\x05\xed\xfd\xc4\x03\x7e\xee\x59\x33\xe9"
+"\x90\xa7\x97\x2f\x20\x69\x13\xa3\x1e\x8d\x04\x93\x13\x66\xd3\xd8"
+"\xbc\xd6\xa4\xa4\xd6\x47\xdd\x4b\xd8\x0b\x0f\xf8\x63\xce\x35\x54"
+"\x83\x3d\x74\x4c\xf0\xe0\xb9\xc0\x7c\xae\x72\x6d\xd2\x3f\x99\x53"
+"\xdf\x1f\x1c\xe3\xac\xeb\x3b\x72\x30\x87\x1e\x92\x31\x0c\xfb\x2b"
+"\x09\x84\x86\xf4\x35\x38\xf8\xe8\x2d\x84\x04\xe5\xc6\xc2\x5f\x66"
+"\xa6\x2e\xbe\x3c\x5f\x26\x23\x26\x40\xe2\x0a\x76\x91\x75\xef\x83"
+"\x48\x3c\xd8\x1e\x6c\xb1\x6e\x78\xdf\xad\x4c\x1b\x71\x4b\x04\xb4"
+"\x5f\x6a\xc8\xd1\x06\x5a\xd1\x8c\x13\x45\x1c\x90\x55\xc4\x7d\xa3"
+"\x00\xf9\x35\x36\xea\x56\xf5\x31\x98\x6d\x64\x92\x77\x53\x93\xc4"
+"\xcc\xb0\x95\x46\x70\x92\xa0\xec\x0b\x43\xed\x7a\x06\x87\xcb\x47"
+"\x0c\xe3\x50\x91\x7b\x0a\xc3\x0c\x6e\x5c\x24\x72\x5a\x78\xc4\x5f"
+"\x9f\x5f\x29\xb6\x62\x68\x67\xf6\xf7\x9c\xe0\x54\x27\x35\x47\xb3"
+"\x6d\xf0\x30\xbd\x24\xaf\x10\xd6\x32\xdb\xa5\x4f\xc4\xe8\x90\xbd"
+"\x05\x86\x92\x8c\x02\x06\xca\x2e\x28\xe4\x4e\x22\x7a\x2d\x50\x63"
+"\x19\x59\x35\xdf\x38\xda\x89\x36\x09\x2e\xef\x01\xe8\x4c\xad\x2e"
+"\x49\xd6\x2e\x47\x0a\x6c\x77\x45\xf6\x25\xec\x39\xe4\xfc\x23\x32"
+"\x9c\x79\xd1\x17\x28\x76\x80\x7c\x36\xd7\x36\xba\x42\xbb\x69\xb0"
+"\x04\xff\x55\xf9\x38\x50\xdc\x33\xc1\xf9\x8a\xbb\x92\x85\x83\x24"
+"\xc7\x6f\xf1\xeb\x08\x5d\xb3\xc1\xfc\x50\xf7\x4e\xc0\x44\x42\xe6"
+"\x22\x97\x3e\xa7\x07\x43\x41\x87\x94\xc3\x88\x14\x0b\xb4\x92\xd6"
+"\x29\x4a\x05\x40\xe5\xa5\x9c\xfa\xe6\x0b\xa0\xf1\x48\x99\xfc\xa7"
+"\x13\x33\x31\x5e\xa0\x83\xa6\x8e\x1d\x7c\x1e\x4c\xdc\x2f\x56\xbc"
+"\xd6\x11\x96\x81\xa4\xad\xbc\x1b\xbf\x42\xaf\xd8\x06\xc3\xcb\xd4"
+"\x2a\x07\x6f\x54\x5d\xee\x4e\x11\x8d\x0b\x39\x67\x54\xbe\x2b\x04"
+"\x2a\x68\x5d\xd4\x72\x7e\x89\xc0\x38\x6a\x94\xd3\xcd\x6e\xcb\x98"
+"\x20\xe9\xd4\x9a\xfe\xed\x66\xc4\x7e\x6f\xc2\x43\xea\xbe\xbb\xcb"
+"\x0b\x02\x45\x38\x77\xf5\xac\x5d\xbf\xbd\xf8\xdb\x10\x52\xa3\xc9"
+"\x94\xb2\x24\xcd\x9a\xaa\xf5\x6b\x02\x6b\xb9\xef\xa2\xe0\x13\x02"
+"\xb3\x64\x01\xab\x64\x94\xe7\x01\x8d\x6e\x5b\x57\x3b\xd3\x8b\xce"
+"\xf0\x23\xb1\xfc\x92\x94\x6b\xbc\xa0\x20\x9c\xa5\xfa\x92\x6b\x49"
+"\x70\xb1\x00\x91\x03\x64\x5c\xb1\xfc\xfe\x55\x23\x11\xff\x73\x05"
+"\x58\x98\x43\x70\x03\x8f\xd2\xcc\xe2\xa9\x1f\xc7\x4d\x6f\x3e\x3e"
+"\xa9\xf8\x43\xee\xd3\x56\xf6\xf8\x2d\x35\xd0\x3b\xc2\x4b\x81\xb5"
+"\x8c\xeb\x1a\x43\xec\x94\x37\xe6\xf1\xe5\x0e\xb6\xf5\x55\xe3\x21"
+"\xfd\x67\xc8\x33\x2e\xb1\xb8\x32\xaa\x8d\x79\x5a\x27\xd4\x79\xc6"
+"\xe2\x7d\x5a\x61\x03\x46\x83\x89\x19\x03\xf6\x64\x21\xd0\x94\xe1"
+"\xb0\x0a\x9a\x13\x8d\x86\x1e\x6f\x78\xa2\x0a\xd3\xe1\x58\x00\x54"
+"\xd2\xe3\x05\x25\x3c\x71\x3a\x02\xfe\x1e\x28\xde\xee\x73\x36\x24"
+"\x6f\x6a\xe3\x43\x31\x80\x6b\x46\xb4\x7b\x83\x3c\x39\xb9\xd3\x1c"
+"\xd3\x00\xc2\xa6\xed\x83\x13\x99\x77\x6d\x07\xf5\x70\xea\xf0\x05"
+"\x9a\x2c\x68\xa5\xf3\xae\x16\xb6\x17\x40\x4a\xf7\xb7\x23\x1a\x4d"
+"\x94\x27\x58\xfc\x02\x0b\x3f\x23\xee\x8c\x15\xe3\x60\x44\xcf\xd6"
+"\x7c\xd6\x40\x99\x3b\x16\x20\x75\x97\xfb\xf3\x85\xea\x7a\x4d\x99"
+"\xe8\xd4\x56\xff\x83\xd4\x1f\x7b\x8b\x4f\x06\x9b\x02\x8a\x2a\x63"
+"\xa9\x19\xa7\x0e\x3a\x10\xe3\x08\x41\x58\xfa\xa5\xba\xfa\x30\x18"
+"\x6c\x6b\x2f\x23\x8e\xb5\x30\xc7\x3e\x17\x03\x03\x01\x19\x73\x71"
+"\x9f\xce\x07\xec\x2f\x6d\x3b\xba\x02\x92\xa0\xd4\x0b\x27\x70\xc0"
+"\x6a\x27\x17\x99\xa5\x33\x14\xf6\xf7\x7f\xc9\x5c\x5f\xe7\xb9\xa4"
+"\x32\x9f\xd9\x54\x8c\x67\x0e\xbe\xea\x2f\x2d\x5c\x35\x1d\xd9\x35"
+"\x6e\xf2\xdc\xd5\x2e\xb1\x37\xbd\x3a\x67\x65\x22\xf8\xcd\x0f\xb7"
+"\x56\x07\x89\xad\x7b\x0e\x3c\xab\xa2\xe3\x7e\x6b\x41\x99\xc6\x79"
+"\x3b\x33\x46\xed\x46\xcf\x74\x0a\x9f\xa1\xfe\xc4\x14\xdc\x71\x5c"
+"\x41\x5c\x60\xe5\x75\x70\x3c\xe6\xa3\x4b\x70\xb5\x19\x1a\xa6\xa6"
+"\x1a\x18\xfa\xff\x21\x6c\x68\x7a\xd8\xd1\x7e\x12\xa7\xe9\x99\x15"
+"\xa6\x11\xbf\xc1\xa2\xbe\xfc\x15\xe6\xe9\x4d\x78\x46\x42\xe6\x82"
+"\xfd\x17\x38\x2a\x34\x8c\x30\x10\x56\xb9\x40\xc9\x84\x72\x00\x40"
+"\x8b\xec\x56\xc8\x1e\xa3\xd7\x21\x7a\xb8\xe8\x5a\x88\x71\x53\x95"
+"\x89\x9c\x90\x58\x7f\x72\xe8\xdd\xd7\x4b\x26\xd8\xed\xc1\xc7\xc8"
+"\x37\xd9\xf2\xeb\xbc\x26\x09\x62\x21\x90\x38\xb0\x56\x54\xa6\x3a"
+"\x0b\x12\x99\x9b\x4a\x83\x06\xa3\xdd\xcc\x0e\x17\xc5\x3b\xa8\xf9"
+"\xc8\x03\x63\xf7\x84\x13\x54\xd2\x91\xb4\xac\xe0\xc0\xf3\x30\xc0"
+"\xfc\xd5\xaa\x9d\xee\xf9\x69\xae\x8a\xb2\xd9\x8d\xa8\x8e\xbb\x6e"
+"\xa8\x0a\x3a\x11\xf0\x0e\xa2\x96\xa3\x23\x23\x67\xff\x07\x5e\x1c"
+"\x66\xdd\x9c\xbe\xdc\x47\x13\x17\x03\x03\x00\x45\x10\x61\xde\x27"
+"\xe5\x1c\x2c\x9f\x34\x29\x11\x80\x6f\x28\x2b\x71\x0c\x10\x63\x2c"
+"\xa5\x00\x67\x55\x88\x0d\xbf\x70\x06\x00\x2d\x0e\x84\xfe\xd9\xad"
+"\xf2\x7a\x43\xb5\x19\x23\x03\xe4\xdf\x5c\x28\x5d\x58\xe3\xc7\x62"
+"\x24\x07\x84\x40\xc0\x74\x23\x74\x74\x4a\xec\xf2\x8c\xf3\x18\x2f"
+"\xd0";
+size_t tls13_test_case_1_serverhello_size = sizeof(tls13_test_case_1_serverhello) - 1;
+
+const char tls13_test_case_1_server_handshake_key[] =
+"\x9f\x13\x57\x5c\xe3\xf8\xcf\xc1\xdf\x64\xa7\x7c\xea\xff\xe8\x97"
+"\x00\xb4\x92\xad\x31\xb4\xfa\xb0\x1c\x47\x92\xbe\x1b\x26\x6b\x7f";
+
+const char tls13_test_case_1_client_handshake_key[] =
+"\x11\x35\xb4\x82\x6a\x9a\x70\x25\x7e\x5a\x39\x1a\xd9\x30\x93\xdf"
+"\xd7\xc4\x21\x48\x12\xf4\x93\xb3\xe3\xda\xae\x1e\xb2\xb1\xac\x69";
+
+const char tls13_test_case_1_server_handshake_iv[] =
+"\x95\x63\xbc\x8b\x59\x0f\x67\x1f\x48\x8d\x2d\xa3";
+
+const char tls13_test_case_1_client_handshake_iv[] =
+"\x42\x56\xd2\xe0\xe8\x8b\xab\xdd\x05\xeb\x2f\x27";
+
+/* TLS 1.3 certificates have a slightly different format. Parse that */
+const char tls13_test_case_2_certs[] =
+"\x00\x00\x10\x95\x00\x04\x73\x30\x82\x04\x6f\x30\x82\x03\x57\xa0"
+"\x03\x02\x01\x02\x02\x12\x04\xd8\x3f\xac\xd5\xe2\x1c\x8a\x0c\xbd"
+"\x60\xab\x5f\x2f\xd1\x8a\x0d\xbd\x30\x0d\x06\x09\x2a\x86\x48\x86"
+"\xf7\x0d\x01\x01\x0b\x05\x00\x30\x32\x31\x0b\x30\x09\x06\x03\x55"
+"\x04\x06\x13\x02\x55\x53\x31\x16\x30\x14\x06\x03\x55\x04\x0a\x13"
+"\x0d\x4c\x65\x74\x27\x73\x20\x45\x6e\x63\x72\x79\x70\x74\x31\x0b"
+"\x30\x09\x06\x03\x55\x04\x03\x13\x02\x52\x33\x30\x1e\x17\x0d\x32"
+"\x33\x30\x32\x32\x37\x31\x31\x30\x31\x32\x38\x5a\x17\x0d\x32\x33"
+"\x30\x35\x32\x38\x31\x31\x30\x31\x32\x37\x5a\x30\x16\x31\x14\x30"
+"\x12\x06\x03\x55\x04\x03\x13\x0b\x74\x6c\x73\x31\x33\x2e\x31\x64"
+"\x2e\x70\x77\x30\x76\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01"
+"\x06\x05\x2b\x81\x04\x00\x22\x03\x62\x00\x04\xde\xad\xc0\xde\xd7"
+"\xcb\xfb\x7e\xa3\xba\x63\x37\x18\x06\x53\x37\xf9\xd0\xf7\x4e\x33"
+"\x32\x17\x65\xbc\xdf\xa9\x0d\xe7\x28\x42\x80\xf2\x18\x60\x61\xce"
+"\x79\x26\x8c\x6d\x8f\xaa\xbe\xf5\x33\xe2\xaf\x93\xc1\x46\x0d\xc9"
+"\xc0\x2d\xca\x87\x30\x7d\xa8\x7d\xd4\x42\x2d\xec\x34\xa8\xdc\xd1"
+"\xdb\x9f\x94\x1d\x54\x44\xc9\xa4\x07\x5e\x77\xfb\xfd\x51\x6d\x26"
+"\x80\x35\xcd\xd1\xe7\x7e\x4d\x6b\xbf\x16\x8f\xa3\x82\x02\x47\x30"
+"\x82\x02\x43\x30\x0e\x06\x03\x55\x1d\x0f\x01\x01\xff\x04\x04\x03"
+"\x02\x07\x80\x30\x1d\x06\x03\x55\x1d\x25\x04\x16\x30\x14\x06\x08"
+"\x2b\x06\x01\x05\x05\x07\x03\x01\x06\x08\x2b\x06\x01\x05\x05\x07"
+"\x03\x02\x30\x0c\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x02\x30\x00"
+"\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x71\x6c\x38\x7d\x80"
+"\x4a\x13\x78\x0c\x59\x4a\x3c\x4a\x04\xd9\xaf\x68\xde\xef\x08\x30"
+"\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x14\x2e\xb3\x17"
+"\xb7\x58\x56\xcb\xae\x50\x09\x40\xe6\x1f\xaf\x9d\x8b\x14\xc2\xc6"
+"\x30\x55\x06\x08\x2b\x06\x01\x05\x05\x07\x01\x01\x04\x49\x30\x47"
+"\x30\x21\x06\x08\x2b\x06\x01\x05\x05\x07\x30\x01\x86\x15\x68\x74"
+"\x74\x70\x3a\x2f\x2f\x72\x33\x2e\x6f\x2e\x6c\x65\x6e\x63\x72\x2e"
+"\x6f\x72\x67\x30\x22\x06\x08\x2b\x06\x01\x05\x05\x07\x30\x02\x86"
+"\x16\x68\x74\x74\x70\x3a\x2f\x2f\x72\x33\x2e\x69\x2e\x6c\x65\x6e"
+"\x63\x72\x2e\x6f\x72\x67\x2f\x30\x16\x06\x03\x55\x1d\x11\x04\x0f"
+"\x30\x0d\x82\x0b\x74\x6c\x73\x31\x33\x2e\x31\x64\x2e\x70\x77\x30"
+"\x4c\x06\x03\x55\x1d\x20\x04\x45\x30\x43\x30\x08\x06\x06\x67\x81"
+"\x0c\x01\x02\x01\x30\x37\x06\x0b\x2b\x06\x01\x04\x01\x82\xdf\x13"
+"\x01\x01\x01\x30\x28\x30\x26\x06\x08\x2b\x06\x01\x05\x05\x07\x02"
+"\x01\x16\x1a\x68\x74\x74\x70\x3a\x2f\x2f\x63\x70\x73\x2e\x6c\x65"
+"\x74\x73\x65\x6e\x63\x72\x79\x70\x74\x2e\x6f\x72\x67\x30\x82\x01"
+"\x05\x06\x0a\x2b\x06\x01\x04\x01\xd6\x79\x02\x04\x02\x04\x81\xf6"
+"\x04\x81\xf3\x00\xf1\x00\x77\x00\x7a\x32\x8c\x54\xd8\xb7\x2d\xb6"
+"\x20\xea\x38\xe0\x52\x1e\xe9\x84\x16\x70\x32\x13\x85\x4d\x3b\xd2"
+"\x2b\xc1\x3a\x57\xa3\x52\xeb\x52\x00\x00\x01\x86\x92\xbf\xca\x80"
+"\x00\x00\x04\x03\x00\x48\x30\x46\x02\x21\x00\xe5\x4b\x5e\x6d\xa3"
+"\xdc\x1d\xc4\xe4\x4e\x6a\xb9\xfc\x03\x85\x9c\xa8\x3b\x71\x2f\x6d"
+"\x99\x6e\x5f\x07\xee\x19\x04\x39\x2d\x75\x10\x02\x21\x00\xa4\x41"
+"\xa3\x0b\x5a\xca\x69\xf2\xbd\xb5\x7e\x81\xbf\xec\xbc\xf3\x48\x09"
+"\x2f\x23\x2c\xe6\xe6\x84\x32\x34\x7b\xd8\x27\xe7\xa4\x76\x00\x76"
+"\x00\xe8\x3e\xd0\xda\x3e\xf5\x06\x35\x32\xe7\x57\x28\xbc\x89\x6b"
+"\xc9\x03\xd3\xcb\xd1\x11\x6b\xec\xeb\x69\xe1\x77\x7d\x6d\x06\xbd"
+"\x6e\x00\x00\x01\x86\x92\xbf\xca\x6c\x00\x00\x04\x03\x00\x47\x30"
+"\x45\x02\x21\x00\xdb\x6d\xcb\xb1\x7f\x79\xaa\x05\xce\xbd\x8f\x0e"
+"\xc6\x51\xf6\x73\xe0\x6a\x37\x43\x25\xa0\x72\x35\x99\x6b\x3b\x3b"
+"\xbb\x41\x3a\x62\x02\x20\x3c\x59\x85\x99\x9b\xda\x63\x13\xe5\x3e"
+"\x5d\x89\x6f\x51\xc8\x9c\x43\x6d\x78\xe0\xdc\x2b\x09\x74\xb5\x30"
+"\x75\x53\x97\xa8\x69\xbc\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d"
+"\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x3f\x58\xc2\xed\x47\xec"
+"\x81\x28\xc4\xfd\x9e\xf1\xbe\x7f\xa2\x55\xf8\x0b\xff\xaa\x2f\x3b"
+"\xfc\x4a\x8b\xd8\x26\x35\x88\x8f\xcd\x62\xb4\x87\xb3\xd6\xac\x97"
+"\xc3\x7b\x26\x62\x0a\xc1\x23\x5f\x2c\xd2\x8c\xbb\xde\x95\x9f\x39"
+"\xa3\x34\xbc\xb8\xe7\x73\x30\x5b\x0d\x43\x06\xcc\x3e\xf2\x7e\xe4"
+"\x17\xcf\xe4\x0f\xf1\xf5\x96\xa9\x44\x5c\x67\xd0\xba\x2b\xdd\xa1"
+"\x44\xf4\xda\x95\xfa\x73\xec\x4a\x06\xa8\x14\xa0\xa7\xa8\xdf\xec"
+"\x95\x28\x8a\x57\x73\x87\x2f\x4b\xae\x73\x02\x0a\x35\x65\x32\x83"
+"\x6e\x1c\x55\x58\xcd\x95\x67\x73\xdf\x66\x61\xd9\xd5\xfd\xec\xdf"
+"\xde\x86\x3a\xc1\xb5\x7a\xce\xef\xfd\x8f\x5a\xb6\x0f\x18\xbc\x91"
+"\x36\x0f\xe9\xea\xa6\xf9\xfc\x03\xd0\x01\xb0\x7e\x8b\x3b\xee\xe7"
+"\x25\xd7\xce\xd6\x35\xd8\xf4\x61\x17\x15\x31\x82\xdc\x85\x66\x70"
+"\x9d\x3d\x8a\xc3\x49\x59\xdb\xd5\xb4\x54\xf8\xac\x79\x51\xc6\xcf"
+"\xec\x98\xfe\x69\xef\x0e\xa5\xb2\x7b\x9b\x25\x9e\x8c\xfc\x3f\xaa"
+"\xe4\x33\xff\xbe\xa2\xc3\x23\x4a\xf7\x51\x35\x1f\x95\xe9\xe3\x10"
+"\x3d\xbd\x1d\x9b\x93\x37\x41\x10\x9b\x99\x5e\xd3\xb7\xba\x3b\x4f"
+"\xc5\x3b\x18\xd9\x80\x82\x79\x85\xb9\x32\x00\x00\x00\x05\x1a\x30"
+"\x82\x05\x16\x30\x82\x02\xfe\xa0\x03\x02\x01\x02\x02\x11\x00\x91"
+"\x2b\x08\x4a\xcf\x0c\x18\xa7\x53\xf6\xd6\x2e\x25\xa7\x5f\x5a\x30"
+"\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x4f"
+"\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x29\x30"
+"\x27\x06\x03\x55\x04\x0a\x13\x20\x49\x6e\x74\x65\x72\x6e\x65\x74"
+"\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x52\x65\x73\x65\x61\x72"
+"\x63\x68\x20\x47\x72\x6f\x75\x70\x31\x15\x30\x13\x06\x03\x55\x04"
+"\x03\x13\x0c\x49\x53\x52\x47\x20\x52\x6f\x6f\x74\x20\x58\x31\x30"
+"\x1e\x17\x0d\x32\x30\x30\x39\x30\x34\x30\x30\x30\x30\x30\x30\x5a"
+"\x17\x0d\x32\x35\x30\x39\x31\x35\x31\x36\x30\x30\x30\x30\x5a\x30"
+"\x32\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x16"
+"\x30\x14\x06\x03\x55\x04\x0a\x13\x0d\x4c\x65\x74\x27\x73\x20\x45"
+"\x6e\x63\x72\x79\x70\x74\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x13"
+"\x02\x52\x33\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7"
+"\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02"
+"\x82\x01\x01\x00\xbb\x02\x15\x28\xcc\xf6\xa0\x94\xd3\x0f\x12\xec"
+"\x8d\x55\x92\xc3\xf8\x82\xf1\x99\xa6\x7a\x42\x88\xa7\x5d\x26\xaa"
+"\xb5\x2b\xb9\xc5\x4c\xb1\xaf\x8e\x6b\xf9\x75\xc8\xa3\xd7\x0f\x47"
+"\x94\x14\x55\x35\x57\x8c\x9e\xa8\xa2\x39\x19\xf5\x82\x3c\x42\xa9"
+"\x4e\x6e\xf5\x3b\xc3\x2e\xdb\x8d\xc0\xb0\x5c\xf3\x59\x38\xe7\xed"
+"\xcf\x69\xf0\x5a\x0b\x1b\xbe\xc0\x94\x24\x25\x87\xfa\x37\x71\xb3"
+"\x13\xe7\x1c\xac\xe1\x9b\xef\xdb\xe4\x3b\x45\x52\x45\x96\xa9\xc1"
+"\x53\xce\x34\xc8\x52\xee\xb5\xae\xed\x8f\xde\x60\x70\xe2\xa5\x54"
+"\xab\xb6\x6d\x0e\x97\xa5\x40\x34\x6b\x2b\xd3\xbc\x66\xeb\x66\x34"
+"\x7c\xfa\x6b\x8b\x8f\x57\x29\x99\xf8\x30\x17\x5d\xba\x72\x6f\xfb"
+"\x81\xc5\xad\xd2\x86\x58\x3d\x17\xc7\xe7\x09\xbb\xf1\x2b\xf7\x86"
+"\xdc\xc1\xda\x71\x5d\xd4\x46\xe3\xcc\xad\x25\xc1\x88\xbc\x60\x67"
+"\x75\x66\xb3\xf1\x18\xf7\xa2\x5c\xe6\x53\xff\x3a\x88\xb6\x47\xa5"
+"\xff\x13\x18\xea\x98\x09\x77\x3f\x9d\x53\xf9\xcf\x01\xe5\xf5\xa6"
+"\x70\x17\x14\xaf\x63\xa4\xff\x99\xb3\x93\x9d\xdc\x53\xa7\x06\xfe"
+"\x48\x85\x1d\xa1\x69\xae\x25\x75\xbb\x13\xcc\x52\x03\xf5\xed\x51"
+"\xa1\x8b\xdb\x15\x02\x03\x01\x00\x01\xa3\x82\x01\x08\x30\x82\x01"
+"\x04\x30\x0e\x06\x03\x55\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01"
+"\x86\x30\x1d\x06\x03\x55\x1d\x25\x04\x16\x30\x14\x06\x08\x2b\x06"
+"\x01\x05\x05\x07\x03\x02\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x01"
+"\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01"
+"\xff\x02\x01\x00\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x14"
+"\x2e\xb3\x17\xb7\x58\x56\xcb\xae\x50\x09\x40\xe6\x1f\xaf\x9d\x8b"
+"\x14\xc2\xc6\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14"
+"\x79\xb4\x59\xe6\x7b\xb6\xe5\xe4\x01\x73\x80\x08\x88\xc8\x1a\x58"
+"\xf6\xe9\x9b\x6e\x30\x32\x06\x08\x2b\x06\x01\x05\x05\x07\x01\x01"
+"\x04\x26\x30\x24\x30\x22\x06\x08\x2b\x06\x01\x05\x05\x07\x30\x02"
+"\x86\x16\x68\x74\x74\x70\x3a\x2f\x2f\x78\x31\x2e\x69\x2e\x6c\x65"
+"\x6e\x63\x72\x2e\x6f\x72\x67\x2f\x30\x27\x06\x03\x55\x1d\x1f\x04"
+"\x20\x30\x1e\x30\x1c\xa0\x1a\xa0\x18\x86\x16\x68\x74\x74\x70\x3a"
+"\x2f\x2f\x78\x31\x2e\x63\x2e\x6c\x65\x6e\x63\x72\x2e\x6f\x72\x67"
+"\x2f\x30\x22\x06\x03\x55\x1d\x20\x04\x1b\x30\x19\x30\x08\x06\x06"
+"\x67\x81\x0c\x01\x02\x01\x30\x0d\x06\x0b\x2b\x06\x01\x04\x01\x82"
+"\xdf\x13\x01\x01\x01\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01"
+"\x01\x0b\x05\x00\x03\x82\x02\x01\x00\x85\xca\x4e\x47\x3e\xa3\xf7"
+"\x85\x44\x85\xbc\xd5\x67\x78\xb2\x98\x63\xad\x75\x4d\x1e\x96\x3d"
+"\x33\x65\x72\x54\x2d\x81\xa0\xea\xc3\xed\xf8\x20\xbf\x5f\xcc\xb7"
+"\x70\x00\xb7\x6e\x3b\xf6\x5e\x94\xde\xe4\x20\x9f\xa6\xef\x8b\xb2"
+"\x03\xe7\xa2\xb5\x16\x3c\x91\xce\xb4\xed\x39\x02\xe7\x7c\x25\x8a"
+"\x47\xe6\x65\x6e\x3f\x46\xf4\xd9\xf0\xce\x94\x2b\xee\x54\xce\x12"
+"\xbc\x8c\x27\x4b\xb8\xc1\x98\x2f\xa2\xaf\xcd\x71\x91\x4a\x08\xb7"
+"\xc8\xb8\x23\x7b\x04\x2d\x08\xf9\x08\x57\x3e\x83\xd9\x04\x33\x0a"
+"\x47\x21\x78\x09\x82\x27\xc3\x2a\xc8\x9b\xb9\xce\x5c\xf2\x64\xc8"
+"\xc0\xbe\x79\xc0\x4f\x8e\x6d\x44\x0c\x5e\x92\xbb\x2e\xf7\x8b\x10"
+"\xe1\xe8\x1d\x44\x29\xdb\x59\x20\xed\x63\xb9\x21\xf8\x12\x26\x94"
+"\x93\x57\xa0\x1d\x65\x04\xc1\x0a\x22\xae\x10\x0d\x43\x97\xa1\x18"
+"\x1f\x7e\xe0\xe0\x86\x37\xb5\x5a\xb1\xbd\x30\xbf\x87\x6e\x2b\x2a"
+"\xff\x21\x4e\x1b\x05\xc3\xf5\x18\x97\xf0\x5e\xac\xc3\xa5\xb8\x6a"
+"\xf0\x2e\xbc\x3b\x33\xb9\xee\x4b\xde\xcc\xfc\xe4\xaf\x84\x0b\x86"
+"\x3f\xc0\x55\x43\x36\xf6\x68\xe1\x36\x17\x6a\x8e\x99\xd1\xff\xa5"
+"\x40\xa7\x34\xb7\xc0\xd0\x63\x39\x35\x39\x75\x6e\xf2\xba\x76\xc8"
+"\x93\x02\xe9\xa9\x4b\x6c\x17\xce\x0c\x02\xd9\xbd\x81\xfb\x9f\xb7"
+"\x68\xd4\x06\x65\xb3\x82\x3d\x77\x53\xf8\x8e\x79\x03\xad\x0a\x31"
+"\x07\x75\x2a\x43\xd8\x55\x97\x72\xc4\x29\x0e\xf7\xc4\x5d\x4e\xc8"
+"\xae\x46\x84\x30\xd7\xf2\x85\x5f\x18\xa1\x79\xbb\xe7\x5e\x70\x8b"
+"\x07\xe1\x86\x93\xc3\xb9\x8f\xdc\x61\x71\x25\x2a\xaf\xdf\xed\x25"
+"\x50\x52\x68\x8b\x92\xdc\xe5\xd6\xb5\xe3\xda\x7d\xd0\x87\x6c\x84"
+"\x21\x31\xae\x82\xf5\xfb\xb9\xab\xc8\x89\x17\x3d\xe1\x4c\xe5\x38"
+"\x0e\xf6\xbd\x2b\xbd\x96\x81\x14\xeb\xd5\xdb\x3d\x20\xa7\x7e\x59"
+"\xd3\xe2\xf8\x58\xf9\x5b\xb8\x48\xcd\xfe\x5c\x4f\x16\x29\xfe\x1e"
+"\x55\x23\xaf\xc8\x11\xb0\x8d\xea\x7c\x93\x90\x17\x2f\xfd\xac\xa2"
+"\x09\x47\x46\x3f\xf0\xe9\xb0\xb7\xff\x28\x4d\x68\x32\xd6\x67\x5e"
+"\x1e\x69\xa3\x93\xb8\xf5\x9d\x8b\x2f\x0b\xd2\x52\x43\xa6\x6f\x32"
+"\x57\x65\x4d\x32\x81\xdf\x38\x53\x85\x5d\x7e\x5d\x66\x29\xea\xb8"
+"\xdd\xe4\x95\xb5\xcd\xb5\x56\x12\x42\xcd\xc4\x4e\xc6\x25\x38\x44"
+"\x50\x6d\xec\xce\x00\x55\x18\xfe\xe9\x49\x64\xd4\x4e\xca\x97\x9c"
+"\xb4\x5b\xc0\x73\xa8\xab\xb8\x47\xc2\x00\x00\x00\x05\x64\x30\x82"
+"\x05\x60\x30\x82\x04\x48\xa0\x03\x02\x01\x02\x02\x10\x40\x01\x77"
+"\x21\x37\xd4\xe9\x42\xb8\xee\x76\xaa\x3c\x64\x0a\xb7\x30\x0d\x06"
+"\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x3f\x31\x24"
+"\x30\x22\x06\x03\x55\x04\x0a\x13\x1b\x44\x69\x67\x69\x74\x61\x6c"
+"\x20\x53\x69\x67\x6e\x61\x74\x75\x72\x65\x20\x54\x72\x75\x73\x74"
+"\x20\x43\x6f\x2e\x31\x17\x30\x15\x06\x03\x55\x04\x03\x13\x0e\x44"
+"\x53\x54\x20\x52\x6f\x6f\x74\x20\x43\x41\x20\x58\x33\x30\x1e\x17"
+"\x0d\x32\x31\x30\x31\x32\x30\x31\x39\x31\x34\x30\x33\x5a\x17\x0d"
+"\x32\x34\x30\x39\x33\x30\x31\x38\x31\x34\x30\x33\x5a\x30\x4f\x31"
+"\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x29\x30\x27"
+"\x06\x03\x55\x04\x0a\x13\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x20"
+"\x53\x65\x63\x75\x72\x69\x74\x79\x20\x52\x65\x73\x65\x61\x72\x63"
+"\x68\x20\x47\x72\x6f\x75\x70\x31\x15\x30\x13\x06\x03\x55\x04\x03"
+"\x13\x0c\x49\x53\x52\x47\x20\x52\x6f\x6f\x74\x20\x58\x31\x30\x82"
+"\x02\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05"
+"\x00\x03\x82\x02\x0f\x00\x30\x82\x02\x0a\x02\x82\x02\x01\x00\xad"
+"\xe8\x24\x73\xf4\x14\x37\xf3\x9b\x9e\x2b\x57\x28\x1c\x87\xbe\xdc"
+"\xb7\xdf\x38\x90\x8c\x6e\x3c\xe6\x57\xa0\x78\xf7\x75\xc2\xa2\xfe"
+"\xf5\x6a\x6e\xf6\x00\x4f\x28\xdb\xde\x68\x86\x6c\x44\x93\xb6\xb1"
+"\x63\xfd\x14\x12\x6b\xbf\x1f\xd2\xea\x31\x9b\x21\x7e\xd1\x33\x3c"
+"\xba\x48\xf5\xdd\x79\xdf\xb3\xb8\xff\x12\xf1\x21\x9a\x4b\xc1\x8a"
+"\x86\x71\x69\x4a\x66\x66\x6c\x8f\x7e\x3c\x70\xbf\xad\x29\x22\x06"
+"\xf3\xe4\xc0\xe6\x80\xae\xe2\x4b\x8f\xb7\x99\x7e\x94\x03\x9f\xd3"
+"\x47\x97\x7c\x99\x48\x23\x53\xe8\x38\xae\x4f\x0a\x6f\x83\x2e\xd1"
+"\x49\x57\x8c\x80\x74\xb6\xda\x2f\xd0\x38\x8d\x7b\x03\x70\x21\x1b"
+"\x75\xf2\x30\x3c\xfa\x8f\xae\xdd\xda\x63\xab\xeb\x16\x4f\xc2\x8e"
+"\x11\x4b\x7e\xcf\x0b\xe8\xff\xb5\x77\x2e\xf4\xb2\x7b\x4a\xe0\x4c"
+"\x12\x25\x0c\x70\x8d\x03\x29\xa0\xe1\x53\x24\xec\x13\xd9\xee\x19"
+"\xbf\x10\xb3\x4a\x8c\x3f\x89\xa3\x61\x51\xde\xac\x87\x07\x94\xf4"
+"\x63\x71\xec\x2e\xe2\x6f\x5b\x98\x81\xe1\x89\x5c\x34\x79\x6c\x76"
+"\xef\x3b\x90\x62\x79\xe6\xdb\xa4\x9a\x2f\x26\xc5\xd0\x10\xe1\x0e"
+"\xde\xd9\x10\x8e\x16\xfb\xb7\xf7\xa8\xf7\xc7\xe5\x02\x07\x98\x8f"
+"\x36\x08\x95\xe7\xe2\x37\x96\x0d\x36\x75\x9e\xfb\x0e\x72\xb1\x1d"
+"\x9b\xbc\x03\xf9\x49\x05\xd8\x81\xdd\x05\xb4\x2a\xd6\x41\xe9\xac"
+"\x01\x76\x95\x0a\x0f\xd8\xdf\xd5\xbd\x12\x1f\x35\x2f\x28\x17\x6c"
+"\xd2\x98\xc1\xa8\x09\x64\x77\x6e\x47\x37\xba\xce\xac\x59\x5e\x68"
+"\x9d\x7f\x72\xd6\x89\xc5\x06\x41\x29\x3e\x59\x3e\xdd\x26\xf5\x24"
+"\xc9\x11\xa7\x5a\xa3\x4c\x40\x1f\x46\xa1\x99\xb5\xa7\x3a\x51\x6e"
+"\x86\x3b\x9e\x7d\x72\xa7\x12\x05\x78\x59\xed\x3e\x51\x78\x15\x0b"
+"\x03\x8f\x8d\xd0\x2f\x05\xb2\x3e\x7b\x4a\x1c\x4b\x73\x05\x12\xfc"
+"\xc6\xea\xe0\x50\x13\x7c\x43\x93\x74\xb3\xca\x74\xe7\x8e\x1f\x01"
+"\x08\xd0\x30\xd4\x5b\x71\x36\xb4\x07\xba\xc1\x30\x30\x5c\x48\xb7"
+"\x82\x3b\x98\xa6\x7d\x60\x8a\xa2\xa3\x29\x82\xcc\xba\xbd\x83\x04"
+"\x1b\xa2\x83\x03\x41\xa1\xd6\x05\xf1\x1b\xc2\xb6\xf0\xa8\x7c\x86"
+"\x3b\x46\xa8\x48\x2a\x88\xdc\x76\x9a\x76\xbf\x1f\x6a\xa5\x3d\x19"
+"\x8f\xeb\x38\xf3\x64\xde\xc8\x2b\x0d\x0a\x28\xff\xf7\xdb\xe2\x15"
+"\x42\xd4\x22\xd0\x27\x5d\xe1\x79\xfe\x18\xe7\x70\x88\xad\x4e\xe6"
+"\xd9\x8b\x3a\xc6\xdd\x27\x51\x6e\xff\xbc\x64\xf5\x33\x43\x4f\x02"
+"\x03\x01\x00\x01\xa3\x82\x01\x46\x30\x82\x01\x42\x30\x0f\x06\x03"
+"\x55\x1d\x13\x01\x01\xff\x04\x05\x30\x03\x01\x01\xff\x30\x0e\x06"
+"\x03\x55\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01\x06\x30\x4b\x06"
+"\x08\x2b\x06\x01\x05\x05\x07\x01\x01\x04\x3f\x30\x3d\x30\x3b\x06"
+"\x08\x2b\x06\x01\x05\x05\x07\x30\x02\x86\x2f\x68\x74\x74\x70\x3a"
+"\x2f\x2f\x61\x70\x70\x73\x2e\x69\x64\x65\x6e\x74\x72\x75\x73\x74"
+"\x2e\x63\x6f\x6d\x2f\x72\x6f\x6f\x74\x73\x2f\x64\x73\x74\x72\x6f"
+"\x6f\x74\x63\x61\x78\x33\x2e\x70\x37\x63\x30\x1f\x06\x03\x55\x1d"
+"\x23\x04\x18\x30\x16\x80\x14\xc4\xa7\xb1\xa4\x7b\x2c\x71\xfa\xdb"
+"\xe1\x4b\x90\x75\xff\xc4\x15\x60\x85\x89\x10\x30\x54\x06\x03\x55"
+"\x1d\x20\x04\x4d\x30\x4b\x30\x08\x06\x06\x67\x81\x0c\x01\x02\x01"
+"\x30\x3f\x06\x0b\x2b\x06\x01\x04\x01\x82\xdf\x13\x01\x01\x01\x30"
+"\x30\x30\x2e\x06\x08\x2b\x06\x01\x05\x05\x07\x02\x01\x16\x22\x68"
+"\x74\x74\x70\x3a\x2f\x2f\x63\x70\x73\x2e\x72\x6f\x6f\x74\x2d\x78"
+"\x31\x2e\x6c\x65\x74\x73\x65\x6e\x63\x72\x79\x70\x74\x2e\x6f\x72"
+"\x67\x30\x3c\x06\x03\x55\x1d\x1f\x04\x35\x30\x33\x30\x31\xa0\x2f"
+"\xa0\x2d\x86\x2b\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x6c\x2e\x69"
+"\x64\x65\x6e\x74\x72\x75\x73\x74\x2e\x63\x6f\x6d\x2f\x44\x53\x54"
+"\x52\x4f\x4f\x54\x43\x41\x58\x33\x43\x52\x4c\x2e\x63\x72\x6c\x30"
+"\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x79\xb4\x59\xe6\x7b\xb6"
+"\xe5\xe4\x01\x73\x80\x08\x88\xc8\x1a\x58\xf6\xe9\x9b\x6e\x30\x0d"
+"\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01"
+"\x01\x00\x0a\x73\x00\x6c\x96\x6e\xff\x0e\x52\xd0\xae\xdd\x8c\xe7"
+"\x5a\x06\xad\x2f\xa8\xe3\x8f\xbf\xc9\x0a\x03\x15\x50\xc2\xe5\x6c"
+"\x42\xbb\x6f\x9b\xf4\xb4\x4f\xc2\x44\x88\x08\x75\xcc\xeb\x07\x9b"
+"\x14\x62\x6e\x78\xde\xec\x27\xba\x39\x5c\xf5\xa2\xa1\x6e\x56\x94"
+"\x70\x10\x53\xb1\xbb\xe4\xaf\xd0\xa2\xc3\x2b\x01\xd4\x96\xf4\xc5"
+"\x20\x35\x33\xf9\xd8\x61\x36\xe0\x71\x8d\xb4\xb8\xb5\xaa\x82\x45"
+"\x95\xc0\xf2\xa9\x23\x28\xe7\xd6\xa1\xcb\x67\x08\xda\xa0\x43\x2c"
+"\xaa\x1b\x93\x1f\xc9\xde\xf5\xab\x69\x5d\x13\xf5\x5b\x86\x58\x22"
+"\xca\x4d\x55\xe4\x70\x67\x6d\xc2\x57\xc5\x46\x39\x41\xcf\x8a\x58"
+"\x83\x58\x6d\x99\xfe\x57\xe8\x36\x0e\xf0\x0e\x23\xaa\xfd\x88\x97"
+"\xd0\xe3\x5c\x0e\x94\x49\xb5\xb5\x17\x35\xd2\x2e\xbf\x4e\x85\xef"
+"\x18\xe0\x85\x92\xeb\x06\x3b\x6c\x29\x23\x09\x60\xdc\x45\x02\x4c"
+"\x12\x18\x3b\xe9\xfb\x0e\xde\xdc\x44\xf8\x58\x98\xae\xea\xbd\x45"
+"\x45\xa1\x88\x5d\x66\xca\xfe\x10\xe9\x6f\x82\xc8\x11\x42\x0d\xfb"
+"\xe9\xec\xe3\x86\x00\xde\x9d\x10\xe3\x38\xfa\xa4\x7d\xb1\xd8\xe8"
+"\x49\x82\x84\x06\x9b\x2b\xe8\x6b\x4f\x01\x0c\x38\x77\x2e\xf9\xdd"
+"\xe7\x39\x00\x00\x00\x01\x90\x30\x82\x01\x8c\x30\x82\x01\x32\xa0"
+"\x03\x02\x01\x02\x02\x08\x79\xe4\xdb\x53\x53\xee\x6a\x34\x30\x0a"
+"\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x18\x31\x16\x30\x14"
+"\x06\x03\x55\x04\x03\x0c\x0d\x48\x53\x20\x44\x48\x3a\x20\x58\x32"
+"\x35\x35\x31\x39\x30\x1e\x17\x0d\x32\x33\x30\x34\x31\x36\x30\x30"
+"\x33\x33\x35\x32\x5a\x17\x0d\x32\x33\x30\x35\x31\x36\x31\x32\x33"
+"\x33\x35\x32\x5a\x30\x27\x31\x25\x30\x23\x06\x03\x55\x04\x03\x0c"
+"\x1c\x49\x50\x2c\x20\x70\x6f\x72\x74\x3a\x20\x38\x32\x2e\x36\x34"
+"\x2e\x37\x35\x2e\x31\x38\x32\x3a\x35\x32\x37\x38\x37\x30\x59\x30"
+"\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce"
+"\x3d\x03\x01\x07\x03\x42\x00\x04\x25\x98\xdb\x7b\x19\xfd\x4d\x11"
+"\x76\x2d\x65\x75\xa5\xb0\x62\xf0\xad\x69\x80\xf8\xb8\x99\xe4\x3a"
+"\xd3\x12\x67\xa4\xe5\xe2\x3a\xb6\xbd\xcc\x4b\x29\x96\x91\xba\x07"
+"\xc5\x35\x9e\xef\xff\xe9\x59\xd0\x80\xad\x99\xb6\x1b\xf0\xd3\xea"
+"\xcb\x1a\x87\xac\xa8\x7c\xaa\x48\xa3\x57\x30\x55\x30\x0e\x06\x03"
+"\x55\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x07\x80\x30\x0c\x06\x03"
+"\x55\x1d\x13\x01\x01\xff\x04\x02\x30\x00\x30\x1d\x06\x03\x55\x1d"
+"\x25\x04\x16\x30\x14\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x01\x06"
+"\x08\x2b\x06\x01\x05\x05\x07\x03\x02\x30\x16\x06\x03\x55\x1d\x11"
+"\x04\x0f\x30\x0d\x82\x0b\x74\x6c\x73\x31\x33\x2e\x31\x64\x2e\x70"
+"\x77\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00"
+"\x30\x45\x02\x20\x0d\xc4\xa3\xb6\xe4\x83\x07\x32\x3b\x74\x99\xc6"
+"\xa4\x6a\x41\x19\x8c\xdc\x1a\xaa\x4f\x49\x41\x00\x05\x0d\x04\x32"
+"\x36\xbd\x4d\x3e\x02\x21\x00\xf8\x3d\xa3\xcb\xdd\x51\x8c\xd8\xc6"
+"\x42\x7e\x3b\x1a\x57\x92\xde\x14\x5f\x79\xdc\xe5\x1a\x48\x66\x6d"
+"\x52\x9f\xad\x68\x59\x6a\xf2\x00\x00";
+size_t tls13_test_case_2_certs_size = sizeof(tls13_test_case_2_certs) - 1;
+
+/* The results are banners as base64 */
+const char tls13_test_case_2_result_cert1[] =
+"MIIBjDCCATKgAwIBAgIIeeTbU1PuajQwCgYIKoZIzj0EAwIwGDEWMBQGA1UEAwwN"
+"SFMgREg6IFgyNTUxOTAeFw0yMzA0MTYwMDMzNTJaFw0yMzA1MTYxMjMzNTJaMCcx"
+"JTAjBgNVBAMMHElQLCBwb3J0OiA4Mi42NC43NS4xODI6NTI3ODcwWTATBgcqhkjO"
+"PQIBBggqhkjOPQMBBwNCAAQlmNt7Gf1NEXYtZXWlsGLwrWmA+LiZ5DrTEmek5eI6"
+"tr3MSymWkboHxTWe7//pWdCArZm2G/DT6ssah6yofKpIo1cwVTAOBgNVHQ8BAf8E"
+"BAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH"
+"AwIwFgYDVR0RBA8wDYILdGxzMTMuMWQucHcwCgYIKoZIzj0EAwIDSAAwRQIgDcSj"
+"tuSDBzI7dJnGpGpBGYzcGqpPSUEABQ0EMja9TT4CIQD4PaPL3VGM2MZCfjsaV5Le"
+"FF953OUaSGZtUp+taFlq8g==";
+const char tls13_test_case_2_result_cert2[] =
+"MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/"
+"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT"
+"DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow"
+"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh"
+"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB"
+"AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC"
+"ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL"
+"wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D"
+"LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK"
+"4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5"
+"bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y"
+"sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ"
+"Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4"
+"FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc"
+"SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql"
+"PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND"
+"TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw"
+"SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1"
+"c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx"
+"+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB"
+"ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu"
+"b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E"
+"U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu"
+"MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC"
+"5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW"
+"9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG"
+"WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O"
+"he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC"
+"Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5";
+const char tls13_test_case_2_result_cert3[] =
+"MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw"
+"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh"
+"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw"
+"WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg"
+"RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK"
+"AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP"
+"R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx"
+"sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm"
+"NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg"
+"Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG"
+"/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC"
+"AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB"
+"Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA"
+"FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw"
+"AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw"
+"Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB"
+"gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W"
+"PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl"
+"ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz"
+"CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm"
+"lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4"
+"avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2"
+"yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O"
+"yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids"
+"hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+"
+"HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv"
+"MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX"
+"nLRbwHOoq7hHwg==";
+const char tls13_test_case_2_result_cert4[] =
+"MIIEbzCCA1egAwIBAgISBNg/rNXiHIoMvWCrXy/Rig29MA0GCSqGSIb3DQEBCwUA"
+"MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD"
+"EwJSMzAeFw0yMzAyMjcxMTAxMjhaFw0yMzA1MjgxMTAxMjdaMBYxFDASBgNVBAMT"
+"C3RsczEzLjFkLnB3MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3q3A3tfL+36jumM3"
+"GAZTN/nQ904zMhdlvN+pDecoQoDyGGBhznkmjG2Pqr71M+Kvk8FGDcnALcqHMH2o"
+"fdRCLew0qNzR25+UHVREyaQHXnf7/VFtJoA1zdHnfk1rvxaPo4ICRzCCAkMwDgYD"
+"VR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV"
+"HRMBAf8EAjAAMB0GA1UdDgQWBBRxbDh9gEoTeAxZSjxKBNmvaN7vCDAfBgNVHSME"
+"GDAWgBQULrMXt1hWy65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYB"
+"BQUHMAGGFWh0dHA6Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDov"
+"L3IzLmkubGVuY3Iub3JnLzAWBgNVHREEDzANggt0bHMxMy4xZC5wdzBMBgNVHSAE"
+"RTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRw"
+"Oi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3"
+"AHoyjFTYty22IOo44FIe6YQWcDIThU070ivBOlejUutSAAABhpK/yoAAAAQDAEgw"
+"RgIhAOVLXm2j3B3E5E5qufwDhZyoO3EvbZluXwfuGQQ5LXUQAiEApEGjC1rKafK9"
+"tX6Bv+y880gJLyMs5uaEMjR72CfnpHYAdgDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr"
+"7Otp4Xd9bQa9bgAAAYaSv8psAAAEAwBHMEUCIQDbbcuxf3mqBc69jw7GUfZz4Go3"
+"QyWgcjWZazs7u0E6YgIgPFmFmZvaYxPlPl2Jb1HInENteODcKwl0tTB1U5eoabww"
+"DQYJKoZIhvcNAQELBQADggEBAD9Ywu1H7IEoxP2e8b5/olX4C/+qLzv8SovYJjWI"
+"j81itIez1qyXw3smYgrBI18s0oy73pWfOaM0vLjnczBbDUMGzD7yfuQXz+QP8fWW"
+"qURcZ9C6K92hRPTalfpz7EoGqBSgp6jf7JUoildzhy9LrnMCCjVlMoNuHFVYzZVn"
+"c99mYdnV/ezf3oY6wbV6zu/9j1q2Dxi8kTYP6eqm+fwD0AGwfos77ucl187WNdj0"
+"YRcVMYLchWZwnT2Kw0lZ29W0VPiseVHGz+yY/mnvDqWye5slnoz8P6rkM/++osMj"
+"SvdRNR+V6eMQPb0dm5M3QRCbmV7Tt7o7T8U7GNmAgnmFuTI=";
\ No newline at end of file
diff --git a/src/proto-ssl.c b/src/proto-ssl.c
index 492d527f..16a8b92c 100644
--- a/src/proto-ssl.c
+++ b/src/proto-ssl.c
@@ -52,12 +52,16 @@
#include "crypto-siphash24.h"
#include "util-safefunc.h"
#include "util-malloc.h"
+
+#include "crypto-aes256.h"
+#include "crypto-curve25519.h"
+#include "crypto-rfc6234.h"
+
+#include
#include
#include
#include
-
-
/**
* Fugly macro for doing state-machine parsing. I know it's bad, but
* it makes stepping through the code in a debugger so much easier.
@@ -117,6 +121,115 @@ BANNER_VERSION(struct BannerOutput *banout, unsigned version_major,
}
}
+/*****************************************************************************
+ *****************************************************************************/
+/*
+ * This key is the private key hardcoded for all X25519 exchanges
+ */
+static const unsigned char
+tls_x25519_privkey[] =
+"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f";
+
+#define iv_length 12
+
+/*
+ * HKDF-Expand-Label as per RFC 8446 sect 7.1.
+ * This is made to be compatible with crypto-rfc6234
+ */
+int hkdfExpandLabel(SHAversion whichSha, const uint8_t prk[ ], int prk_len,
+ const char *label, uint8_t label_len,
+ const unsigned char *ctx, uint8_t ctx_len,
+ uint8_t okm[ ], uint16_t okm_len)
+{
+ if (label_len > 0xf9) {
+ // too big
+ return shaBadParam;
+ }
+ uint16_t info_len = label_len + ctx_len + 10;
+ if (info_len > 514) {
+ // impossible
+ return shaBadParam;
+ }
+ unsigned char info[514];
+ memset(info, 0, 514);
+ info[0] = (okm_len) >> 8;
+ info[1] = (okm_len) & 0xff;
+ info[2] = 6 + label_len;
+ memcpy(info + 3, "tls13 ", 6);
+ memcpy(info + 9, label, label_len);
+ info[9 + label_len] = ctx_len;
+ if (ctx != NULL) {
+ memcpy(info + 10 + label_len, ctx, ctx_len);
+ }
+ return hkdfExpand(whichSha,
+ prk, prk_len,
+ info, info_len,
+ okm, okm_len);
+}
+
+/*
+ * This computes the TLS 1.3 keys, using x25519 + TLS_AES_256_GCM_SHA384.
+ * The ciphers used and the client keys are all hardcoded.
+ */
+
+unsigned char derived_secret[48] =
+"\x15\x91\xda\xc5\xcb\xbf\x03\x30\xa4\xa8\x4d\xe9\xc7\x53\x33\x0e"
+"\x92\xd0\x1f\x0a\x88\x21\x4b\x44\x64\x97\x2f\xd6\x68\x04\x9e\x93"
+"\xe5\x2f\x2b\x16\xfa\xd9\x22\xfd\xc0\x58\x44\x78\x42\x8f\x28\x2b";
+
+enum {
+ NEGO_NONE,
+ NEGO_HANDSHAKE_KEYS,
+ NEGO_APPLICATION_KEYS,
+};
+
+static void
+compute_tls_handshake_keys(
+ struct StreamState *pstate
+)
+{
+ unsigned char pre_master_secret[32];
+ unsigned char hello_hash[48];
+ unsigned char handhake_secret[64]; // usable size: 48 bytes
+ unsigned char client_secret[48];
+ unsigned char server_secret[48];
+
+ // Compute the PreMasterKey
+ curve25519_donna(pre_master_secret,
+ tls_x25519_privkey,
+ pstate->sub.ssl.x.server_hello.kx_data);
+
+ // Finalize the SHA-384 hash
+ SHA384Result(&pstate->sub.ssl.handshake.sha384ctx,
+ hello_hash);
+
+ // Compute the derived secret: HARDCODED for speed
+
+ // static const unsigned char _zerokey[48] = {0};
+ // unsigned char early_secret[48];
+ // hkdfExtract(SHA384, NULL, 0, _zerokey, 48, early_secret);
+ // unsigned char empty_hash[48];
+ // SHA384Context empty_hashctx;
+ // SHA384Reset(&empty_hashctx);
+ // SHA384Result(&empty_hashctx, empty_hash);
+ // hkdfExpandLabel(SHA384, early_secret, 48, "derived", 7, empty_hash, 48, derived_secret, 48);
+
+ // Compute the handshake secret
+ hkdfExtract(SHA384, derived_secret, 48, pre_master_secret, 32, handhake_secret);
+
+ // compute client and server secret
+ hkdfExpandLabel(SHA384, handhake_secret, 48, "c hs traffic", 12, hello_hash, 48, client_secret, 48);
+ hkdfExpandLabel(SHA384, handhake_secret, 48, "s hs traffic", 12, hello_hash, 48, server_secret, 48);
+
+ // compute handshake keys
+ hkdfExpandLabel(SHA384, client_secret, 48, "key", 3, NULL, 0, pstate->sub.ssl.handshake.client_handshake_key.raw, 32);
+ hkdfExpandLabel(SHA384, server_secret, 48, "key", 3, NULL, 0, pstate->sub.ssl.handshake.server_handshake_key.raw, 32);
+ hkdfExpandLabel(SHA384, client_secret, 48, "iv", 2, NULL, 0, pstate->sub.ssl.handshake.client_handshake_iv, 12);
+ hkdfExpandLabel(SHA384, server_secret, 48, "iv", 2, NULL, 0, pstate->sub.ssl.handshake.server_handshake_iv, 12);
+
+ pstate->sub.ssl.handshake.negotiation_state = NEGO_HANDSHAKE_KEYS;
+}
/*****************************************************************************
* This parses the "Server Hello" packet, the response to our "ClientHello"
@@ -150,6 +263,7 @@ parse_server_hello(
EXT_DATA,
EXT_DATA_HEARTBEAT,
EXT_DATA_SUPPORTED_VERSIONS,
+ EXT_DATA_KEY_SHARE,
UNKNOWN,
};
@@ -277,37 +391,42 @@ parse_server_hello(
state = UNKNOWN;
continue;
}
- hello->ext_tag = px[i]<<8;
+ hello->ext.i = 0;
+ hello->ext.tag = px[i]<<8;
remaining--;
DROPDOWN(i,length,state);
case EXT_TAG1:
- hello->ext_tag |= px[i];
+ hello->ext.tag |= px[i];
remaining--;
DROPDOWN(i,length,state);
case EXT_LEN0:
- hello->ext_remaining = px[i]<<8;
+ hello->ext.len = px[i]<<8;
remaining--;
DROPDOWN(i,length,state);
case EXT_LEN1:
- hello->ext_remaining |= px[i];
+ hello->ext.len |= px[i];
remaining--;
// Next step depends on the tag
- switch (hello->ext_tag) {
+ switch (hello->ext.tag) {
case 0x000f: /* heartbeat */
state = EXT_DATA_HEARTBEAT;
continue;
case 0x002b: /* supported_versions */
state = EXT_DATA_SUPPORTED_VERSIONS;
continue;
+ case 0x0033: /* key_share */
+ state = EXT_DATA_KEY_SHARE;
+ continue;
}
DROPDOWN(i,length,state);
case EXT_DATA:
case EXT_DATA_HEARTBEAT:
case EXT_DATA_SUPPORTED_VERSIONS:
- if (hello->ext_remaining == 0) {
+ case EXT_DATA_KEY_SHARE:
+ if (hello->ext.i >= hello->ext.len) {
state = EXT_TAG0;
goto ext_tag;
}
@@ -316,7 +435,7 @@ parse_server_hello(
continue;
}
remaining--;
- hello->ext_remaining--;
+ hello->ext.i++;
switch (state) {
case EXT_DATA_HEARTBEAT:
@@ -324,26 +443,42 @@ parse_server_hello(
banout_append( banout, PROTO_VULN, "SSL[heartbeat] ", 15);
}
state = EXT_DATA;
+ continue;
case EXT_DATA_SUPPORTED_VERSIONS:
- if (hello->ext_remaining) {
+ if (hello->ext.i == 1) {
hello->version_major = px[i];
- } else {
+ } else if (hello->ext.i == 2) {
hello->version_minor = px[i];
if ((hello->version_major<<8 | hello->version_minor) == 0x0304) { // TLS 1.3
banout_replacefirst(banout, PROTO_SSL3, "TLS/1.2", "TLS/1.3");
}
}
+ continue;
+ case EXT_DATA_KEY_SHARE:
+ // This is a TLS 1.3 only extension
+ // get the 32bytes (x25519) of the server public key
+ if (hello->ext.i > 4 && hello->ext.i <= 36) {
+ hello->kx_data[hello->ext.i - 5] = px[i];
+ }
+ continue;
default:
+ // skip unknown extension
+ hello->ext.i = hello->ext.len;
+ i += hello->ext.len;
+ remaining -= (hello->ext.len - 1);
}
continue;
-
-
case UNKNOWN:
default:
i = (unsigned)length;
}
+ if (remaining == 0) {
+ /* end of the serverhello */
+ state = 0;
+ }
+
hello->state = state;
hello->remaining = remaining;
}
@@ -384,7 +519,8 @@ parse_server_cert(
struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct stack_handle_t *socket)
+ struct stack_handle_t *socket,
+ bool tls_13)
{
struct SSL_SERVER_CERT *data = &pstate->sub.ssl.x.server_cert;
unsigned state = data->state;
@@ -392,11 +528,13 @@ parse_server_cert(
unsigned cert_remaining = data->sub.remaining;
unsigned i;
enum {
+ CTXTLEN, CTXT, // TLS 1.3 cert only
LEN0, LEN1, LEN2,
CLEN0, CLEN1, CLEN2,
CERT,
CALEN0, CALEN1, CALEN2,
CACERT,
+ EXTLEN1, EXTLEN2, EXT, // TLS 1.3 cert only
UNKNOWN,
};
@@ -404,8 +542,30 @@ parse_server_cert(
UNUSEDPARM(banner1_private);
UNUSEDPARM(socket);
+ if (state == CTXTLEN && !tls_13) {
+ // If not on TLS 1.3, skip to LEN0 directly
+ state = LEN0;
+ }
+
for (i=0; i remaining)
+ len = remaining;
+
+ // skip
+ remaining -= len;
+ i += len-1;
+ if (remaining != 0)
+ break;
+ }
+ DROPDOWN(i,length,state);
case LEN0:
remaining = px[i];
DROPDOWN(i,length,state);
@@ -451,7 +611,7 @@ parse_server_cert(
case CACERT:
{
unsigned len = (unsigned)length-i;
- unsigned proto = (state == CERT ? PROTO_X509_CERT : PROTO_X509_CACERT);
+ unsigned proto = (state == CERT ? PROTO_X509_CERT : PROTO_X509_CACERT);
if (len > remaining)
len = remaining;
if (len > cert_remaining)
@@ -481,18 +641,49 @@ parse_server_cert(
&pstate->base64);
banout_end(banout, proto);
}
- state = CALEN0;
- if (remaining == 0) {
- /* FIXME: reduce this logic, it should only flush the
- * FIXME: ertificate, not close the connection*/
- if (!banner1->is_heartbleed) {
- ; //tcpapi_close(socket);
+ if (tls_13) {
+ // TLS 1.3 has a 2 extra fields
+ state = EXTLEN1;
+ } else {
+ state = CALEN0;
+ if (remaining == 0) {
+ /* FIXME: reduce this logic, it should only flush the
+ * FIXME: ertificate, not close the connection*/
+ if (!banner1->is_heartbleed) {
+ ; //tcpapi_close(socket);
+ }
}
}
}
}
break;
+ /* TLS 1.3 only */
+ case EXTLEN1:
+ // we use cert_remaining to store extlen
+ cert_remaining = px[i] << 8;
+ remaining--;
+ DROPDOWN(i,length,state);
+ case EXTLEN2:
+ cert_remaining |= px[i];
+ remaining--;
+ DROPDOWN(i,length,state);
+ case EXT:
+ {
+ unsigned len = (unsigned)length-i;
+ if (len > remaining)
+ len = remaining;
+ if (len > cert_remaining)
+ len = cert_remaining;
+ // skip
+ remaining -= len;
+ cert_remaining -= len;
+ i += len-1;
+ if (!cert_remaining || !remaining) {
+ state = CALEN0;
+ break;
+ }
+ }
case UNKNOWN:
default:
@@ -536,7 +727,9 @@ parse_handshake(
struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct stack_handle_t *socket)
+ struct stack_handle_t *socket,
+ const unsigned char *client_hello, size_t client_hello_length,
+ bool tls_13)
{
struct SSLRECORD *ssl = &pstate->sub.ssl;
unsigned state = ssl->handshake.state;
@@ -549,6 +742,23 @@ parse_handshake(
UNKNOWN,
};
+ /*
+ * TLS 1.3 needs to SHA384 the client hello + server hello
+ */
+ if (tls_13) {
+ if (state == START && client_hello != NULL) {
+ SHA384Reset(&ssl->handshake.sha384ctx);
+ // dump client hello (skip record)
+ SHA384Input(&ssl->handshake.sha384ctx,
+ client_hello + 5,
+ client_hello_length - 5);
+ }
+ // dump server hello as it comes
+ SHA384Input(&ssl->handshake.sha384ctx,
+ px,
+ length);
+ }
+
/*
* `for all bytes in the segment`
* `do a state transition for that byte `
@@ -627,7 +837,7 @@ parse_handshake(
break;
case 2: /* server hello */
- parse_server_hello( banner1,
+ parse_server_hello(banner1,
banner1_private,
pstate,
px+i, len,
@@ -640,15 +850,25 @@ parse_handshake(
pstate,
px+i, len,
banout,
- socket);
+ socket,
+ tls_13);
break;
}
remaining -= len;
i += len-1;
- if (remaining == 0)
+ if (remaining == 0) {
+ /* end of handshake record */
state = START;
+ /* reset the sequence number */
+ ssl->seqnum = 0;
+ if (tls_13 && ssl->handshake.type == 2) {
+ // we should have everything to compute the
+ // TLS 1.3 keys by now.
+ compute_tls_handshake_keys(pstate);
+ }
+ }
}
break;
@@ -736,7 +956,6 @@ parse_heartbeat(
/* if we've been configured to "capture" the heartbleed contents,
* then initialize the BASE64 encoder */
if (banner1->is_capture_heartbleed) {
- banout_init_base64(&pstate->base64);
banout_append(banout, PROTO_HEARTBLEED, "", 0);
}
}
@@ -876,6 +1095,134 @@ parse_alert(
ssl->handshake.remaining = remaining;
}
+/*****************************************************************************
+ * Called to decrypt encrypted application_data.
+ *
+ * This is mainly used to retrieve the server certificate, which is encrypted
+ * in the case of TLS 1.3. Note that to stick to masscan's paradigm, the TLS
+ * fragments are not reassembled: instead only the minimum 128 bits of data are
+ * aggregated in the AES state, which is decrypted and sent to banout directly.
+ * Unlike normal AES this requires an additional offset that allows to handle
+ * cross-packet skips.
+ *
+ *****************************************************************************/
+static void
+parse_application_data(
+ const struct Banner1 *banner1,
+ void *banner1_private,
+ struct StreamState *pstate,
+ const unsigned char *px, size_t length,
+ struct BannerOutput *banout,
+ struct stack_handle_t *socket,
+ bool record_end,
+ bool tls_13)
+{
+ struct SSLRECORD *ssl = &pstate->sub.ssl;
+ unsigned state = ssl->application_data.state;
+ struct AES_CTR_STATE *aes = &ssl->application_data.aes;
+ unsigned i,j;
+ enum {
+ START,
+ DATA,
+ UNKNOWN,
+ };
+
+ if (ssl->handshake.negotiation_state != NEGO_HANDSHAKE_KEYS) {
+ /* We don't have the handshake keys */
+ return;
+ }
+
+ if (tls_13 && state == START) {
+ /* We perform AES decryption bloc by bloc, so that we don't
+ * ever aggregate more than 128 bits at a time. However when
+ * fragmented, we must remember what's left in the current
+ * AES buffer. This is what 'offset' is for.
+ */
+ aes->offset = 0;
+ /* Initialize aes key */
+ aes256_init(&aes->key, &ssl->handshake.server_handshake_key);
+ /* Calculate the ICB: last 64 bits are seqnum as big endian */
+ memset(aes->counter, 0, 16);
+ for (i=0; i<8; i++)
+ aes->counter[iv_length-1-i] = (ssl->seqnum >> (8*i)) & 0xFF;
+ /* XOR with iv */
+ for (i = 0; i < iv_length; i++)
+ aes->counter[i] ^= ssl->handshake.server_handshake_iv[i];
+ /* HERE aes->counter is the ICB */
+ /* Increment the counter once (as the counter 0 is only for Auth tag) */
+ aes256_ctr_inc(aes->counter);
+ state = DATA;
+ }
+
+ switch(state) {
+ case DATA:
+ {
+ /* This is a TLS 1.3 encrypted certificate */
+ unsigned remaining = length;
+ aes256_blk_t temp;
+ uint8_t len;
+ i = 0;
+ do {
+ /* Fill the 128 bits buffer: len is how much we want */
+ len = 16 - aes->offset;
+ if (len > remaining) {
+ if (!record_end) {
+ /* Not the end of the record + remaining */
+ memcpy(aes->buf+aes->offset, px+i, remaining);
+ aes->offset += (uint8_t) remaining;
+ break;
+ } else {
+ /* End of record: pad and continue */
+ memset(aes->buf+aes->offset+remaining, 0, len - remaining);
+ len = remaining;
+ }
+ }
+ memcpy(aes->buf+aes->offset, px+i, len);
+
+ // Reminder of how GCM works (but we ignore the authTag part. yolo)
+ // https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Galois/counter_(GCM)
+
+ /* Increment the counter */
+ aes256_ctr_inc(aes->counter);
+
+ /* Perform encryption of the counter */
+ memcpy(temp.raw, aes->counter, 16);
+ aes256_encrypt_ecb(&aes->key, &temp);
+
+ /* XOR the result with the ciphertext */
+ for (j = 0; j < 16; j++)
+ temp.raw[j] ^= aes->buf[j];
+
+ /* Parse the decrypted data */
+ parse_handshake(banner1,
+ banner1_private,
+ pstate,
+ temp.raw, len+aes->offset,
+ banout,
+ socket,
+ NULL,
+ 0,
+ tls_13);
+
+ i += len;
+ remaining -= len;
+ aes->offset = 0;
+ } while(remaining);
+ }
+ break;
+ }
+
+ /* End of current application_data record */
+ if(record_end) {
+ state = START;
+ ssl->seqnum += 1;
+ }
+
+ /* Any data we don't handle is discarded by ssl_parse_record */
+
+ ssl->application_data.state = state;
+}
+
/*****************************************************************************
* This is the main SSL parsing function.
@@ -906,7 +1253,9 @@ ssl_parse_record(
struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct stack_handle_t *socket)
+ struct stack_handle_t *socket,
+ const unsigned char *client_hello, size_t client_hello_length,
+ bool tls_13)
{
unsigned state = pstate->state;
unsigned remaining = pstate->remaining;
@@ -1021,10 +1370,33 @@ ssl_parse_record(
pstate,
px+i, len,
banout,
- socket);
+ socket,
+ client_hello,
+ client_hello_length,
+ tls_13);
break;
case 23: /* application data */
- /* encrypted, always*/
+ /* encrypted, always */
+
+ /* IMPORTANT !
+ * We are using an AEAD cipher.
+ * Therefore the last 16 bytes are the Auth tag, which
+ * we currently simply IGNORE. This is obviously crytographically
+ * broken, but faster to compute, and we just 'trust' the server. */
+ if (remaining <= 16)
+ break;
+ unsigned data_len = len;
+ if (data_len > remaining - 16)
+ data_len = remaining - 16;
+
+ parse_application_data(banner1,
+ banner1_private,
+ pstate,
+ px+i, data_len,
+ banout,
+ socket,
+ (data_len == remaining - 16),
+ tls_13);
break;
case 24: /* heartbeat */
/* encrypted, in theory, but not practice */
@@ -1119,17 +1491,82 @@ ssl_hello_template[] =
"\x04\x01\x05\x01\x06\x01\x03\x03\x02\x03\x03\x01\x02\x01\x03\x02"
"\x02\x02\x04\x02\x05\x02\x06\x02"
;
+static const size_t ssl_hello_template_length = sizeof(ssl_hello_template) - 1;
+
/*
* If the previous packet didn't work, the server is most likely TLS 1.3 only.
+ *
+ * The following is:
+ * - ciphers supported: [TLS_AES_256_GCM_SHA384]
+ * - ec_point_formats: [uncompressed]
+ * - supported_groups: [x25519]
+ * - key_share: x25519
+ *
+ * Client x25519:
+ * - privkey: 202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
+ * - pubkey: 358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254
+ *
+ * (why x25519 and not a simpler FFDHE? Because openssl<3.0 doesn't support it)
+ *
+ * to debug this string:
+ * $ scapy
+ * >>> load_layer("tls")
+ * >>> TLS(b"\x16\x03\x01.....").show()
*/
static const unsigned char
tls_13_hello_template[] =
-"\x16\x03\x01\x01\x1a"
+"\x16\x03\x01\x00\xd4"
"\x01"
-"\x00\x01\x16"
-"\x03\x03\x02\x58\x33\x79\x5f\x71\x03\xef\x07\xfe\x36\x61\xb0\x32\x81\xaa\x99\x10\x87\x6a\x8e\x5b\xf9\x03\x93\x44\x58\x4b\x19\xff\x42\x6a\x20\x64\x84\xcd\x28\x9c\xe9\xb1\x9d\xcd\x8a\x11\x4c\x3b\x40\x1c\x90\x02\xf2\xb5\x1a\xf1\x7e\x5d\xb8\x42\xc2\x1e\x17\x1e\x59\xa4\xac\x00\x3e\x13\x02\x13\x03\x13\x01\xc0\x2c\xc0\x30\x00\x9f\xcc\xa9\xcc\xa8\xcc\xaa\xc0\x2b\xc0\x2f\x00\x9e\xc0\x24\xc0\x28\x00\x6b\xc0\x23\xc0\x27\x00\x67\xc0\x0a\xc0\x14\x00\x39\xc0\x09\xc0\x13\x00\x33\x00\x9d\x00\x9c\x00\x3d\x00\x3c\x00\x35\x00\x2f\x00\xff\x01\x00\x00\x8f\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x0c\x00\x0a\x00\x1d\x00\x17\x00\x1e\x00\x19\x00\x18\x00\x23\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\x0d\x00\x2a\x00\x28\x04\x03\x05\x03\x06\x03\x08\x07\x08\x08\x08\x09\x08\x0a\x08\x0b\x08\x04\x08\x05\x08\x06\x04\x01\x05\x01\x06\x01\x03\x03\x03\x01\x03\x02\x04\x02\x05\x02\x06\x02\x00\x2b\x00\x09\x08\x03\x04\x03\x03\x03\x02\x03\x01\x00\x2d\x00\x02\x01\x01\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20\xb6\x87\xb7\x72\xb9\xcb\x07\xe0\x14\x0a\x14\x81\x3f\x3f\x0a\xcc\xc4\x7d\x80\xf7\xe8\xaa\x1e\x73\xb0\xa9\xad\xb8\x3a\xa7\x3c\x64";
-;
+"\x00\x00\xd0"
+"\x03\x03\x02\x58\x33\x79\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x00\x02\x13\x02\x01\x00\x00\x85\x00\x0b\x00\x02\x01\x00\x00\x0a\x00\x04\x00\x02\x00\x1d\x00\x23\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\x0d\x00\x2a\x00\x28\x04\x03\x05\x03\x06\x03\x08\x07\x08\x08\x08\x09\x08\x0a\x08\x0b\x08\x04\x08\x05\x08\x06\x04\x01\x05\x01\x06\x01\x03\x03\x03\x01\x03\x02\x04\x02\x05\x02\x06\x02\x00\x2b\x00\x09\x08\x03\x04\x03\x03\x03\x02\x03\x01\x00\x2d\x00\x02\x01\x01\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20\x35\x80\x72\xd6\x36\x58\x80\xd1\xae\xea\x32\x9a\xdf\x91\x21\x38\x38\x51\xed\x21\xa2\x8e\x3b\x75\xe9\x65\xd0\xd2\xcd\x16\x62\x54";
+static const size_t tls_13_hello_template_length = sizeof(tls_13_hello_template) - 1;
+
+/*****************************************************************************
+ * Those functions are stubs that call ssl_parse_record slightly differently
+ * depending on whether the client hello sent was for TLS1.3 or not.
+ *****************************************************************************/
+
+static void
+ssl_parse_record_tls13(
+ const struct Banner1 *banner1,
+ void *banner1_private,
+ struct StreamState *pstate,
+ const unsigned char *px, size_t length,
+ struct BannerOutput *banout,
+ struct stack_handle_t *socket)
+{
+ ssl_parse_record(banner1,
+ banner1_private,
+ pstate,
+ px, length,
+ banout,
+ socket,
+ tls_13_hello_template,
+ tls_13_hello_template_length,
+ true);
+}
+
+static void
+ssl_parse_record_tls1(
+ const struct Banner1 *banner1,
+ void *banner1_private,
+ struct StreamState *pstate,
+ const unsigned char *px, size_t length,
+ struct BannerOutput *banout,
+ struct stack_handle_t *socket)
+{
+ ssl_parse_record(banner1,
+ banner1_private,
+ pstate,
+ px, length,
+ banout,
+ socket,
+ ssl_hello_template,
+ ssl_hello_template_length,
+ false);
+}
+
/*****************************************************************************
*****************************************************************************/
static char *
@@ -1274,7 +1711,21 @@ extern unsigned char google_cert[];
extern size_t google_cert_size;
extern unsigned char yahoo_cert[];
extern size_t yahoo_cert_size;
-
+extern unsigned char tls13_test_case_1_clienthello[];
+extern size_t tls13_test_case_1_clienthello_size;
+extern unsigned char tls13_test_case_1_kxdata[32];
+extern unsigned char tls13_test_case_1_serverhello[];
+extern size_t tls13_test_case_1_serverhello_size;
+extern unsigned char tls13_test_case_1_server_handshake_key[32];
+extern unsigned char tls13_test_case_1_client_handshake_key[32];
+extern unsigned char tls13_test_case_1_server_handshake_iv[12];
+extern unsigned char tls13_test_case_1_client_handshake_iv[12];
+extern unsigned char tls13_test_case_2_certs[];
+extern size_t tls13_test_case_2_certs_size;
+extern char tls13_test_case_2_result_cert1[];
+extern char tls13_test_case_2_result_cert2[];
+extern char tls13_test_case_2_result_cert3[];
+extern char tls13_test_case_2_result_cert4[];
/*****************************************************************************
*****************************************************************************/
@@ -1308,7 +1759,7 @@ ssl_selftest(void)
x = banout_is_contains(banout1, PROTO_SSL3,
", fr.yahoo.com, ");
if (!x) {
- printf("x.509 parser failure: google.com\n");
+ printf("x.509 parser failure: fr.yahoo.com\n");
return 1;
}
@@ -1344,7 +1795,6 @@ ssl_selftest(void)
banout_release(banout1);
}
-
/*
* Do the normal parse
*/
@@ -1355,14 +1805,14 @@ ssl_selftest(void)
{
size_t i;
for (i=0; iis_capture_cert = 1;
+ memset(state, 0, sizeof(state));
+ banout_init(banout1);
+ // set the private key
+ memcpy(state->sub.ssl.x.server_hello.kx_data, tls13_test_case_1_kxdata, 32);
+ // parse the handshake
+ size_t i;
+ for (i=0; isub.ssl.handshake.server_handshake_key.raw,
+ tls13_test_case_1_server_handshake_key,
+ 32) != 0)
+ {
+ printf("Error: server handshake key is wrong !\n");
+ return 1;
+ }
+ if(memcmp(state->sub.ssl.handshake.client_handshake_key.raw,
+ tls13_test_case_1_client_handshake_key,
+ 32) != 0)
+ {
+ printf("Error: client handshake key is wrong !\n");
+ return 1;
+ }
+ if(memcmp(state->sub.ssl.handshake.server_handshake_iv,
+ tls13_test_case_1_server_handshake_iv,
+ 12) != 0)
+ {
+ printf("Error: server handshake iv is wrong !\n");
+ return 1;
+ }
+ if(memcmp(state->sub.ssl.handshake.client_handshake_iv,
+ tls13_test_case_1_client_handshake_iv,
+ 12) != 0)
+ {
+ printf("Error: client handshake iv is wrong !\n");
+ return 1;
+ }
+ banner1_destroy(banner1);
+ banout_release(banout1);
+ }
+ /* TLS 1.3 certificates parsing.
+ * This test payload contains 4 different certs */
+ {
+ banner1 = banner1_create();
+ banner1->is_capture_cert = 1;
+ memset(state, 0, sizeof(state));
+ banout_init(banout1);
+ size_t i;
+ for (i=0; inext->banner;
+ strsize = banout1->next->length;
+ if(memcmp(str, tls13_test_case_2_result_cert1, strsize) != 0)
+ {
+ printf("TLS 1.3 certificate n°1 is wrong !\n");
+ return 1;
+ }
+ str = banout1->next->next->banner;
+ strsize = banout1->next->next->length;
+ if(memcmp(str, tls13_test_case_2_result_cert2, strsize) != 0)
+ {
+ printf("TLS 1.3 certificate n°2 is wrong !\n");
+ return 1;
+ }
+ str = banout1->next->next->next->banner;
+ strsize = banout1->next->next->next->length;
+ if(memcmp(str, tls13_test_case_2_result_cert3, strsize) != 0)
+ {
+ printf("TLS 1.3 certificate n°3 is wrong !\n");
+ return 1;
+ }
+ str = banout1->next->next->next->next->banner;
+ strsize = banout1->next->next->next->next->length;
+ if(memcmp(str, tls13_test_case_2_result_cert4, strsize) != 0)
+ {
+ printf("TLS 1.3 certificate n°4 is wrong !\n");
+ return 1;
+ }
+ banner1_destroy(banner1);
+ banout_release(banout1);
+ }
return 0;
}
@@ -1447,19 +2009,19 @@ ssl_selftest(void)
// if TLS 1.0-1.2 didn't work, try TLS 1.3
struct ProtocolParserStream banner_tls_13 = {
- "ssl", 443, tls_13_hello_template, sizeof(tls_13_hello_template)-1, 0,
+ "ssl", 443, tls_13_hello_template, tls_13_hello_template_length, 0,
ssl_selftest,
ssl_init,
- ssl_parse_record,
+ ssl_parse_record_tls13,
};
// this will be tried first: try TLS 1.0-TLS 1.2
struct ProtocolParserStream banner_ssl = {
- "ssl", 443, ssl_hello_template, sizeof(ssl_hello_template)-1,
+ "ssl", 443, ssl_hello_template, ssl_hello_template_length,
SF__close, /* send FIN after the hello */
ssl_selftest,
ssl_init,
- ssl_parse_record,
+ ssl_parse_record_tls1,
0,
0,
&banner_tls_13,
From 684f6503ae387bdc1afedfd7744f72665fd97625 Mon Sep 17 00:00:00 2001
From: gpotter2
Date: Tue, 2 Jul 2024 17:48:23 +0200
Subject: [PATCH 3/3] Properly use the banner_tls_13.parse if the TLS1.3 probe
was used
---
src/proto-banner1.c | 11 ++++++++++-
src/proto-banner1.h | 1 +
src/stack-tcp-app.c | 1 +
src/stack-tcp-app.h | 3 +++
src/stack-tcp-core.c | 6 ++++++
5 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/proto-banner1.c b/src/proto-banner1.c
index fadb3631..d5fe1dfd 100644
--- a/src/proto-banner1.c
+++ b/src/proto-banner1.c
@@ -256,7 +256,16 @@ banner1_parse(
socket);
break;
case PROTO_SSL3:
- banner_ssl.parse(
+ if (tcb_state->is_sent_tls13)
+ banner_tls_13.parse(
+ banner1,
+ banner1->http_fields,
+ tcb_state,
+ px, length,
+ banout,
+ socket);
+ else
+ banner_ssl.parse(
banner1,
banner1->http_fields,
tcb_state,
diff --git a/src/proto-banner1.h b/src/proto-banner1.h
index e7f0eb2b..ae96ae0e 100644
--- a/src/proto-banner1.h
+++ b/src/proto-banner1.h
@@ -277,6 +277,7 @@ struct StreamState {
unsigned short port;
unsigned short app_proto;
unsigned is_sent_sslhello:1;
+ unsigned is_sent_tls13:1;
struct BannerBase64 base64;
union {
diff --git a/src/stack-tcp-app.c b/src/stack-tcp-app.c
index 3606ce7e..327d5259 100644
--- a/src/stack-tcp-app.c
+++ b/src/stack-tcp-app.c
@@ -160,6 +160,7 @@ application_event(struct stack_handle_t *socket,
* I don't even know what this does any longer
*/
banner_set_sslhello(socket, true);
+ banner_set_ssltls13(socket, stream == &banner_tls_13);
}
if (banner_is_heartbleed(socket)) {
diff --git a/src/stack-tcp-app.h b/src/stack-tcp-app.h
index e33ddef6..43bbdee8 100644
--- a/src/stack-tcp-app.h
+++ b/src/stack-tcp-app.h
@@ -31,6 +31,9 @@ application_event( struct stack_handle_t *socket,
void
banner_set_sslhello(struct stack_handle_t *socket, bool is_true);
+void
+banner_set_ssltls13(struct stack_handle_t *socket, bool is_true);
+
void
banner_set_small_window(struct stack_handle_t *socket, bool is_true);
diff --git a/src/stack-tcp-core.c b/src/stack-tcp-core.c
index 911056de..eac81c5c 100644
--- a/src/stack-tcp-core.c
+++ b/src/stack-tcp-core.c
@@ -1556,6 +1556,12 @@ banner_set_sslhello(struct stack_handle_t *socket, bool is_true) {
tcb->banner1_state.is_sent_sslhello = is_true;
}
+void
+banner_set_ssltls13(struct stack_handle_t *socket, bool is_true) {
+ struct TCP_Control_Block *tcb = socket->tcb;
+ tcb->banner1_state.is_sent_tls13 = is_true;
+}
+
void
banner_set_small_window(struct stack_handle_t *socket, bool is_true) {
struct TCP_Control_Block *tcb = socket->tcb;