]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
algorithms: expose SHAKE from public API
authorDaiki Ueno <ueno@gnu.org>
Wed, 29 May 2024 08:41:36 +0000 (17:41 +0900)
committerDaiki Ueno <ueno@gnu.org>
Wed, 29 May 2024 21:14:50 +0000 (06:14 +0900)
This adds a new function gnutls_hash_squeeze, which works similarly to
gnutls_hash_output but enables to retrieve output of arbitrary length.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
17 files changed:
NEWS
devel/libgnutls.abignore
devel/symbols.last
doc/Makefile.am
doc/manpages/Makefile.am
lib/algorithms/mac.c
lib/crypto-api.c
lib/crypto-selftests.c
lib/fips.c
lib/fips.h
lib/gnutls_int.h
lib/hash_int.c
lib/hash_int.h
lib/includes/gnutls/crypto.h
lib/includes/gnutls/gnutls.h.in
lib/libgnutls.map
lib/nettle/Makefile.am

diff --git a/NEWS b/NEWS
index ff48914aa57be7e45b4fd7051651c44ab8e76c05..9ae1f1c6d2d4f009a78a0a8bf09eead0be9f0d92 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,9 +12,14 @@ See the end for copying conditions.
    PBKDF2 (PBMAC1) is now supported, according to the specification
    proposed in draft-ietf-lamps-pkcs12-pbmac1.
 
+** libgnutls: SHA3 extendable output functions (XOF) are now supported
+   SHA3 XOF, SHAKE128 and SHAKE256, are now usable through a new
+   public API gnutls_hash_squeeze.
+
 ** API and ABI modifications:
 gnutls_pkcs12_generate_mac3: New function
 gnutls_pkcs12_flags_t: New enum
+gnutls_hash_squeeze: New function
 
 * Version 3.8.5 (released 2024-04-04)
 
index 1f9c298564f227194c47e98d404aad9e30f60099..d381e9fdc87c476d86ef2cfd2d6304e33be3e5d7 100644 (file)
@@ -76,3 +76,6 @@ name = gnutls_pkcs12_generate_mac3
 [suppress_type]
 name = gnutls_mac_algorithm_t
 changed_enumerators = GNUTLS_MAC_PBMAC1
+
+[suppress_function]
+name = gnutls_hash_squeeze
index cff43e9e292ec7a75448d93cd1cf72835fa2e816..d4c1b1ac190c057c13ce388de507ae03193caee9 100644 (file)
@@ -308,6 +308,7 @@ gnutls_hash_fast@GNUTLS_3_4
 gnutls_hash_get_len@GNUTLS_3_4
 gnutls_hash_init@GNUTLS_3_4
 gnutls_hash_output@GNUTLS_3_4
+gnutls_hash_squeeze@GNUTLS_3_8_6
 gnutls_heartbeat_allowed@GNUTLS_3_4
 gnutls_heartbeat_enable@GNUTLS_3_4
 gnutls_heartbeat_get_timeout@GNUTLS_3_4
index 7c092c6352b62a7030e283ebecdaca4b91f3d9ed..af7431961c22ff78401205e9a5f88569e8f2b48b 100644 (file)
@@ -1146,6 +1146,8 @@ FUNCS += functions/gnutls_hash_init
 FUNCS += functions/gnutls_hash_init.short
 FUNCS += functions/gnutls_hash_output
 FUNCS += functions/gnutls_hash_output.short
+FUNCS += functions/gnutls_hash_squeeze
+FUNCS += functions/gnutls_hash_squeeze.short
 FUNCS += functions/gnutls_heartbeat_allowed
 FUNCS += functions/gnutls_heartbeat_allowed.short
 FUNCS += functions/gnutls_heartbeat_enable
index 9492b351aa2a27dea99942194cafca062da5d956..b2867bc2a67306435af9b286f06dddc14dd7d2bd 100644 (file)
@@ -419,6 +419,7 @@ APIMANS += gnutls_hash_fast.3
 APIMANS += gnutls_hash_get_len.3
 APIMANS += gnutls_hash_init.3
 APIMANS += gnutls_hash_output.3
+APIMANS += gnutls_hash_squeeze.3
 APIMANS += gnutls_heartbeat_allowed.3
 APIMANS += gnutls_heartbeat_enable.3
 APIMANS += gnutls_heartbeat_get_timeout.3
index af9458fd80b21af2f66711463647b34ea34702d3..e6a8835a38517f330b921ae885cb29c3f659c822 100644 (file)
@@ -186,11 +186,13 @@ static SYSTEM_CONFIG_OR_CONST mac_entry_st hash_algorithms[] = {
        { .name = "SHAKE-128",
          .oid = HASH_OID_SHAKE_128,
          .id = GNUTLS_MAC_SHAKE_128,
-         .block_size = 168 },
+         .block_size = 168,
+         .flags = GNUTLS_MAC_FLAG_XOF },
        { .name = "SHAKE-256",
          .oid = HASH_OID_SHAKE_256,
          .id = GNUTLS_MAC_SHAKE_256,
-         .block_size = 136 },
+         .block_size = 136,
+         .flags = GNUTLS_MAC_FLAG_XOF },
        { .name = "OMAC-MAGMA",
          .id = GNUTLS_MAC_MAGMA_OMAC,
          .output_size = 8,
index bb5c3ecaee274a97fc213981f4316e670fde5f81..9742a1d7cd1597e527078e123d121f12b94b1f25 100644 (file)
@@ -1011,6 +1011,28 @@ gnutls_hash_hd_t gnutls_hash_copy(gnutls_hash_hd_t handle)
        return dig;
 }
 
+/**
+ * gnutls_hash_squeeze:
+ * @handle: a #gnutls_hash_hd_t
+ * @output: destination to store the output; must be equal to or larger than @length
+ * @length: length of @output
+ *
+ * This function will extract digest output of @length bytes. The @handle must
+ * be initialized with gnutls_hash_init() as an extended output function (XOF),
+ * such as %GNUTLS_DIG_SHAKE_128 or %GNUTLS_DIG_SHAKE_256.
+ *
+ * This function can be called multiple times. To reset the state of @handle,
+ * call gnutls_hash_deinit() with %NULL as the digest argument.
+ *
+ * Returns: %GNUTLS_E_SUCCESS (0) on success; negative error code otherwise.
+ *
+ * Since: 3.8.6
+ */
+int gnutls_hash_squeeze(gnutls_hash_hd_t handle, void *output, size_t length)
+{
+       return _gnutls_hash_squeeze((digest_hd_st *)handle, output, length);
+}
+
 /**
  * gnutls_key_generate:
  * @key: is a pointer to a #gnutls_datum_t which will contain a newly
index f08101c164546bb978597c3c7804dda31cb51c3f..9fa32f3a970a400e5ef76942ea9beb4806dd811b 100644 (file)
@@ -2184,6 +2184,34 @@ const struct hash_vectors_st sha3_512_vectors[] = {
        },
 };
 
+const struct hash_vectors_st shake128_vectors[] = {
+       {
+               STR(plaintext, plaintext_size, "\xC1\xEC\xFD\xFC"),
+               STR(output, output_size,
+                   "\xB5\xEB\x98\x7E\x7C\xBF\xC7\xC9\xD1\x40\xAF\xD2\x0B\x50\x0E\x30"),
+       },
+       {
+               STR(plaintext, plaintext_size, "\xC1\xEC\xFD\xFC"),
+               STR(output, output_size,
+                   "\xB5\xEB\x98\x7E\x7C\xBF\xC7\xC9\xD1\x40\xAF\xD2\x0B\x50\x0E\x30"
+                   "\xF2\xF7\x11\x88\xBC\xE8\x85\x95\x1F\x22\xFB\xC3\x5D\xE4\x0E\x74"),
+       },
+};
+
+const struct hash_vectors_st shake256_vectors[] = {
+       {
+               STR(plaintext, plaintext_size, "\xC1\xEC\xFD\xFC"),
+               STR(output, output_size,
+                   "\xCE\x7F\xBC\x15\x50\x39\x86\xE3\xB8\x45\x30\xD8\x4A\x16\xEF\x64"),
+       },
+       {
+               STR(plaintext, plaintext_size, "\xC1\xEC\xFD\xFC"),
+               STR(output, output_size,
+                   "\xCE\x7F\xBC\x15\x50\x39\x86\xE3\xB8\x45\x30\xD8\x4A\x16\xEF\x64"
+                   "\x33\x2A\x6E\xA5\x7E\x35\x4E\x9F\x20\x54\xBF\xC2\xAA\x88\x91\xF9"),
+       },
+};
+
 const struct hash_vectors_st gostr_94_vectors[] = {
        {
                STR(plaintext, plaintext_size,
@@ -2322,6 +2350,62 @@ static int test_digest(gnutls_digest_algorithm_t dig,
        return 0;
 }
 
+static int test_xof(gnutls_digest_algorithm_t dig,
+                   const struct hash_vectors_st *vectors, size_t vectors_size,
+                   unsigned flags)
+{
+       uint8_t data[2 * HASH_DATA_SIZE];
+       unsigned int i;
+       int ret;
+       gnutls_hash_hd_t hd;
+
+       if (!_gnutls_digest_exists(dig))
+               return 0;
+
+       for (i = 0; i < vectors_size; i++) {
+               ret = gnutls_hash_init(&hd, dig);
+               if (ret < 0) {
+                       _gnutls_debug_log("error initializing: %s\n",
+                                         gnutls_digest_get_name(dig));
+                       return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+               }
+
+               ret = gnutls_hash(hd, vectors[i].plaintext, 1);
+               if (ret < 0) {
+                       gnutls_hash_deinit(hd, NULL);
+                       return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+               }
+
+               ret = gnutls_hash(hd, &vectors[i].plaintext[1],
+                                 vectors[i].plaintext_size - 1);
+               if (ret < 0) {
+                       gnutls_hash_deinit(hd, NULL);
+                       return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+               }
+
+               assert(sizeof(data) >= vectors[i].output_size);
+               ret = gnutls_hash_squeeze(hd, data, vectors[i].output_size);
+               if (ret < 0) {
+                       gnutls_hash_deinit(hd, NULL);
+                       return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+               }
+
+               gnutls_hash_deinit(hd, NULL);
+
+               if (memcmp(data, vectors[i].output, vectors[i].output_size) !=
+                   0) {
+                       _gnutls_debug_log("%s test vector %d failed!\n",
+                                         gnutls_digest_get_name(dig), i);
+                       return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+               }
+       }
+
+       _gnutls_debug_log("%s self check succeeded\n",
+                         gnutls_digest_get_name(dig));
+
+       return 0;
+}
+
 struct mac_vectors_st {
        const uint8_t *key;
        unsigned int key_size;
@@ -2891,6 +2975,10 @@ int gnutls_digest_self_test(unsigned flags, gnutls_digest_algorithm_t digest)
                FALLTHROUGH;
                CASE(GNUTLS_DIG_SHA3_512, test_digest, sha3_512_vectors);
 #endif
+               FALLTHROUGH;
+               CASE(GNUTLS_DIG_SHAKE_128, test_xof, shake128_vectors);
+               FALLTHROUGH;
+               CASE(GNUTLS_DIG_SHAKE_256, test_xof, shake256_vectors);
 #if ENABLE_GOST
                FALLTHROUGH;
                NON_FIPS_CASE(GNUTLS_DIG_GOSTR_94, test_digest,
index 59e0808689ced766e1e1d4d9aabb4418a4cec665..1611200be8285b9c96523204ad6452e38910cf5a 100644 (file)
@@ -562,6 +562,16 @@ int _gnutls_fips_perform_self_checks2(void)
                return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
        }
 
+       ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHAKE_128);
+       if (ret < 0) {
+               return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+       }
+
+       ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHAKE_256);
+       if (ret < 0) {
+               return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+       }
+
        /* MAC (includes message digest test) */
        ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA1);
        if (ret < 0) {
index b2cfc0b6023db94510d05d9fcac9c12796a2fd02..4708fec3d33019608f18344f876db6a75e3fb8be 100644 (file)
@@ -108,6 +108,9 @@ inline static bool is_mac_algo_approved_in_fips(gnutls_mac_algorithm_t algo)
        case GNUTLS_MAC_AES_GMAC_128:
        case GNUTLS_MAC_AES_GMAC_192:
        case GNUTLS_MAC_AES_GMAC_256:
+       /* They are not a MAC algorithm, but go through the same check */
+       case GNUTLS_MAC_SHAKE_128:
+       case GNUTLS_MAC_SHAKE_256:
                return true;
        default:
                return false;
index ec685acd1ae2e9b9053ce618e561bafb2f706614..258a08c8427098088222c267beabd326dd4edde5 100644 (file)
@@ -777,6 +777,8 @@ typedef struct gnutls_group_entry_st {
 #define GNUTLS_MAC_FLAG_ALLOW_INSECURE_REVERTIBLE \
        (1                                        \
         << 3) /* when checking with _gnutls_digest_is_insecure2, don't treat revertible setting as fatal */
+#define GNUTLS_MAC_FLAG_XOF \
+       (1 << 4) /* this function is an extendable output function (XOF) */
 /* This structure is used both for MACs and digests
  */
 typedef struct mac_entry_st {
index 1fef44f5612f63e331e58194023c5d1af408c0cd..3cf34e58a1f76ed43aeb4eb5a1506cf9a1aa8a24 100644 (file)
@@ -148,6 +148,18 @@ int _gnutls_hash_fast(gnutls_digest_algorithm_t algorithm, const void *text,
        return 0;
 }
 
+int _gnutls_hash_squeeze(digest_hd_st *handle, void *output, size_t length)
+{
+       if (handle->output == NULL)
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+       if (!(handle->e->flags & GNUTLS_MAC_FLAG_XOF))
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+       handle->output(handle->handle, output, length);
+       return 0;
+}
+
 /* HMAC interface */
 
 int _gnutls_mac_fast(gnutls_mac_algorithm_t algorithm, const void *key,
index 103f525134985a23fc2cc710cb88dbb1a96118fa..340f18223714dafbd0a44fb85409c7eac68bd326 100644 (file)
@@ -139,6 +139,8 @@ int _gnutls_hash_copy(const digest_hd_st *handle, digest_hd_st *dst);
 int _gnutls_hash_fast(gnutls_digest_algorithm_t algorithm, const void *text,
                      size_t textlen, void *digest);
 
+int _gnutls_hash_squeeze(digest_hd_st *handle, void *output, size_t length);
+
 #ifdef ENABLE_SSL3
 /* helper functions */
 int _gnutls_mac_init_ssl3(digest_hd_st *, const mac_entry_st *e, void *key,
index 2325825cafb878d4dc9c5ef313add18ef0b2ca4a..400072daced1a089ad9f04b6c9c29bb834fe4472 100644 (file)
@@ -154,6 +154,7 @@ gnutls_hash_get_len(gnutls_digest_algorithm_t algorithm) __GNUTLS_CONST__;
 int gnutls_hash_fast(gnutls_digest_algorithm_t algorithm, const void *text,
                     size_t textlen, void *digest);
 gnutls_hash_hd_t gnutls_hash_copy(gnutls_hash_hd_t handle);
+int gnutls_hash_squeeze(gnutls_hash_hd_t handle, void *output, size_t length);
 
 /* KDF API */
 
index fc461fa76e7f48812d818f2a3f2ac7ab67a78ed8..6b87610c443b122c373fd2a8c08397f922fbe8f9 100644 (file)
@@ -318,8 +318,8 @@ typedef enum {
  * @GNUTLS_MAC_SHA3_384: Reserved; unimplemented.
  * @GNUTLS_MAC_SHA3_512: Reserved; unimplemented.
  * @GNUTLS_MAC_GOST28147_TC26Z_IMIT: The GOST 28147-89 working in IMIT mode with TC26 Z S-box.
- * @GNUTLS_MAC_SHAKE_128: Reserved; unimplemented.
- * @GNUTLS_MAC_SHAKE_256: Reserved; unimplemented.
+ * @GNUTLS_MAC_SHAKE_128: The SHAKE128 extendable output function.
+ * @GNUTLS_MAC_SHAKE_256: The SHAKE256 extendable output function.
  * @GNUTLS_MAC_MAGMA_OMAC: GOST R 34.12-2015 (Magma) in OMAC (CMAC) mode.
  * @GNUTLS_MAC_KUZNYECHIK_OMAC: GOST R 34.12-2015 (Kuznyechik) in OMAC (CMAC) mode.
  *
@@ -384,8 +384,8 @@ typedef enum {
  * @GNUTLS_DIG_GOSTR_94: GOST R 34.11-94 algorithm.
  * @GNUTLS_DIG_STREEBOG_256: GOST R 34.11-2001 (Streebog) algorithm, 256 bit.
  * @GNUTLS_DIG_STREEBOG_512: GOST R 34.11-2001 (Streebog) algorithm, 512 bit.
- * @GNUTLS_DIG_SHAKE_128: Reserved; unimplemented.
- * @GNUTLS_DIG_SHAKE_256: Reserved; unimplemented.
+ * @GNUTLS_DIG_SHAKE_128: The SHAKE128 extendable output function.
+ * @GNUTLS_DIG_SHAKE_256: The SHAKE256 extendable output function.
  *
  * Enumeration of different digest (hash) algorithms.
  */
index 88a2d5e730431e48cc7824880409696b2deb232c..c2366833d025f8568a3ad25be0f1c86fec126c9a 100644 (file)
@@ -1445,6 +1445,7 @@ GNUTLS_3_8_6
 {
  global:
        gnutls_pkcs12_generate_mac3;
+       gnutls_hash_squeeze;
  local:
        *;
 } GNUTLS_3_8_4;
index f18f48e68ec18b3c5587d1acd5e41da0e15d8e17..b855c8c193fc50f92e6f7150a0c7a889bad12919 100644 (file)
@@ -133,10 +133,12 @@ endif
 if NEED_SHAKE_OUTPUT
 libcrypto_la_SOURCES += \
        backport/md-internal.h \
+       backport/nettle-write.h \
        backport/sha3.c \
        backport/sha3-internal.h \
        backport/sha3-shake.c \
        backport/shake128.c \
        backport/shake256.c \
+       backport/write-le64.c \
        $(NULL)
 endif