Commit cf43ded0 authored by Daiki Ueno's avatar Daiki Ueno

Add PSS variants for RSA sign/verify functions

Signed-off-by: default avatarDaiki Ueno <dueno@redhat.com>
parent 7d16432b
......@@ -151,6 +151,8 @@ hogweed_SOURCES = sexp.c sexp-format.c \
rsa-sha1-sign.c rsa-sha1-sign-tr.c rsa-sha1-verify.c \
rsa-sha256-sign.c rsa-sha256-sign-tr.c rsa-sha256-verify.c \
rsa-sha512-sign.c rsa-sha512-sign-tr.c rsa-sha512-verify.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-decrypt-tr.c \
rsa-keygen.c rsa-blind.c \
rsa2sexp.c sexp2rsa.c \
......
......@@ -3770,6 +3770,43 @@ of the digest together with an object identifier for the used hash
algorithm.
@end deftypefun
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
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}
algorithm, a longer salt value does not always mean a better security
@uref{http://www.iacr.org/archive/eurocrypt2002/23320268/coron.pdf}.
The typical choices of the length are between 0 and the digest size of
the underlying hash function.
Creating an RSA signature with the PSS padding scheme is done with one
of the following functions:
@deftypefun int rsa_pss_sha256_sign_digest_tr(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{salt_length}, const uint8_t *@var{salt}, const uint8_t *@var{digest}, mpz_t @var{signature})
@deftypefunx int rsa_pss_sha384_sign_digest_tr(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{salt_length}, const uint8_t *@var{salt}, const uint8_t *@var{digest}, mpz_t @var{signature})
@deftypefunx int rsa_pss_sha512_sign_digest_tr(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{salt_length}, const uint8_t *@var{salt}, const uint8_t *@var{digest}, mpz_t @var{signature})
Creates a signature using the PSS padding scheme. @var{salt} should
point to a salt string of size @var{salt_length}. @var{digest} should
point to a digest of size @code{SHA256_DIGEST_SIZE},
@code{SHA384_DIGEST_SIZE}, or @code{SHA512_DIGEST_SIZE}respectively. The
signature is stored in @var{signature} (which must have been
@code{mpz_init}:ed earlier).
Returns one on success, or zero on failure.
@end deftypefun
Verifying an RSA signature with the PSS padding scheme is done with one
of the following functions:
@deftypefun int rsa_pss_sha256_verify_digest (const struct rsa_public_key *@var{key}, size_t @var{salt_length}, const uint8_t *@var{digest}, const mpz_t @var{signature})
@deftypefunx int rsa_pss_sha384_verify_digest (const struct rsa_public_key *@var{key}, size_t @var{salt_length}, const uint8_t *@var{digest}, const mpz_t @var{signature})
@deftypefunx int rsa_pss_sha512_verify_digest (const struct rsa_public_key *@var{key}, size_t @var{salt_length}, const uint8_t *@var{digest}, const mpz_t @var{signature})
Returns 1 if the signature is valid, or 0 if it isn't. @var{digest}
should point to a digest of size @code{SHA256_DIGEST_SIZE},
@code{SHA384_DIGEST_SIZE}, or @code{SHA512_DIGEST_SIZE} respectively.
@end deftypefun
The following function is used to encrypt a clear text message using RSA.
@deftypefun int rsa_encrypt (const struct rsa_public_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{length}, const uint8_t *@var{cleartext}, mpz_t @var{ciphertext})
Returns 1 on success, 0 on failure. If the message is too long then this
......
/* rsa-pss-sha256-sign-tr.c
Signatures using RSA and SHA-256, with PSS padding.
Copyright (C) 2017 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 "bignum.h"
#include "pss.h"
int
rsa_pss_sha256_sign_digest_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
size_t salt_length, const uint8_t *salt,
const uint8_t *digest,
mpz_t s)
{
mpz_t m;
int res;
mpz_init (m);
res = (pss_encode_mgf1(m, mpz_sizeinbase(pub->n, 2) - 1, &nettle_sha256,
salt_length, salt, digest)
&& rsa_compute_root_tr (pub, key,
random_ctx, random,
s, m));
mpz_clear (m);
return res;
}
/* rsa-pss-sha256-verify.c
Verifying signatures created with RSA and SHA-256, with PSS padding.
Copyright (C) 2017 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 "bignum.h"
#include "pss.h"
int
rsa_pss_sha256_verify_digest(const struct rsa_public_key *key,
size_t salt_length,
const uint8_t *digest,
const mpz_t signature)
{
int res;
mpz_t m;
mpz_init (m);
res = (_rsa_verify_recover(key, m, signature) &&
pss_verify_mgf1(m, mpz_sizeinbase(key->n, 2) - 1, &nettle_sha256,
salt_length, digest));
mpz_clear (m);
return res;
}
/* rsa-pss-sha512-sign-tr.c
Signatures using RSA and SHA-384/SHA-512, with PSS padding.
Copyright (C) 2017 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 "bignum.h"
#include "pss.h"
int
rsa_pss_sha384_sign_digest_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
size_t salt_length, const uint8_t *salt,
const uint8_t *digest,
mpz_t s)
{
mpz_t m;
int res;
mpz_init (m);
res = (pss_encode_mgf1(m, mpz_sizeinbase(pub->n, 2) - 1, &nettle_sha384,
salt_length, salt, digest)
&& rsa_compute_root_tr (pub, key,
random_ctx, random,
s, m));
mpz_clear (m);
return res;
}
int
rsa_pss_sha512_sign_digest_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
size_t salt_length, const uint8_t *salt,
const uint8_t *digest,
mpz_t s)
{
mpz_t m;
int res;
mpz_init (m);
res = (pss_encode_mgf1(m, mpz_sizeinbase(pub->n, 2) - 1, &nettle_sha512,
salt_length, salt, digest)
&& rsa_compute_root_tr (pub, key,
random_ctx, random,
s, m));
mpz_clear (m);
return res;
}
/* rsa-pss-sha512-verify.c
Verifying signatures created with RSA and SHA-384/SHA-512, with PSS padding.
Copyright (C) 2017 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 "bignum.h"
#include "pss.h"
int
rsa_pss_sha384_verify_digest(const struct rsa_public_key *key,
size_t salt_length,
const uint8_t *digest,
const mpz_t signature)
{
int res;
mpz_t m;
mpz_init (m);
res = (_rsa_verify_recover(key, m, signature) &&
pss_verify_mgf1(m, mpz_sizeinbase(key->n, 2) - 1, &nettle_sha384,
salt_length, digest));
mpz_clear (m);
return res;
}
int
rsa_pss_sha512_verify_digest(const struct rsa_public_key *key,
size_t salt_length,
const uint8_t *digest,
const mpz_t signature)
{
int res;
mpz_t m;
mpz_init (m);
res = (_rsa_verify_recover(key, m, signature) &&
pss_verify_mgf1(m, mpz_sizeinbase(key->n, 2) - 1, &nettle_sha512,
salt_length, digest));
mpz_clear (m);
return res;
}
......@@ -62,3 +62,17 @@ _rsa_verify(const struct rsa_public_key *key,
return res;
}
int
_rsa_verify_recover(const struct rsa_public_key *key,
mpz_t m,
const mpz_t s)
{
if ( (mpz_sgn(s) <= 0)
|| (mpz_cmp(s, key->n) >= 0) )
return 0;
mpz_powm(m, s, key->e, key->n);
return 1;
}
......@@ -79,6 +79,12 @@ extern "C" {
#define rsa_sha512_sign_digest nettle_rsa_sha512_sign_digest
#define rsa_sha512_sign_digest_tr nettle_rsa_sha512_sign_digest_tr
#define rsa_sha512_verify_digest nettle_rsa_sha512_verify_digest
#define rsa_pss_sha256_sign_digest_tr nettle_rsa_pss_sha256_sign_digest_tr
#define rsa_pss_sha256_verify_digest nettle_rsa_pss_sha256_verify_digest
#define rsa_pss_sha384_sign_digest_tr nettle_rsa_pss_sha384_sign_digest_tr
#define rsa_pss_sha384_verify_digest nettle_rsa_pss_sha384_verify_digest
#define rsa_pss_sha512_sign_digest_tr nettle_rsa_pss_sha512_sign_digest_tr
#define rsa_pss_sha512_verify_digest nettle_rsa_pss_sha512_verify_digest
#define rsa_encrypt nettle_rsa_encrypt
#define rsa_decrypt nettle_rsa_decrypt
#define rsa_decrypt_tr nettle_rsa_decrypt_tr
......@@ -93,6 +99,7 @@ extern "C" {
#define rsa_keypair_from_der nettle_rsa_keypair_from_der
#define rsa_keypair_to_openpgp nettle_rsa_keypair_to_openpgp
#define _rsa_verify _nettle_rsa_verify
#define _rsa_verify_recover _nettle_rsa_verify_recover
#define _rsa_check_size _nettle_rsa_check_size
#define _rsa_blind _nettle_rsa_blind
#define _rsa_unblind _nettle_rsa_unblind
......@@ -341,6 +348,49 @@ rsa_sha512_verify_digest(const struct rsa_public_key *key,
const uint8_t *digest,
const mpz_t signature);
/* PSS style signatures */
int
rsa_pss_sha256_sign_digest_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
size_t salt_length, const uint8_t *salt,
const uint8_t *digest,
mpz_t s);
int
rsa_pss_sha256_verify_digest(const struct rsa_public_key *key,
size_t salt_length,
const uint8_t *digest,
const mpz_t signature);
int
rsa_pss_sha384_sign_digest_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
size_t salt_length, const uint8_t *salt,
const uint8_t *digest,
mpz_t s);
int
rsa_pss_sha384_verify_digest(const struct rsa_public_key *key,
size_t salt_length,
const uint8_t *digest,
const mpz_t signature);
int
rsa_pss_sha512_sign_digest_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
size_t salt_length, const uint8_t *salt,
const uint8_t *digest,
mpz_t s);
int
rsa_pss_sha512_verify_digest(const struct rsa_public_key *key,
size_t salt_length,
const uint8_t *digest,
const mpz_t signature);
/* RSA encryption, using PKCS#1 */
/* These functions uses the v1.5 padding. What should the v2 (OAEP)
......@@ -480,6 +530,11 @@ _rsa_verify(const struct rsa_public_key *key,
const mpz_t m,
const mpz_t s);
int
_rsa_verify_recover(const struct rsa_public_key *key,
mpz_t m,
const mpz_t s);
size_t
_rsa_check_size(mpz_t n);
......
......@@ -187,6 +187,9 @@ pss-test$(EXEEXT): pss-test.$(OBJEXT)
rsa-sign-tr-test$(EXEEXT): rsa-sign-tr-test.$(OBJEXT)
$(LINK) rsa-sign-tr-test.$(OBJEXT) $(TEST_OBJS) -o rsa-sign-tr-test$(EXEEXT)
rsa-pss-sign-tr-test$(EXEEXT): rsa-pss-sign-tr-test.$(OBJEXT)
$(LINK) rsa-pss-sign-tr-test.$(OBJEXT) $(TEST_OBJS) -o rsa-pss-sign-tr-test$(EXEEXT)
rsa-test$(EXEEXT): rsa-test.$(OBJEXT)
$(LINK) rsa-test.$(OBJEXT) $(TEST_OBJS) -o rsa-test$(EXEEXT)
......
......@@ -36,6 +36,7 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \
rsa2sexp-test.c sexp2rsa-test.c \
bignum-test.c random-prime-test.c \
pkcs1-test.c pss-test.c rsa-sign-tr-test.c \
rsa-pss-sign-tr-test.c \
rsa-test.c rsa-encrypt-test.c rsa-keygen-test.c \
dsa-test.c dsa-keygen-test.c \
curve25519-dh-test.c \
......
#include "testutils.h"
#include "knuth-lfib.h"
#include "nettle-internal.h"
#define SALT "This is a magic salt"
#define MSG1 "None so blind as those who will not see"
#define MSG2 "Fortune knocks once at every man's door"
typedef int (*test_pss_sign_tr_func) (const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
size_t salt_length, const uint8_t *salt,
const uint8_t *digest,
mpz_t s);
typedef int (*test_pss_verify_func) (const struct rsa_public_key *key,
size_t salt_length,
const uint8_t *digest,
const mpz_t signature);
static void
test_rsa_pss_sign_tr(struct rsa_public_key *pub,
struct rsa_private_key *key,
test_pss_sign_tr_func sign_tr_func,
test_pss_verify_func verify_func,
void *ctx, const struct nettle_hash *hash,
size_t salt_length, const uint8_t *salt,
size_t length, const uint8_t *message,
mpz_t expected)
{
mpz_t signature;
struct knuth_lfib_ctx lfib;
uint8_t digest[NETTLE_MAX_HASH_DIGEST_SIZE];
uint8_t bad_digest[NETTLE_MAX_HASH_DIGEST_SIZE];
knuth_lfib_init(&lfib, 1111);
hash->init(ctx);
hash->update(ctx, length, message);
hash->digest(ctx, hash->digest_size, digest);
mpz_init(signature);
mpz_set_ui (signature, 17);
/* Try bad private key */
mpz_add_ui(key->p, key->p, 2);
ASSERT(!sign_tr_func(pub, key,
&lfib, (nettle_random_func *) knuth_lfib_random,
salt_length, salt,
digest, signature));
mpz_sub_ui(key->p, key->p, 2);
ASSERT(!mpz_cmp_ui(signature, 17));
/* Try the good private key */
ASSERT(sign_tr_func(pub, key,
&lfib, (nettle_random_func *) knuth_lfib_random,
salt_length, salt,
digest, signature));
if (verbose)
{
fprintf(stderr, "rsa-pss-tr signature: ");
mpz_out_str(stderr, 16, signature);
fprintf(stderr, "\nrsa-pss-tr expected: ");
mpz_out_str(stderr, 16, expected);
fprintf(stderr, "\n");
}
ASSERT (mpz_cmp(signature, expected) == 0);
/* Try bad digest */
memset(bad_digest, 0x17, sizeof(bad_digest));
ASSERT (!verify_func(pub, salt_length, bad_digest, signature));
/* Try the good digest */
ASSERT (verify_func(pub, salt_length, digest, signature));
/* Try bad signature */
mpz_combit(signature, 17);
ASSERT (!verify_func(pub, salt_length, digest, signature));
mpz_clear(signature);
}
void
test_main(void)
{
struct rsa_public_key pub;
struct rsa_private_key key;
struct sha256_ctx sha256ctx;
struct sha384_ctx sha384ctx;
struct sha512_ctx sha512ctx;
mpz_t p1;
mpz_t q1;
struct tstring *salt;
struct tstring *msg;
mpz_t expected;
mpz_init(expected);
mpz_init(p1);
mpz_init(q1);
rsa_private_key_init(&key);
rsa_public_key_init(&pub);
test_rsa_set_key_1(&pub, &key);
/* Test signatures */
mpz_set_str(expected,
"25e6ce0cc00e917e177a09cb4dfd843d104c179b71aded60e68ebc"
"ca2cabb1e51502adf28e53fa7ede42619f21a1162755b9658edf88"
"a038bb4fea2bb73306fb384d5785c1a8c98a255277c91a4f88ddd3"
"52ebdc78f71f7e62b7a870dac4ab25f1004453457e831a1572f7c9"
"23fcc48e3b69db582127d14471c7195dce", 16);
test_rsa_pss_sign_tr(&pub, &key,
rsa_pss_sha256_sign_digest_tr,
rsa_pss_sha256_verify_digest,
&sha256ctx, &nettle_sha256,
LDATA(SALT), LDATA(MSG1), expected);
mpz_set_str(expected,
"52f4393ccc92b5672dd3cfd8624765d3a4cdb50c7a92060c33b4663"
"fa545b32ce56ec8cd44fe9720df301906ae40921e844b6d80331194"
"972f98e309c937c887c53da940778f29d52dd9489e6016a07e9aa16"
"b1ea8fefc0860ad69068ad6f94a4b0c8fc8a0797b08c58cf4a8df90"
"ee1375feedf7bf73f16ebb2d1cc7e4", 16);
test_rsa_pss_sign_tr(&pub, &key,
rsa_pss_sha256_sign_digest_tr,
rsa_pss_sha256_verify_digest,
&sha256ctx, &nettle_sha256,
LDATA(SALT), LDATA(MSG2), expected);
/* 777-bit key, generated by
*
* lsh-keygen -a rsa -l 777 -f advanced-hex
*
* Interesting because the size of n doesn't equal the sum of the
* sizes of p and q.
*
* (private-key (rsa-pkcs1
* (n #013b04440e3eef25 d51c738d508a7fa8 b3445180c342af0f
* 4cb5a789047300e2 cfc5c5450974cfc2 448aeaaa7f43c374
* c9a3b038b181f2d1 0f1a2327fd2c087b a49bf1086969fd2c
* d1df3fd69f81fa4b 162cc8bbb363fc95 b7b24b9c53d0c67e
* f52b#)
* (e #3f1a012d#)
* (d #f9bae89dacca6cca c21e0412b4df8355 6fe7c5322bbae8ad
* 3f11494fd12bc076 d4a7da3050fe109d 2074db09cc6a93b4
* 745479522558379e a0ddfa74f86c9e9e a22c3b0e93d51447
* 0feb38105dd35395 63b91ee32776f40c 67b2a175690f7abb
* 25#)
* (p #0b73c990eeda0a2a 2c26416052c85560 0c5c0f5ce86a8326
* 166acea91786237a 7ff884e66dbfdd3a ab9d9801414c1506
* 8b#)
* (q #1b81c19a62802a41 9c99283331b0badb 08eb0c25ffce0fbf
* 50017850036f32f3 2132a845b91a5236 61f7b451d587383f
* e1#)
* (a #0a912fc93a6cca6b 3521725a3065b3be 3c9745e29c93303d
* 7d29316c6cafa4a2 89945f964fcdea59 1f9d248b0b6734be
* c9#)
* (b #1658eca933251813 1eb19c77aba13d73 e0b8f4ce986d7615
* 764c6b0b03c18146 46b7f332c43e05c5 351e09006979ca5b
* 05#)
* (c #0114720dace7b27f 2bf2850c1804869f 79a0aad0ec02e6b4
* 05e1831619db2f10 bb9b6a8fd5c95df2 eb78f303ea0c0cc8
* 06#)))
*/
mpz_set_str(pub.n,
"013b04440e3eef25" "d51c738d508a7fa8" "b3445180c342af0f"
"4cb5a789047300e2" "cfc5c5450974cfc2" "448aeaaa7f43c374"
"c9a3b038b181f2d1" "0f1a2327fd2c087b" "a49bf1086969fd2c"
"d1df3fd69f81fa4b" "162cc8bbb363fc95" "b7b24b9c53d0c67e"
"f52b", 16);
mpz_set_str(pub.e, "3f1a012d", 16);
ASSERT (rsa_public_key_prepare(&pub));
mpz_set_str(key.p,
"0b73c990eeda0a2a" "2c26416052c85560" "0c5c0f5ce86a8326"
"166acea91786237a" "7ff884e66dbfdd3a" "ab9d9801414c1506"