From cfd45e459598d0603d0c7c4f6bdb31c31e6a477c Mon Sep 17 00:00:00 2001 From: Nicolas Mora Date: Fri, 12 Feb 2021 13:59:41 -0500 Subject: [PATCH] Implement encryption/decryption RSA-OAEP Modified-by: Daiki Ueno --- Makefile.in | 4 +- nettle.texinfo | 31 +- oaep.c | 237 +++++++++++++ oaep.h | 67 ++++ rsa-internal.h | 20 ++ rsa-oaep-decrypt.c | 133 +++++++ rsa-oaep-encrypt.c | 128 +++++++ rsa.h | 55 ++- testsuite/.gitignore | 1 + testsuite/Makefile.in | 2 + testsuite/rsa-oaep-encrypt-test.c | 535 +++++++++++++++++++++++++++++ testsuite/sc-rsa-oaep-encrypt-test | 6 + testsuite/testutils.c | 185 ++++++++++ testsuite/testutils.h | 4 + 14 files changed, 1404 insertions(+), 4 deletions(-) create mode 100644 oaep.c create mode 100644 oaep.h create mode 100644 rsa-oaep-decrypt.c create mode 100644 rsa-oaep-encrypt.c create mode 100644 testsuite/rsa-oaep-encrypt-test.c create mode 100755 testsuite/sc-rsa-oaep-encrypt-test diff --git a/Makefile.in b/Makefile.in index bde6cf2a..a083f7a1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -172,6 +172,7 @@ hogweed_SOURCES = sexp.c sexp-format.c \ bignum.c bignum-random.c bignum-random-prime.c \ sexp2bignum.c \ pkcs1.c pkcs1-encrypt.c pkcs1-decrypt.c \ + oaep.c \ pkcs1-sec-decrypt.c \ pkcs1-rsa-digest.c pkcs1-rsa-md5.c pkcs1-rsa-sha1.c \ pkcs1-rsa-sha256.c pkcs1-rsa-sha512.c \ @@ -186,6 +187,7 @@ hogweed_SOURCES = sexp.c sexp-format.c \ rsa-pss-sha256-sign-tr.c rsa-pss-sha256-verify.c \ rsa-pss-sha512-sign-tr.c rsa-pss-sha512-verify.c \ rsa-encrypt.c rsa-decrypt.c \ + rsa-oaep-encrypt.c rsa-oaep-decrypt.c \ rsa-sec-decrypt.c rsa-decrypt-tr.c \ rsa-keygen.c rsa-blind.c \ rsa2sexp.c sexp2rsa.c \ @@ -276,7 +278,7 @@ DISTFILES = $(SOURCES) $(HEADERS) getopt.h getopt_int.h \ ctr-internal.h chacha-internal.h sha3-internal.h \ salsa20-internal.h umac-internal.h hogweed-internal.h \ rsa-internal.h pkcs1-internal.h dsa-internal.h eddsa-internal.h \ - gmp-glue.h ecc-internal.h fat-setup.h \ + gmp-glue.h ecc-internal.h fat-setup.h oaep.h \ mini-gmp.h asm.m4 m4-utils.m4 \ nettle.texinfo nettle.info nettle.html nettle.pdf sha-example.c diff --git a/nettle.texinfo b/nettle.texinfo index 3d1626f3..25bce6fb 100644 --- a/nettle.texinfo +++ b/nettle.texinfo @@ -5134,7 +5134,7 @@ algorithm. While the above functions for the RSA signature operations use the @cite{PKCS#1} padding scheme, Nettle also provides the variants based on -the PSS padding scheme, specified in @cite{RFC 3447}. These variants +the PSS padding scheme, specified in @cite{RFC 8017}. These variants take advantage of a randomly choosen salt value, which could enhance the security by causing output to be different for equivalent inputs. However, assuming the same security level as inverting the @acronym{RSA} @@ -5188,6 +5188,35 @@ randomized RSA blinding. Returns 1 on success, 0 on failure. @end deftypefun +While the above functions for the RSA encryption operations use the +@cite{PKCS#1} padding scheme, Nettle also provides the variants based +on the OAEP padding scheme, specified in @cite{RFC 8017}. These +variants take advantage of a randomly choosen seed value, which could +enhance the security by causing output to be different for equivalent +inputs. + +Encrypting a clear text message using RSA with the OAEP padding scheme +is done with one of the following functions: + +@deftypefun int rsa_oaep_sha256_encrypt (const struct rsa_public_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{label_length}, const uint8_t *@var{label}, size_t @var{length}, const uint8_t *@var{message}, uint8_t *@var{ciphertext}) +@deftypefunx int rsa_oaep_sha384_encrypt (const struct rsa_public_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{label_length}, const uint8_t *@var{label}, size_t @var{length}, const uint8_t *@var{message}, uint8_t *@var{ciphertext}) +@deftypefunx int rsa_oaep_sha512_encrypt (const struct rsa_public_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{label_length}, const uint8_t *@var{label}, size_t @var{length}, const uint8_t *@var{message}, uint8_t *@var{ciphertext}) +Returns 1 on success, 0 on failure. The label is optional and if +omitted, @var{label_length} and @var{label} can be set to 0 and +@code{NULL} respectively. +@end deftypefun + +Decrypting a cipher text message using RSA with the OAEP padding +scheme is done with one of the following functions: + +@deftypefun int rsa_oaep_sha256_decrypt (const struct rsa_public_key *@var{pub}, const struct rsa_private_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{label_length}, const uint8_t *@var{label}, size_t *@var{length}, uint8_t *@var{message}, const uint8_t *@var{ciphertext}) +@deftypefunx int rsa_oaep_sha384_decrypt (const struct rsa_public_key *@var{pub}, const struct rsa_private_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{label_length}, const uint8_t *@var{label}, size_t *@var{length}, uint8_t *@var{message}, const uint8_t *@var{ciphertext}) +@deftypefunx int rsa_oaep_sha512_decrypt (const struct rsa_public_key *@var{pub}, const struct rsa_private_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{label_length}, const uint8_t *@var{label}, size_t *@var{length}, uint8_t *@var{message}, const uint8_t *@var{ciphertext}) +Returns 1 on success, 0 on failure. These function utilize randomized +RSA blinding similarly to @code{rsa_decrypt_tr}. +@end deftypefun + + If you need to use the @acronym{RSA} trapdoor, the private key, in a way that isn't supported by the above functions Nettle also includes a function that computes @code{x^d mod n} and nothing more, using the diff --git a/oaep.c b/oaep.c new file mode 100644 index 00000000..c504fbb9 --- /dev/null +++ b/oaep.c @@ -0,0 +1,237 @@ +/* oaep.c + + PKCS#1 RSA-OAEP (RFC-8017). + + Copyright (C) 2021-2024 Nicolas Mora + Copyright (C) 2024 Daiki Ueno + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "oaep.h" + +#include "gmp-glue.h" +#include "memops.h" +#include "memxor.h" +#include "nettle-internal.h" +#include "pss-mgf1.h" +#include +#include + +/* Inputs are always cast to uint32_t values. But all values used in this + * function should never exceed the maximum value of a uint32_t anyway. + * these macros returns 1 on success, 0 on failure */ +#define NOT_EQUAL(a, b) \ + ((0U - ((uint32_t)(a) ^ (uint32_t)(b))) >> 31) +#define EQUAL(a, b) (IS_ZERO_SMALL ((a) ^ (b))) +#define GREATER_OR_EQUAL(a, b) \ + (1U - (((uint32_t)(a) - (uint32_t)(b)) >> 31)) + +/* This is a copy of _pkcs1_sec_decrypt_variable with a slight + * modification for the padding format. + */ +static int +_oaep_sec_decrypt_variable(size_t *length, uint8_t *message, + size_t padded_message_length, + const volatile uint8_t *padded_message, + volatile size_t offset) +{ + volatile int not_found = 1; + volatile int ok = 1; + size_t buflen, msglen; + size_t shift, i; + + /* length is discovered in a side-channel silent way. + * not_found goes to 0 when the terminator is found. */ + for (i = offset; i < padded_message_length; i++) + { + not_found &= NOT_EQUAL(padded_message[i], 1); + offset += not_found; + } + /* check if we ran out of buffer */ + ok &= NOT_EQUAL(not_found, 1); + + /* skip terminator */ + offset++; + + /* offset can be up to padded_message_length, due to the loop above, + * therefore msglen can't underflow */ + msglen = padded_message_length - offset; + + /* we always fill the whole buffer but only up to + * padded_message_length length */ + buflen = *length; + if (buflen > padded_message_length) { /* input independent branch */ + buflen = padded_message_length; + } + + /* if the message length is larger than the buffer we must fail */ + ok &= GREATER_OR_EQUAL(buflen, msglen); + + /* fill destination buffer fully regardless of outcome. Copies the message + * in a memory access independent way. The destination message buffer will + * be clobbered past the message length. */ + shift = padded_message_length - buflen; + cnd_memcpy(ok, message, padded_message + shift, buflen); + offset -= shift; + /* In this loop, the bits of the 'offset' variable are used as shifting + * conditions, starting from the least significant bit. The end result is + * that the buffer is shifted left exactly 'offset' bytes. */ + for (shift = 1; shift < buflen; shift <<= 1, offset >>= 1) + { + /* 'ok' is both a least significant bit mask and a condition */ + cnd_memcpy(offset & ok, message, message + shift, buflen - shift); + } + + /* update length only if we succeeded, otherwise leave unchanged */ + *length = (msglen & (-(size_t) ok)) + (*length & ((size_t) ok - 1)); + + return ok; +} + +int +_oaep_decode_mgf1 (const uint8_t *em, + size_t key_size, + void *hash_ctx, const struct nettle_hash *hash, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message) +{ + const uint8_t *db; + size_t db_length; + const uint8_t *seed; + TMP_GMP_DECL(db_mask, uint8_t); + uint8_t seed_mask[NETTLE_MAX_HASH_DIGEST_SIZE]; + uint8_t lhash[NETTLE_MAX_HASH_DIGEST_SIZE]; + int ok = 1; + + assert (key_size >= 2 * hash->digest_size - 2); + + /* EM = 0x00 || maskedSeed || maskedDB */ + ok &= EQUAL(*em, 0); + seed = em + 1; + db = seed + hash->digest_size; + db_length = key_size - hash->digest_size - 1; + + TMP_GMP_ALLOC(db_mask, db_length); + + /* seedMask = MGF(maskedDB, hLen) */ + hash->init (hash_ctx); + hash->update (hash_ctx, db_length, db); + pss_mgf1 (hash_ctx, hash, hash->digest_size, seed_mask); + + /* seed = maskedSeed \xor seedMask */ + memxor (seed_mask, seed, hash->digest_size); + + /* dbMask = MGF(seed, seed - hLen - 1) */ + hash->init (hash_ctx); + hash->update (hash_ctx, hash->digest_size, seed_mask); + pss_mgf1 (hash_ctx, hash, db_length, db_mask); + + /* DB = maskedDB \xor dbMask */ + memxor (db_mask, db, db_length); + + hash->init (hash_ctx); + hash->update (hash_ctx, label_length, label); + hash->digest (hash_ctx, hash->digest_size, lhash); + + ok &= memeql_sec (db_mask, lhash, hash->digest_size); + + ok &= _oaep_sec_decrypt_variable (length, message, + db_length, db_mask, + hash->digest_size); + + TMP_GMP_FREE (db_mask); + + return ok; +} + +int +_oaep_encode_mgf1 (mpz_t m, size_t key_size, + void *random_ctx, nettle_random_func *random, + void *hash_ctx, const struct nettle_hash *hash, + size_t label_length, const uint8_t *label, + size_t message_length, const uint8_t *message) +{ + TMP_GMP_DECL(em, uint8_t); + TMP_GMP_DECL(db_mask, uint8_t); + uint8_t *db; + size_t db_length; + uint8_t *seed; + uint8_t seed_mask[NETTLE_MAX_HASH_DIGEST_SIZE]; + + assert (key_size >= 2 * hash->digest_size - 2); + + if (message_length > key_size - 2 * hash->digest_size - 2) + return 0; + + TMP_GMP_ALLOC(em, key_size); + TMP_GMP_ALLOC(db_mask, key_size); + + /* EM = 0x00 || maskedSeed || maskedDB */ + *em = 0; + seed = em + 1; + db = seed + hash->digest_size; + db_length = key_size - hash->digest_size - 1; + + /* DB = Hash(L) || PS || 0x01 || M */ + memset (db, 0, db_length); + hash->init (hash_ctx); + hash->update (hash_ctx, label_length, label); + hash->digest (hash_ctx, hash->digest_size, db); + memcpy (&db[db_length - message_length], message, message_length); + db[db_length - message_length - 1] = 0x01; + + /* Generate seed */ + random (random_ctx, hash->digest_size, seed); + + /* dbMask = MGF(seed, k - hLen - 1) */ + hash->init (hash_ctx); + hash->update (hash_ctx, hash->digest_size, seed); + pss_mgf1 (hash_ctx, hash, db_length, db_mask); + + /* maskedDB = DB \xor dbMask */ + memxor (db, db_mask, db_length); + + /* seedMask = MGF(maskedDB, hLen) */ + hash->init (hash_ctx); + hash->update (hash_ctx, db_length, db); + pss_mgf1 (hash_ctx, hash, hash->digest_size, seed_mask); + + /* maskedSeed = seed \xor seedMask */ + memxor (seed, seed_mask, hash->digest_size); + + nettle_mpz_set_str_256_u (m, key_size, em); + + TMP_GMP_FREE (em); + TMP_GMP_FREE (db_mask); + + return 1; +} diff --git a/oaep.h b/oaep.h new file mode 100644 index 00000000..a2e179fb --- /dev/null +++ b/oaep.h @@ -0,0 +1,67 @@ +/* oaep.h + + PKCS#1 RSA-OAEP (RFC-8017). + + Copyright (C) 2021-2024 Nicolas Mora + Copyright (C) 2024 Daiki Ueno + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#ifndef NETTLE_OAEP_H_INCLUDED +#define NETTLE_OAEP_H_INCLUDED + +#include "nettle-meta.h" +#include "bignum.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Namespace mangling */ +#define _oaep_encode_mgf1 _nettle_oaep_encode_mgf1 +#define _oaep_decode_mgf1 _nettle_oaep_decode_mgf1 + +int +_oaep_decode_mgf1 (const uint8_t *em, size_t key_size, + void *hash_ctx, const struct nettle_hash *hash, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message); + +int +_oaep_encode_mgf1 (mpz_t m, size_t key_size, + void *random_ctx, nettle_random_func *random, + void *hash_ctx, const struct nettle_hash *hash, + size_t label_length, const uint8_t *label, + size_t message_length, const uint8_t *message); + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_OAEP_H_INCLUDED */ diff --git a/rsa-internal.h b/rsa-internal.h index f66a7df0..fd54b9d5 100644 --- a/rsa-internal.h +++ b/rsa-internal.h @@ -35,6 +35,7 @@ #define NETTLE_RSA_INTERNAL_H_INCLUDED #include "rsa.h" +#include "nettle-meta.h" #define _rsa_verify _nettle_rsa_verify #define _rsa_verify_recover _nettle_rsa_verify_recover @@ -44,6 +45,8 @@ #define _rsa_sec_compute_root_itch _nettle_rsa_sec_compute_root_itch #define _rsa_sec_compute_root _nettle_rsa_sec_compute_root #define _rsa_sec_compute_root_tr _nettle_rsa_sec_compute_root_tr +#define _rsa_oaep_encrypt _nettle_rsa_oaep_encrypt +#define _rsa_oaep_decrypt _nettle_rsa_oaep_decrypt /* Internal functions. */ int @@ -85,4 +88,21 @@ _rsa_sec_compute_root_tr(const struct rsa_public_key *pub, void *random_ctx, nettle_random_func *random, mp_limb_t *x, const mp_limb_t *m); +int +_rsa_oaep_encrypt (const struct rsa_public_key *key, + void *random_ctx, nettle_random_func *random, + void *hash_ctx, const struct nettle_hash *hash, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t *message, + uint8_t *ciphertext); + +int +_rsa_oaep_decrypt (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + void *hash_ctx, const struct nettle_hash *hash, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext); + #endif /* NETTLE_RSA_INTERNAL_H_INCLUDED */ diff --git a/rsa-oaep-decrypt.c b/rsa-oaep-decrypt.c new file mode 100644 index 00000000..4006a021 --- /dev/null +++ b/rsa-oaep-decrypt.c @@ -0,0 +1,133 @@ +/* rsa-oaep-decrypt.c + + The RSA publickey algorithm. OAEP decryption. + + Copyright (C) 2021-2024 Nicolas Mora + Copyright (C) 2024 Daiki Ueno + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rsa.h" + +#include "gmp-glue.h" +#include "nettle-internal.h" +#include "oaep.h" +#include "rsa-internal.h" + +int +_rsa_oaep_decrypt (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + void *hash_ctx, const struct nettle_hash *hash, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext) +{ + TMP_GMP_DECL (m, mp_limb_t); + TMP_GMP_DECL (em, uint8_t); + int res; + + TMP_GMP_ALLOC (m, mpz_size (pub->n)); + TMP_GMP_ALLOC (em, key->size); + + mpn_set_base256 (m, mpz_size (pub->n), ciphertext, pub->size); + + /* Check that input is in range. */ + if (mpn_cmp (m, mpz_limbs_read (pub->n), mpz_size (pub->n)) >= 0) + { + TMP_GMP_FREE (em); + TMP_GMP_FREE (m); + return 0; + } + + res = _rsa_sec_compute_root_tr (pub, key, random_ctx, random, m, m); + + mpn_get_base256 (em, key->size, m, mpz_size (pub->n)); + + res &= _oaep_decode_mgf1 (em, key->size, hash_ctx, hash, label_length, label, + length, message); + + TMP_GMP_FREE (em); + TMP_GMP_FREE (m); + return res; +} + +int +rsa_oaep_sha256_decrypt (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext) +{ + struct sha256_ctx ctx; + + sha256_init (&ctx); + + return _rsa_oaep_decrypt (pub, key, random_ctx, random, + &ctx, &nettle_sha256, label_length, label, + length, message, ciphertext); +} + +int +rsa_oaep_sha384_decrypt (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext) +{ + struct sha384_ctx ctx; + + sha384_init (&ctx); + + return _rsa_oaep_decrypt (pub, key, random_ctx, random, + &ctx, &nettle_sha384, label_length, label, + length, message, ciphertext); +} + +int +rsa_oaep_sha512_decrypt (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext) +{ + struct sha512_ctx ctx; + + sha512_init (&ctx); + + return _rsa_oaep_decrypt (pub, key, random_ctx, random, + &ctx, &nettle_sha512, label_length, label, + length, message, ciphertext); +} diff --git a/rsa-oaep-encrypt.c b/rsa-oaep-encrypt.c new file mode 100644 index 00000000..488821f0 --- /dev/null +++ b/rsa-oaep-encrypt.c @@ -0,0 +1,128 @@ +/* rsa-oaep-encrypt.c + + The RSA publickey algorithm. OAEP encryption. + + Copyright (C) 2021-2024 Nicolas Mora + Copyright (C) 2024 Daiki Ueno + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rsa.h" + +#include "nettle-internal.h" +#include "oaep.h" +#include "rsa-internal.h" + +int +_rsa_oaep_encrypt (const struct rsa_public_key *key, + void *random_ctx, nettle_random_func *random, + void *hash_ctx, const struct nettle_hash *hash, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t *message, + uint8_t *ciphertext) +{ + mpz_t gibberish; + + mpz_init (gibberish); + + if (_oaep_encode_mgf1 (gibberish, key->size, + random_ctx, random, + hash_ctx, hash, + label_length, label, + length, message)) + { + mpz_powm (gibberish, gibberish, key->e, key->n); + nettle_mpz_get_str_256 (key->size, ciphertext, gibberish); + mpz_clear (gibberish); + return 1; + } + + mpz_clear (gibberish); + return 0; +} + +int +rsa_oaep_sha256_encrypt (const struct rsa_public_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t *message, + uint8_t *ciphertext) +{ + struct sha256_ctx ctx; + + sha256_init (&ctx); + + return _rsa_oaep_encrypt (key, + random_ctx, random, + &ctx, &nettle_sha256, + label_length, label, + length, message, + ciphertext); +} + +int +rsa_oaep_sha384_encrypt (const struct rsa_public_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t *message, + uint8_t *ciphertext) +{ + struct sha384_ctx ctx; + + sha384_init (&ctx); + + return _rsa_oaep_encrypt (key, + random_ctx, random, + &ctx, &nettle_sha384, + label_length, label, + length, message, + ciphertext); +} + +int +rsa_oaep_sha512_encrypt (const struct rsa_public_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t *message, + uint8_t *ciphertext) +{ + struct sha512_ctx ctx; + + sha512_init (&ctx); + + return _rsa_oaep_encrypt (key, + random_ctx, random, + &ctx, &nettle_sha512, + label_length, label, + length, message, + ciphertext); +} diff --git a/rsa.h b/rsa.h index 2dd35a2d..054b318c 100644 --- a/rsa.h +++ b/rsa.h @@ -88,6 +88,12 @@ extern "C" { #define rsa_encrypt nettle_rsa_encrypt #define rsa_decrypt nettle_rsa_decrypt #define rsa_decrypt_tr nettle_rsa_decrypt_tr +#define rsa_oaep_sha256_encrypt nettle_rsa_oaep_sha256_encrypt +#define rsa_oaep_sha256_decrypt nettle_rsa_oaep_sha256_decrypt +#define rsa_oaep_sha384_encrypt nettle_rsa_oaep_sha384_encrypt +#define rsa_oaep_sha384_decrypt nettle_rsa_oaep_sha384_decrypt +#define rsa_oaep_sha512_encrypt nettle_rsa_oaep_sha512_encrypt +#define rsa_oaep_sha512_decrypt nettle_rsa_oaep_sha512_decrypt #define rsa_sec_decrypt nettle_rsa_sec_decrypt #define rsa_compute_root nettle_rsa_compute_root #define rsa_compute_root_tr nettle_rsa_compute_root_tr @@ -389,8 +395,6 @@ rsa_pss_sha512_verify_digest(const struct rsa_public_key *key, /* RSA encryption, using PKCS#1 */ -/* These functions uses the v1.5 padding. What should the v2 (OAEP) - * functions be called? */ /* Returns 1 on success, 0 on failure, which happens if the * message is too long for the key. */ @@ -428,6 +432,53 @@ rsa_sec_decrypt(const struct rsa_public_key *pub, size_t length, uint8_t *message, const mpz_t gibberish); +/* RSA encryption, using OAEP */ + +int +rsa_oaep_sha256_encrypt (const struct rsa_public_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t * message, + uint8_t *ciphertext); + +int +rsa_oaep_sha256_decrypt (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext); + +int +rsa_oaep_sha384_encrypt (const struct rsa_public_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t * message, + uint8_t *ciphertext); + +int +rsa_oaep_sha384_decrypt (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext); + +int +rsa_oaep_sha512_encrypt (const struct rsa_public_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t *message, + uint8_t *ciphertext); + +int +rsa_oaep_sha512_decrypt (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext); + /* Compute x, the e:th root of m. Calling it with x == m is allowed. It is required that 0 <= m < n. */ void diff --git a/testsuite/.gitignore b/testsuite/.gitignore index f2378152..9cc90985 100644 --- a/testsuite/.gitignore +++ b/testsuite/.gitignore @@ -76,6 +76,7 @@ /rsa-compute-root-test /rsa-encrypt-test /rsa-keygen-test +/rsa-oaep-encrypt-test /rsa-pss-sign-tr-test /rsa-sign-tr-test /rsa-test diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index c4513005..bd630524 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -43,6 +43,7 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \ pss-test.c rsa-sign-tr-test.c \ pss-mgf1-test.c rsa-pss-sign-tr-test.c \ rsa-test.c rsa-encrypt-test.c rsa-keygen-test.c \ + rsa-oaep-encrypt-test.c \ rsa-sec-decrypt-test.c \ rsa-compute-root-test.c \ dsa-test.c dsa-keygen-test.c \ @@ -67,6 +68,7 @@ TS_C = $(TS_NETTLE) @IF_HOGWEED@ $(TS_HOGWEED) TS_CXX = @IF_CXX@ $(CXX_SOURCES:.cxx=$(EXEEXT)) TARGETS = $(TS_C) $(TS_CXX) TS_SC_HOGWEED = sc-pkcs1-sec-decrypt-test sc-rsa-sec-decrypt-test \ + sc-rsa-oaep-encrypt-test \ sc-ecdsa-sign-test sc-curve25519-dh-test sc-curve448-dh-test \ sc-ed25519-test sc-ed448-test TS_SC = sc-cnd-memcpy-test sc-gcm-test sc-memeql-test \ diff --git a/testsuite/rsa-oaep-encrypt-test.c b/testsuite/rsa-oaep-encrypt-test.c new file mode 100644 index 00000000..3d9808a5 --- /dev/null +++ b/testsuite/rsa-oaep-encrypt-test.c @@ -0,0 +1,535 @@ +#include "testutils.h" +#include "knuth-lfib.h" +#include "nettle-meta.h" +#include "rsa-internal.h" +#include "sha1.h" + +#define MARK_MPZ_LIMBS_UNDEFINED(x) \ + mark_bytes_undefined (mpz_size (x) * sizeof (mp_limb_t), mpz_limbs_read (x)) + +#define MARK_MPZ_LIMBS_DEFINED(x) \ + mark_bytes_defined (mpz_size (x) * sizeof (mp_limb_t), mpz_limbs_read (x)) + +typedef int (*test_rsa_oaep_encrypt_func) (const struct rsa_public_key *key, + void *random_ctx, + nettle_random_func *random, + size_t label_length, + const uint8_t *label, + size_t length, + const uint8_t *message, + uint8_t *ciphertext); + +typedef int (*test_rsa_oaep_decrypt_func) (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, + nettle_random_func *random, + size_t label_length, + const uint8_t *label, + size_t *length, + uint8_t *message, + const uint8_t *ciphertext); + +static int +rsa_decrypt_for_test(test_rsa_oaep_decrypt_func decrypt_func, + const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext) +{ + int ret; + + /* Makes valgrind trigger on any branches depending on the input + data. Except that (i) we have to allow rsa_sec_compute_root_tr to + check that p and q are odd, (ii) mpn_sec_div_r may leak + information about the most significant bits of p and q, due to + normalization check and table lookup in invert_limb, and (iii) + mpn_sec_powm may leak information about the least significant + bits of p and q, due to table lookup in binvert_limb. */ + mark_bytes_undefined (*length, message); + MARK_MPZ_LIMBS_UNDEFINED(key->a); + MARK_MPZ_LIMBS_UNDEFINED(key->b); + MARK_MPZ_LIMBS_UNDEFINED(key->c); + mark_bytes_undefined ((mpz_size (key->p) - 3) * sizeof(mp_limb_t), + mpz_limbs_read (key->p) + 1); + mark_bytes_undefined((mpz_size (key->q) - 3) * sizeof(mp_limb_t), + mpz_limbs_read (key->q) + 1); + + ret = decrypt_func (pub, key, random_ctx, random, label_length, label, + length, message, ciphertext); + + mark_bytes_defined (sizeof(*length), length); + mark_bytes_defined (*length, message); + mark_bytes_defined (sizeof(ret), &ret); + MARK_MPZ_LIMBS_DEFINED(key->a); + MARK_MPZ_LIMBS_DEFINED(key->b); + MARK_MPZ_LIMBS_DEFINED(key->c); + MARK_MPZ_LIMBS_DEFINED(key->p); + MARK_MPZ_LIMBS_DEFINED(key->q); + + return ret; +} + +static void +test_rsa_oaep_encrypt_decrypt (struct rsa_public_key *pub, + struct rsa_private_key *key, + test_rsa_oaep_encrypt_func encrypt_func, + test_rsa_oaep_decrypt_func decrypt_func, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t *message) +{ + uint8_t *ciphertext; + uint8_t *decrypted; + size_t decrypted_length; + uint8_t after; + struct knuth_lfib_ctx lfib; + + knuth_lfib_init(&lfib, 1111); + + ciphertext = xalloc (key->size + 1); + knuth_lfib_random (&lfib, key->size + 1, ciphertext); + after = ciphertext[key->size]; + + ASSERT (encrypt_func (pub, + &lfib, (nettle_random_func *) knuth_lfib_random, + label_length, label, + length, message, + ciphertext)); + ASSERT (ciphertext[key->size] == after); + + if (verbose) + { + fprintf (stderr, "encrypted: "); + print_hex (key->size, ciphertext); + fprintf (stderr, "\n"); + } + + decrypted = xalloc (length + 1); + + knuth_lfib_random (&lfib, length + 1, decrypted); + after = decrypted[length]; + + /* Test short buffer */ + decrypted_length = length - 1; + ASSERT (!rsa_decrypt_for_test (decrypt_func, + pub, key, + &lfib, (nettle_random_func *) knuth_lfib_random, + label_length, label, + &decrypted_length, decrypted, + ciphertext)); + + decrypted_length = length; + ASSERT (rsa_decrypt_for_test (decrypt_func, + pub, key, + &lfib, (nettle_random_func *) knuth_lfib_random, + label_length, label, + &decrypted_length, decrypted, + ciphertext)); + ASSERT (decrypted_length == length); + ASSERT (MEMEQ (length, message, decrypted)); + ASSERT (decrypted[length] == after); + + free (decrypted); + free (ciphertext); +} + +static void +test_encrypt_decrypt (void) +{ + struct rsa_public_key pub; + struct rsa_private_key key; + + const unsigned char msg[] = "Squemish ossifrage"; + size_t msg_length = LLENGTH(msg); + const unsigned char label[] = "This is a magic label"; + size_t label_length = LLENGTH(label); + + rsa_private_key_init(&key); + rsa_public_key_init(&pub); + + test_rsa_set_key_2(&pub, &key); + + /* Test without label */ + test_rsa_oaep_encrypt_decrypt (&pub, &key, + rsa_oaep_sha256_encrypt, + rsa_oaep_sha256_decrypt, + 0, NULL, + msg_length, msg); + + test_rsa_oaep_encrypt_decrypt (&pub, &key, + rsa_oaep_sha384_encrypt, + rsa_oaep_sha384_decrypt, + 0, NULL, + msg_length, msg); + + test_rsa_oaep_encrypt_decrypt (&pub, &key, + rsa_oaep_sha512_encrypt, + rsa_oaep_sha512_decrypt, + 0, NULL, + msg_length, msg); + + /* Test with label */ + test_rsa_oaep_encrypt_decrypt (&pub, &key, + rsa_oaep_sha256_encrypt, + rsa_oaep_sha256_decrypt, + label_length, label, + msg_length, msg); + + test_rsa_oaep_encrypt_decrypt (&pub, &key, + rsa_oaep_sha384_encrypt, + rsa_oaep_sha384_decrypt, + label_length, label, + msg_length, msg); + + test_rsa_oaep_encrypt_decrypt (&pub, &key, + rsa_oaep_sha512_encrypt, + rsa_oaep_sha512_decrypt, + label_length, label, + msg_length, msg); + + rsa_public_key_clear (&pub); + rsa_private_key_clear (&key); +} + +static int +rsa_oaep_sha1_encrypt (const struct rsa_public_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t *message, + uint8_t *ciphertext) +{ + struct sha1_ctx ctx; + + sha1_init (&ctx); + + return _rsa_oaep_encrypt (key, + random_ctx, random, + &ctx, &nettle_sha1, + label_length, label, + length, message, + ciphertext); +} + +static int +rsa_oaep_sha1_decrypt (const struct rsa_public_key *pub, + const struct rsa_private_key *key, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t *length, uint8_t *message, + const uint8_t *ciphertext) +{ + struct sha1_ctx ctx; + + sha1_init (&ctx); + + return _rsa_oaep_decrypt (pub, key, random_ctx, random, + &ctx, &nettle_sha1, label_length, label, + length, message, ciphertext); +} + +static void +random_from_seed (struct tstring *seed, size_t n, uint8_t *dst) +{ + ASSERT (n <= seed->length); + memcpy (dst, seed->data, n); +} + +static void +test_rsa_oaep_encrypt_decrypt_kat (struct rsa_public_key *pub, + struct rsa_private_key *key, + test_rsa_oaep_encrypt_func encrypt_func, + test_rsa_oaep_decrypt_func decrypt_func, + void *random_ctx, nettle_random_func *random, + size_t label_length, const uint8_t *label, + size_t length, const uint8_t *message, + const uint8_t *expected) +{ + uint8_t *ciphertext; + uint8_t *decrypted; + size_t decrypted_length; + uint8_t after; + /* For blinding at decryption */ + struct knuth_lfib_ctx lfib; + + knuth_lfib_init(&lfib, 1111); + + ciphertext = xalloc (key->size + 1); + knuth_lfib_random (&lfib, key->size + 1, ciphertext); + after = ciphertext[key->size]; + + ASSERT (encrypt_func (pub, + random_ctx, random, + label_length, label, + length, message, + ciphertext)); + ASSERT (MEMEQ (key->size, ciphertext, expected)); + ASSERT (ciphertext[key->size] == after); + + decrypted = xalloc (length + 1); + knuth_lfib_random (&lfib, length + 1, decrypted); + after = decrypted[length]; + + decrypted_length = length; + + ASSERT (rsa_decrypt_for_test (decrypt_func, + pub, key, + &lfib, (nettle_random_func *) knuth_lfib_random, + label_length, label, + &decrypted_length, decrypted, + ciphertext)); + ASSERT (decrypted_length == length); + ASSERT (MEMEQ (length, message, decrypted)); + ASSERT (decrypted[length] == after); + + free (decrypted); + free (ciphertext); +} + +/* The below are known answer tests constructed using the draft + * version of PKCS #1 2.1 test vectors from RSA Laboratories: + * + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1d2-vec.zip + * + * While the original zip file is no longer accessible, a copy is + * kept in the python-cryptography repository, under the following license: + * https://github.com/pyca/cryptography/tree/49bf4e408cd2f93276687f451dd28982e5d501e0/vectors/cryptography_vectors/asymmetric/RSA/pkcs-1v2-1d2-vec + */ + +/* + * Copyright (c) Individual contributors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. Neither the name of PyCA Cryptography nor the names of its 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. + */ + +static void +test_rsa_oaep_set_key(struct rsa_public_key *pub, + struct rsa_private_key *key) +{ + mpz_set_str(pub->n, + "a8b3b284af8eb50b" "387034a860f146c4" "919f318763cd6c55" + "98c8ae4811a1e0ab" "c4c7e0b082d693a5" "e7fced675cf46685" + "12772c0cbc64a742" "c6c630f533c8cc72" "f62ae833c40bf258" + "42e984bb78bdbf97" "c0107d55bdb662f5" "c4e0fab9845cb514" + "8ef7392dd3aaff93" "ae1e6b667bb3d424" "7616d4f5ba10d4cf" + "d226de88d39f16fb", 16); + mpz_set_str(pub->e, "010001", 16); + + ASSERT (rsa_public_key_prepare(pub)); + + /* d is not used */ +#if 0 + mpz_set_str(key->d, + "53339cfdb79fc846" "6a655c7316aca85c" "55fd8f6dd898fdaf" + "119517ef4f52e8fd" "8e258df93fee180f" "a0e4ab29693cd83b" + "152a553d4ac4d181" "2b8b9fa5af0e7f55" "fe7304df41570926" + "f3311f15c4d65a73" "2c483116ee3d3d2d" "0af3549ad9bf7cbf" + "b78ad884f84d5beb" "04724dc7369b31de" "f37d0cf539e9cfcd" + "d3de653729ead5d1" , 16); +#endif + + mpz_set_str(key->p, + "d32737e7267ffe13" "41b2d5c0d150a81b" "586fb3132bed2f8d" + "5262864a9cb9f30a" "f38be448598d413a" "172efb802c21acf1" + "c11c520c2f26a471" "dcad212eac7ca39d", 16); + + mpz_set_str(key->q, + "cc8853d1d54da630" "fac004f471f281c7" "b8982d8224a490ed" + "beb33d3e3d5cc93c" "4765703d1dd79164" "2f1f116a0dd852be" + "2419b2af72bfe9a0" "30e860b0288b5d77", 16); + + mpz_set_str(key->a, + "0e12bf1718e9cef5" "599ba1c3882fe804" "6a90874eefce8f2c" + "cc20e4f2741fb0a3" "3a3848aec9c9305f" "becbd2d76819967d" + "4671acc6431e4037" "968db37878e695c1", 16); + + mpz_set_str(key->b, + "95297b0f95a2fa67" "d00707d609dfd4fc" "05c89dafc2ef6d6e" + "a55bec771ea33373" "4d9251e79082ecda" "866efef13c459e1a" + "631386b7e354c899" "f5f112ca85d71583", 16); + + mpz_set_str(key->c, + "4f456c502493bdc0" "ed2ab756a3a6ed4d" "67352a697d4216e9" + "3212b127a63d5411" "ce6fa98d5dbefd73" "263e372814274381" + "8166ed7dd63687dd" "2a8ca1d2f4fbd8e1", 16); + + ASSERT (rsa_private_key_prepare(key)); + ASSERT (pub->size == key->size); +} + +static void +test_encrypt (void) +{ + struct rsa_public_key pub; + struct rsa_private_key key; + + struct tstring *seed; + struct tstring *msg; + struct tstring *ciphertext; + + rsa_private_key_init(&key); + rsa_public_key_init(&pub); + + /* Test vector from RSA labs */ + test_rsa_oaep_set_key(&pub, &key); + + /* Example 1.1 */ + msg = tstring_hex ("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"); + seed = tstring_hex ("18b776ea21069d69776a33e96bad48e1dda0a5ef"); + ciphertext = tstring_hex ("354fe67b4a126d5d" "35fe36c777791a3f" + "7ba13def484e2d39" "08aff722fad468fb" + "21696de95d0be911" "c2d3174f8afcc201" + "035f7b6d8e69402d" "e5451618c21a535f" + "a9d7bfc5b8dd9fc2" "43f8cf927db31322" + "d6e881eaa91a9961" "70e657a05a266426" + "d98c88003f8477c1" "227094a0d9fa1e8c" + "4024309ce1ecccb5" "210035d47ac72e8a"); + ASSERT (ciphertext->length == key.size); + + test_rsa_oaep_encrypt_decrypt_kat (&pub, &key, + rsa_oaep_sha1_encrypt, + rsa_oaep_sha1_decrypt, + seed, (nettle_random_func *) random_from_seed, + 0, NULL, + msg->length, msg->data, + ciphertext->data); + + /* Example 1.2 */ + msg = tstring_hex ("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"); + seed = tstring_hex ("0cc742ce4a9b7f32f951bcb251efd925fe4fe35f"); + ciphertext = tstring_hex ("640db1acc58e0568" "fe5407e5f9b701df" + "f8c3c91e716c536f" "c7fcec6cb5b71c11" + "65988d4a279e1577" "d730fc7a29932e3f" + "00c81515236d8d8e" "31017a7a09df4352" + "d904cdeb79aa583a" "dcc31ea698a4c052" + "83daba9089be5491" "f67c1a4ee48dc74b" + "bbe6643aef846679" "b4cb395a352d5ed1" + "15912df696ffe070" "2932946d71492b44"); + ASSERT (ciphertext->length == key.size); + + test_rsa_oaep_encrypt_decrypt_kat (&pub, &key, + rsa_oaep_sha1_encrypt, + rsa_oaep_sha1_decrypt, + seed, (nettle_random_func *) random_from_seed, + 0, NULL, + msg->length, msg->data, + ciphertext->data); + + /* Example 1.3 */ + msg = tstring_hex ("d94ae0832e6445ce42331cb06d531a82b1db4baad30f746dc916df24d4e3c2451fff59a6423eb0e1d02d4fe646cf699dfd818c6e97b051"); + seed = tstring_hex ("2514df4695755a67b288eaf4905c36eec66fd2fd"); + ciphertext = tstring_hex ("423736ed035f6026" "af276c35c0b3741b" + "365e5f76ca091b4e" "8c29e2f0befee603" + "595aa8322d602d2e" "625e95eb81b2f1c9" + "724e822eca76db86" "18cf09c5343503a4" + "360835b5903bc637" "e3879fb05e0ef326" + "85d5aec5067cd7cc" "96fe4b2670b6eac3" + "066b1fcf5686b685" "89aafb7d629b02d8" + "f8625ca3833624d4" "800fb081b1cf94eb"); + ASSERT (ciphertext->length == key.size); + + test_rsa_oaep_encrypt_decrypt_kat (&pub, &key, + rsa_oaep_sha1_encrypt, + rsa_oaep_sha1_decrypt, + seed, (nettle_random_func *) random_from_seed, + 0, NULL, + msg->length, msg->data, + ciphertext->data); + + /* Example 1.4 */ + msg = tstring_hex ("52e650d98e7f2a048b4f86852153b97e01dd316f346a19f67a85"); + seed = tstring_hex ("c4435a3e1a18a68b6820436290a37cefb85db3fb"); + ciphertext = tstring_hex ("45ead4ca551e662c" "9800f1aca8283b05" + "25e6abae30be4b4a" "ba762fa40fd3d38e" + "22abefc69794f6eb" "bbc05ddbb1121624" + "7d2f412fd0fba87c" "6e3acd888813646f" + "d0e48e785204f9c3" "f73d6d8239562722" + "dddd8771fec48b83" "a31ee6f592c4cfd4" + "bc88174f3b13a112" "aae3b9f7b80e0fc6" + "f7255ba880dc7d80" "21e22ad6a85f0755"); + ASSERT (ciphertext->length == key.size); + + test_rsa_oaep_encrypt_decrypt_kat (&pub, &key, + rsa_oaep_sha1_encrypt, + rsa_oaep_sha1_decrypt, + seed, (nettle_random_func *) random_from_seed, + 0, NULL, + msg->length, msg->data, + ciphertext->data); + + /* Example 1.5 */ + msg = tstring_hex ("8da89fd9e5f974a29feffb462b49180f6cf9e802"); + seed = tstring_hex ("b318c42df3be0f83fea823f5a7b47ed5e425a3b5"); + ciphertext = tstring_hex ("36f6e34d94a8d34d" "aacba33a2139d00a" + "d85a9345a86051e7" "3071620056b920e2" + "19005855a213a0f2" "3897cdcd731b4525" + "7c777fe908202bef" "dd0b58386b1244ea" + "0cf539a05d5d1032" "9da44e13030fd760" + "dcd644cfef2094d1" "910d3f433e1c7c6d" + "d18bc1f2df7f643d" "662fb9dd37ead905" + "9190f4fa66ca39e8" "69c4eb449cbdc439"); + ASSERT (ciphertext->length == key.size); + + test_rsa_oaep_encrypt_decrypt_kat (&pub, &key, + rsa_oaep_sha1_encrypt, + rsa_oaep_sha1_decrypt, + seed, (nettle_random_func *) random_from_seed, + 0, NULL, + msg->length, msg->data, + ciphertext->data); + + /* Example 1.6 */ + msg = tstring_hex ("26521050844271"); + seed = tstring_hex ("e4ec0982c2336f3a677f6a356174eb0ce887abc2"); + ciphertext = tstring_hex ("42cee2617b1ecea4" "db3f4829386fbd61" + "dafbf038e180d837" "c96366df24c097b4" + "ab0fac6bdf590d82" "1c9f10642e681ad0" + "5b8d78b378c0f46c" "e2fad63f74e0ad3d" + "f06b075d7eb5f563" "6f8d403b9059ca76" + "1b5c62bb52aa4500" "2ea70baace08ded2" + "43b9d8cbd62a68ad" "e265832b56564e43" + "a6fa42ed199a0997" "69742df1539e8255"); + ASSERT (ciphertext->length == key.size); + + test_rsa_oaep_encrypt_decrypt_kat (&pub, &key, + rsa_oaep_sha1_encrypt, + rsa_oaep_sha1_decrypt, + seed, (nettle_random_func *) random_from_seed, + 0, NULL, + msg->length, msg->data, + ciphertext->data); + + rsa_public_key_clear (&pub); + rsa_private_key_clear (&key); +} + +void +test_main (void) +{ + test_encrypt_decrypt (); + test_encrypt (); +} diff --git a/testsuite/sc-rsa-oaep-encrypt-test b/testsuite/sc-rsa-oaep-encrypt-test new file mode 100755 index 00000000..a414b07a --- /dev/null +++ b/testsuite/sc-rsa-oaep-encrypt-test @@ -0,0 +1,6 @@ +#! /bin/sh + +srcdir=`dirname $0` +. "${srcdir}/sc-valgrind.sh" + +with_valgrind ./rsa-oaep-encrypt-test diff --git a/testsuite/testutils.c b/testsuite/testutils.c index 4c9e4768..6fc8a8b8 100644 --- a/testsuite/testutils.c +++ b/testsuite/testutils.c @@ -1516,6 +1516,191 @@ test_rsa_set_key_1(struct rsa_public_key *pub, ASSERT (pub->size == key->size); } +void +test_rsa_set_key_2(struct rsa_public_key *pub, + struct rsa_private_key *key) +{ + /* Initialize key pair for test programs */ + /* 2048-bit key, generated by + * + * certtool --generate-privkey --key-type=rsa --bits=2048 --outfile - + * + * Public Key Info: + * Public Key Algorithm: RSA + * Key Security Level: Medium (2048 bits) + * + * modulus: + * 00:dd:ef:1d:66:d5:f0:b3:56:9b:da:2a:59:c7:96:e6 + * 7a:c9:c8:13:61:89:da:f1:5a:01:65:61:ac:fb:53:1a + * 09:49:41:dd:fd:db:6e:68:c4:3a:8a:61:46:c3:ea:8b + * 34:5f:e1:f6:60:91:9b:09:ae:8e:8c:ad:fa:99:ef:2a + * b5:7d:32:ad:cc:2d:4f:3f:df:21:42:b7:ce:6e:ab:ca + * eb:a4:93:97:8f:55:c4:8f:19:de:dd:ea:0a:83:10:3c + * 8c:5f:f5:ce:01:7f:32:3d:d6:f8:82:f2:2d:3f:8f:20 + * 6a:02:68:a9:8b:0d:12:99:93:67:f9:1c:23:ae:5f:0d + * df:ec:2b:5d:78:c8:14:ac:6b:e9:2a:f7:aa:3e:cd:a1 + * c8:c8:3e:11:24:50:eb:68:34:4c:0c:c1:2a:be:13:95 + * ee:a0:73:dd:09:f2:38:5c:58:a7:dc:60:30:90:c9:a4 + * 1b:19:ed:51:5c:15:51:54:cd:8a:92:10:76:d4:19:88 + * f8:93:ff:8d:08:a2:46:0f:59:af:c1:3d:4e:24:b5:e5 + * 8a:8e:44:10:85:74:8d:06:64:72:b2:f7:c5:6c:75:09 + * fa:bc:9d:73:5d:14:c5:a6:81:f5:2e:8a:2d:a9:aa:c1 + * 43:b9:07:cf:77:90:7a:28:c5:41:53:51:d1:b3:6a:e2 + * 7b: + * + * public exponent: + * 01:00:01: + * + * private exponent: + * 73:2e:6f:66:f8:af:d4:93:a5:8d:63:9f:76:cb:a5:50 + * a2:ba:b8:fc:4d:4c:99:28:2a:43:50:9f:33:4c:9c:dd + * a6:ec:8d:66:fb:e4:60:71:3f:24:a4:79:d2:a2:3e:9e + * ef:08:5a:13:22:5e:81:76:db:ba:bd:6c:ab:49:8a:33 + * e9:07:4d:56:03:49:f7:0f:39:b6:e3:a8:3a:9d:e4:51 + * c9:f7:63:98:5b:5e:09:1a:d7:24:fb:1b:7b:8c:08:b0 + * 9d:f8:f7:72:a5:6e:10:d4:29:e3:e4:06:81:cf:29:76 + * 7b:4b:90:7a:7f:4d:60:f1:34:eb:ff:a3:b1:12:da:22 + * 9e:87:c0:77:22:38:03:4b:80:ab:0c:8a:07:14:c3:c0 + * 08:9e:2c:13:9f:74:f4:19:86:51:61:67:b0:ce:bc:7b + * 8f:81:18:8e:3c:8e:e7:e5:d4:e9:ed:49:b8:0b:21:b1 + * 2a:82:0f:7b:4d:8d:e4:f7:bc:8a:6c:c9:20:8c:4b:ba + * 1e:67:43:9e:58:a4:e4:20:c6:4b:22:05:9d:33:d3:11 + * 92:f2:94:88:d8:fb:c9:53:8f:9c:52:4e:d3:66:f3:2b + * 8c:3b:56:a7:4c:25:10:44:a0:62:79:4d:44:fb:9d:0e + * 35:8b:92:b0:49:af:5d:a4:00:36:44:3c:e7:31:9d:f9 + * + * + * prime1: + * 00:ed:6b:29:25:c1:4f:9c:df:08:4b:c1:43:e3:e6:f3 + * d6:6e:1e:2d:46:d6:eb:97:aa:c7:c9:32:5e:0a:6b:39 + * ac:be:2a:49:98:f6:c3:c8:d0:08:33:5b:75:62:f7:d9 + * 7e:87:d6:90:2d:9d:ce:94:be:2b:ed:8e:aa:85:29:86 + * d9:bc:c0:10:2e:95:30:cc:3f:72:75:81:d1:60:f6:89 + * 86:f7:42:dc:29:8f:dc:d7:15:e8:99:1a:1d:12:92:89 + * 88:95:47:3e:25:c5:f4:e5:c4:82:87:32:d3:d7:a8:ce + * d9:77:2c:fc:87:bb:d9:f9:e6:a4:ec:1e:c8:a9:7b:0b + * 35: + * + * prime2: + * 00:ef:4d:b5:f6:53:12:9a:4e:3c:3f:56:ff:25:86:44 + * 0e:b1:b7:81:c4:0e:31:40:90:e7:91:d7:e7:80:8e:8a + * cc:99:1a:1b:0b:5d:9b:9b:00:81:fa:36:95:02:6a:44 + * 16:6e:67:64:db:ba:35:9b:5b:1c:e7:96:ac:2a:e3:c8 + * 7a:a9:de:1d:e4:75:54:cf:73:c9:76:92:2f:03:8b:ef + * a4:dc:5c:4d:54:2a:cc:f6:c3:cd:a7:0e:84:ce:33:96 + * 9b:99:68:e5:a9:cf:80:5b:df:2b:5a:a4:02:b2:d5:65 + * a7:b8:d0:33:c8:23:ed:89:d1:44:7b:d1:94:99:9f:3c + * ef: + * + * coefficient: + * 5c:ba:5a:d7:98:43:ab:ac:a0:d2:9c:1f:ab:3d:5e:a0 + * 54:c9:6e:54:19:9b:ff:9c:dc:05:75:93:97:3a:88:e9 + * bb:1f:79:05:03:79:9b:b7:ac:07:71:bf:b0:a7:12:fc + * 22:6c:38:04:40:2f:b9:0d:2d:0a:f3:b8:2e:88:3e:ab + * d8:ee:30:5c:fb:dc:59:0e:d9:9f:96:cd:4a:4a:12:88 + * aa:c9:f0:03:e2:01:df:5d:0e:ec:e6:ac:0b:f1:81:b8 + * 85:9b:f7:69:b6:c8:e4:54:d8:02:5b:58:b4:c2:45:02 + * b7:65:d4:5c:dc:aa:b6:47:6e:dd:1f:72:46:6c:27:22 + * + * + * exp1: + * 41:78:03:68:bd:dd:ce:4c:52:65:51:6d:ff:32:78:9a + * f0:d2:b1:79:8f:5a:78:00:48:07:5b:34:43:7b:3d:f4 + * 3c:9c:3c:9f:49:ac:c3:7b:5a:47:8f:38:d7:89:b1:18 + * 0b:2d:47:a4:cc:97:62:bc:ee:30:1b:df:39:c9:31:be + * 69:26:2d:50:2b:23:c1:ae:dd:49:39:fb:1a:d9:e1:22 + * ae:9c:69:49:ac:ba:21:35:91:66:66:a5:0d:b2:0a:ea + * f6:ff:26:4c:14:42:6b:f9:bc:64:bb:c7:5e:f8:d5:d1 + * 71:e3:9d:df:70:15:b3:ab:be:5e:be:3e:67:3d:de:e1 + * + * + * exp2: + * 63:00:4a:5c:5a:e7:e2:50:a5:9a:2a:ba:a9:e2:8f:3b + * 69:08:9b:35:ea:0d:34:41:fe:9b:96:af:de:be:99:eb + * a5:17:68:c2:dd:fa:27:39:21:8c:cb:92:00:0a:c8:9a + * 63:18:81:60:69:fc:0d:86:b7:41:94:53:2b:f7:4a:94 + * 7c:bc:38:af:b0:5e:e2:e8:6b:1b:93:c4:c1:79:de:2d + * dd:40:8e:79:58:af:ad:13:3a:7c:77:84:37:ee:9d:cb + * 47:bf:5e:ec:4e:bd:32:c4:f4:21:ae:a2:b3:2b:97:bf + * b8:b4:e2:07:55:dd:ca:db:79:b2:a3:f5:0f:4d:12:9f + */ + + mpz_set_str(pub->n, + "00ddef1d66d5f0b3" "569bda2a59c796e6" "7ac9c8136189daf1" + "5a016561acfb531a" "094941ddfddb6e68" "c43a8a6146c3ea8b" + "345fe1f660919b09" "ae8e8cadfa99ef2a" "b57d32adcc2d4f3f" + "df2142b7ce6eabca" "eba493978f55c48f" "19deddea0a83103c" + "8c5ff5ce017f323d" "d6f882f22d3f8f20" "6a0268a98b0d1299" + "9367f91c23ae5f0d" "dfec2b5d78c814ac" "6be92af7aa3ecda1" + "c8c83e112450eb68" "344c0cc12abe1395" "eea073dd09f2385c" + "58a7dc603090c9a4" "1b19ed515c155154" "cd8a921076d41988" + "f893ff8d08a2460f" "59afc13d4e24b5e5" "8a8e441085748d06" + "6472b2f7c56c7509" "fabc9d735d14c5a6" "81f52e8a2da9aac1" + "43b907cf77907a28" "c5415351d1b36ae2" "7b", 16); + mpz_set_str(pub->e, "010001", 16); + + ASSERT (rsa_public_key_prepare(pub)); + + /* d is not used */ +#if 0 + mpz_set_str(key->d, + "732e6f66f8afd493" "a58d639f76cba550" "a2bab8fc4d4c9928" + "2a43509f334c9cdd" "a6ec8d66fbe46071" "3f24a479d2a23e9e" + "ef085a13225e8176" "dbbabd6cab498a33" "e9074d560349f70f" + "39b6e3a83a9de451" "c9f763985b5e091a" "d724fb1b7b8c08b0" + "9df8f772a56e10d4" "29e3e40681cf2976" "7b4b907a7f4d60f1" + "34ebffa3b112da22" "9e87c0772238034b" "80ab0c8a0714c3c0" + "089e2c139f74f419" "86516167b0cebc7b" "8f81188e3c8ee7e5" + "d4e9ed49b80b21b1" "2a820f7b4d8de4f7" "bc8a6cc9208c4bba" + "1e67439e58a4e420" "c64b22059d33d311" "92f29488d8fbc953" + "8f9c524ed366f32b" "8c3b56a74c251044" "a062794d44fb9d0e" + "358b92b049af5da4" "0036443ce7319df9" , 16); +#endif + + mpz_set_str(key->p, + "00ed6b2925c14f9c" "df084bc143e3e6f3" "d66e1e2d46d6eb97" + "aac7c9325e0a6b39" "acbe2a4998f6c3c8" "d008335b7562f7d9" + "7e87d6902d9dce94" "be2bed8eaa852986" "d9bcc0102e9530cc" + "3f727581d160f689" "86f742dc298fdcd7" "15e8991a1d129289" + "8895473e25c5f4e5" "c4828732d3d7a8ce" "d9772cfc87bbd9f9" + "e6a4ec1ec8a97b0b" "35", 16); + + mpz_set_str(key->q, + "00ef4db5f653129a" "4e3c3f56ff258644" "0eb1b781c40e3140" + "90e791d7e7808e8a" "cc991a1b0b5d9b9b" "0081fa3695026a44" + "166e6764dbba359b" "5b1ce796ac2ae3c8" "7aa9de1de47554cf" + "73c976922f038bef" "a4dc5c4d542accf6" "c3cda70e84ce3396" + "9b9968e5a9cf805b" "df2b5aa402b2d565" "a7b8d033c823ed89" + "d1447bd194999f3c" "ef", 16); + + mpz_set_str(key->a, + "41780368bdddce4c" "5265516dff32789a" "f0d2b1798f5a7800" + "48075b34437b3df4" "3c9c3c9f49acc37b" "5a478f38d789b118" + "0b2d47a4cc9762bc" "ee301bdf39c931be" "69262d502b23c1ae" + "dd4939fb1ad9e122" "ae9c6949acba2135" "916666a50db20aea" + "f6ff264c14426bf9" "bc64bbc75ef8d5d1" "71e39ddf7015b3ab" + "be5ebe3e673ddee1", 16); + + mpz_set_str(key->b, + "63004a5c5ae7e250" "a59a2abaa9e28f3b" "69089b35ea0d3441" + "fe9b96afdebe99eb" "a51768c2ddfa2739" "218ccb92000ac89a" + "6318816069fc0d86" "b74194532bf74a94" "7cbc38afb05ee2e8" + "6b1b93c4c179de2d" "dd408e7958afad13" "3a7c778437ee9dcb" + "47bf5eec4ebd32c4" "f421aea2b32b97bf" "b8b4e20755ddcadb" + "79b2a3f50f4d129f", 16); + + mpz_set_str(key->c, + "5cba5ad79843abac" "a0d29c1fab3d5ea0" "54c96e54199bff9c" + "dc057593973a88e9" "bb1f790503799bb7" "ac0771bfb0a712fc" + "226c3804402fb90d" "2d0af3b82e883eab" "d8ee305cfbdc590e" + "d99f96cd4a4a1288" "aac9f003e201df5d" "0eece6ac0bf181b8" + "859bf769b6c8e454" "d8025b58b4c24502" "b765d45cdcaab647" + "6edd1f72466c2722", 16); + + ASSERT (rsa_private_key_prepare(key)); + ASSERT (pub->size == key->size); +} + void test_rsa_md5(struct rsa_public_key *pub, struct rsa_private_key *key, diff --git a/testsuite/testutils.h b/testsuite/testutils.h index 97710fc9..c0366541 100644 --- a/testsuite/testutils.h +++ b/testsuite/testutils.h @@ -227,6 +227,10 @@ void test_rsa_set_key_1(struct rsa_public_key *pub, struct rsa_private_key *key); +void +test_rsa_set_key_2(struct rsa_public_key *pub, + struct rsa_private_key *key); + void test_rsa_md5(struct rsa_public_key *pub, struct rsa_private_key *key, -- 2.47.2