Re: Add RSA-OAEP encryption/decryption to Nettle

2024-02-15 Thread Daiki Ueno
Hello Niels,

Thank you for merging it and the suggestions.

Niels Möller  writes:

> Thanks to the doc update, I now noticed the possibility of failure from
> the encryption functions. Failure is propagated from _oaep_encode_mgf1,
> which does
>
>   assert (key_size >= 2 * hash->digest_size - 2);
>
>   if (message_length > key_size - 2 * hash->digest_size - 2)
> return 0;
>
> Why is the first an assert (it could be triggered by using an unusually
> small RSA key with a large hash function, say rsa_oaep_sha512_encrypt
> with an old 512-bit RSA key, which from the docs isn't an obviously
> invalid usage), and the other a return value to indicate failure?

I think I split these conditions that way, as the first condition is
more about the algorithm setup, i.e., the user should choose RSA key
size and hash digest size appropriately, before using any of the
rsa_oaep_*_encrypt functions; otherwise treat it as a programming error.

That said, I agree that it would be more user friendly to combine them
and treat it as a regular error, as we do in pss_encode_mgf1.

> One alternative could be to instead check
>
>   if (message_length > key_size 
>  || message_length + 2 + 2*hash->digest_size > key_size)
> return 0;
>
> (with two tests, to not trigger overflow in case message_length is close
> to the maximum size_t value; maybe that is more defensive than necessary
> since message_length large enough to trigger overflow can't be the size of
> properly allocated memory area).

I made this change in the attached patch.

> The opposite alternative would to be to have a documented way for the
> application to get the maximum message size, and have an assertion
> failure for both cases. That would have the advantage that no return
> value is needed, simplifying the api (at least very locally).

It is tempting, though for now I just documented the size restriction.

> Another doc detail: The docs for the decrypt functions don't say
> explicitly that *length is both an input and output argument. The text
> for the older function rsa_decrypt could be reused (or possibly
> improved).

Updated the documentation.

Regards,
-- 
Daiki Ueno
>From 04a7eb300a555617fd6f0503fdd48e8cf389e790 Mon Sep 17 00:00:00 2001
From: Daiki Ueno 
Date: Fri, 16 Feb 2024 14:47:18 +0900
Subject: [PATCH] Clarify message length limitation in RSA-OAEP

Signed-off-by: Daiki Ueno 
---
 nettle.texinfo | 13 ++---
 oaep.c |  5 ++---
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/nettle.texinfo b/nettle.texinfo
index 25bce6fb..95e89971 100644
--- a/nettle.texinfo
+++ b/nettle.texinfo
@@ -5202,8 +5202,12 @@ is done with one of the following functions:
 @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.
+omitted, @var{label_length} and @var{label} is set to 0 and
+@code{NULL} respectively. The maximum size of @var{message} can be
+calculated with @code{k - 2 * hLen - 2}, where @code{k} is the key
+size in octets obtained with @var{key}->size, and @code{hLen} is the
+output size of the underlying hash function (e.g.,
+@code{SHA256_DIGEST_SIZE} for @code{rsa_oaep_sha256_encrypt}).
 @end deftypefun
 
 Decrypting a cipher text message using RSA with the OAEP padding
@@ -5213,7 +5217,10 @@ scheme is done with one of the following functions:
 @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}.
+RSA blinding similarly to @code{rsa_decrypt_tr}. The message buffer
+pointed to by @var{cleartext} must be of size *@var{length}. After
+decryption, *@var{length} will be updated with the size of the
+message.
 @end deftypefun
 
 
diff --git a/oaep.c b/oaep.c
index c504fbb9..5ebf8ba0 100644
--- a/oaep.c

Re: Add RSA-OAEP encryption/decryption to Nettle

2024-02-15 Thread Niels Möller
Daiki Ueno  writes:

> Thank you; I have addressed those issues.  As for the merging, I think
> it is ready now.

Thanks, merged.

Thanks to the doc update, I now noticed the possibility of failure from
the encryption functions. Failure is propagated from _oaep_encode_mgf1,
which does

  assert (key_size >= 2 * hash->digest_size - 2);

  if (message_length > key_size - 2 * hash->digest_size - 2)
return 0;

Why is the first an assert (it could be triggered by using an unusually
small RSA key with a large hash function, say rsa_oaep_sha512_encrypt
with an old 512-bit RSA key, which from the docs isn't an obviously
invalid usage), and the other a return value to indicate failure?

One alternative could be to instead check

  if (message_length > key_size 
 || message_length + 2 + 2*hash->digest_size > key_size)
return 0;

(with two tests, to not trigger overflow in case message_length is close
to the maximum size_t value; maybe that is more defensive than necessary
since message_length large enough to trigger overflow can't be the size of
properly allocated memory area).

The opposite alternative would to be to have a documented way for the
application to get the maximum message size, and have an assertion
failure for both cases. That would have the advantage that no return
value is needed, simplifying the api (at least very locally).

Another doc detail: The docs for the decrypt functions don't say
explicitly that *length is both an input and output argument. The text
for the older function rsa_decrypt could be reused (or possibly
improved).


Regards,
/Niels

-- 
Niels Möller. PGP key CB4962D070D77D7FCB8BA36271D8F1FF368C6677.
Internet email is subject to wholesale government surveillance.
___
nettle-bugs mailing list -- nettle-bugs@lists.lysator.liu.se
To unsubscribe send an email to nettle-bugs-le...@lists.lysator.liu.se