diff options
author | Niels Möller <nisse@lysator.liu.se> | 2017-10-23 22:25:58 +0200 |
---|---|---|
committer | Niels Möller <nisse@lysator.liu.se> | 2017-10-23 22:25:58 +0200 |
commit | 61460b2e8edda447a40fb1264cb1327114ea61d3 (patch) | |
tree | 206ba0138631e83f9cfdeab9f5458c286a71801d | |
parent | 54e1450a0ebdd24cdf6234741e5275bb3d83ebda (diff) | |
parent | f1366bc97b8cd93f4797ee42fcfafd5584d038df (diff) | |
download | nettle-61460b2e8edda447a40fb1264cb1327114ea61d3.tar.gz |
Merge remote-tracking branch 'origin/master' into api-opaque
77 files changed, 3299 insertions, 500 deletions
@@ -50,6 +50,7 @@ core /ecc-384.h /ecc-521.h /ecc-25519.h +/version.h /nettle.aux /nettle.cp /nettle.cps diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f8394163..6cfc1dcb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,27 +4,40 @@ before_script: - yum install -y git make autoconf libtool automake gettext-devel glibc-devel gcc valgrind libasan-static libgcc.i686 glibc-devel.i686 # See http://doc.gitlab.com/ce/ci/yaml/ for documentation. -Build and Check (x86-64): +build/x86-64: script: - yum install -y gmp-devel - ./.bootstrap && - ./configure --disable-documentation && make -j4 && + ./configure --enable-fat --disable-documentation && make -j4 && make check -j4 tags: - shared except: - tags -Build and Check (x86): +build/x86: script: - yum install -y gmp-devel.i686 - ./.bootstrap && - PKG_CONFIG_PATH="/usr/lib/pkgconfig/" CFLAGS="-O2 -g -m32" LDFLAGS="-m32" ./configure --build=i686-redhat-linux --disable-documentation && make -j4 && + PKG_CONFIG_PATH="/usr/lib/pkgconfig/" CFLAGS="-O2 -g -m32" LDFLAGS="-m32" ./configure --build=i686-redhat-linux --enable-fat --disable-documentation && make -j4 && make check -j4 tags: - shared except: - tags -Build and Check with mini-gmp: +build/aarch64: + before_script: + - /bin/true + script: + - ./.bootstrap && + ./configure --enable-fat --disable-documentation && make -j4 && + make check -j4 + tags: + - aarch64 + only: + - branches@gnutls/nettle + except: + - tags +build/mini-gmp: script: - ./.bootstrap && ./configure --disable-documentation --enable-mini-gmp && make -j4 && @@ -33,8 +46,8 @@ Build and Check with mini-gmp: - shared except: - tags -Build and Check with ubsan: - image: fedora:24 +build/ubsan: + image: fedora:26 script: - yum install -y gmp-devel libubsan-static libubsan - ./.bootstrap && @@ -44,7 +57,8 @@ Build and Check with ubsan: - shared except: - tags -Build and Check with asan: +build/asan: + image: fedora:26 script: - yum install -y gmp-devel - ./.bootstrap && @@ -54,3 +68,20 @@ Build and Check with asan: - shared except: - tags +build/static-analyzers: + image: fedora:26 + script: + - yum install -y gmp-devel clang compiler-rt cppcheck clang-analyzer + - ./.bootstrap + - scan-build ./configure --disable-documentation + - scan-build --status-bugs -o scan-build-lib make -j$(nproc) + tags: + - shared + except: + - tags + artifacts: + expire_in: 1 week + when: on_failure + paths: + - scan-build-lib/* + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..92200abc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,21 @@ +# nettle -- Information about our contribution rules + +# Test suite: + + New functionality should be accompanied by a test case which verifies +its correctness, on successful use of the new functionality, as well as on +failure cases. The nettle test suite is run on "make check". + +# Continuous Integration (CI) + +We utilize a continuous integration systems, using gitlab-ci. + +This is run on a repository mirror at: +https://gitlab.com/gnutls/nettle + +# Sending patches + +Please do not utilize the gitlab web interfaces. They are not +being followed on. Please send your patches to nettle-bugs@lists.lysator.liu.se + + @@ -44,6 +44,220 @@ (nettle_hashes): ... old name. (nettle_get_hashes): New function. +2017-10-16 Niels Möller <nisse@lysator.liu.se> + + CFB support, contributed by Dmitry Eremin-Solenikov. + * cfb.c (cfb_encrypt, cfb_decrypt): New file, new functions. + * cfb.h: New header file. + (CFB_CTX, CFB_SET_IV, CFB_ENCRYPT, CFB_DECRYPT): New macros. + * Makefile.in (nettle_SOURCES): Add cfb.c. + (HEADERS): Add cfb.h. + * testsuite/cfb-test.c: New test case. + * testsuite/testutils.c (test_cipher_cfb): New function. + * nettle.texinfo (CFB): Documentation. + +2017-10-16 Niels Möller <nisse@lysator.liu.se> + + * aclocal.m4 (GMP_PROG_CC_FOR_BUILD): Add -g when compiling with + gcc. + +2017-09-24 Niels Möller <nisse@lysator.liu.se> + + * tools/pkcs1-conv.c (base64_decode_in_place): New helper + function. + (decode_base64): Use it. + + * sexp-transport-format.c (base64_encode_in_place): New helper + function. + (sexp_transport_vformat): Use it. + + * testsuite/base64-test.c (test_fuzz_once): Update to use char + type where appropriate. + (test_main): Use helper functions base64_encode_in_place and + base64_decode_in_place (copied to this file). + + * testsuite/testutils.c (tstring_data): Use uint8_t for data + argument. + * testsuite/testutils.h (SDATA): Use US macro to cast data + argument. + +2017-09-14 Niels Möller <nisse@lysator.liu.se> + + * hkdf.c: Delete unneeded includes. Use Nettle licensing notice. + * hkdf.h: Include only nettle-types.h, not nettle-meta.h. + + * ecc-mod.c (ecc_mod): Workaround to silence a false positive from + the clang static analyzer. + +2017-09-12 Niels Möller <nisse@lysator.liu.se> + + * testsuite/testutils.h (mpn_zero_p): Avoid redefining mpn_zero_p + when building with mini-gmp. Since the mini-gmp update, this + function is defined by mini-gmp, causing link errors if nettle is + configured with --enable-mini-gmp --disable-shared. Reported by + Tim Rühsen. + +2017-09-09 Daiki Ueno <dueno@redhat.com> + + * testsuite/ecc-mul-g-test.c (test_main): Fixed mpn_cmp call. + * testsuite/ecc-mul-a-test.c (test_main): Likewise. + * eccdata.c (ecc_point_out): Write to given stream, instead of + stderr. + * eccdata.c (output_curve): In curve448, the bit size of the order + is slightly smaller than the one of p's. Adjust ecc_Bmodq_shifted + accordingly. + +2017-09-09 Niels Möller <nisse@lysator.liu.se> + + * mini-gmp.c: Updated mini-gmp from the gmp repository, latest + change from 2017-07-23. + * mini-gmp.h: Likewise. + +2017-09-06 Niels Möller <nisse@lysator.liu.se> + + * hkdf.c (hkdf_expand): Eliminate a (signed) ssize_t variable, use + break rather than return at loop termination. + +2017-09-06 Niels Möller <nisse@lysator.liu.se> + + HKDF implementation, contributed by Nikos Mavrogiannopoulos. + * hkdf.c (hkdf_extract, hkdf_expand): New file, new functions. + * hkdf.h: New file. + * Makefile.in (nettle_SOURCES): Add hkdf.c. + (HEADERS): Add hkdf.h. + * testsuite/hkdf-test.c: Tests for hkdf-sha256 and hkdf-sha1. + * testsuite/Makefile.in (TS_NETTLE_SOURCES): Added hkdf-test.c. + * nettle.texinfo (Key derivation functions): Document HKDF. + +2017-09-04 Andreas Schneider <asn@samba.org> + + * fat-arm.c: Add missing define for _GNU_SOURCE. + +2017-08-27 Niels Möller <nisse@lysator.liu.se> + + * configure.ac (GMP_NUMB_BITS): Set to dummy value "n/a" in + mini-gmp builds. + (NUMB_BITS): New substituted variable which always holds the + configured value. + * Makefile.in (GMP_NUMB_BITS): Renamed variable... + (NUMB_BITS): ...new name + * config.make.in: Update corresponding substitution. + +2017-08-26 Niels Möller <nisse@lysator.liu.se> + + * ecc-mod-inv.c (ecc_mod_inv): Add missing assert. Fixes a + "dead increment" warning from the clang static analyzer. + +2017-08-26 Niels Möller <nisse@lysator.liu.se> + + * examples/nettle-openssl.c (struct openssl_cipher_ctx): New + struct. Use everywhere, instead of typing EVP_CIPHER_CTX pointers + directly. + + * configure.ac: Update openssl-related tests. Checks for + cipher-specific headers are replaced by a check for openssl/evp.h, + and the check for the BF_ecb_encrypt function is replaced by a + check for EVP_CIPHER_CTX_new. + +2017-08-03 Daniel P. Berrange <berrange@redhat.com> + + * examples/nettle-openssl.c: Rewritten to use openssl's EVP APIs. + The older cipher-specific functions always use openssl's generic + software implementation, while the EVP functions enables + platform-specific code, e.g., using the x86 AES-NI instructions. + (nettle_openssl_init): New function. + +2017-07-18 Niels Möller <nisse@lysator.liu.se> + + * ecc-add-eh.c (ecc_add_eh): Fix in-place operation by reordering + two multiplies. Previously, in-place operation resulted in an + invalid call to mpn_mul with overlapping operands. Reported by + Sergei Trofimovich. + +2017-06-09 Niels Möller <nisse@lysator.liu.se> + + * pss.c (pss_verify_mgf1): Check for m being too large, fixing an + assertion failure for certain invalid signatures. Based on a patch + contributed by Daiki Ueno. + + * testsuite/rsa-pss-sign-tr-test.c (test_main): Add test case + contributed by Daiki Ueno. Problem originally found by oss-fuzz, + see https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2132. + That problem report is currently embargoed, but will hopefully be + public in a month or two. + +2017-05-23 Niels Möller <nisse@lysator.liu.se> + + Rework the previous change, which had the unintended effect of + always regenerating .test-rules.make after ./configure is run. + * testsuite/Makefile.in (test-rules.stamp): New stamp file target, + depend on Makefile.in, and run $(MAKE) test-rules. + (.test-rules.make): Add a level of indirection, by depending on + test-rules.stamp. + +2017-05-20 Niels Möller <nisse@lysator.liu.se> + + * testsuite/Makefile.in (test-rules): Use $(srddir)/-prefix for + .test-rules.make target, and change dependency from Makefile.in to + Makefile. + +2017-05-17 Nikos Mavrogiannopoulos <nmav@redhat.com> + + * testsuite/Makefile.in: Ensure .test-rules.make is regenerated + when Makefile.in is modified. + +2017-04-09 Niels Möller <nisse@lysator.liu.se> + + * testsuite/dlopen-test.c (main): Call dlclose, to fix memory leak + on success. + + * testsuite/pss-test.c: Delete magic to let valgrind to check if + pss_encode_mgf1 is side-channel silent with respect to the salt + and digest inputs. It turns out that the most significant bits of + the padded bignum, and hence its size, depends on these inputs. + Which results in a data-dependent branch in the normalization code + of at the end of gmp's mpz_import. + +2017-04-04 Niels Möller <nisse@lysator.liu.se> + + * pss.c (pss_verify_mgf1): Use const for input mpz_t argument. + (pss_encode_mgf1): Avoid unnecessary memset and xor operations. + + Merged RSA-PSS support, contributed by Daiki Ueno. + * pss-mgf1.h, pss.h: New header files. + * pss-mgf1.c (pss_mgf1): New file and function. + * pss.c (pss_encode_mgf1, pss_verify_mgf1): New file and + functions. + * rsa-verify.c (_rsa_verify_recover): New function. + * rsa-pss-sha256-sign-tr.c: (rsa_pss_sha256_sign_digest_tr): New + file and function. + * rsa-pss-sha256-verify.c (rsa_pss_sha256_verify_digest): New + file and function. + * rsa-pss-sha512-sign-tr.c (rsa_pss_sha384_sign_digest_tr) + (rsa_pss_sha512_sign_digest_tr): New file and functions. + * rsa-pss-sha512-verify.c (rsa_pss_sha384_verify_digest) + (rsa_pss_sha512_verify_digest): New file and functions. + * rsa.h: Prototypes for new functions. + * testsuite/rsa-pss-sign-tr-test.c: New test case. + * testsuite/pss-test.c: New test case. + * testsuite/pss-mgf1-test.c: New test case. + * Makefile.in, testsuite/Makefile.in: Added new files. + * nettle.texinfo: Documentation of rsa-pss functions. + +2017-03-20 Niels Möller <nisse@lysator.liu.se> + + * nettle-internal.h (NETTLE_MAX_HASH_CONTEXT_SIZE): New constant. + * testsuite/meta-hash-test.c (test_main): Add sanity check for + NETTLE_MAX_HASH_CONTEXT_SIZE. + + * tools/nettle-hash.c (list_algorithms): Also display the internal + context size. + +2017-01-03 Nikos Mavrogiannopoulos <nmav@redhat.com> + + * ecdsa-verify.c (ecdsa_verify): Eliminated memory leak on error + path. + 2016-10-10 Niels Möller <nisse@lysator.liu.se> * write-be32.c (_nettle_write_be32): Use const for source argument. diff --git a/Makefile.in b/Makefile.in index 52886622..6a0c13ec 100644 --- a/Makefile.in +++ b/Makefile.in @@ -91,7 +91,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \ camellia256-set-decrypt-key.c \ camellia256-meta.c \ cast128.c cast128-meta.c cbc.c \ - ccm.c ccm-aes128.c ccm-aes192.c ccm-aes256.c \ + ccm.c ccm-aes128.c ccm-aes192.c ccm-aes256.c cfb.c \ chacha-crypt.c chacha-core-internal.c \ chacha-poly1305.c chacha-poly1305-meta.c \ chacha-set-key.c chacha-set-nonce.c \ @@ -106,7 +106,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \ gosthash94.c gosthash94-meta.c \ hmac.c hmac-md5.c hmac-ripemd160.c hmac-sha1.c \ hmac-sha224.c hmac-sha256.c hmac-sha384.c hmac-sha512.c \ - knuth-lfib.c \ + knuth-lfib.c hkdf.c \ md2.c md2-meta.c md4.c md4-meta.c \ md5.c md5-compress.c md5-compat.c md5-meta.c \ memeql-sec.c memxor.c memxor3.c \ @@ -145,12 +145,15 @@ hogweed_SOURCES = sexp.c sexp-format.c \ pkcs1.c pkcs1-encrypt.c pkcs1-decrypt.c \ pkcs1-rsa-digest.c pkcs1-rsa-md5.c pkcs1-rsa-sha1.c \ pkcs1-rsa-sha256.c pkcs1-rsa-sha512.c \ + pss.c pss-mgf1.c \ rsa.c rsa-sign.c rsa-sign-tr.c rsa-verify.c \ rsa-pkcs1-sign.c rsa-pkcs1-sign-tr.c rsa-pkcs1-verify.c \ rsa-md5-sign.c rsa-md5-sign-tr.c rsa-md5-verify.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 \ @@ -186,18 +189,18 @@ OPT_SOURCES = fat-x86_64.c fat-arm.c mini-gmp.c HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \ base16.h base64.h bignum.h buffer.h camellia.h cast128.h \ - cbc.h ccm.h chacha.h chacha-poly1305.h ctr.h \ + cbc.h ccm.h cfb.h chacha.h chacha-poly1305.h ctr.h \ curve25519.h des.h des-compat.h dsa.h dsa-compat.h eax.h \ ecc-curve.h ecc.h ecdsa.h eddsa.h \ gcm.h gosthash94.h hmac.h \ - knuth-lfib.h \ + knuth-lfib.h hkdf.h \ macros.h \ md2.h md4.h \ md5.h md5-compat.h \ memops.h memxor.h \ nettle-meta.h nettle-types.h \ pbkdf2.h \ - pgp.h pkcs1.h realloc.h ripemd160.h rsa.h \ + pgp.h pkcs1.h pss.h pss-mgf1.h realloc.h ripemd160.h rsa.h \ salsa20.h sexp.h \ serpent.h sha.h sha1.h sha2.h sha3.h twofish.h \ umac.h yarrow.h poly1305.h @@ -218,7 +221,7 @@ DISTFILES = $(SOURCES) $(HEADERS) getopt.h getopt_int.h \ libnettle.map.in libhogweed.map.in \ config.guess config.sub install-sh texinfo.tex \ config.h.in config.m4.in config.make.in Makefile.in \ - README AUTHORS COPYING.LESSERv3 COPYINGv2 COPYINGv3 \ + README CONTRIBUTING.md AUTHORS COPYING.LESSERv3 COPYINGv2 COPYINGv3 \ INSTALL NEWS TODO ChangeLog \ nettle.pc.in hogweed.pc.in \ $(des_headers) descore.README \ @@ -324,7 +327,7 @@ des.$(OBJEXT): des.c des.h $(des_headers) # k = 7, c = 6, 320 entries, ~15 KB # k = 9, c = 7, 512 entries, ~24 KB ecc-192.h: eccdata.stamp - ./eccdata$(EXEEXT_FOR_BUILD) 192 7 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@ + ./eccdata$(EXEEXT_FOR_BUILD) 192 7 6 $(NUMB_BITS) > $@T && mv $@T $@ # Some possible choices for 224: # k = 18, c = 4, 64 entries, ~4 KB # k = 24, c = 6, 128 entries, ~8 KB @@ -332,7 +335,7 @@ ecc-192.h: eccdata.stamp # k = 8, c = 6, 320 entries, ~20 KB # k = 10, c = 7, 512 entries, ~32 KB ecc-224.h: eccdata.stamp - ./eccdata$(EXEEXT_FOR_BUILD) 224 12 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@ + ./eccdata$(EXEEXT_FOR_BUILD) 224 12 6 $(NUMB_BITS) > $@T && mv $@T $@ # Some possible choices for 256: # k = 20, c = 4, 64 entries, ~4 KB # k = 27, c = 6, 128 entries, ~8 KB @@ -340,7 +343,7 @@ ecc-224.h: eccdata.stamp # k = 9, c = 6, 320 entries, ~20 KB # k = 12, c = 7, 512 entries, ~32 KB ecc-256.h: eccdata.stamp - ./eccdata$(EXEEXT_FOR_BUILD) 256 14 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@ + ./eccdata$(EXEEXT_FOR_BUILD) 256 14 6 $(NUMB_BITS) > $@T && mv $@T $@ # Some possible choices for 384: # k = 31, c = 4, 64 entries, ~6 KB # k = 41, c = 6, 128 entries, ~12 KB @@ -348,7 +351,7 @@ ecc-256.h: eccdata.stamp # k = 14, c = 6, 320 entries, ~30 KB # k = 18, c = 7, 512 entries, ~48 KB ecc-384.h: eccdata.stamp - ./eccdata$(EXEEXT_FOR_BUILD) 384 41 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@ + ./eccdata$(EXEEXT_FOR_BUILD) 384 41 6 $(NUMB_BITS) > $@T && mv $@T $@ # Some possible choices for 521: # k = 42, c = 4, 64 entries, ~9 KB # k = 56, c = 6, 128 entries, ~18 KB @@ -356,10 +359,10 @@ ecc-384.h: eccdata.stamp # k = 19, c = 6, 320 entries, ~44 KB # k = 24, c = 7, 512 entries, ~70 KB ecc-521.h: eccdata.stamp - ./eccdata$(EXEEXT_FOR_BUILD) 521 56 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@ + ./eccdata$(EXEEXT_FOR_BUILD) 521 56 6 $(NUMB_BITS) > $@T && mv $@T $@ ecc-25519.h: eccdata.stamp - ./eccdata$(EXEEXT_FOR_BUILD) 255 14 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@ + ./eccdata$(EXEEXT_FOR_BUILD) 255 14 6 $(NUMB_BITS) > $@T && mv $@T $@ eccdata.stamp: eccdata.c $(MAKE) eccdata$(EXEEXT_FOR_BUILD) @@ -42,6 +42,8 @@ Read the manual. Mail me if you have any questions or suggestions. You may want to subscribe to the nettle-bugs mailing list. See <URL: http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs>. +See CONTRIBUTING.md for information on contibuting patches. + Happy hacking, /Niels Möller <nisse@lysator.liu.se> @@ -526,7 +526,7 @@ else fi fi if test "$CC_FOR_BUILD" = gcc ; then - CC_FOR_BUILD="$CC_FOR_BUILD -O" + CC_FOR_BUILD="$CC_FOR_BUILD -O -g" fi fi diff --git a/aes-set-key-internal.c b/aes-set-key-internal.c index 9b515bfd..88728d85 100644 --- a/aes-set-key-internal.c +++ b/aes-set-key-internal.c @@ -39,6 +39,7 @@ #endif #include "aes-internal.h" +#include <assert.h> #include "macros.h" void @@ -52,6 +53,7 @@ _aes_set_key(unsigned nr, unsigned nk, unsigned lastkey, i; uint32_t t; + assert(nk != 0); lastkey = (AES_BLOCK_SIZE/4) * (nr + 1); for (i=0, rp = rcon; i<nk; i++) diff --git a/arm/ecc-521-modp.asm b/arm/ecc-521-modp.asm index c311a891..3fba2396 100644 --- a/arm/ecc-521-modp.asm +++ b/arm/ecc-521-modp.asm @@ -91,7 +91,7 @@ PROLOGUE(nettle_ecc_521_modp) adcs F0, F0, F3, lsr #9 C Copy low 9 bits to H, then shift right including carry and H, F0, T0 - rrx F0, F0 + mov F0, F0, rrx lsr F0, F0, #8 C Add in F1 = rp[33], with weight 2^1056 = 2^14 adds F0, F0, F1, lsl #14 diff --git a/base16-decode.c b/base16-decode.c index 28acc404..fc331236 100644 --- a/base16-decode.c +++ b/base16-decode.c @@ -66,14 +66,16 @@ hex_decode_table[0x80] = int base16_decode_single(struct base16_decode_ctx *ctx, uint8_t *dst, - uint8_t src) + char src) { + /* Avoid signed char for indexing. */ + unsigned char usrc = src; int digit; - if (src >= 0x80) + if (usrc >= 0x80) return -1; - digit = hex_decode_table[src]; + digit = hex_decode_table[usrc]; switch (digit) { case -1: @@ -104,7 +106,7 @@ base16_decode_update(struct base16_decode_ctx *ctx, size_t *dst_length, uint8_t *dst, size_t src_length, - const uint8_t *src) + const char *src) { size_t done; size_t i; diff --git a/base16-encode.c b/base16-encode.c index 297491ad..9c7f0b1e 100644 --- a/base16-encode.c +++ b/base16-encode.c @@ -45,7 +45,7 @@ hex_digits[16] = "0123456789abcdef"; /* Encodes a single byte. Always stores two digits in dst[0] and dst[1]. */ void -base16_encode_single(uint8_t *dst, +base16_encode_single(char *dst, uint8_t src) { dst[0] = DIGIT(src/0x10); @@ -54,7 +54,7 @@ base16_encode_single(uint8_t *dst, /* Always stores BASE16_ENCODE_LENGTH(length) digits in dst. */ void -base16_encode_update(uint8_t *dst, +base16_encode_update(char *dst, size_t length, const uint8_t *src) { diff --git a/base16-meta.c b/base16-meta.c index a2a10906..a7789c50 100644 --- a/base16-meta.c +++ b/base16-meta.c @@ -59,7 +59,7 @@ base16_encode_init(void *ctx UNUSED) static nettle_armor_encode_update_func base16_encode_update_wrapper; static size_t -base16_encode_update_wrapper(void *ctx UNUSED, uint8_t *dst, +base16_encode_update_wrapper(void *ctx UNUSED, char *dst, size_t length, const uint8_t *src) { base16_encode_update(dst, length, src); @@ -71,7 +71,7 @@ base16_encode_update_wrapper(void *ctx UNUSED, uint8_t *dst, static nettle_armor_encode_final_func base16_encode_final; static size_t -base16_encode_final(void *ctx UNUSED, uint8_t *dst UNUSED) +base16_encode_final(void *ctx UNUSED, char *dst UNUSED) { return 0; } @@ -56,12 +56,12 @@ extern "C" { /* Encodes a single byte. Always stores two digits in dst[0] and dst[1]. */ void -base16_encode_single(uint8_t *dst, +base16_encode_single(char *dst, uint8_t src); /* Always stores BASE16_ENCODE_LENGTH(length) digits in dst. */ void -base16_encode_update(uint8_t *dst, +base16_encode_update(char *dst, size_t length, const uint8_t *src); @@ -86,7 +86,7 @@ base16_decode_init(struct base16_decode_ctx *ctx); int base16_decode_single(struct base16_decode_ctx *ctx, uint8_t *dst, - uint8_t src); + char src); /* Returns 1 on success, 0 on error. DST should point to an area of * size at least BASE16_DECODE_LENGTH(length). The amount of data @@ -97,7 +97,7 @@ base16_decode_update(struct base16_decode_ctx *ctx, size_t *dst_length, uint8_t *dst, size_t src_length, - const uint8_t *src); + const char *src); /* Returns 1 on success. */ int diff --git a/base64-decode.c b/base64-decode.c index 337ea395..b993117a 100644 --- a/base64-decode.c +++ b/base64-decode.c @@ -73,9 +73,9 @@ base64_decode_init(struct base64_decode_ctx *ctx) int base64_decode_single(struct base64_decode_ctx *ctx, uint8_t *dst, - uint8_t src) + char src) { - int data = ctx->table[src]; + int data = ctx->table[(uint8_t) src]; switch(data) { @@ -122,7 +122,7 @@ base64_decode_update(struct base64_decode_ctx *ctx, size_t *dst_length, uint8_t *dst, size_t src_length, - const uint8_t *src) + const char *src) { size_t done; size_t i; diff --git a/base64-encode.c b/base64-encode.c index f23115a9..42fa016d 100644 --- a/base64-encode.c +++ b/base64-encode.c @@ -41,11 +41,11 @@ #define ENCODE(alphabet,x) ((alphabet)[0x3F & (x)]) static void -encode_raw(const uint8_t *alphabet, - uint8_t *dst, size_t length, const uint8_t *src) +encode_raw(const char *alphabet, + char *dst, size_t length, const uint8_t *src) { const uint8_t *in = src + length; - uint8_t *out = dst + BASE64_ENCODE_RAW_LENGTH(length); + char *out = dst + BASE64_ENCODE_RAW_LENGTH(length); unsigned left_over = length % 3; @@ -83,19 +83,19 @@ encode_raw(const uint8_t *alphabet, assert(out == dst); } -static const uint8_t base64_encode_table[64] = +static const char base64_encode_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; void -base64_encode_raw(uint8_t *dst, size_t length, const uint8_t *src) +base64_encode_raw(char *dst, size_t length, const uint8_t *src) { encode_raw(base64_encode_table, dst, length, src); } void -base64_encode_group(uint8_t *dst, uint32_t group) +base64_encode_group(char *dst, uint32_t group) { *dst++ = ENCODE(base64_encode_table, (group >> 18)); *dst++ = ENCODE(base64_encode_table, (group >> 12)); @@ -113,7 +113,7 @@ base64_encode_init(struct base64_encode_ctx *ctx) /* Encodes a single byte. */ size_t base64_encode_single(struct base64_encode_ctx *ctx, - uint8_t *dst, + char *dst, uint8_t src) { unsigned done = 0; @@ -138,7 +138,7 @@ base64_encode_single(struct base64_encode_ctx *ctx, * area of size at least BASE64_ENCODE_LENGTH(length). */ size_t base64_encode_update(struct base64_encode_ctx *ctx, - uint8_t *dst, + char *dst, size_t length, const uint8_t *src) { @@ -181,7 +181,7 @@ base64_encode_update(struct base64_encode_ctx *ctx, * BASE64_ENCODE_FINAL_SIZE */ size_t base64_encode_final(struct base64_encode_ctx *ctx, - uint8_t *dst) + char *dst) { unsigned done = 0; unsigned bits = ctx->bits; @@ -73,7 +73,7 @@ extern "C" { struct base64_encode_ctx { - const uint8_t *alphabet; /* Alphabet to use for encoding */ + const char *alphabet; /* Alphabet to use for encoding */ unsigned short word; /* Leftover bits */ unsigned char bits; /* Number of bits, always 0, 2, or 4. */ }; @@ -89,14 +89,14 @@ base64url_encode_init(struct base64_encode_ctx *ctx); /* Encodes a single byte. Returns amount of output (always 1 or 2). */ size_t base64_encode_single(struct base64_encode_ctx *ctx, - uint8_t *dst, + char *dst, uint8_t src); /* Returns the number of output characters. DST should point to an * area of size at least BASE64_ENCODE_LENGTH(length). */ size_t base64_encode_update(struct base64_encode_ctx *ctx, - uint8_t *dst, + char *dst, size_t length, const uint8_t *src); @@ -104,18 +104,20 @@ base64_encode_update(struct base64_encode_ctx *ctx, * BASE64_ENCODE_FINAL_LENGTH */ size_t base64_encode_final(struct base64_encode_ctx *ctx, - uint8_t *dst); + char *dst); /* Lower level functions */ /* Encodes a string in one go, including any padding at the end. * Generates exactly BASE64_ENCODE_RAW_LENGTH(length) bytes of output. - * Supports overlapped operation, if src <= dst. */ + * Supports overlapped operation, if src <= dst. FIXME: Use of overlap + * is deprecated, if needed there should be a separate public fucntion + * to do that.*/ void -base64_encode_raw(uint8_t *dst, size_t length, const uint8_t *src); +base64_encode_raw(char *dst, size_t length, const uint8_t *src); void -base64_encode_group(uint8_t *dst, uint32_t group); +base64_encode_group(char *dst, uint32_t group); /* Base64 decoding */ @@ -147,7 +149,7 @@ base64url_decode_init(struct base64_decode_ctx *ctx); int base64_decode_single(struct base64_decode_ctx *ctx, uint8_t *dst, - uint8_t src); + char src); /* Returns 1 on success, 0 on error. DST should point to an area of * size at least BASE64_DECODE_LENGTH(length). The amount of data @@ -157,7 +159,7 @@ base64_decode_update(struct base64_decode_ctx *ctx, size_t *dst_length, uint8_t *dst, size_t src_length, - const uint8_t *src); + const char *src); /* Returns 1 on success. */ int diff --git a/base64url-encode.c b/base64url-encode.c index 6af33fb8..d30044ea 100644 --- a/base64url-encode.c +++ b/base64url-encode.c @@ -38,7 +38,7 @@ void base64url_encode_init(struct base64_encode_ctx *ctx) { - static const uint8_t base64url_encode_table[64] = + static const char base64url_encode_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789-_"; @@ -0,0 +1,165 @@ +/* cfb.c + + Cipher feedback mode. + + Copyright (C) 2015, 2017 Dmitry Eremin-Solenikov + Copyright (C) 2001, 2011 Niels Möller + + 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 <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "cfb.h" + +#include "memxor.h" +#include "nettle-internal.h" + +void +cfb_encrypt(const void *ctx, nettle_cipher_func *f, + size_t block_size, uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src) +{ + uint8_t *p; + TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE); + + TMP_ALLOC(buffer, block_size); + + if (src != dst) + { + for (p = iv; length >= block_size; p = dst, dst += block_size, src += block_size, length -= block_size) + { + f(ctx, block_size, dst, p); + memxor(dst, src, block_size); + } + } + else + { + for (p = iv; length >= block_size; p = dst, dst += block_size, src += block_size, length -= block_size) + { + f(ctx, block_size, buffer, p); + memxor(dst, buffer, block_size); + } + } + + if (p != iv) + memcpy(iv, p, block_size); + + if (length) + { + f(ctx, block_size, buffer, iv); + memxor3(dst, buffer, src, length); + /* We do not care about updating IV here. This is the last call in + * message sequence and one has to set IV afterwards anyway */ + } +} + +/* Don't allocate any more space than this on the stack */ +#define CFB_BUFFER_LIMIT 512 + +void +cfb_decrypt(const void *ctx, nettle_cipher_func *f, + size_t block_size, uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src) +{ + if (src != dst) + { + size_t left = length % block_size; + + length -= left; + if (length > 0) + { + /* Decrypt in ECB mode */ + f(ctx, block_size, dst, iv); + f(ctx, length - block_size, dst + block_size, src); + memcpy(iv, src + length - block_size, block_size); + memxor(dst, src, length); + } + + if (left > 0) + { + TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE); + TMP_ALLOC(buffer, block_size); + + f(ctx, block_size, buffer, iv); + memxor3(dst + length, src + length, buffer, left); + } + } + else + { + /* For in-place CFB, we decrypt into a temporary buffer of size + * at most CFB_BUFFER_LIMIT, and process that amount of data at + * a time. */ + + /* NOTE: We assume that block_size <= CFB_BUFFER_LIMIT */ + + TMP_DECL(buffer, uint8_t, CFB_BUFFER_LIMIT); + TMP_DECL(initial_iv, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE); + + size_t buffer_size; + size_t left; + + buffer_size = CFB_BUFFER_LIMIT - (CFB_BUFFER_LIMIT % block_size); + + TMP_ALLOC(buffer, buffer_size); + TMP_ALLOC(initial_iv, block_size); + + left = length % block_size; + length -= left; + + while (length > 0) + { + size_t part = length > buffer_size ? buffer_size : length; + + /* length is greater that zero and is divided by block_size, so it is + * not less than block_size. So does part */ + + f(ctx, block_size, buffer, iv); + f(ctx, part - block_size, buffer + block_size, src); + memcpy(iv, src + part - block_size, block_size); + memxor(dst, buffer, part); + + length -= part; + src += part; + dst += part; + } + + if (left > 0) + { + f(ctx, block_size, buffer, iv); + memxor(dst, buffer, left); + } + } +} @@ -0,0 +1,87 @@ +/* cfb.h + + Cipher feedback mode. + + Copyright (C) 2015, 2017 Dmitry Eremin-Solenikov + Copyright (C) 2001 Niels Möller + + 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_CFB_H_INCLUDED +#define NETTLE_CFB_H_INCLUDED + +#include "nettle-types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Name mangling */ +#define cfb_encrypt nettle_cfb_encrypt +#define cfb_decrypt nettle_cfb_decrypt + +void +cfb_encrypt(const void *ctx, nettle_cipher_func *f, + size_t block_size, uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src); + +void +cfb_decrypt(const void *ctx, nettle_cipher_func *f, + size_t block_size, uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src); + +#define CFB_CTX(type, size) \ +{ type ctx; uint8_t iv[size]; } + +#define CFB_SET_IV(ctx, data) \ +memcpy((ctx)->iv, (data), sizeof((ctx)->iv)) + +/* NOTE: Avoid using NULL, as we don't include anything defining it. */ +#define CFB_ENCRYPT(self, f, length, dst, src) \ + (0 ? ((f)(&(self)->ctx, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0)) \ + : cfb_encrypt((void *) &(self)->ctx, \ + (nettle_cipher_func *) (f), \ + sizeof((self)->iv), (self)->iv, \ + (length), (dst), (src))) + +#define CFB_DECRYPT(self, f, length, dst, src) \ + (0 ? ((f)(&(self)->ctx, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0)) \ + : cfb_decrypt((void *) &(self)->ctx, \ + (nettle_cipher_func *) (f), \ + sizeof((self)->iv), (self)->iv, \ + (length), (dst), (src))) + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_CFB_H_INCLUDED */ diff --git a/config.make.in b/config.make.in index 2981379a..af2068ce 100644 --- a/config.make.in +++ b/config.make.in @@ -46,7 +46,7 @@ LIBHOGWEED_FORLINK = @LIBHOGWEED_FORLINK@ LIBHOGWEED_LIBS = @LIBHOGWEED_LIBS@ LIBHOGWEED_LINK = @LIBHOGWEED_LINK@ -GMP_NUMB_BITS = @GMP_NUMB_BITS@ +NUMB_BITS = @NUMB_BITS@ AR = @AR@ ARFLAGS = cru diff --git a/configure.ac b/configure.ac index 1d1951b5..45ef50e1 100644 --- a/configure.ac +++ b/configure.ac @@ -185,7 +185,7 @@ AC_HEADER_TIME AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(size_t) -AC_CHECK_HEADERS([openssl/blowfish.h openssl/des.h openssl/cast.h openssl/aes.h openssl/ecdsa.h],, +AC_CHECK_HEADERS([openssl/evp.h openssl/ecdsa.h],, [enable_openssl=no break]) @@ -268,7 +268,16 @@ if test "x$enable_public_key" = "xyes" ; then fi fi -GMP_NUMB_BITS="$nettle_cv_gmp_numb_bits" +# Substituted in Makefile, passed on to the eccdata command. +NUMB_BITS="$nettle_cv_gmp_numb_bits" +AC_SUBST([NUMB_BITS]) + +# Substituted in version.h, used only with mini-gmp. +if test "x$enable_mini_gmp" = "xyes" ; then + GMP_NUMB_BITS="$NUMB_BITS" +else + GMP_NUMB_BITS="n/a" +fi AC_SUBST([GMP_NUMB_BITS]) # Figure out ABI. Currently, configurable only by setting CFLAGS. @@ -876,7 +885,7 @@ OPENSSL_LIBFLAGS='' # Check for openssl's libcrypto (used only for benchmarking) if test x$enable_openssl = xyes ; then - AC_CHECK_LIB(crypto, BF_ecb_encrypt, + AC_CHECK_LIB(crypto, EVP_CIPHER_CTX_new, [OPENSSL_LIBFLAGS='-lcrypto'], [enable_openssl=no]) fi diff --git a/ecc-add-eh.c b/ecc-add-eh.c index a16be4cb..c07ff49a 100644 --- a/ecc-add-eh.c +++ b/ecc-add-eh.c @@ -98,8 +98,8 @@ ecc_add_eh (const struct ecc_curve *ecc, ecc_modp_mul (ecc, x3, B, z1); /* y3 */ - ecc_modp_mul (ecc, B, F, C); /* ! */ - ecc_modp_mul (ecc, y3, B, z1); + ecc_modp_mul (ecc, B, F, z1); /* ! */ + ecc_modp_mul (ecc, y3, B, C); /* Clobbers z1 in case r == p. */ /* z3 */ ecc_modp_mul (ecc, B, F, G); diff --git a/ecc-mod-inv.c b/ecc-mod-inv.c index f65c9da4..8cfd2e3b 100644 --- a/ecc-mod-inv.c +++ b/ecc-mod-inv.c @@ -145,6 +145,7 @@ ecc_mod_inv (const struct ecc_modulo *m, cnd_swap (swap, up, vp, n); cy = cnd_sub_n (odd, up, vp, n); cy -= cnd_add_n (cy, up, m->m, n); + assert (cy == 0); cy = mpn_rshift (ap, ap, n, 1); assert (cy == 0); @@ -51,7 +51,7 @@ ecc_mod (const struct ecc_modulo *m, mp_limb_t *rp) mp_size_t i; unsigned shift; - assert (sn > 0); + assert (bn < mn); /* FIXME: Could use mpn_addmul_2. */ /* Eliminate sn limbs at a time */ @@ -72,6 +72,12 @@ ecc_mod (const struct ecc_modulo *m, mp_limb_t *rp) } else { + /* The loop below always runs at least once. But the analyzer + doesn't realize that, and complains about hi being used later + on without a well defined value. */ +#ifdef __clang_analyzer__ + hi = 0; +#endif while (rn >= 2 * mn - bn) { rn -= sn; @@ -121,8 +121,8 @@ ecc_point_mul_g (struct ecc_point *r, const struct ecc_scalar *n); /* Points on a curve are represented as arrays of mp_limb_t, with curve-specific representation. For the secp curves, we use Jacobian - coordinates (possibly in Montgomery for for mod multiplication). - For curve25519 we use homogeneous coordiantes on an equivalent + coordinates (possibly in Montgomery form for mod multiplication). + For curve25519 we use homogeneous coordinates on an equivalent Edwards curve. The suffix "_h" denotes this internal representation. @@ -694,11 +694,11 @@ ecc_point_out (FILE *f, const struct ecc_point *p) fprintf (f, "zero"); else { - fprintf (stderr, "("); - mpz_out_str (stderr, 16, p->x); - fprintf (stderr, ",\n "); - mpz_out_str (stderr, 16, (p)->y); - fprintf (stderr, ")"); + fprintf (f, "("); + mpz_out_str (f, 16, p->x); + fprintf (f, ",\n "); + mpz_out_str (f, 16, (p)->y); + fprintf (f, ")"); } } #define ASSERT_EQUAL(p, q) do { \ @@ -1014,16 +1014,19 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb) exit (EXIT_FAILURE); } } + } + else + printf ("#define ecc_Bmodp_shifted ecc_Bmodp\n"); + + if (bits < limb_size * bits_per_limb) + { mpz_set_ui (t, 0); - mpz_setbit (t, ecc->bit_size); + mpz_setbit (t, bits); mpz_sub (t, t, ecc->q); output_bignum ("ecc_Bmodq_shifted", t, limb_size, bits_per_limb); } else - { - printf ("#define ecc_Bmodp_shifted ecc_Bmodp\n"); - printf ("#define ecc_Bmodq_shifted ecc_Bmodq\n"); - } + printf ("#define ecc_Bmodq_shifted ecc_Bmodq\n"); mpz_add_ui (t, ecc->p, 1); mpz_fdiv_q_2exp (t, t, 1); diff --git a/ecdsa-verify.c b/ecdsa-verify.c index 05c174ec..ab8e19f3 100644 --- a/ecdsa-verify.c +++ b/ecdsa-verify.c @@ -52,7 +52,7 @@ ecdsa_verify (const struct ecc_point *pub, /* For ECC_MUL_A_WBITS == 0, at most 1512 bytes. With ECC_MUL_A_WBITS == 4, currently needs 67 * ecc->size, at most 4824 bytes. Don't use stack allocation for this. */ - mp_limb_t *scratch = gmp_alloc_limbs (itch); + mp_limb_t *scratch; int res; #define rp scratch @@ -62,6 +62,8 @@ ecdsa_verify (const struct ecc_point *pub, if (mpz_sgn (signature->r) <= 0 || mpz_size (signature->r) > size || mpz_sgn (signature->s) <= 0 || mpz_size (signature->s) > size) return 0; + + scratch = gmp_alloc_limbs (itch); mpz_limbs_copy (rp, signature->r, size); mpz_limbs_copy (sp, signature->s, size); diff --git a/examples/base16dec.c b/examples/base16dec.c index 70714567..1185b3e1 100644 --- a/examples/base16dec.c +++ b/examples/base16dec.c @@ -58,7 +58,7 @@ int main(int argc UNUSED, char **argv UNUSED) { /* "buffer" will hold the bytes from disk: */ - uint8_t * buffer = xalloc (CHUNK_SIZE); + char * buffer = xalloc (CHUNK_SIZE); /* "result" will hold bytes before output: */ uint8_t * result = xalloc (DECODED_SIZE); diff --git a/examples/base16enc.c b/examples/base16enc.c index 02e4f280..6ac08e1d 100644 --- a/examples/base16enc.c +++ b/examples/base16enc.c @@ -70,7 +70,7 @@ main(int argc UNUSED, char **argv UNUSED) /* "buffer" will hold the bytes from disk: */ uint8_t buffer[CHUNK_SIZE]; /* "result" will hold bytes before output: */ - uint8_t result[ENCODED_SIZE + 1]; + char result[ENCODED_SIZE + 1]; unsigned nbytes; /* Number of bytes read from stdin */ int encoded_bytes; /* Total number of bytes encoded per iteration */ diff --git a/examples/base64dec.c b/examples/base64dec.c index 624de628..d05d924a 100644 --- a/examples/base64dec.c +++ b/examples/base64dec.c @@ -58,7 +58,7 @@ int main(int argc UNUSED, char **argv UNUSED) { /* "buffer" will hold the bytes from disk: */ - uint8_t * buffer = xalloc (CHUNK_SIZE); + char * buffer = xalloc (CHUNK_SIZE); /* "result" will hold bytes before output: */ uint8_t * result = xalloc (DECODED_SIZE); diff --git a/examples/base64enc.c b/examples/base64enc.c index f8ba829b..cc6010cc 100644 --- a/examples/base64enc.c +++ b/examples/base64enc.c @@ -72,7 +72,7 @@ main(int argc UNUSED, char **argv UNUSED) /* "buffer" will hold the bytes from disk: */ uint8_t buffer[CHUNK_SIZE]; /* "result" is the result vector: */ - uint8_t result[ENCODED_SIZE + BASE64_ENCODE_FINAL_LENGTH + 1]; + char result[ENCODED_SIZE + BASE64_ENCODE_FINAL_LENGTH + 1]; unsigned nbytes; /* Number of bytes read from stdin */ int encoded_bytes; /* total number of bytes encoded per iteration */ nbytes = fread(buffer,1,CHUNK_SIZE,stdin); diff --git a/examples/hogweed-benchmark.c b/examples/hogweed-benchmark.c index 3fabe207..ebce9034 100644 --- a/examples/hogweed-benchmark.c +++ b/examples/hogweed-benchmark.c @@ -612,7 +612,10 @@ bench_openssl_ecdsa_init (unsigned size) /* This curve isn't supported in this build of openssl */ if (ctx->key == NULL) - return NULL; + { + free(ctx); + return NULL; + } if (!EC_KEY_generate_key( ctx->key)) die ("Openssl EC_KEY_generate_key failed.\n"); diff --git a/examples/nettle-benchmark.c b/examples/nettle-benchmark.c index c00486cc..11f62709 100644 --- a/examples/nettle-benchmark.c +++ b/examples/nettle-benchmark.c @@ -723,6 +723,10 @@ main(int argc, char **argv) int c; const char *alg; +#if WITH_OPENSSL + nettle_openssl_init(); +#endif + const struct nettle_hash *hashes[] = { &nettle_md2, &nettle_md4, &nettle_md5, diff --git a/examples/nettle-openssl.c b/examples/nettle-openssl.c index 86c5321c..b549ba54 100644 --- a/examples/nettle-openssl.c +++ b/examples/nettle-openssl.c @@ -2,7 +2,8 @@ Glue that's used only by the benchmark, and subject to change. - Copyright (C) 2002 Niels Möller + Copyright (C) 2002, 2017 Niels Möller + Copyright (C) 2017 Red Hat, Inc. This file is part of GNU Nettle. @@ -45,17 +46,69 @@ #include <assert.h> -#include <openssl/aes.h> -#include <openssl/blowfish.h> -#include <openssl/des.h> -#include <openssl/cast.h> -#include <openssl/rc4.h> +#include <openssl/conf.h> +#include <openssl/evp.h> +#include <openssl/err.h> #include <openssl/md5.h> #include <openssl/sha.h> #include "nettle-internal.h" +/* We use Openssl's EVP api for all openssl ciphers. This API selects + platform-specific implementations if appropriate, e.g., using x86 + AES-NI instructions. */ +struct openssl_cipher_ctx { + EVP_CIPHER_CTX *evp; +}; + +void +nettle_openssl_init(void) +{ + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); +#if OPENSSL_VERSION_NUMBER >= 0x1010000 + CONF_modules_load_file(NULL, NULL, 0); +#else + OPENSSL_config(NULL); +#endif +} + +static void +openssl_evp_set_encrypt_key(void *p, const uint8_t *key, + const EVP_CIPHER *cipher) +{ + struct openssl_cipher_ctx *ctx = p; + ctx->evp = EVP_CIPHER_CTX_new(); + assert(EVP_EncryptInit_ex(ctx->evp, cipher, NULL, key, NULL) == 1); + EVP_CIPHER_CTX_set_padding(ctx->evp, 0); +} +static void +openssl_evp_set_decrypt_key(void *p, const uint8_t *key, + const EVP_CIPHER *cipher) +{ + struct openssl_cipher_ctx *ctx = p; + ctx->evp = EVP_CIPHER_CTX_new(); + assert(EVP_DecryptInit_ex(ctx->evp, cipher, NULL, key, NULL) == 1); + EVP_CIPHER_CTX_set_padding(ctx->evp, 0); +} + +static void +openssl_evp_encrypt(const void *p, size_t length, + uint8_t *dst, const uint8_t *src) +{ + const struct openssl_cipher_ctx *ctx = p; + int len; + assert(EVP_EncryptUpdate(ctx->evp, dst, &len, src, length) == 1); +} +static void +openssl_evp_decrypt(const void *p, size_t length, + uint8_t *dst, const uint8_t *src) +{ + const struct openssl_cipher_ctx *ctx = p; + int len; + assert(EVP_DecryptUpdate(ctx->evp, dst, &len, src, length) == 1); +} /* AES */ static nettle_set_key_func openssl_aes128_set_encrypt_key; @@ -64,273 +117,152 @@ static nettle_set_key_func openssl_aes192_set_encrypt_key; static nettle_set_key_func openssl_aes192_set_decrypt_key; static nettle_set_key_func openssl_aes256_set_encrypt_key; static nettle_set_key_func openssl_aes256_set_decrypt_key; + static void openssl_aes128_set_encrypt_key(void *ctx, const uint8_t *key) { - AES_set_encrypt_key(key, 128, ctx); + openssl_evp_set_encrypt_key(ctx, key, EVP_aes_128_ecb()); } static void openssl_aes128_set_decrypt_key(void *ctx, const uint8_t *key) { - AES_set_decrypt_key(key, 128, ctx); + openssl_evp_set_decrypt_key(ctx, key, EVP_aes_128_ecb()); } static void openssl_aes192_set_encrypt_key(void *ctx, const uint8_t *key) { - AES_set_encrypt_key(key, 192, ctx); + openssl_evp_set_encrypt_key(ctx, key, EVP_aes_192_ecb()); } static void openssl_aes192_set_decrypt_key(void *ctx, const uint8_t *key) { - AES_set_decrypt_key(key, 192, ctx); + openssl_evp_set_decrypt_key(ctx, key, EVP_aes_192_ecb()); } static void openssl_aes256_set_encrypt_key(void *ctx, const uint8_t *key) { - AES_set_encrypt_key(key, 256, ctx); + openssl_evp_set_encrypt_key(ctx, key, EVP_aes_256_ecb()); } static void openssl_aes256_set_decrypt_key(void *ctx, const uint8_t *key) { - AES_set_decrypt_key(key, 256, ctx); -} - -static nettle_cipher_func openssl_aes_encrypt; -static void -openssl_aes_encrypt(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - assert (!(length % AES_BLOCK_SIZE)); - while (length) - { - AES_ecb_encrypt(src, dst, ctx, AES_ENCRYPT); - length -= AES_BLOCK_SIZE; - dst += AES_BLOCK_SIZE; - src += AES_BLOCK_SIZE; - } -} - -static nettle_cipher_func openssl_aes_decrypt; -static void -openssl_aes_decrypt(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - assert (!(length % AES_BLOCK_SIZE)); - while (length) - { - AES_ecb_encrypt(src, dst, ctx, AES_DECRYPT); - length -= AES_BLOCK_SIZE; - dst += AES_BLOCK_SIZE; - src += AES_BLOCK_SIZE; - } + openssl_evp_set_decrypt_key(ctx, key, EVP_aes_256_ecb()); } const struct nettle_cipher nettle_openssl_aes128 = { - "openssl aes128", sizeof(AES_KEY), + "openssl aes128", sizeof(struct openssl_cipher_ctx), 16, 16, openssl_aes128_set_encrypt_key, openssl_aes128_set_decrypt_key, - openssl_aes_encrypt, openssl_aes_decrypt + openssl_evp_encrypt, openssl_evp_decrypt }; const struct nettle_cipher nettle_openssl_aes192 = { - "openssl aes192", sizeof(AES_KEY), - /* Claim no block size, so that the benchmark doesn't try CBC mode - * (as openssl cipher + nettle cbc is somewhat pointless to - * benchmark). */ + "openssl aes192", sizeof(struct openssl_cipher_ctx), 16, 24, openssl_aes192_set_encrypt_key, openssl_aes192_set_decrypt_key, - openssl_aes_encrypt, openssl_aes_decrypt + openssl_evp_encrypt, openssl_evp_decrypt }; const struct nettle_cipher nettle_openssl_aes256 = { - "openssl aes256", sizeof(AES_KEY), - /* Claim no block size, so that the benchmark doesn't try CBC mode - * (as openssl cipher + nettle cbc is somewhat pointless to - * benchmark). */ + "openssl aes256", sizeof(struct openssl_cipher_ctx), 16, 32, openssl_aes256_set_encrypt_key, openssl_aes256_set_decrypt_key, - openssl_aes_encrypt, openssl_aes_decrypt + openssl_evp_encrypt, openssl_evp_decrypt }; /* Arcfour */ -static nettle_set_key_func openssl_arcfour128_set_key; static void -openssl_arcfour128_set_key(void *ctx, const uint8_t *key) +openssl_arcfour128_set_encrypt_key(void *ctx, const uint8_t *key) { - RC4_set_key(ctx, 16, key); + openssl_evp_set_encrypt_key(ctx, key, EVP_rc4()); } -static nettle_crypt_func openssl_arcfour_crypt; static void -openssl_arcfour_crypt(void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) +openssl_arcfour128_set_decrypt_key(void *ctx, const uint8_t *key) { - RC4(ctx, length, src, dst); + openssl_evp_set_decrypt_key(ctx, key, EVP_rc4()); } const struct nettle_aead nettle_openssl_arcfour128 = { - "openssl arcfour128", sizeof(RC4_KEY), + "openssl arcfour128", sizeof(struct openssl_cipher_ctx), 1, 16, 0, 0, - openssl_arcfour128_set_key, - openssl_arcfour128_set_key, + openssl_arcfour128_set_encrypt_key, + openssl_arcfour128_set_decrypt_key, NULL, NULL, - openssl_arcfour_crypt, - openssl_arcfour_crypt, + (nettle_crypt_func *)openssl_evp_encrypt, + (nettle_crypt_func *)openssl_evp_decrypt, NULL, }; /* Blowfish */ -static nettle_set_key_func openssl_bf128_set_key; -static void -openssl_bf128_set_key(void *ctx, const uint8_t *key) -{ - BF_set_key(ctx, 16, key); -} - -static nettle_cipher_func openssl_bf_encrypt; static void -openssl_bf_encrypt(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) +openssl_bf128_set_encrypt_key(void *ctx, const uint8_t *key) { - assert (!(length % BF_BLOCK)); - while (length) - { - BF_ecb_encrypt(src, dst, ctx, BF_ENCRYPT); - length -= BF_BLOCK; - dst += BF_BLOCK; - src += BF_BLOCK; - } + openssl_evp_set_encrypt_key(ctx, key, EVP_bf_ecb()); } -static nettle_cipher_func openssl_bf_decrypt; static void -openssl_bf_decrypt(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) +openssl_bf128_set_decrypt_key(void *ctx, const uint8_t *key) { - assert (!(length % BF_BLOCK)); - while (length) - { - BF_ecb_encrypt(src, dst, ctx, BF_DECRYPT); - length -= BF_BLOCK; - dst += BF_BLOCK; - src += BF_BLOCK; - } + openssl_evp_set_decrypt_key(ctx, key, EVP_bf_ecb()); } const struct nettle_cipher nettle_openssl_blowfish128 = { - "openssl bf128", sizeof(BF_KEY), + "openssl bf128", sizeof(struct openssl_cipher_ctx), 8, 16, - openssl_bf128_set_key, openssl_bf128_set_key, - openssl_bf_encrypt, openssl_bf_decrypt + openssl_bf128_set_encrypt_key, openssl_bf128_set_decrypt_key, + openssl_evp_encrypt, openssl_evp_decrypt }; /* DES */ -static nettle_set_key_func openssl_des_set_key; static void -openssl_des_set_key(void *ctx, const uint8_t *key) +openssl_des_set_encrypt_key(void *ctx, const uint8_t *key) { - /* Not sure what "unchecked" means. We want to ignore parity bits, - but it would still make sense to check for weak keys. */ - /* Explicit cast used as I don't want to care about openssl's broken - array typedefs DES_cblock and const_DES_cblock. */ - DES_set_key_unchecked( (void *) key, ctx); + openssl_evp_set_encrypt_key(ctx, key, EVP_des_ecb()); } -#define DES_BLOCK_SIZE 8 - -static nettle_cipher_func openssl_des_encrypt; -static void -openssl_des_encrypt(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - assert (!(length % DES_BLOCK_SIZE)); - while (length) - { - DES_ecb_encrypt((void *) src, (void *) dst, - (void *) ctx, DES_ENCRYPT); - length -= DES_BLOCK_SIZE; - dst += DES_BLOCK_SIZE; - src += DES_BLOCK_SIZE; - } -} - -static nettle_cipher_func openssl_des_decrypt; static void -openssl_des_decrypt(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) +openssl_des_set_decrypt_key(void *ctx, const uint8_t *key) { - assert (!(length % DES_BLOCK_SIZE)); - while (length) - { - DES_ecb_encrypt((void *) src, (void *) dst, - (void *) ctx, DES_DECRYPT); - length -= DES_BLOCK_SIZE; - dst += DES_BLOCK_SIZE; - src += DES_BLOCK_SIZE; - } + openssl_evp_set_decrypt_key(ctx, key, EVP_des_ecb()); } const struct nettle_cipher nettle_openssl_des = { - "openssl des", sizeof(DES_key_schedule), + "openssl des", sizeof(struct openssl_cipher_ctx), 8, 8, - openssl_des_set_key, openssl_des_set_key, - openssl_des_encrypt, openssl_des_decrypt + openssl_des_set_encrypt_key, openssl_des_set_decrypt_key, + openssl_evp_encrypt, openssl_evp_decrypt }; /* Cast128 */ -static nettle_set_key_func openssl_cast128_set_key; -static void -openssl_cast128_set_key(void *ctx, const uint8_t *key) -{ - CAST_set_key(ctx, 16, key); -} - -static nettle_cipher_func openssl_cast_encrypt; static void -openssl_cast_encrypt(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) +openssl_cast128_set_encrypt_key(void *ctx, const uint8_t *key) { - assert (!(length % CAST_BLOCK)); - while (length) - { - CAST_ecb_encrypt(src, dst, ctx, CAST_ENCRYPT); - length -= CAST_BLOCK; - dst += CAST_BLOCK; - src += CAST_BLOCK; - } + openssl_evp_set_encrypt_key(ctx, key, EVP_cast5_ecb()); } -static nettle_cipher_func openssl_cast_decrypt; static void -openssl_cast_decrypt(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) +openssl_cast128_set_decrypt_key(void *ctx, const uint8_t *key) { - assert (!(length % CAST_BLOCK)); - while (length) - { - CAST_ecb_encrypt(src, dst, ctx, CAST_DECRYPT); - length -= CAST_BLOCK; - dst += CAST_BLOCK; - src += CAST_BLOCK; - } + openssl_evp_set_decrypt_key(ctx, key, EVP_cast5_ecb()); } const struct nettle_cipher nettle_openssl_cast128 = { - "openssl cast128", sizeof(CAST_KEY), - 8, CAST_KEY_LENGTH, - openssl_cast128_set_key, openssl_cast128_set_key, - openssl_cast_encrypt, openssl_cast_decrypt + "openssl cast128", sizeof(struct openssl_cipher_ctx), + 8, 16, + openssl_cast128_set_encrypt_key, openssl_cast128_set_decrypt_key, + openssl_evp_encrypt, openssl_evp_decrypt }; /* Hash functions */ @@ -29,6 +29,8 @@ not, see http://www.gnu.org/licenses/. */ +#define _GNU_SOURCE + #if HAVE_CONFIG_H # include "config.h" #endif @@ -0,0 +1,84 @@ +/* hkdf.c + + Copyright (C) 2017 Red Hat, Inc. + + Author: Nikos Mavrogiannopoulos + + 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/. + */ + +/* Functions for the HKDF handling. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "hkdf.h" + +/* hkdf_extract: Outputs a PRK of digest_size + */ +void +hkdf_extract(void *mac_ctx, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_size, + size_t secret_size, const uint8_t *secret, + uint8_t *dst) +{ + update(mac_ctx, secret_size, secret); + digest(mac_ctx, digest_size, dst); +} + +/* hkdf_expand: Outputs an arbitrary key of size specified by length + */ +void +hkdf_expand(void *mac_ctx, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_size, + size_t info_size, const uint8_t *info, + size_t length, uint8_t *dst) +{ + uint8_t i = 1; + + if (!length) + return; + + for (;; dst += digest_size, length -= digest_size, i++) + { + update(mac_ctx, info_size, info); + update(mac_ctx, 1, &i); + if (length <= digest_size) + break; + + digest(mac_ctx, digest_size, dst); + update(mac_ctx, digest_size, dst); + } + + digest(mac_ctx, length, dst); +} @@ -0,0 +1,67 @@ +/* hkdf.h + + TLS PRF code (RFC-5246, RFC-2246). + + Copyright (C) 2017 Red Hat, Inc. + + 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_HKDF_H_INCLUDED +#define NETTLE_HKDF_H_INCLUDED + +#include "nettle-types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Namespace mangling */ +#define hkdf_extract nettle_hkdf_extract +#define hkdf_expand nettle_hkdf_expand + +void +hkdf_extract(void *mac_ctx, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_size, + size_t secret_size, const uint8_t *secret, + uint8_t *dst); + +void +hkdf_expand(void *mac_ctx, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_size, + size_t info_size, const uint8_t *info, + size_t length, uint8_t *dst); + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_HKDF_H_INCLUDED */ @@ -2,7 +2,7 @@ Contributed to the GNU project by Niels Möller -Copyright 1991-1997, 1999-2014 Free Software Foundation, Inc. +Copyright 1991-1997, 1999-2017 Free Software Foundation, Inc. This file is part of the GNU MP Library. @@ -69,8 +69,16 @@ see https://www.gnu.org/licenses/. */ #define GMP_MIN(a, b) ((a) < (b) ? (a) : (b)) #define GMP_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b))) + +/* Return non-zero if xp,xsize and yp,ysize overlap. + If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no + overlap. If both these are false, there's an overlap. */ +#define GMP_MPN_OVERLAP_P(xp, xsize, yp, ysize) \ + ((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp)) + #define gmp_assert_nocarry(x) do { \ - mp_limb_t __cy = x; \ + mp_limb_t __cy = (x); \ assert (__cy == 0); \ } while (0) @@ -264,12 +272,12 @@ gmp_default_alloc (size_t size) static void * gmp_default_realloc (void *old, size_t old_size, size_t new_size) { - mp_ptr p; + void * p; p = realloc (old, new_size); if (!p) - gmp_die("gmp_default_realoc: Virtual memory exhausted."); + gmp_die("gmp_default_realloc: Virtual memory exhausted."); return p; } @@ -322,14 +330,14 @@ mp_set_memory_functions (void *(*alloc_func) (size_t), static mp_ptr gmp_xalloc_limbs (mp_size_t size) { - return gmp_xalloc (size * sizeof (mp_limb_t)); + return (mp_ptr) gmp_xalloc (size * sizeof (mp_limb_t)); } static mp_ptr gmp_xrealloc_limbs (mp_ptr old, mp_size_t size) { assert (size > 0); - return (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t)); + return (mp_ptr) (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t)); } @@ -346,7 +354,7 @@ mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n) void mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n) { - while (n-- > 0) + while (--n >= 0) d[n] = s[n]; } @@ -373,20 +381,22 @@ mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn) static mp_size_t mpn_normalized_size (mp_srcptr xp, mp_size_t n) { - for (; n > 0 && xp[n-1] == 0; n--) - ; + while (n > 0 && xp[n-1] == 0) + --n; return n; } -#define mpn_zero_p(xp, n) (mpn_normalized_size ((xp), (n)) == 0) +int +mpn_zero_p(mp_srcptr rp, mp_size_t n) +{ + return mpn_normalized_size (rp, n) == 0; +} void mpn_zero (mp_ptr rp, mp_size_t n) { - mp_size_t i; - - for (i = 0; i < n; i++) - rp[i] = 0; + while (--n >= 0) + rp[n] = 0; } mp_limb_t @@ -452,7 +462,7 @@ mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b) { mp_limb_t a = ap[i]; /* Carry out */ - mp_limb_t cy = a < b;; + mp_limb_t cy = a < b; rp[i] = a - b; b = cy; } @@ -572,23 +582,24 @@ mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn) { assert (un >= vn); assert (vn >= 1); + assert (!GMP_MPN_OVERLAP_P(rp, un + vn, up, un)); + assert (!GMP_MPN_OVERLAP_P(rp, un + vn, vp, vn)); /* We first multiply by the low order limb. This result can be stored, not added, to rp. We also avoid a loop for zeroing this way. */ rp[un] = mpn_mul_1 (rp, up, un, vp[0]); - rp += 1, vp += 1, vn -= 1; /* Now accumulate the product of up[] and the next higher limb from vp[]. */ - while (vn >= 1) + while (--vn >= 1) { + rp += 1, vp += 1; rp[un] = mpn_addmul_1 (rp, up, un, vp[0]); - rp += 1, vp += 1, vn -= 1; } - return rp[un - 1]; + return rp[un]; } void @@ -608,7 +619,6 @@ mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt) { mp_limb_t high_limb, low_limb; unsigned int tnc; - mp_size_t i; mp_limb_t retval; assert (n >= 1); @@ -623,7 +633,7 @@ mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt) retval = low_limb >> tnc; high_limb = (low_limb << cnt); - for (i = n; --i != 0;) + while (--n != 0) { low_limb = *--up; *--rp = high_limb | (low_limb >> tnc); @@ -639,7 +649,6 @@ mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt) { mp_limb_t high_limb, low_limb; unsigned int tnc; - mp_size_t i; mp_limb_t retval; assert (n >= 1); @@ -651,7 +660,7 @@ mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt) retval = (high_limb << tnc); low_limb = high_limb >> cnt; - for (i = n; --i != 0;) + while (--n != 0) { high_limb = *up++; *rp++ = low_limb | (high_limb << tnc); @@ -702,24 +711,68 @@ mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit) i, ptr, i, GMP_LIMB_MAX); } +void +mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n) +{ + while (--n >= 0) + *rp++ = ~ *up++; +} + +mp_limb_t +mpn_neg (mp_ptr rp, mp_srcptr up, mp_size_t n) +{ + while (*up == 0) + { + *rp = 0; + if (!--n) + return 0; + ++up; ++rp; + } + *rp = - *up; + mpn_com (++rp, ++up, --n); + return 1; +} + /* MPN division interface. */ + +/* The 3/2 inverse is defined as + + m = floor( (B^3-1) / (B u1 + u0)) - B +*/ mp_limb_t mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0) { - mp_limb_t r, p, m; - unsigned ul, uh; - unsigned ql, qh; + mp_limb_t r, p, m, ql; + unsigned ul, uh, qh; - /* First, do a 2/1 inverse. */ - /* The inverse m is defined as floor( (B^2 - 1 - u1)/u1 ), so that 0 < - * B^2 - (B + m) u1 <= u1 */ assert (u1 >= GMP_LIMB_HIGHBIT); + /* For notation, let b denote the half-limb base, so that B = b^2. + Split u1 = b uh + ul. */ ul = u1 & GMP_LLIMB_MASK; uh = u1 >> (GMP_LIMB_BITS / 2); + /* Approximation of the high half of quotient. Differs from the 2/1 + inverse of the half limb uh, since we have already subtracted + u0. */ qh = ~u1 / uh; + + /* Adjust to get a half-limb 3/2 inverse, i.e., we want + + qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u + = floor( (b (~u) + b-1) / u), + + and the remainder + + r = b (~u) + b-1 - qh (b uh + ul) + = b (~u - qh uh) + b-1 - qh ul + + Subtraction of qh ul may underflow, which implies adjustments. + But by normalization, 2 u >= B > qh ul, so we need to adjust by + at most 2. + */ + r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK; p = (mp_limb_t) qh * ul; @@ -737,11 +790,19 @@ mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0) } r -= p; - /* Do a 3/2 division (with half limb size) */ + /* Low half of the quotient is + + ql = floor ( (b r + b-1) / u1). + + This is a 3/2 division (on half-limbs), for which qh is a + suitable inverse. */ + p = (r >> (GMP_LIMB_BITS / 2)) * qh + r; + /* Unlike full-limb 3/2, we can add 1 without overflow. For this to + work, it is essential that ql is a full mp_limb_t. */ ql = (p >> (GMP_LIMB_BITS / 2)) + 1; - /* By the 3/2 method, we don't need the high half limb. */ + /* By the 3/2 trick, we don't need the high half limb. */ r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1; if (r >= (p << (GMP_LIMB_BITS / 2))) @@ -756,6 +817,8 @@ mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0) r -= u1; } + /* Now m is the 2/1 invers of u1. If u0 > 0, adjust it to become a + 3/2 inverse. */ if (u0 > 0) { mp_limb_t th, tl; @@ -876,7 +939,7 @@ mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn, d = inv->d1; di = inv->di; - while (nn-- > 0) + while (--nn >= 0) { mp_limb_t q; @@ -1160,7 +1223,7 @@ mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un) unsigned char mask; size_t sn, j; mp_size_t i; - int shift; + unsigned shift; sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]) + bits - 1) / bits; @@ -1301,6 +1364,8 @@ mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn, return rn; } +/* Result is usually normalized, except for all-zero input, in which + case a single zero limb is written at *RP, and 1 is returned. */ static mp_size_t mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn, mp_limb_t b, const struct mpn_base_info *info) @@ -1310,16 +1375,18 @@ mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn, unsigned k; size_t j; + assert (sn > 0); + k = 1 + (sn - 1) % info->exp; j = 0; w = sp[j++]; - for (; --k > 0; ) + while (--k != 0) w = w * b + sp[j++]; rp[0] = w; - for (rn = (w > 0); j < sn;) + for (rn = 1; j < sn;) { mp_limb_t cy; @@ -1362,9 +1429,11 @@ mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base) void mpz_init (mpz_t r) { - r->_mp_alloc = 1; + static const mp_limb_t dummy_limb = 0xc1a0; + + r->_mp_alloc = 0; r->_mp_size = 0; - r->_mp_d = gmp_xalloc_limbs (1); + r->_mp_d = (mp_ptr) &dummy_limb; } /* The utility of this function is a bit limited, since many functions @@ -1385,15 +1454,19 @@ mpz_init2 (mpz_t r, mp_bitcnt_t bits) void mpz_clear (mpz_t r) { - gmp_free (r->_mp_d); + if (r->_mp_alloc) + gmp_free (r->_mp_d); } -static void * +static mp_ptr mpz_realloc (mpz_t r, mp_size_t size) { size = GMP_MAX (size, 1); - r->_mp_d = gmp_xrealloc_limbs (r->_mp_d, size); + if (r->_mp_alloc) + r->_mp_d = gmp_xrealloc_limbs (r->_mp_d, size); + else + r->_mp_d = gmp_xalloc_limbs (size); r->_mp_alloc = size; if (GMP_ABS (r->_mp_size) > size) @@ -1416,7 +1489,7 @@ mpz_set_si (mpz_t r, signed long int x) else /* (x < 0) */ { r->_mp_size = -1; - r->_mp_d[0] = GMP_NEG_CAST (unsigned long int, x); + MPZ_REALLOC (r, 1)[0] = GMP_NEG_CAST (unsigned long int, x); } } @@ -1426,7 +1499,7 @@ mpz_set_ui (mpz_t r, unsigned long int x) if (x > 0) { r->_mp_size = 1; - r->_mp_d[0] = x; + MPZ_REALLOC (r, 1)[0] = x; } else r->_mp_size = 0; @@ -1475,14 +1548,12 @@ mpz_fits_slong_p (const mpz_t u) { mp_size_t us = u->_mp_size; - if (us == 0) - return 1; - else if (us == 1) + if (us == 1) return u->_mp_d[0] < GMP_LIMB_HIGHBIT; else if (us == -1) return u->_mp_d[0] <= GMP_LIMB_HIGHBIT; else - return 0; + return (us == 0); } int @@ -1496,14 +1567,11 @@ mpz_fits_ulong_p (const mpz_t u) long int mpz_get_si (const mpz_t u) { - mp_size_t us = u->_mp_size; - - if (us > 0) - return (long) (u->_mp_d[0] & ~GMP_LIMB_HIGHBIT); - else if (us < 0) - return (long) (- u->_mp_d[0] | GMP_LIMB_HIGHBIT); + if (u->_mp_size < 0) + /* This expression is necessary to properly handle 0x80000000 */ + return -1 - (long) ((u->_mp_d[0] - 1) & ~GMP_LIMB_HIGHBIT); else - return 0; + return (long) (mpz_get_ui (u) & ~GMP_LIMB_HIGHBIT); } unsigned long int @@ -1536,7 +1604,7 @@ mpz_realloc2 (mpz_t x, mp_bitcnt_t n) mp_srcptr mpz_limbs_read (mpz_srcptr x) { - return x->_mp_d;; + return x->_mp_d; } mp_ptr @@ -1716,9 +1784,7 @@ mpz_cmp_d (const mpz_t x, double d) int mpz_sgn (const mpz_t u) { - mp_size_t usize = u->_mp_size; - - return (usize > 0) - (usize < 0); + return GMP_CMP (u->_mp_size, 0); } int @@ -1733,13 +1799,7 @@ mpz_cmp_si (const mpz_t u, long v) else if (usize >= 0) return 1; else /* usize == -1 */ - { - mp_limb_t ul = u->_mp_d[0]; - if ((mp_limb_t)GMP_NEG_CAST (unsigned long int, v) < ul) - return -1; - else - return (mp_limb_t)GMP_NEG_CAST (unsigned long int, v) > ul; - } + return GMP_CMP (GMP_NEG_CAST (mp_limb_t, v), u->_mp_d[0]); } int @@ -1752,10 +1812,7 @@ mpz_cmp_ui (const mpz_t u, unsigned long v) else if (usize < 0) return -1; else - { - mp_limb_t ul = (usize > 0) ? u->_mp_d[0] : 0; - return (ul > v) - (ul < v); - } + return GMP_CMP (mpz_get_ui (u), v); } int @@ -1775,15 +1832,10 @@ mpz_cmp (const mpz_t a, const mpz_t b) int mpz_cmpabs_ui (const mpz_t u, unsigned long v) { - mp_size_t un = GMP_ABS (u->_mp_size); - mp_limb_t ul; - - if (un > 1) + if (GMP_ABS (u->_mp_size) > 1) return 1; - - ul = (un == 1) ? u->_mp_d[0] : 0; - - return (ul > v) - (ul < v); + else + return GMP_CMP (mpz_get_ui (u), v); } int @@ -1796,18 +1848,14 @@ mpz_cmpabs (const mpz_t u, const mpz_t v) void mpz_abs (mpz_t r, const mpz_t u) { - if (r != u) - mpz_set (r, u); - + mpz_set (r, u); r->_mp_size = GMP_ABS (r->_mp_size); } void mpz_neg (mpz_t r, const mpz_t u) { - if (r != u) - mpz_set (r, u); - + mpz_set (r, u); r->_mp_size = -r->_mp_size; } @@ -1833,7 +1881,7 @@ mpz_abs_add_ui (mpz_t r, const mpz_t a, unsigned long b) an = GMP_ABS (a->_mp_size); if (an == 0) { - r->_mp_d[0] = b; + MPZ_REALLOC (r, 1)[0] = b; return b > 0; } @@ -1852,14 +1900,15 @@ static mp_size_t mpz_abs_sub_ui (mpz_t r, const mpz_t a, unsigned long b) { mp_size_t an = GMP_ABS (a->_mp_size); - mp_ptr rp = MPZ_REALLOC (r, an); + mp_ptr rp; if (an == 0) { - rp[0] = b; + MPZ_REALLOC (r, 1)[0] = b; return -(b > 0); } - else if (an == 1 && a->_mp_d[0] < b) + rp = MPZ_REALLOC (r, an); + if (an == 1 && a->_mp_d[0] < b) { rp[0] = b - a->_mp_d[0]; return -1; @@ -2077,8 +2126,7 @@ mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits) else mpn_copyd (rp + limbs, u->_mp_d, un); - while (limbs > 0) - rp[--limbs] = 0; + mpn_zero (rp, limbs); r->_mp_size = (u->_mp_size < 0) ? - rn : rn; } @@ -2331,7 +2379,6 @@ mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index, if (qn <= 0) qn = 0; - else { qp = MPZ_REALLOC (q, qn); @@ -2385,16 +2432,9 @@ mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index, { /* Have to negate and sign extend. */ mp_size_t i; - mp_limb_t cy; - for (cy = 1, i = 0; i < un; i++) - { - mp_limb_t s = ~u->_mp_d[i] + cy; - cy = s < cy; - rp[i] = s; - } - assert (cy == 0); - for (; i < rn - 1; i++) + gmp_assert_nocarry (! mpn_neg (rp, u->_mp_d, un)); + for (i = un; i < rn - 1; i++) rp[i] = GMP_LIMB_MAX; rp[rn-1] = mask; @@ -2419,23 +2459,13 @@ mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index, if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */ { /* If r != 0, compute 2^{bit_count} - r. */ - mp_size_t i; + mpn_neg (rp, rp, rn); - for (i = 0; i < rn && rp[i] == 0; i++) - ; - if (i < rn) - { - /* r > 0, need to flip sign. */ - rp[i] = ~rp[i] + 1; - while (++i < rn) - rp[i] = ~rp[i]; - - rp[rn-1] &= mask; + rp[rn-1] &= mask; - /* us is not used for anything else, so we can modify it - here to indicate flipped sign. */ - us = -us; - } + /* us is not used for anything else, so we can modify it + here to indicate flipped sign. */ + us = -us; } } rn = mpn_normalized_size (rp, rn); @@ -2550,7 +2580,7 @@ mpz_div_qr_ui (mpz_t q, mpz_t r, if (r) { - r->_mp_d[0] = rl; + MPZ_REALLOC (r, 1)[0] = rl; r->_mp_size = rs; } if (q) @@ -3074,9 +3104,7 @@ void mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e) { mpz_t b; - mpz_init_set_ui (b, blimb); - mpz_pow_ui (r, b, e); - mpz_clear (b); + mpz_pow_ui (r, mpz_roinit_n (b, &blimb, 1), e); } void @@ -3148,7 +3176,7 @@ mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m) } mpz_init_set_ui (tr, 1); - while (en-- > 0) + while (--en >= 0) { mp_limb_t w = e->_mp_d[en]; mp_limb_t bit; @@ -3188,9 +3216,7 @@ void mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m) { mpz_t e; - mpz_init_set_ui (e, elimb); - mpz_powm (r, b, e, m); - mpz_clear (e); + mpz_powm (r, b, mpz_roinit_n (e, &elimb, 1), m); } /* x=trunc(y^(1/z)), r=y-x^z */ @@ -3215,12 +3241,8 @@ mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z) } mpz_init (u); - { - mp_bitcnt_t tb; - tb = mpz_sizeinbase (y, 2) / z + 1; - mpz_init2 (t, tb); - mpz_setbit (t, tb); - } + mpz_init (t); + mpz_setbit (t, mpz_sizeinbase (y, 2) / z + 1); if (z == 2) /* simplify sqrt loop: z-1 == 1 */ do { @@ -3333,7 +3355,7 @@ void mpz_fac_ui (mpz_t x, unsigned long n) { mpz_set_ui (x, n + (n == 0)); - for (;n > 2;) + while (n > 2) mpz_mul_ui (x, x, --n); } @@ -3504,7 +3526,7 @@ mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index) must be complemented. */ if (shift > 0 && (w << (GMP_LIMB_BITS - shift)) > 0) return bit ^ 1; - while (limb_index-- > 0) + while (--limb_index >= 0) if (d->_mp_d[limb_index] > 0) return bit ^ 1; } @@ -3647,7 +3669,7 @@ mpz_and (mpz_t r, const mpz_t u, const mpz_t v) /* If the smaller input is positive, higher limbs don't matter. */ rn = vx ? un : vn; - rp = MPZ_REALLOC (r, rn + rc); + rp = MPZ_REALLOC (r, rn + (mp_size_t) rc); up = u->_mp_d; vp = v->_mp_d; @@ -3720,7 +3742,7 @@ mpz_ior (mpz_t r, const mpz_t u, const mpz_t v) don't matter. */ rn = vx ? vn : un; - rp = MPZ_REALLOC (r, rn + rc); + rp = MPZ_REALLOC (r, rn + (mp_size_t) rc); up = u->_mp_d; vp = v->_mp_d; @@ -3789,7 +3811,7 @@ mpz_xor (mpz_t r, const mpz_t u, const mpz_t v) vx = -vc; rx = -rc; - rp = MPZ_REALLOC (r, un + rc); + rp = MPZ_REALLOC (r, un + (mp_size_t) rc); up = u->_mp_d; vp = v->_mp_d; @@ -3999,7 +4021,7 @@ mpz_sizeinbase (const mpz_t u, int base) size_t ndigits; assert (base >= 2); - assert (base <= 36); + assert (base <= 62); un = GMP_ABS (u->_mp_size); if (un == 0) @@ -4049,23 +4071,26 @@ mpz_get_str (char *sp, int base, const mpz_t u) mp_size_t un; size_t i, sn; - if (base >= 0) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + if (base > 1) { - digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + if (base <= 36) + digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + else if (base > 62) + return NULL; } + else if (base >= -1) + base = 10; else { base = -base; - digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (base > 36) + return NULL; } - if (base <= 1) - base = 10; - if (base > 36) - return NULL; sn = 1 + mpz_sizeinbase (u, base); if (!sp) - sp = gmp_xalloc (1 + sn); + sp = (char *) gmp_xalloc (1 + sn); un = GMP_ABS (u->_mp_size); @@ -4109,14 +4134,14 @@ mpz_get_str (char *sp, int base, const mpz_t u) int mpz_set_str (mpz_t r, const char *sp, int base) { - unsigned bits; + unsigned bits, value_of_a; mp_size_t rn, alloc; mp_ptr rp; - size_t sn; + size_t dn; int sign; unsigned char *dp; - assert (base == 0 || (base >= 2 && base <= 36)); + assert (base == 0 || (base >= 2 && base <= 62)); while (isspace( (unsigned char) *sp)) sp++; @@ -4126,18 +4151,17 @@ mpz_set_str (mpz_t r, const char *sp, int base) if (base == 0) { - if (*sp == '0') + if (sp[0] == '0') { - sp++; - if (*sp == 'x' || *sp == 'X') + if (sp[1] == 'x' || sp[1] == 'X') { base = 16; - sp++; + sp += 2; } - else if (*sp == 'b' || *sp == 'B') + else if (sp[1] == 'b' || sp[1] == 'B') { base = 2; - sp++; + sp += 2; } else base = 8; @@ -4146,49 +4170,63 @@ mpz_set_str (mpz_t r, const char *sp, int base) base = 10; } - sn = strlen (sp); - dp = gmp_xalloc (sn + (sn == 0)); + if (!*sp) + { + r->_mp_size = 0; + return -1; + } + dp = (unsigned char *) gmp_xalloc (strlen (sp)); - for (sn = 0; *sp; sp++) + value_of_a = (base > 36) ? 36 : 10; + for (dn = 0; *sp; sp++) { unsigned digit; if (isspace ((unsigned char) *sp)) continue; - if (*sp >= '0' && *sp <= '9') + else if (*sp >= '0' && *sp <= '9') digit = *sp - '0'; else if (*sp >= 'a' && *sp <= 'z') - digit = *sp - 'a' + 10; + digit = *sp - 'a' + value_of_a; else if (*sp >= 'A' && *sp <= 'Z') digit = *sp - 'A' + 10; else digit = base; /* fail */ - if (digit >= base) + if (digit >= (unsigned) base) { gmp_free (dp); r->_mp_size = 0; return -1; } - dp[sn++] = digit; + dp[dn++] = digit; } + if (!dn) + { + gmp_free (dp); + r->_mp_size = 0; + return -1; + } bits = mpn_base_power_of_two_p (base); if (bits > 0) { - alloc = (sn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS; + alloc = (dn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS; rp = MPZ_REALLOC (r, alloc); - rn = mpn_set_str_bits (rp, dp, sn, bits); + rn = mpn_set_str_bits (rp, dp, dn, bits); } else { struct mpn_base_info info; mpn_get_base_info (&info, base); - alloc = (sn + info.exp - 1) / info.exp; + alloc = (dn + info.exp - 1) / info.exp; rp = MPZ_REALLOC (r, alloc); - rn = mpn_set_str_other (rp, dp, sn, base, &info); + rn = mpn_set_str_other (rp, dp, dn, base, &info); + /* Normalization, needed for all-zero input. */ + assert (rn > 0); + rn -= rp[rn-1] == 0; } assert (rn <= alloc); gmp_free (dp); @@ -1,6 +1,6 @@ /* mini-gmp, a minimalistic implementation of a GNU GMP subset. -Copyright 2011-2014 Free Software Foundation, Inc. +Copyright 2011-2015 Free Software Foundation, Inc. This file is part of the GNU MP Library. @@ -82,6 +82,7 @@ void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t); void mpn_zero (mp_ptr, mp_size_t); int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t); +int mpn_zero_p (mp_srcptr, mp_size_t); mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t); mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t); @@ -107,6 +108,9 @@ mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int); mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t); mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t); +void mpn_com (mp_ptr, mp_srcptr, mp_size_t); +mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t); + mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t); mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t); diff --git a/misc/plan.html b/misc/plan.html index 71ddba3a..99be07d5 100644 --- a/misc/plan.html +++ b/misc/plan.html @@ -12,9 +12,9 @@ </head> <body> <h1> Nettle release plans </h1> - <p> This is an attempt at defining a development target for - Nettle-3.3, inspired by similar pages for recent GMP releases. - [Last updated 2016-09-19]</p> + <p> This is an attempt at defining a development target for the next + release of Nettle, inspired by similar pages for recent GMP + releases. [Last updated 2017-10-01]</p> <p class='should'> This really ought to be done before release </p> @@ -28,21 +28,36 @@ Leave for some later release! </p> - <h1> Plans for nettle-3.3 </h1> + <h1> Plans for nettle-3.4 </h1> + + <h2> Bug fixes </h2> + <p class='should'> Fix issues with sizes of objects like the + nettle_hashes array and the ecc_curve structs accidentally leaking + into the ABI. Fix by another level of indirection, with a function + call to return the start address. + </p> <h2> New features </h2> <p class='postponed'> Add larger "safe" curves, e.g., M-383, curve41417, curve448 and - E-521. + E-521. (curve448 in progress, on its own branch). </p> + <p class='postponed'> Add functions for converting ECC points to and from ANSI x9.62. </p> - <p class='done'> - Use side-channel silent mpz_powm_sec for RSA and DSA. + + <p class='postponed'> + Support for the Skein hash function. </p> - <p class='done'> - Side-channel silent memeql_sec. + + <p class='postponed'> + Support for more GOST standard algorithms. + </p> + + <p class='wish'> + Support for CFB mode (patch by Dmitry Eremin-Solenikov posted on + the list). </p> <h2> Optimizations </h2> @@ -58,42 +73,43 @@ </p> <h2> Miscellaneous </h2> - <p class='done'> Use GMP-5 functions unconditionally. </p> <p class='postponed'> Use more functions from GMP-6 and later, when available: mpn_sec_add_1, mpn_sec_tabselect, mpn_sec_invert, mpn_cnd_swap, ... </p> - <h2> Documentation </h2> - <p class='done'> - Document memeql_sec. + <p class='done'> Change base16 and base64 interfaces to use char + for encoded data, and fix remaining pointer-signedness warnings. </p> + <h2> Documentation </h2> + + <h2> Build system </h2> - <p class='postponed'> - Update AX_CREATE_STDINT_H to the latest version. + <p class='should'> + Delete AX_CREATE_STDINT_H, use stdint.h unconditionally. </p> <h2> Testing </h2> <p> Since xenofarm isn't up and running, do some manual testing: </p> <ul> - <li class='done'> x86_64-linux-gnu</li> - <li class='done'> x86-linux-gnu</li> - <li class='done'> x86_64-freebsd</li> - <li class='done'> x86-w*ndows (using cross compiler and wine)</li> - <li class='done'> x86_64-w*ndows (using cross compiler and wine)</li> + <li class='should'> x86_64-linux-gnu</li> + <li class='should'> x86-linux-gnu</li> + <li class='should'> x86_64-freebsd</li> + <li class='should'> x86-w*ndows (using cross compiler and wine)</li> + <li class='should'> x86_64-w*ndows (using cross compiler and wine)</li> <li class='should'> x86-darwin (needs help from Nettle users)</li> <li class='should'> x86_64-darwin (needs help from Nettle users)</li> <li class='should'> armv5-linux-gnu (qemu)</li> - <li class='done'> armv7-linux-gnu (qemu)</li> + <li class='should'> armv7-linux-gnu (qemu)</li> <li class='should'> armv8-linux-gnu (qemu)</li> <li class='should'> ppc64-linux-gnu (qemu)</li> <li class='should'> ppc32-linux-gnu (qemu)</li> - <li class='done'> mips64-linux-gnu (qemu)</li> + <li class='should'> mips64-linux-gnu (qemu)</li> <li class='should'> mips32-linux-gnu (qemu)</li> - <li class='done'> m68k-linux-gnu (aranym)</li> + <li class='should'> m68k-linux-gnu (aranym)</li> <li class='wish'> armv7-android </li> </ul> diff --git a/nettle-internal.h b/nettle-internal.h index 4e3098bb..0b0d25c9 100644 --- a/nettle-internal.h +++ b/nettle-internal.h @@ -54,6 +54,7 @@ /* Arbitrary limits which apply to systems that don't have alloca */ #define NETTLE_MAX_HASH_BLOCK_SIZE 128 #define NETTLE_MAX_HASH_DIGEST_SIZE 64 +#define NETTLE_MAX_HASH_CONTEXT_SIZE (sizeof(struct sha3_224_ctx)) #define NETTLE_MAX_SEXP_ASSOC 17 #define NETTLE_MAX_CIPHER_BLOCK_SIZE 32 @@ -78,6 +79,7 @@ extern const struct nettle_aead nettle_salsa20r12; /* Glue to openssl, for comparative benchmarking. Code in * examples/nettle-openssl.c. */ +extern void nettle_openssl_init(void); extern const struct nettle_cipher nettle_openssl_aes128; extern const struct nettle_cipher nettle_openssl_aes192; extern const struct nettle_cipher nettle_openssl_aes256; diff --git a/nettle-types.h b/nettle-types.h index 475937d2..84c375d2 100644 --- a/nettle-types.h +++ b/nettle-types.h @@ -89,17 +89,17 @@ typedef size_t nettle_armor_length_func(size_t length); typedef void nettle_armor_init_func(void *ctx); typedef size_t nettle_armor_encode_update_func(void *ctx, - uint8_t *dst, + char *dst, size_t src_length, const uint8_t *src); -typedef size_t nettle_armor_encode_final_func(void *ctx, uint8_t *dst); +typedef size_t nettle_armor_encode_final_func(void *ctx, char *dst); typedef int nettle_armor_decode_update_func(void *ctx, size_t *dst_length, uint8_t *dst, size_t src_length, - const uint8_t *src); + const char *src); typedef int nettle_armor_decode_final_func(void *ctx); diff --git a/nettle.texinfo b/nettle.texinfo index 9cfaf43a..23eed335 100644 --- a/nettle.texinfo +++ b/nettle.texinfo @@ -93,6 +93,7 @@ Cipher modes * CBC:: * CTR:: +* CFB:: * GCM:: * CCM:: @@ -1884,21 +1885,23 @@ a message that is larger than the cipher's block size. As explained in processing them independently with the block cipher (Electronic Code Book mode, @acronym{ECB}), leaks information. -Besides @acronym{ECB}, Nettle provides a two other modes of operation: -Cipher Block Chaining (@acronym{CBC}), Counter mode (@acronym{CTR}), and -a couple of @acronym{AEAD} modes (@pxref{Authenticated encryption}). -@acronym{CBC} is widely used, but there are a few subtle issues of -information leakage, see, e.g., +Besides @acronym{ECB}, Nettle provides several other modes of operation: +Cipher Block Chaining (@acronym{CBC}), Counter mode (@acronym{CTR}), Cipher +Feedback (@acronym{CFB}) and a couple of @acronym{AEAD} modes +(@pxref{Authenticated encryption}). @acronym{CBC} is widely used, but +there are a few subtle issues of information leakage, see, e.g., @uref{http://www.kb.cert.org/vuls/id/958563, @acronym{SSH} @acronym{CBC} vulnerability}. Today, @acronym{CTR} is usually preferred over @acronym{CBC}. -Modes like @acronym{CBC} and @acronym{CTR} provide @emph{no} message -authentication, and should always be used together with a @acronym{MAC} -(@pxref{Keyed hash functions}) or signature to authenticate the message. +Modes like @acronym{CBC}, @acronym{CTR} and @acronym{CFB} provide @emph{no} +message authentication, and should always be used together with a +@acronym{MAC} (@pxref{Keyed hash functions}) or signature to authenticate +the message. @menu * CBC:: * CTR:: +* CFB:: @end menu @node CBC, CTR, Cipher modes, Cipher modes @@ -1994,7 +1997,7 @@ These macros use some tricks to make the compiler display a warning if the types of @var{f} and @var{ctx} don't match, e.g. if you try to use an @code{struct aes_ctx} context with the @code{des_encrypt} function. -@node CTR, , CBC, Cipher modes +@node CTR, CFB, CBC, Cipher modes @comment node-name, next, previous, up @subsection Counter mode @@ -2070,6 +2073,91 @@ last three arguments define the source and destination area for the operation. @end deffn +@node CFB, , CTR, Cipher modes +@comment node-name, next, previous, up +@subsection Cipher Feedback mode + +@cindex Cipher Feedback Mode +@cindex CFB Mode + +Cipher Feedback mode (@acronym{CFB}) being a close relative to both +@acronym{CBC} mode and @acronym{CTR} mode borrows some characteristics +from stream ciphers. + +The message is divided into @code{n} blocks @code{M_1},@dots{} +@code{M_n}, where @code{M_n} is of size @code{m} which may be smaller +than the block size. Except for the last block, all the message blocks +must be of size equal to the cipher's block size. + +If @code{E_k} is the encryption function of a block cipher, @code{IV} is +the initialization vector, then the @code{n} plaintext blocks are +transformed into @code{n} ciphertext blocks @code{C_1},@dots{} +@code{C_n} as follows: + +@example +C_1 = E_k(IV) XOR M_1 +C_2 = E_k(C_1) XOR M_2 + +@dots{} + +C_(n-1) = E_k(C_(n - 2)) XOR M_(n-1) +C_n = E_k(C_(n - 1)) [1..m] XOR M_n +@end example + +Nettle's includes two functions for applying a block cipher in Cipher +Feedback (@acronym{CFB}) mode, one for encryption and one for +decryption. These functions uses @code{void *} to pass cipher contexts +around. + +@deftypefun {void} cfb_encrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src}) +@deftypefunx {void} cfb_decrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src}) + +Applies the encryption or decryption function @var{f} in @acronym{CFB} +mode. The final ciphertext block processed is copied into @var{iv} +before returning, so that a large message can be processed by a sequence +of calls to @code{cfb_encrypt}. Note that for @acronym{CFB} mode +internally uses encryption only function and hence @var{f} should always +be the encryption function for the underlying block cipher. + +When a message is encrypted using a sequence of calls to +@code{cfb_encrypt}, all but the last call @emph{must} use a length that +is a multiple of the block size. +@end deftypefun + +Like for @acronym{CBC}, there are also a couple of helper macros. + +@deffn Macro CFB_CTX (@var{context_type}, @var{block_size}) +Expands to +@example +@{ + context_type ctx; + uint8_t iv[block_size]; +@} +@end example +@end deffn + +@deffn Macro CFB_SET_IV(@var{ctx}, @var{iv}) +First argument is a pointer to a context struct as defined by +@code{CFB_CTX}, and the second is a pointer to an initialization vector +that is copied into that context. +@end deffn + +@deffn Macro CFB_ENCRYPT (@var{ctx}, @var{f}, @var{length}, @var{dst}, @var{src}) +A simpler way to invoke @code{cfb_encrypt}. The first argument is a +pointer to a context struct as defined by @code{CFB_CTX}, and the second +argument is an encryption function following Nettle's conventions. The +last three arguments define the source and destination area for the +operation. +@end deffn + +@deffn Macro CFB_DECRYPT (@var{ctx}, @var{f}, @var{length}, @var{dst}, @var{src}) +A simpler way to invoke @code{cfb_decrypt}. The first argument is a +pointer to a context struct as defined by @code{CFB_CTX}, and the second +argument is an encryption function following Nettle's conventions. The +last three arguments define the source and destination area for the +operation. +@end deffn + @node Authenticated encryption, Keyed hash functions, Cipher modes, Reference @comment node-name, next, previous, up @@ -3366,12 +3454,7 @@ processing a new message. @node Key derivation functions, Public-key algorithms, Keyed hash functions, Reference @comment node-name, next, previous, up @section Key derivation Functions - @cindex Key Derivation Function -@cindex Password Based Key Derivation Function -@cindex PKCS #5 -@cindex KDF -@cindex PBKDF A @dfn{key derivation function} (@acronym{KDF}) is a function that from a given symmetric key derives other symmetric keys. A sub-class of KDFs @@ -3380,7 +3463,51 @@ which take as input a password or passphrase, and its purpose is typically to strengthen it and protect against certain pre-computation attacks by using salting and expensive computation. +@subsection HKDF: HMAC-based Extract-and-Expand +@cindex HKDF + +HKDF is a key derivation function used as a building block of +higher-level protocols like TLS 1.3. It is a derivation function +based on HMAC described in @cite{RFC 5869}, +and is split into two logical modules, called 'extract' and 'expand'. +The extract module takes an initial secret and a random +salt to "extract" a fixed-length pseudorandom key (PRK). The second stage +takes as input the previous PRK and some informational data (e.g., +text) and expands them into multiple keys. + +Nettle's @acronym{HKDF} functions are defined in +@file{<nettle/hkdf.h>}. There are two abstract functions for the extract +and expand operations that operate on any HMAC implemented via the @code{nettle_hash_update_func}, +and @code{nettle_hash_digest_func} interfaces. + +@deftypefun void hkdf_extract (void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size,size_t secret_size, const uint8_t *secret, uint8_t *dst) +Extract a Pseudorandom Key (PRK) from a secret and a salt according +to HKDF. The HMAC must have been initialized, with its key being the +salt for the Extract operation. This function will call the +@var{update} and @var{digest} functions passing the @var{mac_ctx} +context parameter as an argument in order to compute digest of size +@var{digest_size}. Inputs are the secret @var{secret} of length +@var{secret_length}. The output length is fixed to @var{digest_size} octets, +thus the output buffer @var{dst} must have room for at least @var{digest_size} octets. +@end deftypefun + +@deftypefun void hkdf_expand (void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size, size_t info_size, const uint8_t *info, size_t length, uint8_t *dst) +Expand a Pseudorandom Key (PRK) to an arbitrary size according to HKDF. +The HMAC must have been initialized, with its key being the +PRK from the Extract operation. This function will call the +@var{update} and @var{digest} functions passing the @var{mac_ctx} +context parameter as an argument in order to compute digest of size +@var{digest_size}. Inputs are the info @var{info} of length +@var{info_length}, and the desired derived output length @var{length}. +The output buffer is @var{dst} which must have room for at least @var{length} octets. +@end deftypefun + + @subsection @acronym{PBKDF2} +@cindex Password Based Key Derivation Function +@cindex PKCS #5 +@cindex KDF +@cindex PBKDF The most well known PBKDF is the @code{PKCS #5 PBKDF2} described in @cite{RFC 2898} which uses a pseudo-random function such as @acronym{HMAC-SHA1}. @@ -3770,6 +3897,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 diff --git a/pgp-encode.c b/pgp-encode.c index fc78e7f6..c051f9e4 100644 --- a/pgp-encode.c +++ b/pgp-encode.c @@ -371,8 +371,8 @@ pgp_armor(struct nettle_buffer *buffer, length -= BINARY_PER_LINE, data += BINARY_PER_LINE) { unsigned done; - uint8_t *p - = nettle_buffer_space(buffer, TEXT_PER_LINE); + char *p + = (char *) nettle_buffer_space(buffer, TEXT_PER_LINE); if (!p) return 0; @@ -393,8 +393,8 @@ pgp_armor(struct nettle_buffer *buffer, + BASE64_ENCODE_FINAL_LENGTH; unsigned done; - uint8_t *p - = nettle_buffer_space(buffer, text_size); + char *p + = (char *) nettle_buffer_space(buffer, text_size); if (!p) return 0; @@ -412,7 +412,7 @@ pgp_armor(struct nettle_buffer *buffer, return 0; { - uint8_t *p = nettle_buffer_space(buffer, 4); + char *p = (char *) nettle_buffer_space(buffer, 4); if (!p) return 0; base64_encode_group(p, crc); diff --git a/pss-mgf1.c b/pss-mgf1.c new file mode 100644 index 00000000..67df5570 --- /dev/null +++ b/pss-mgf1.c @@ -0,0 +1,73 @@ +/* pss-mgf1.c + + PKCS#1 mask generation function 1, used in RSA-PSS (RFC-3447). + + 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 "pss-mgf1.h" + +#include <assert.h> +#include <string.h> + +#include "nettle-internal.h" +#include "macros.h" + +void +pss_mgf1(const void *seed, const struct nettle_hash *hash, + size_t length, uint8_t *mask) +{ + TMP_DECL(h, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE); + TMP_DECL(state, uint8_t, NETTLE_MAX_HASH_CONTEXT_SIZE); + size_t i; + uint8_t c[4]; + + TMP_ALLOC(h, hash->digest_size); + TMP_ALLOC(state, hash->context_size); + + for (i = 0;; + i++, mask += hash->digest_size, length -= hash->digest_size) + { + WRITE_UINT32(c, i); + + memcpy(state, seed, hash->context_size); + hash->update(state, 4, c); + + if (length <= hash->digest_size) + { + hash->digest(state, length, mask); + return; + } + hash->digest(state, hash->digest_size, mask); + } +} diff --git a/pss-mgf1.h b/pss-mgf1.h new file mode 100644 index 00000000..4a29c108 --- /dev/null +++ b/pss-mgf1.h @@ -0,0 +1,58 @@ +/* pss-mgf1.h + + PKCS#1 mask generation function 1, used in RSA-PSS (RFC-3447). + + 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/. +*/ + +#ifndef NETTLE_PSS_MGF1_H_INCLUDED +#define NETTLE_PSS_MGF1_H_INCLUDED + +#include "nettle-meta.h" + +#include "sha1.h" +#include "sha2.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Namespace mangling */ +#define pss_mgf1 nettle_pss_mgf1 + +void +pss_mgf1(const void *seed, const struct nettle_hash *hash, + size_t length, uint8_t *mask); + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_PSS_MGF1_H_INCLUDED */ @@ -0,0 +1,198 @@ +/* pss.c + + PKCS#1 RSA-PSS padding (RFC-3447). + + 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 <assert.h> +#include <string.h> + +#include "pss.h" +#include "pss-mgf1.h" + +#include "bignum.h" +#include "gmp-glue.h" + +#include "memxor.h" +#include "nettle-internal.h" + +/* Masks to clear the leftmost N bits. */ +static const uint8_t pss_masks[8] = { + 0xFF, 0x7F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x1 +}; + +static const uint8_t pss_pad[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + +/* Format the PKCS#1 PSS padding for given salt and digest, using + * pss_mgf1() as the mask generation function. + * + * The encoded messsage is stored in M, and the consistency can be + * checked with pss_verify_mgf1(), which takes the encoded message, + * the length of salt, and the digest. */ +int +pss_encode_mgf1(mpz_t m, size_t bits, + const struct nettle_hash *hash, + size_t salt_length, const uint8_t *salt, + const uint8_t *digest) +{ + TMP_GMP_DECL(em, uint8_t); + TMP_DECL(state, uint8_t, NETTLE_MAX_HASH_CONTEXT_SIZE); + size_t key_size = (bits + 7) / 8; + size_t j; + + TMP_GMP_ALLOC(em, key_size); + TMP_ALLOC(state, hash->context_size); + + if (key_size < hash->digest_size + salt_length + 2) + { + TMP_GMP_FREE(em); + return 0; + } + + /* Compute M'. */ + hash->init(state); + hash->update(state, sizeof(pss_pad), pss_pad); + hash->update(state, hash->digest_size, digest); + hash->update(state, salt_length, salt); + + /* Store H in EM, right after maskedDB. */ + hash->digest(state, hash->digest_size, em + key_size - hash->digest_size - 1); + + /* Compute dbMask. */ + hash->init(state); + hash->update(state, hash->digest_size, em + key_size - hash->digest_size - 1); + + pss_mgf1(state, hash, key_size - hash->digest_size - 1, em); + + /* Compute maskedDB and store it in front of H in EM. */ + j = key_size - salt_length - hash->digest_size - 2; + + em[j++] ^= 1; + memxor(em + j, salt, salt_length); + j += salt_length; + + /* Store the trailer field following H. */ + j += hash->digest_size; + em[j] = 0xbc; + + /* Clear the leftmost 8 * emLen - emBits of the leftmost octet in EM. */ + *em &= pss_masks[(8 * key_size - bits)]; + + nettle_mpz_set_str_256_u(m, key_size, em); + TMP_GMP_FREE(em); + return 1; +} + +/* Check the consistency of given PKCS#1 PSS encoded message, created + * with pss_encode_mgf1(). + * + * Returns 1 if the encoded message is consistent, 0 if it is + * inconsistent. */ +int +pss_verify_mgf1(const mpz_t m, size_t bits, + const struct nettle_hash *hash, + size_t salt_length, + const uint8_t *digest) +{ + TMP_GMP_DECL(em, uint8_t); + TMP_DECL(h2, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE); + TMP_DECL(state, uint8_t, NETTLE_MAX_HASH_CONTEXT_SIZE); + uint8_t *h, *db, *salt; + size_t key_size = (bits + 7) / 8; + size_t j; + int ret = 0; + + /* Allocate twice the key size to store the intermediate data DB + * following the EM value. */ + TMP_GMP_ALLOC(em, key_size * 2); + + TMP_ALLOC(h2, hash->digest_size); + TMP_ALLOC(state, hash->context_size); + + if (key_size < hash->digest_size + salt_length + 2) + goto cleanup; + + if (mpz_sizeinbase(m, 2) > bits) + goto cleanup; + + nettle_mpz_get_str_256(key_size, em, m); + + /* Check the trailer field. */ + if (em[key_size - 1] != 0xbc) + goto cleanup; + + /* Extract H. */ + h = em + (key_size - hash->digest_size - 1); + + /* The leftmost 8 * emLen - emBits bits of the leftmost octet of EM + * must all equal to zero. Always true here, thanks to the above + * check on the bit size of m. */ + assert((*em & ~pss_masks[(8 * key_size - bits)]) == 0); + + /* Compute dbMask. */ + hash->init(state); + hash->update(state, hash->digest_size, h); + + db = em + key_size; + pss_mgf1(state, hash, key_size - hash->digest_size - 1, db); + + /* Compute DB. */ + memxor(db, em, key_size - hash->digest_size - 1); + + *db &= pss_masks[(8 * key_size - bits)]; + for (j = 0; j < key_size - salt_length - hash->digest_size - 2; j++) + if (db[j] != 0) + goto cleanup; + + /* Check the octet right after PS is 0x1. */ + if (db[j] != 0x1) + goto cleanup; + salt = db + j + 1; + + /* Compute H'. */ + hash->init(state); + hash->update(state, sizeof(pss_pad), pss_pad); + hash->update(state, hash->digest_size, digest); + hash->update(state, salt_length, salt); + hash->digest(state, hash->digest_size, h2); + + /* Check if H' = H. */ + if (memcmp(h2, h, hash->digest_size) != 0) + goto cleanup; + + ret = 1; + cleanup: + TMP_GMP_FREE(em); + return ret; +} @@ -0,0 +1,65 @@ +/* pss.h + + PKCS#1 RSA-PSS (RFC-3447). + + 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/. +*/ + +#ifndef NETTLE_PSS_H_INCLUDED +#define NETTLE_PSS_H_INCLUDED + +#include "nettle-types.h" +#include "bignum.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Namespace mangling */ +#define pss_encode_mgf1 nettle_pss_encode_mgf1 +#define pss_verify_mgf1 nettle_pss_verify_mgf1 + +int +pss_encode_mgf1(mpz_t m, size_t bits, + const struct nettle_hash *hash, + size_t salt_length, const uint8_t *salt, + const uint8_t *digest); + +int +pss_verify_mgf1(const mpz_t m, size_t bits, + const struct nettle_hash *hash, + size_t salt_length, + const uint8_t *digest); + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_PSS_H_INCLUDED */ diff --git a/rsa-pss-sha256-sign-tr.c b/rsa-pss-sha256-sign-tr.c new file mode 100644 index 00000000..b17e40ed --- /dev/null +++ b/rsa-pss-sha256-sign-tr.c @@ -0,0 +1,64 @@ +/* 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; +} diff --git a/rsa-pss-sha256-verify.c b/rsa-pss-sha256-verify.c new file mode 100644 index 00000000..81bc4e68 --- /dev/null +++ b/rsa-pss-sha256-verify.c @@ -0,0 +1,60 @@ +/* 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; +} diff --git a/rsa-pss-sha512-sign-tr.c b/rsa-pss-sha512-sign-tr.c new file mode 100644 index 00000000..59536d6d --- /dev/null +++ b/rsa-pss-sha512-sign-tr.c @@ -0,0 +1,87 @@ +/* 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; +} diff --git a/rsa-pss-sha512-verify.c b/rsa-pss-sha512-verify.c new file mode 100644 index 00000000..34f8e81d --- /dev/null +++ b/rsa-pss-sha512-verify.c @@ -0,0 +1,79 @@ +/* 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; +} diff --git a/rsa-verify.c b/rsa-verify.c index 07715e2b..43a55d21 100644 --- a/rsa-verify.c +++ b/rsa-verify.c @@ -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); diff --git a/sexp-transport-format.c b/sexp-transport-format.c index c9946a70..4f83f888 100644 --- a/sexp-transport-format.c +++ b/sexp-transport-format.c @@ -40,6 +40,12 @@ #include "base64.h" #include "buffer.h" +static inline void +base64_encode_in_place (size_t length, uint8_t *data) +{ + base64_encode_raw ((char *) data, length, data); +} + size_t sexp_transport_vformat(struct nettle_buffer *buffer, const char *format, va_list args) @@ -68,8 +74,7 @@ sexp_transport_vformat(struct nettle_buffer *buffer, if (!nettle_buffer_space(buffer, base64_length - length)) return 0; - base64_encode_raw(buffer->contents + start, - length, buffer->contents + start); + base64_encode_in_place(length, buffer->contents + start); if (!NETTLE_BUFFER_PUTC(buffer, '}')) return 0; diff --git a/sexp-transport.c b/sexp-transport.c index 8736478a..1a34db71 100644 --- a/sexp-transport.c +++ b/sexp-transport.c @@ -84,7 +84,7 @@ sexp_transport_iterator_first(struct sexp_iterator *iterator, base64_decode_init(&ctx); if (base64_decode_update(&ctx, &coded_length, input + out, - end - in, input + in) + end - in, (const char*) (input + in)) && base64_decode_final(&ctx)) { out += coded_length; diff --git a/testsuite/.gitignore b/testsuite/.gitignore index 8e5521b4..5db4e789 100644 --- a/testsuite/.gitignore +++ b/testsuite/.gitignore @@ -12,39 +12,61 @@ /cast128-test /cbc-test /ccm-test +/cfb-test +/chacha-poly1305-test +/chacha-test /ctr-test +/curve25519-dh-test /cxx-test /des-compat-test /des-test /des3-test +/dlopen-test /dsa-keygen-test /dsa-test +/eax-test +/ecc-add-test +/ecc-dup-test /ecc-mod-test /ecc-modinv-test /ecc-mul-a-test /ecc-mul-g-test /ecc-redc-test +/ecc-sqrt-test +/ecdh-test /ecdsa-keygen-test /ecdsa-sign-test /ecdsa-verify-test +/ed25519-test +/eddsa-compress-test +/eddsa-sign-test +/eddsa-verify-test /gcm-test /gosthash94-test +/hkdf-test /hmac-test /knuth-lfib-test /md2-test /md4-test /md5-compat-test /md5-test +/memeql-test /memxor-test +/meta-aead-test /meta-armor-test /meta-cipher-test /meta-hash-test /pbkdf2-test /pkcs1-test +/poly1305-test +/pss-mgf1-test +/pss-test /random-prime-test /ripemd160-test /rsa-encrypt-test /rsa-keygen-test +/rsa-pss-sign-tr-test +/rsa-sign-tr-test /rsa-test /rsa2sexp-test /salsa20-test @@ -62,9 +84,12 @@ /sha3-512-test /sha3-permute-test /sha384-test +/sha512-224-test +/sha512-256-test /sha512-test /twofish-test /umac-test +/version-test /yarrow-test /test.in diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make index b263e1fd..1f780310 100644 --- a/testsuite/.test-rules.make +++ b/testsuite/.test-rules.make @@ -58,6 +58,9 @@ gosthash94-test$(EXEEXT): gosthash94-test.$(OBJEXT) ripemd160-test$(EXEEXT): ripemd160-test.$(OBJEXT) $(LINK) ripemd160-test.$(OBJEXT) $(TEST_OBJS) -o ripemd160-test$(EXEEXT) +hkdf-test$(EXEEXT): hkdf-test.$(OBJEXT) + $(LINK) hkdf-test.$(OBJEXT) $(TEST_OBJS) -o hkdf-test$(EXEEXT) + salsa20-test$(EXEEXT): salsa20-test.$(OBJEXT) $(LINK) salsa20-test.$(OBJEXT) $(TEST_OBJS) -o salsa20-test$(EXEEXT) @@ -112,6 +115,9 @@ knuth-lfib-test$(EXEEXT): knuth-lfib-test.$(OBJEXT) cbc-test$(EXEEXT): cbc-test.$(OBJEXT) $(LINK) cbc-test.$(OBJEXT) $(TEST_OBJS) -o cbc-test$(EXEEXT) +cfb-test$(EXEEXT): cfb-test.$(OBJEXT) + $(LINK) cfb-test.$(OBJEXT) $(TEST_OBJS) -o cfb-test$(EXEEXT) + ctr-test$(EXEEXT): ctr-test.$(OBJEXT) $(LINK) ctr-test.$(OBJEXT) $(TEST_OBJS) -o ctr-test$(EXEEXT) @@ -157,6 +163,9 @@ yarrow-test$(EXEEXT): yarrow-test.$(OBJEXT) pbkdf2-test$(EXEEXT): pbkdf2-test.$(OBJEXT) $(LINK) pbkdf2-test.$(OBJEXT) $(TEST_OBJS) -o pbkdf2-test$(EXEEXT) +pss-mgf1-test$(EXEEXT): pss-mgf1-test.$(OBJEXT) + $(LINK) pss-mgf1-test.$(OBJEXT) $(TEST_OBJS) -o pss-mgf1-test$(EXEEXT) + sexp-test$(EXEEXT): sexp-test.$(OBJEXT) $(LINK) sexp-test.$(OBJEXT) $(TEST_OBJS) -o sexp-test$(EXEEXT) @@ -178,9 +187,15 @@ random-prime-test$(EXEEXT): random-prime-test.$(OBJEXT) pkcs1-test$(EXEEXT): pkcs1-test.$(OBJEXT) $(LINK) pkcs1-test.$(OBJEXT) $(TEST_OBJS) -o pkcs1-test$(EXEEXT) +pss-test$(EXEEXT): pss-test.$(OBJEXT) + $(LINK) pss-test.$(OBJEXT) $(TEST_OBJS) -o pss-test$(EXEEXT) + 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) diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 790b3c78..3117d66d 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -17,7 +17,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \ des-test.c des3-test.c des-compat-test.c \ md2-test.c md4-test.c md5-test.c md5-compat-test.c \ memeql-test.c memxor-test.c gosthash94-test.c \ - ripemd160-test.c \ + ripemd160-test.c hkdf-test.c \ salsa20-test.c \ sha1-test.c sha224-test.c sha256-test.c \ sha384-test.c sha512-test.c sha512-224-test.c sha512-256-test.c \ @@ -25,17 +25,18 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \ sha3-384-test.c sha3-512-test.c \ serpent-test.c twofish-test.c version-test.c \ knuth-lfib-test.c \ - cbc-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \ + cbc-test.c cfb-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \ poly1305-test.c chacha-poly1305-test.c \ hmac-test.c umac-test.c \ meta-hash-test.c meta-cipher-test.c\ meta-aead-test.c meta-armor-test.c \ - buffer-test.c yarrow-test.c pbkdf2-test.c + buffer-test.c yarrow-test.c pbkdf2-test.c pss-mgf1-test.c 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 rsa-sign-tr-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 \ @@ -66,6 +67,7 @@ EXTRA_TARGETS = $(EXTRA_SOURCES:.c=$(EXEEXT)) SOURCES = $(TS_SOURCES) $(EXTRA_SOURCES) testutils.c dlopen-test.c DISTFILES = $(SOURCES) $(CXX_SOURCES) Makefile.in .test-rules.make \ + test-rules.stamp \ $(TS_SH) setup-env teardown-env \ gold-bug.txt testutils.h sha3.awk @@ -107,6 +109,14 @@ test-rules: echo ; \ done) > $(srcdir)/.test-rules.make +$(srcdir)/.test-rules.make: $(srcdir)/test-rules.stamp + +# Updates the stamp file *first*, so that this rule isn't triggered +# again and again by the recursive $(MAKE). +$(srcdir)/test-rules.stamp: Makefile.in + echo stamp > $(srcdir)/test-rules.stamp + $(MAKE) test-rules + include $(srcdir)/.test-rules.make $(TARGETS) $(EXTRA_TARGETS): testutils.$(OBJEXT) ../nettle-internal.$(OBJEXT) \ diff --git a/testsuite/base64-test.c b/testsuite/base64-test.c index f366a413..cc45c471 100644 --- a/testsuite/base64-test.c +++ b/testsuite/base64-test.c @@ -9,7 +9,7 @@ test_fuzz_once(struct base64_encode_ctx *encode, { size_t base64_len = BASE64_ENCODE_RAW_LENGTH (size); size_t out_len; - uint8_t *base64 = xalloc (base64_len + 2); + char *base64 = xalloc (base64_len + 2); uint8_t *decoded = xalloc (size + 2); *base64++ = 0x12; @@ -66,6 +66,20 @@ test_fuzz(void) } } +static inline void +base64_encode_in_place (size_t length, uint8_t *data) +{ + base64_encode_raw ((char *) data, length, data); +} + +static inline int +base64_decode_in_place (struct base64_decode_ctx *ctx, size_t *dst_length, + size_t length, uint8_t *data) +{ + return base64_decode_update (ctx, dst_length, + data, length, (const char *) data); +} + void test_main(void) { @@ -111,12 +125,12 @@ test_main(void) size_t dst_length; ASSERT(BASE64_ENCODE_RAW_LENGTH(5) == 8); - base64_encode_raw(buffer, 5, buffer); + base64_encode_in_place(5, buffer); ASSERT(MEMEQ(9, buffer, "SGVsbG8=x")); base64_decode_init(&ctx); dst_length = 0; /* Output parameter only. */ - ASSERT(base64_decode_update(&ctx, &dst_length, buffer, 8, buffer)); + ASSERT(base64_decode_in_place(&ctx, &dst_length, 8, buffer)); ASSERT(dst_length == 5); ASSERT(MEMEQ(9, buffer, "HelloG8=x")); diff --git a/testsuite/cfb-test.c b/testsuite/cfb-test.c new file mode 100644 index 00000000..b59bee22 --- /dev/null +++ b/testsuite/cfb-test.c @@ -0,0 +1,287 @@ +#include "testutils.h" +#include "aes.h" +#include "cfb.h" +#include "knuth-lfib.h" + +/* Test with more data and inplace decryption, to check that the + * cfb_decrypt buffering works. */ +#define CFB_BULK_DATA 10000 + +static void +test_cfb_bulk(void) +{ + struct knuth_lfib_ctx random; + + uint8_t clear[CFB_BULK_DATA]; + + uint8_t cipher[CFB_BULK_DATA + 1]; + + const uint8_t *key = H("966c7bf00bebe6dc 8abd37912384958a" + "743008105a08657d dcaad4128eee38b3"); + + const uint8_t *start_iv = H("11adbff119749103 207619cfa0e8d13a"); + const uint8_t *end_iv = H("1fd0a9189b8480b7 b06a2b36ef5943ba"); + + struct CFB_CTX(struct aes_ctx, AES_BLOCK_SIZE) aes; + + knuth_lfib_init(&random, CFB_BULK_DATA); + knuth_lfib_random(&random, CFB_BULK_DATA, clear); + + /* Byte that should not be overwritten */ + cipher[CFB_BULK_DATA] = 17; + + aes_set_encrypt_key(&aes.ctx, 32, key); + CFB_SET_IV(&aes, start_iv); + + CFB_ENCRYPT(&aes, aes_encrypt, CFB_BULK_DATA, cipher, clear); + + ASSERT(cipher[CFB_BULK_DATA] == 17); + + if (verbose) + { + printf("IV after bulk encryption: "); + print_hex(AES_BLOCK_SIZE, aes.iv); + printf("\n"); + } + + ASSERT(MEMEQ(AES_BLOCK_SIZE, aes.iv, end_iv)); + + /* Decrypt, in place */ + aes_set_encrypt_key(&aes.ctx, 32, key); + CFB_SET_IV(&aes, start_iv); + CFB_DECRYPT(&aes, aes_encrypt, CFB_BULK_DATA, cipher, cipher); + + ASSERT(cipher[CFB_BULK_DATA] == 17); + + if (verbose) + { + printf("IV after bulk decryption: "); + print_hex(AES_BLOCK_SIZE, aes.iv); + printf("\n"); + } + + ASSERT (MEMEQ(AES_BLOCK_SIZE, aes.iv, end_iv)); + ASSERT (MEMEQ(CFB_BULK_DATA, clear, cipher)); +} + +void +test_main(void) +{ + /* From NIST spec 800-38a on AES modes. + * + * F.3 CFB Example Vectors + * F.3.13 CFB128-AES128.Encrypt + */ + + /* Intermediate values, blocks input to AES: + * + * 000102030405060708090a0b0c0d0e0f + * 3b3fd92eb72dad20333449f8e83cfb4a + * c8a64537a0b3a93fcde3cdad9f1ce58b + * 26751f67a3cbb140b1808cf187a4f4df + */ + test_cipher_cfb(&nettle_aes128, + SHEX("2b7e151628aed2a6abf7158809cf4f3c"), + SHEX("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710"), + SHEX("3b3fd92eb72dad20333449f8e83cfb4a" + "c8a64537a0b3a93fcde3cdad9f1ce58b" + "26751f67a3cbb140b1808cf187a4f4df" + "c04b05357c5d1c0eeac4c66f9ff7f2e6"), + SHEX("000102030405060708090a0b0c0d0e0f")); + + /* F.3.15 CFB128-AES192.Encrypt */ + + /* Intermediate values, blocks input to AES: + * + * 000102030405060708090a0b0c0d0e0f + * cdc80d6fddf18cab34c25909c99a4174 + * 67ce7f7f81173621961a2b70171d3d7a + * 2e1e8a1dd59b88b1c8e60fed1efac4c9 + */ + + test_cipher_cfb(&nettle_aes192, + SHEX("8e73b0f7da0e6452c810f32b809079e5" + "62f8ead2522c6b7b"), + SHEX("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710"), + SHEX("cdc80d6fddf18cab34c25909c99a4174" + "67ce7f7f81173621961a2b70171d3d7a" + "2e1e8a1dd59b88b1c8e60fed1efac4c9" + "c05f9f9ca9834fa042ae8fba584b09ff"), + SHEX("000102030405060708090a0b0c0d0e0f")); + + /* F.3.17 CFB128-AES256.Encrypt */ + + /* Intermediate values, blcoks input to AES: + * + * 000102030405060708090a0b0c0d0e0f + * dc7e84bfda79164b7ecd8486985d3860 + * 39ffed143b28b1c832113c6331e5407b + * df10132415e54b92a13ed0a8267ae2f9 + */ + + test_cipher_cfb(&nettle_aes256, + SHEX("603deb1015ca71be2b73aef0857d7781" + "1f352c073b6108d72d9810a30914dff4"), + SHEX("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710"), + SHEX("dc7e84bfda79164b7ecd8486985d3860" + "39ffed143b28b1c832113c6331e5407b" + "df10132415e54b92a13ed0a8267ae2f9" + "75a385741ab9cef82031623d55b1e471"), + SHEX("000102030405060708090a0b0c0d0e0f")); + + test_cfb_bulk(); +} + +/* +F.3.13 CFB128-AES128.Encrypt +Key 2b7e151628aed2a6abf7158809cf4f3c +IV 000102030405060708090a0b0c0d0e0f +Segment #1 +Input Block 000102030405060708090a0b0c0d0e0f +Output Block 50fe67cc996d32b6da0937e99bafec60 +Plaintext 6bc1bee22e409f96e93d7e117393172a +Ciphertext 3b3fd92eb72dad20333449f8e83cfb4a +Segment #2 +Input Block 3b3fd92eb72dad20333449f8e83cfb4a +Output Block 668bcf60beb005a35354a201dab36bda +Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 +Ciphertext c8a64537a0b3a93fcde3cdad9f1ce58b +Segment #3 +Input Block c8a64537a0b3a93fcde3cdad9f1ce58b +Output Block 16bd032100975551547b4de89daea630 +Plaintext 30c81c46a35ce411e5fbc1191a0a52ef +Ciphertext 26751f67a3cbb140b1808cf187a4f4df +Segment #4 +Input Block 26751f67a3cbb140b1808cf187a4f4df +Output Block 36d42170a312871947ef8714799bc5f6 +Plaintext f69f2445df4f9b17ad2b417be66c3710 +Ciphertext c04b05357c5d1c0eeac4c66f9ff7f2e6 +F.3.14 CFB128-AES128.Decrypt +Key 2b7e151628aed2a6abf7158809cf4f3c +IV 000102030405060708090a0b0c0d0e0f +Segment #1 +Input Block 000102030405060708090a0b0c0d0e0f +Output Block 50fe67cc996d32b6da0937e99bafec60 +Ciphertext 3b3fd92eb72dad20333449f8e83cfb4a +Plaintext 6bc1bee22e409f96e93d7e117393172a +Segment #2 +Input Block 3b3fd92eb72dad20333449f8e83cfb4a +Output Block 668bcf60beb005a35354a201dab36bda +Ciphertext c8a64537a0b3a93fcde3cdad9f1ce58b +Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 +Segment #3 +Input Block c8a64537a0b3a93fcde3cdad9f1ce58b +Output Block 16bd032100975551547b4de89daea630 +Ciphertext 26751f67a3cbb140b1808cf187a4f4df +Plaintext 30c81c46a35ce411e5fbc1191a0a52ef +Segment #4 +Input Block 26751f67a3cbb140b1808cf187a4f4df +Output Block 36d42170a312871947ef8714799bc5f6 +Ciphertext c04b05357c5d1c0eeac4c66f9ff7f2e6 +Plaintext f69f2445df4f9b17ad2b417be66c3710 +F.3.15 CFB128-AES192.Encrypt +Key 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b +000102030405060708090a0b0c0d0e0f +Segment #1 +50 +IV +Input Block 000102030405060708090a0b0c0d0e0f +Output Block a609b38df3b1133dddff2718ba09565e +Plaintext 6bc1bee22e409f96e93d7e117393172a +Ciphertext cdc80d6fddf18cab34c25909c99a4174 +Segment #2 +Input Block cdc80d6fddf18cab34c25909c99a4174 +Output Block c9e3f5289f149abd08ad44dc52b2b32b +Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 +Ciphertext 67ce7f7f81173621961a2b70171d3d7a +Segment #3 +Input Block 67ce7f7f81173621961a2b70171d3d7a +Output Block 1ed6965b76c76ca02d1dcef404f09626 +Plaintext 30c81c46a35ce411e5fbc1191a0a52ef +Ciphertext 2e1e8a1dd59b88b1c8e60fed1efac4c9 +Segment #4 +Input Block 2e1e8a1dd59b88b1c8e60fed1efac4c9 +Output Block 36c0bbd976ccd4b7ef85cec1be273eef +Plaintext f69f2445df4f9b17ad2b417be66c3710 +Ciphertext c05f9f9ca9834fa042ae8fba584b09ff +F.3.16 CFB128-AES192.Decrypt +Key 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b +IV 000102030405060708090a0b0c0d0e0f +Segment #1 +Input Block 000102030405060708090a0b0c0d0e0f +Output Block a609b38df3b1133dddff2718ba09565e +Ciphertext cdc80d6fddf18cab34c25909c99a4174 +Plaintext 6bc1bee22e409f96e93d7e117393172a +Segment #2 +Input Block cdc80d6fddf18cab34c25909c99a4174 +Output Block c9e3f5289f149abd08ad44dc52b2b32b +Ciphertext 67ce7f7f81173621961a2b70171d3d7a +Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 +Segment #3 +Input Block 67ce7f7f81173621961a2b70171d3d7a +Output Block 1ed6965b76c76ca02d1dcef404f09626 +Ciphertext 2e1e8a1dd59b88b1c8e60fed1efac4c9 +Plaintext 30c81c46a35ce411e5fbc1191a0a52ef +Segment #4 +Input Block 2e1e8a1dd59b88b1c8e60fed1efac4c9 +Output Block 36c0bbd976ccd4b7ef85cec1be273eef +Ciphertext c05f9f9ca9834fa042ae8fba584b09ff +Plaintext f69f2445df4f9b17ad2b417be66c3710 +F.3.17 CFB128-AES256.Encrypt +Key 603deb1015ca71be2b73aef0857d7781 +1f352c073b6108d72d9810a30914dff4 +IV 000102030405060708090a0b0c0d0e0f +Segment #1 +Input Block 000102030405060708090a0b0c0d0e0f +Output Block b7bf3a5df43989dd97f0fa97ebce2f4a +Plaintext 6bc1bee22e409f96e93d7e117393172a +Ciphertext dc7e84bfda79164b7ecd8486985d3860 +Segment #2 +Input Block dc7e84bfda79164b7ecd8486985d3860 +Output Block 97d26743252b1d54aca653cf744ace2a +Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 +Ciphertext 39ffed143b28b1c832113c6331e5407b +Segment #3 +Input Block 39ffed143b28b1c832113c6331e5407b +Output Block efd80f62b6b9af8344c511b13c70b016 +Plaintext 30c81c46a35ce411e5fbc1191a0a52ef +Ciphertext df10132415e54b92a13ed0a8267ae2f9 +Segment #4 +Input Block df10132415e54b92a13ed0a8267ae2f9 +Output Block 833ca131c5f655ef8d1a2346b3ddd361 +Plaintext f69f2445df4f9b17ad2b417be66c3710 +Ciphertext 75a385741ab9cef82031623d55b1e471 +F.3.18 CFB128-AES256.Decrypt +Key 603deb1015ca71be2b73aef0857d7781 +1f352c073b6108d72d9810a30914dff4 +IV 000102030405060708090a0b0c0d0e0f +Segment #1 +Input Block 000102030405060708090a0b0c0d0e0f +Output Block b7bf3a5df43989dd97f0fa97ebce2f4a +Ciphertext dc7e84bfda79164b7ecd8486985d3860 +Plaintext 6bc1bee22e409f96e93d7e117393172a +Segment #2 +Input Block dc7e84bfda79164b7ecd8486985d3860 +Output Block 97d26743252b1d54aca653cf744ace2a +Ciphertext 39ffed143b28b1c832113c6331e5407b +Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 +Segment #3 +Input Block 39ffed143b28b1c832113c6331e5407b +Output Block efd80f62b6b9af8344c511b13c70b016 +Ciphertext df10132415e54b92a13ed0a8267ae2f9 +Plaintext 30c81c46a35ce411e5fbc1191a0a52ef +Segment #4 +Input Block df10132415e54b92a13ed0a8267ae2f9 +Output Block 833ca131c5f655ef8d1a2346b3ddd361 +Ciphertext 75a385741ab9cef82031623d55b1e471 +Plaintext f69f2445df4f9b17ad2b417be66c3710 +*/ diff --git a/testsuite/dlopen-test.c b/testsuite/dlopen-test.c index 23ff25ad..99d3535b 100644 --- a/testsuite/dlopen-test.c +++ b/testsuite/dlopen-test.c @@ -28,6 +28,7 @@ main (int argc UNUSED, char **argv UNUSED) fprintf (stderr, "unexpected nettle version\n"); FAIL (); } + dlclose (handle); return EXIT_SUCCESS; #else SKIP(); diff --git a/testsuite/ecc-mul-a-test.c b/testsuite/ecc-mul-a-test.c index b206b848..245016aa 100644 --- a/testsuite/ecc-mul-a-test.c +++ b/testsuite/ecc-mul-a-test.c @@ -26,7 +26,7 @@ test_main (void) ecc->mul (ecc, p, n, ecc->g, scratch); ecc->h_to_a (ecc, 0, p, p, scratch); - if (mpn_cmp (p, ecc->g, 2*size != 0)) + if (mpn_cmp (p, ecc->g, 2*size) != 0) die ("curve %d: ecc->mul with n = 1 failed.\n", ecc->p.bit_size); for (n[0] = 2; n[0] <= 4; n[0]++) diff --git a/testsuite/ecc-mul-g-test.c b/testsuite/ecc-mul-g-test.c index 1c4d0c05..27239484 100644 --- a/testsuite/ecc-mul-g-test.c +++ b/testsuite/ecc-mul-g-test.c @@ -25,7 +25,7 @@ test_main (void) ecc->mul_g (ecc, p, n, scratch); ecc->h_to_a (ecc, 0, p, p, scratch); - if (mpn_cmp (p, ecc->g, 2*size != 0)) + if (mpn_cmp (p, ecc->g, 2*size) != 0) { fprintf (stderr, "ecc->mul_g with n = 1 failed.\n"); abort (); diff --git a/testsuite/hkdf-test.c b/testsuite/hkdf-test.c new file mode 100644 index 00000000..80f4c813 --- /dev/null +++ b/testsuite/hkdf-test.c @@ -0,0 +1,143 @@ +#include "testutils.h" +#include "hkdf.h" +#include "hmac.h" + +static void +test_hkdf_sha256(const struct tstring *ikm, + const struct tstring *salt, + const struct tstring *info, + const struct tstring *extract_output, + const struct tstring *expand_output) +{ + struct hmac_sha256_ctx ctx; + uint8_t prk[SHA256_DIGEST_SIZE]; + uint8_t *buffer = xalloc(expand_output->length); + + hmac_sha256_set_key(&ctx, salt->length, salt->data); + hkdf_extract(&ctx, + (nettle_hash_update_func*) hmac_sha256_update, + (nettle_hash_digest_func*) hmac_sha256_digest, + SHA256_DIGEST_SIZE, + ikm->length, ikm->data, prk); + + if (MEMEQ(SHA256_DIGEST_SIZE, prk, extract_output->data) == 0) + { + fprintf(stdout, "\nGot:\n"); + print_hex(SHA256_DIGEST_SIZE, prk); + fprintf(stdout, "\nExpected:\n"); + print_hex(extract_output->length, extract_output->data); + abort(); + } + + hmac_sha256_set_key(&ctx, SHA256_DIGEST_SIZE, prk); + hkdf_expand(&ctx, + (nettle_hash_update_func*) hmac_sha256_update, + (nettle_hash_digest_func*) hmac_sha256_digest, + SHA256_DIGEST_SIZE, + info->length, info->data, + expand_output->length, buffer); + + if (MEMEQ(expand_output->length, expand_output->data, buffer) == 0) + { + fprintf(stdout, "\nGot:\n"); + print_hex(expand_output->length, buffer); + fprintf(stdout, "\nExpected:\n"); + print_hex(expand_output->length, expand_output->data); + abort(); + } + free(buffer); +} + +static void +test_hkdf_sha1(const struct tstring *ikm, + const struct tstring *salt, + const struct tstring *info, + const struct tstring *extract_output, + const struct tstring *expand_output) +{ + struct hmac_sha1_ctx ctx; + uint8_t prk[SHA1_DIGEST_SIZE]; + uint8_t *buffer = xalloc(expand_output->length); + + hmac_sha1_set_key(&ctx, salt->length, salt->data); + hkdf_extract(&ctx, + (nettle_hash_update_func*) hmac_sha1_update, + (nettle_hash_digest_func*) hmac_sha1_digest, + SHA1_DIGEST_SIZE, + ikm->length, ikm->data, + prk); + + if (MEMEQ(SHA1_DIGEST_SIZE, prk, extract_output->data) == 0) + { + fprintf(stdout, "\nGot:\n"); + print_hex(SHA1_DIGEST_SIZE, prk); + fprintf(stdout, "\nExpected:\n"); + print_hex(extract_output->length, extract_output->data); + abort(); + } + + hmac_sha1_set_key(&ctx, SHA1_DIGEST_SIZE, prk); + hkdf_expand(&ctx, + (nettle_hash_update_func*) hmac_sha1_update, + (nettle_hash_digest_func*) hmac_sha1_digest, + SHA1_DIGEST_SIZE, + info->length, info->data, + expand_output->length, buffer); + + if (MEMEQ(expand_output->length, expand_output->data, buffer) == 0) + { + fprintf(stdout, "\nGot:\n"); + print_hex(expand_output->length, buffer); + fprintf(stdout, "\nExpected:\n"); + print_hex(expand_output->length, expand_output->data); + abort(); + } + free(buffer); +} + +void +test_main(void) +{ + /* HKDF test vectors from RFC5869 */ + test_hkdf_sha256(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + SHEX("000102030405060708090a0b0c"), + SHEX("f0f1f2f3f4f5f6f7f8f9"), + SHEX("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"), + SHEX("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865")); + + test_hkdf_sha256(SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"), + SHEX("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"), + SHEX("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), + SHEX("06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244"), + SHEX("b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87")); + + test_hkdf_sha256(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + SDATA(""), + SDATA(""), + SHEX("19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04"), + SHEX("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8")); + + test_hkdf_sha1(SHEX("0b0b0b0b0b0b0b0b0b0b0b"), + SHEX("000102030405060708090a0b0c"), + SHEX("f0f1f2f3f4f5f6f7f8f9"), + SHEX("9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243"), + SHEX("085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896")); + + test_hkdf_sha1(SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"), + SHEX("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"), + SHEX("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), + SHEX("8adae09a2a307059478d309b26c4115a224cfaf6"), + SHEX("0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4")); + + test_hkdf_sha1(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + SDATA(""), + SDATA(""), + SHEX("da8c8a73c7fa77288ec6f5e7c297786aa0d32d01"), + SHEX("0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918")); + + test_hkdf_sha1(SHEX("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"), + SHEX(""), + SHEX(""), + SHEX("2adccada18779e7c2077ad2eb19d3f3e731385dd"), + SHEX("2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48")); +} diff --git a/testsuite/meta-hash-test.c b/testsuite/meta-hash-test.c index afc71504..4754f665 100644 --- a/testsuite/meta-hash-test.c +++ b/testsuite/meta-hash-test.c @@ -1,6 +1,8 @@ #include "testutils.h" #include "nettle-internal.h" #include "nettle-meta.h" +/* For NETTLE_MAX_HASH_CONTEXT_SIZE */ +#include "sha3.h" const char* hashes[] = { "md2", @@ -28,9 +30,9 @@ test_main(void) ASSERT(nettle_lookup_hash(hashes[i]) != NULL); } - while (NULL != nettle_hashes[i]) - i++; - ASSERT(i == count); /* we are not missing testing any hashes */ - for (i = 0; NULL != nettle_hashes[i]; i++) + for (i = 0; NULL != nettle_hashes[i]; i++) { ASSERT(nettle_hashes[i]->digest_size <= NETTLE_MAX_HASH_DIGEST_SIZE); + ASSERT(nettle_hashes[i]->context_size <= NETTLE_MAX_HASH_CONTEXT_SIZE); + } + ASSERT(i == count); /* we are not missing testing any hashes */ } diff --git a/testsuite/pss-mgf1-test.c b/testsuite/pss-mgf1-test.c new file mode 100644 index 00000000..640500b5 --- /dev/null +++ b/testsuite/pss-mgf1-test.c @@ -0,0 +1,36 @@ +#include "testutils.h" +#include "pss-mgf1.h" + +void +test_main(void) +{ + struct sha1_ctx sha1ctx; + struct sha256_ctx sha256ctx; + const struct tstring *seed, *expected; + uint8_t mask[120]; + + /* From ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1d2-vec.zip */ + seed = SHEX("df1a896f9d8bc816d97cd7a2c43bad54" + "6fbe8cfe"); + expected = SHEX("66e4672e836ad121ba244bed6576b867d9a447c28a6e66a5b87dee" + "7fbc7e65af5057f86fae8984d9ba7f969ad6fe02a4d75f7445fefd" + "d85b6d3a477c28d24ba1e3756f792dd1dce8ca94440ecb5279ecd3" + "183a311fc89739a96643136e8b0f465e87a4535cd4c59b10028d"); + sha1_init(&sha1ctx); + sha1_update(&sha1ctx, seed->length, seed->data); + pss_mgf1(&sha1ctx, &nettle_sha1, expected->length, mask); + ASSERT(MEMEQ (expected->length, mask, expected->data)); + + /* Test with our own data. */ + seed = SDATA("abc"); + expected = SHEX("cf2db1ac9867debdf8ce91f99f141e5544bf26ca36b3fd4f8e4035" + "eec42cab0d46c386ebccef82ba0bb0b095aaa5548b03cdff695187" + "1c6fb505af68af688332f885d324a47d2145a3d8392c37978d7dc9" + "84c95728950c4cf3de6becc59e60ea506951bd40e6de3863095064" + "3ab2edbb47dc66cb54beb2d1"); + + sha256_init(&sha256ctx); + sha256_update(&sha256ctx, seed->length, seed->data); + pss_mgf1(&sha256ctx, &nettle_sha256, expected->length, mask); + ASSERT(MEMEQ (expected->length, mask, expected->data)); +} diff --git a/testsuite/pss-test.c b/testsuite/pss-test.c new file mode 100644 index 00000000..f6ba697c --- /dev/null +++ b/testsuite/pss-test.c @@ -0,0 +1,86 @@ +#include "testutils.h" + +#include "pss.h" + +void +test_main(void) +{ + struct tstring *salt; + struct tstring *digest; + mpz_t m; + mpz_t expected; + + /* From ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1d2-vec.zip */ + mpz_init(m); + mpz_init(expected); + + salt = SHEX("e3b5d5d002c1bce50c2b65ef88a188d83bce7e61"); + digest = SHEX("37b66ae0445843353d47ecb0b4fd14c110e62d6a"); + ASSERT(pss_encode_mgf1(m, 1024, &nettle_sha1, + salt->length, salt->data, digest->data)); + + mpz_set_str(expected, + "66e4672e836ad121ba244bed6576b867d9a447c28a6e66a5b87dee" + "7fbc7e65af5057f86fae8984d9ba7f969ad6fe02a4d75f7445fefd" + "d85b6d3a477c28d24ba1e3756f792dd1dce8ca94440ecb5279ecd3" + "183a311fc896da1cb39311af37ea4a75e24bdbfd5c1da0de7cecdf" + "1a896f9d8bc816d97cd7a2c43bad546fbe8cfebc", 16); + + ASSERT(mpz_cmp(m, expected) == 0); + + mpz_add_ui(m, m, 2); + ASSERT(!pss_verify_mgf1(m, 1024, &nettle_sha1, salt->length, digest->data)); + + mpz_sub_ui(m, m, 2); + ASSERT(pss_verify_mgf1(m, 1024, &nettle_sha1, salt->length, digest->data)); + + mpz_clear(m); + mpz_clear(expected); + + /* Test with our own data. */ + mpz_init(m); + mpz_init(expected); + + salt = SHEX("11223344556677889900"); + /* From sha256-test.c */ + digest = SHEX("ba7816bf8f01cfea 414140de5dae2223" + "b00361a396177a9c b410ff61f20015ad"); + + mpz_set_str(expected, + "76b9a52705c8382c5367732f993184eff340b6305c9f73e7e308c8" + "004fcc15cbbaab01e976bae4b774628595379a2d448a36b3ea6fa8" + "353b97eeea7bdac93b4b7807ac98cd4b3bebfb31f3718e1dd3625f" + "227fbb8696606498e7070e21c3cbbd7386ea20eb81ac7927e0c6d1" + "d7788826a63af767f301bcc05dd65b00da862cbc", 16); + + /* Try bad salt */ + salt->data[6] = 0x00; + ASSERT(pss_encode_mgf1(m, 1024, &nettle_sha256, + salt->length, salt->data, digest->data)); + ASSERT(mpz_cmp(m, expected) != 0); + + /* Try the good salt */ + salt->data[6] = 0x77; + ASSERT(pss_encode_mgf1(m, 1024, &nettle_sha256, + salt->length, salt->data, digest->data)); + ASSERT(mpz_cmp(m, expected) == 0); + + /* Try bad message */ + mpz_add_ui(m, m, 2); + ASSERT(!pss_verify_mgf1(m, 1024, &nettle_sha256, salt->length, digest->data)); + + /* Try the good message */ + mpz_sub_ui(m, m, 2); + ASSERT(pss_verify_mgf1(m, 1024, &nettle_sha256, salt->length, digest->data)); + + /* Try bad digest */ + digest->data[17] = 0x00; + ASSERT(!pss_verify_mgf1(m, 1024, &nettle_sha256, salt->length, digest->data)); + + /* Try the good digest */ + digest->data[17] = 0x03; + ASSERT(pss_verify_mgf1(m, 1024, &nettle_sha256, salt->length, digest->data)); + + mpz_clear(m); + mpz_clear(expected); +} diff --git a/testsuite/rsa-pss-sign-tr-test.c b/testsuite/rsa-pss-sign-tr-test.c new file mode 100644 index 00000000..6dfba734 --- /dev/null +++ b/testsuite/rsa-pss-sign-tr-test.c @@ -0,0 +1,356 @@ +#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" + "8b", 16); + + mpz_set_str(key.q, + "1b81c19a62802a41" "9c99283331b0badb" "08eb0c25ffce0fbf" + "50017850036f32f3" "2132a845b91a5236" "61f7b451d587383f" + "e1", 16); + + mpz_set_str(key.a, + "0a912fc93a6cca6b" "3521725a3065b3be" "3c9745e29c93303d" + "7d29316c6cafa4a2" "89945f964fcdea59" "1f9d248b0b6734be" + "c9", 16); + + mpz_set_str(key.b, + "1658eca933251813" "1eb19c77aba13d73" "e0b8f4ce986d7615" + "764c6b0b03c18146" "46b7f332c43e05c5" "351e09006979ca5b" + "05", 16); + + mpz_set_str(key.c, + "0114720dace7b27f" "2bf2850c1804869f" "79a0aad0ec02e6b4" + "05e1831619db2f10" "bb9b6a8fd5c95df2" "eb78f303ea0c0cc8" + "06", 16); + + ASSERT (rsa_private_key_prepare(&key)); + ASSERT (pub.size == key.size); + + /* Test signatures */ + mpz_set_str(expected, + "1a4d28331341cabf7ac85bc59a58d439b7ec2c607c6a74e35b5909" + "1dfa3d9de9fde93e4a431f0f768bec07c39995d253209f86e3dc84" + "037ecd5d23d963fab4fa8a001e018d82cb19d743a94ba7dc7a821e" + "87b72e67a0fe058f956208f7060dc104", 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); + + /* From FIPS 186-2 */ + mpz_set_str(pub.n, + "be499b5e7f06c83f" "a0293e31465c8eb6" "b58af920bae52a7b" + "5b9bfeb7aa72db12" "64112eb3fd431d31" "a2a7e50941566929" + "494a0e891ed56139" "18b4b51b0d1fb977" "83b26acf7d0f384c" + "fb35f4d2824f5dd3" "80623a26bf180b63" "961c619dcdb20cae" + "406f22f6e276c80a" "37259490cfeb72c1" "a71a84f1846d3308" + "77ba3e3101ec9c7b" , 16); + + mpz_set_str(pub.e, "11", 16); + + ASSERT (rsa_public_key_prepare(&pub)); + + mpz_set_str(key.p, + "e7a80c5d211c06ac" "b900939495f26d36" "5fc2b4825b75e356" + "f89003eaa5931e6b" "e5c3f7e6a633ad59" "db6289d06c354c23" + "5e739a1e3f3d39fb" "40d1ffb9cb44288f", 16); + + mpz_set_str(key.q, + "d248aa248000f720" "258742da67b71194" "0c8f76e1ecd52b67" + "a6ffe1e49354d66f" "f84fa601804743f5" "838da2ed4693a5a2" + "8658d6528cc1803b" "f6c8dc73c5230b55", 16); + + mpz_set_str(key.d, + "0d0f17362bdad181" "db4e1fe03e8de1a3" "208989914e14bf26" + "9558826bfa20faf4" "b68dba6bb989a01f" "03a21c44665dc5f6" + "48cb5b59b954eb10" "77a80263bd22cdfb" "88d39164b7404f4f" + "1106ee01cf60b776" "95748d8fdaf9fd42" "8963fe75144010b1" + "934c8e26a8823967" "2cf49b3422a07c4d" "834ba208d570fe40" + "8e7095c90547e68d", 16); + + /* a = d % (p-1) */ + mpz_sub_ui(p1, key.p, 1); + mpz_fdiv_r(key.a, key.d, p1); + mpz_clear(p1); + + /* b = d % (q-1) */ + mpz_sub_ui(q1, key.q, 1); + mpz_fdiv_r(key.b, key.d, q1); + mpz_clear(q1); + + /* c = q^{-1} (mod p) */ + mpz_invert(key.c, key.q, key.p); + + ASSERT (rsa_private_key_prepare(&key)); + ASSERT (pub.size == key.size); + + mpz_set_str(expected, + "11e169f2fd40b07641b9768a2ab19965fb6c27f10fcf0323fcc6d1" + "2eb4f1c06b330ddaa1ea504407afa29de9ebe0374fe9d1e7d0ffbd" + "5fc1cf3a3446e4145415d2ab24f789b3464c5c43a256bbc1d692cf" + "7f04801dac5bb401a4a03ab7d5728a860c19e1a4dc797ca542c820" + "3cec2e601eb0c51f567f2eda022b0b9ebddeeefa", 16); + + salt = SHEX("11223344555432167890"); + msg = SHEX("c7f5270fca725f9bd19f519a8d7cca3cc5c079024029f3bae510f9" + "b02140fe238908e4f6c18f07a89c687c8684669b1f1db2baf9251a" + "3c829faccb493084e16ec9e28d58868074a5d6221667dd6e528d16" + "fe2c9f3db4cfaf6c4dce8c8439af38ceaaaa9ce2ecae7bc8f4a5a5" + "5e3bf96df9cd575c4f9cb327951b8cdfe4087168"); + + test_rsa_pss_sign_tr(&pub, &key, + rsa_pss_sha256_sign_digest_tr, + rsa_pss_sha256_verify_digest, + &sha256ctx, &nettle_sha256, + salt->length, salt->data, msg->length, msg->data, + expected); + + mpz_set_str(expected, + "b281ad934b2775c0cba5fb10aa574d2ed85c7f99b942b78e497024" + "80069362ed394baded55e56cfcbe7b0b8d2217a05a60e1acd725cb" + "09060dfac585bc2132b99b41cdbd530c69d17cdbc84bc6b9830fc7" + "dc8e1b2412cfe06dcf8c1a0cc3453f93f25ebf10cb0c90334fac57" + "3f449138616e1a194c67f44efac34cc07a526267", 16); + + test_rsa_pss_sign_tr(&pub, &key, + rsa_pss_sha384_sign_digest_tr, + rsa_pss_sha384_verify_digest, + &sha384ctx, &nettle_sha384, + salt->length, salt->data, msg->length, msg->data, + expected); + mpz_set_str(expected, + "8ffc38f9b820ef6b080fd2ec7de5626c658d79056f3edf610a295b" + "7b0546f73e01ffdf4d0070ebf79c33fd86c2d608be9438b3d420d0" + "9535b97cd3d846ecaf8f6551cdf93197e9f8fb048044473ab41a80" + "1e9f7fc983c62b324361dade9f71a65952bd35c59faaa4d6ff462f" + "68a6c4ec0b428aa47336f2178aeb276136563b7d", 16); + + test_rsa_pss_sign_tr(&pub, &key, + rsa_pss_sha512_sign_digest_tr, + rsa_pss_sha512_verify_digest, + &sha512ctx, &nettle_sha512, + salt->length, salt->data, msg->length, msg->data, + expected); + + /* The public key n for this test is of size k = 1017 bits, and the + pss "em" value is limited to k - 1 = 1016 bits or 127 octets. The + alleged signature below results in a 1017 bit number during the + signature verification, which is too large, and used to result in + an assertion failure when attempting to convert the number to a + 127 octet string. + */ + mpz_set_str(pub.n, + "1d64559685aad3490e976b48aacf442ecee847268f882341eafe78" + "a0ca4ef88f66edbaf55b70e5285cc117aa9ceb322a4227c17e9e89" + "27bf38e5672faecf79e2983d92766fbb6624522f072ae0e4e46d37" + "052ce1e5745c2dd8fd67de3862e4711161e359b96bda85911ebf4e" + "6ce1bea625970269c77004a3cb03f9c382c5f79", 16); + mpz_set_str(pub.e, "10001", 16); + + ASSERT (rsa_public_key_prepare(&pub)); + + msg = SHEX("7f85e4909ff7bb29536e540a53031ef03ddcb129e553a43273fa1f" + "ed28c22a8b57c7bde101ff746f335ba69b29642019"); + /* Alleged signature, resulting in a too large m. */ + mpz_set_str(expected, + "000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000005ffff05" + "000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000", 16); + + ASSERT(!rsa_pss_sha384_verify_digest(&pub, 48, msg->data, expected)); + + rsa_private_key_clear(&key); + rsa_public_key_clear(&pub); + mpz_clear(expected); +} diff --git a/testsuite/test-rules.stamp b/testsuite/test-rules.stamp new file mode 100644 index 00000000..859afb1d --- /dev/null +++ b/testsuite/test-rules.stamp @@ -0,0 +1 @@ +stamp diff --git a/testsuite/testutils.c b/testsuite/testutils.c index 6f897617..6ce13c4e 100644 --- a/testsuite/testutils.c +++ b/testsuite/testutils.c @@ -4,6 +4,7 @@ #include "base16.h" #include "cbc.h" +#include "cfb.h" #include "ctr.h" #include "knuth-lfib.h" #include "macros.h" @@ -62,7 +63,7 @@ tstring_clear(void) } struct tstring * -tstring_data(size_t length, const char *data) +tstring_data(size_t length, const uint8_t *data) { struct tstring *s = tstring_alloc (length); memcpy (s->data, data, length); @@ -245,6 +246,184 @@ test_cipher_cbc(const struct nettle_cipher *cipher, } void +test_cipher_cfb(const struct nettle_cipher *cipher, + const struct tstring *key, + const struct tstring *cleartext, + const struct tstring *ciphertext, + const struct tstring *iiv) +{ + void *ctx = xalloc(cipher->context_size); + uint8_t *data, *data2; + uint8_t *iv = xalloc(cipher->block_size); + size_t length; + + ASSERT (cleartext->length == ciphertext->length); + length = cleartext->length; + + ASSERT (key->length == cipher->key_size); + ASSERT (iiv->length == cipher->block_size); + + data = xalloc(length); + data2 = xalloc(length); + + cipher->set_encrypt_key(ctx, key->data); + memcpy(iv, iiv->data, cipher->block_size); + + cfb_encrypt(ctx, cipher->encrypt, + cipher->block_size, iv, + length, data, cleartext->data); + + if (!MEMEQ(length, data, ciphertext->data)) + { + fprintf(stderr, "CFB encrypt failed:\nInput:"); + tstring_print_hex(cleartext); + fprintf(stderr, "\nOutput: "); + print_hex(length, data); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(ciphertext); + fprintf(stderr, "\n"); + FAIL(); + } + cipher->set_encrypt_key(ctx, key->data); + memcpy(iv, iiv->data, cipher->block_size); + + cfb_decrypt(ctx, cipher->encrypt, + cipher->block_size, iv, + length, data2, data); + + if (!MEMEQ(length, data2, cleartext->data)) + { + fprintf(stderr, "CFB decrypt failed:\nInput:"); + tstring_print_hex(ciphertext); + fprintf(stderr, "\nOutput: "); + print_hex(length, data2); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(cleartext); + fprintf(stderr, "\n"); + FAIL(); + } + cipher->set_encrypt_key(ctx, key->data); + memcpy(iv, iiv->data, cipher->block_size); + memcpy(data, cleartext->data, length); + + cfb_encrypt(ctx, cipher->encrypt, + cipher->block_size, iv, + length, data, data); + + if (!MEMEQ(length, data, ciphertext->data)) + { + fprintf(stderr, "CFB inplace encrypt failed:\nInput:"); + tstring_print_hex(cleartext); + fprintf(stderr, "\nOutput: "); + print_hex(length, data); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(ciphertext); + fprintf(stderr, "\n"); + FAIL(); + } + cipher->set_encrypt_key(ctx, key->data); + memcpy(iv, iiv->data, cipher->block_size); + + cfb_decrypt(ctx, cipher->encrypt, + cipher->block_size, iv, + length, data, data); + + if (!MEMEQ(length, data, cleartext->data)) + { + fprintf(stderr, "CFB inplace decrypt failed:\nInput:"); + tstring_print_hex(ciphertext); + fprintf(stderr, "\nOutput: "); + print_hex(length, data); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(cleartext); + fprintf(stderr, "\n"); + FAIL(); + } + + /* Repeat all tests with incomplete last block */ + length -= 1; + + cipher->set_encrypt_key(ctx, key->data); + memcpy(iv, iiv->data, cipher->block_size); + + cfb_encrypt(ctx, cipher->encrypt, + cipher->block_size, iv, + length, data, cleartext->data); + + if (!MEMEQ(length, data, ciphertext->data)) + { + fprintf(stderr, "CFB encrypt failed:\nInput:"); + print_hex(length, cleartext->data); + fprintf(stderr, "\nOutput: "); + print_hex(length, data); + fprintf(stderr, "\nExpected:"); + print_hex(length, ciphertext->data); + fprintf(stderr, "\n"); + FAIL(); + } + cipher->set_encrypt_key(ctx, key->data); + memcpy(iv, iiv->data, cipher->block_size); + + cfb_decrypt(ctx, cipher->encrypt, + cipher->block_size, iv, + length, data2, data); + + if (!MEMEQ(length, data2, cleartext->data)) + { + fprintf(stderr, "CFB decrypt failed:\nInput:"); + print_hex(length, ciphertext->data); + fprintf(stderr, "\nOutput: "); + print_hex(length, data2); + fprintf(stderr, "\nExpected:"); + print_hex(length, cleartext->data); + fprintf(stderr, "\n"); + FAIL(); + } + cipher->set_encrypt_key(ctx, key->data); + memcpy(iv, iiv->data, cipher->block_size); + memcpy(data, cleartext->data, length); + + cfb_encrypt(ctx, cipher->encrypt, + cipher->block_size, iv, + length, data, data); + + if (!MEMEQ(length, data, ciphertext->data)) + { + fprintf(stderr, "CFB inplace encrypt failed:\nInput:"); + print_hex(length, cleartext->data); + fprintf(stderr, "\nOutput: "); + print_hex(length, data); + fprintf(stderr, "\nExpected:"); + print_hex(length, ciphertext->data); + fprintf(stderr, "\n"); + FAIL(); + } + cipher->set_encrypt_key(ctx, key->data); + memcpy(iv, iiv->data, cipher->block_size); + + cfb_decrypt(ctx, cipher->encrypt, + cipher->block_size, iv, + length, data, data); + + if (!MEMEQ(length, data, cleartext->data)) + { + fprintf(stderr, "CFB inplace decrypt failed:\nInput:"); + print_hex(length, ciphertext->data); + fprintf(stderr, "\nOutput: "); + print_hex(length, data); + fprintf(stderr, "\nExpected:"); + print_hex(length, cleartext->data); + fprintf(stderr, "\n"); + FAIL(); + } + + free(ctx); + free(data); + free(data2); + free(iv); +} + +void test_cipher_ctr(const struct nettle_cipher *cipher, const struct tstring *key, const struct tstring *cleartext, @@ -566,7 +745,7 @@ test_armor(const struct nettle_armor *armor, const char *ascii) { size_t ascii_length = strlen(ascii); - uint8_t *buffer = xalloc(1 + ascii_length); + char *buffer = xalloc(1 + ascii_length); uint8_t *check = xalloc(1 + armor->decode_length(ascii_length)); void *encode = xalloc(armor->encode_context_size); void *decode = xalloc(armor->decode_context_size); diff --git a/testsuite/testutils.h b/testsuite/testutils.h index 7c44772b..fbbba7b9 100644 --- a/testsuite/testutils.h +++ b/testsuite/testutils.h @@ -60,7 +60,7 @@ void tstring_clear(void); struct tstring * -tstring_data(size_t length, const char *data); +tstring_data(size_t length, const uint8_t *data); struct tstring * tstring_hex(const char *hex); @@ -123,6 +123,13 @@ test_cipher_cbc(const struct nettle_cipher *cipher, const struct tstring *iv); void +test_cipher_cfb(const struct nettle_cipher *cipher, + const struct tstring *key, + const struct tstring *cleartext, + const struct tstring *ciphertext, + const struct tstring *iv); + +void test_cipher_ctr(const struct nettle_cipher *cipher, const struct tstring *key, const struct tstring *cleartext, @@ -163,13 +170,6 @@ test_armor(const struct nettle_armor *armor, const char *ascii); #if WITH_HOGWEED -#ifndef mpn_zero_p -int -mpn_zero_p (mp_srcptr ap, mp_size_t n); -#endif - -void -mpn_out_str (FILE *f, int base, const mp_limb_t *xp, mp_size_t xn); #if NETTLE_USE_MINI_GMP typedef struct knuth_lfib_ctx gmp_randstate_t[1]; @@ -180,8 +180,20 @@ void mpz_urandomb (mpz_t r, struct knuth_lfib_ctx *ctx, mp_bitcnt_t bits); /* This is cheating */ #define mpz_rrandomb mpz_urandomb +/* mini-gmp defines this function (in the GMP library, it was added in + gmp in version 6.1.0). */ +#define mpn_zero_p mpn_zero_p + #endif /* NETTLE_USE_MINI_GMP */ +#ifndef mpn_zero_p +int +mpn_zero_p (mp_srcptr ap, mp_size_t n); +#endif + +void +mpn_out_str (FILE *f, int base, const mp_limb_t *xp, mp_size_t xn); + mp_limb_t * xalloc_limbs (mp_size_t n); @@ -281,7 +293,7 @@ test_ecc_mul_h (unsigned curve, unsigned n, const mp_limb_t *p); #define LDUP(x) strlen(x), strdup(x) #define SHEX(x) (tstring_hex(x)) -#define SDATA(x) ((const struct tstring *)tstring_data(LLENGTH(x), x)) +#define SDATA(x) ((const struct tstring *)tstring_data(LLENGTH(x), US(x))) #define H(x) (SHEX(x)->data) #define MEMEQ(length, a, b) (!memcmp((a), (b), (length))) diff --git a/tools/input.c b/tools/input.c index 18a9dff5..90e41a29 100644 --- a/tools/input.c +++ b/tools/input.c @@ -90,7 +90,7 @@ sexp_get_char(struct sexp_input *input) * character at a time. */ if (!input->coding->decode_update(&input->state, &done, &input->c, - 1, &input->c)) + 1, (const char*) &input->c)) die("Invalid coded data.\n"); if (done) diff --git a/tools/nettle-hash.c b/tools/nettle-hash.c index d7d4ce2e..24199921 100644 --- a/tools/nettle-hash.c +++ b/tools/nettle-hash.c @@ -53,11 +53,11 @@ list_algorithms (void) { unsigned i; const struct nettle_hash *alg; - printf ("%10s digestsize (internal block size), in units of octets\n", "name"); + printf ("%10s digestsize (internal block size, context size), in units of octets\n", "name"); for (i = 0; (alg = nettle_hashes[i]); i++) - printf ("%10s %d (%d)\n", - alg->name, alg->digest_size, alg->block_size); + printf ("%10s %d (%d, %d)\n", + alg->name, alg->digest_size, alg->block_size, alg->context_size); }; /* Also in examples/io.c */ diff --git a/tools/nettle-pbkdf2.c b/tools/nettle-pbkdf2.c index c9e4d11c..1f0a3015 100644 --- a/tools/nettle-pbkdf2.c +++ b/tools/nettle-pbkdf2.c @@ -73,7 +73,7 @@ main (int argc, char **argv) size_t password_length; uint8_t *output; size_t salt_length; - uint8_t *salt; + char *salt; int raw = 0; int hex_salt = 0; int c; @@ -141,7 +141,7 @@ main (int argc, char **argv) return EXIT_FAILURE; } - salt = (uint8_t *) strdup (argv[0]); + salt = strdup (argv[0]); salt_length = strlen(argv[0]); if (hex_salt) @@ -150,7 +150,7 @@ main (int argc, char **argv) base16_decode_init (&base16); if (!base16_decode_update (&base16, - &salt_length, salt, + &salt_length, (uint8_t *) salt, salt_length, salt) || !base16_decode_final (&base16)) die ("Invalid salt (expecting hex encoding).\n"); @@ -165,7 +165,7 @@ main (int argc, char **argv) output = xalloc (output_length); pbkdf2_hmac_sha256 (password_length, (const uint8_t *) password, - iterations, salt_length, salt, + iterations, salt_length, (const uint8_t*) salt, output_length, output); free (salt); diff --git a/tools/output.c b/tools/output.c index 02e43d58..80a44a97 100644 --- a/tools/output.c +++ b/tools/output.c @@ -114,7 +114,7 @@ sexp_put_char(struct sexp_output *output, uint8_t c) if (output->coding) { /* Two is enough for both base16 and base64. */ - uint8_t encoded[2]; + char encoded[2]; unsigned done; unsigned i; @@ -183,7 +183,7 @@ void sexp_put_code_end(struct sexp_output *output) { /* Enough for both hex and base64 */ - uint8_t encoded[BASE64_ENCODE_FINAL_LENGTH]; + char encoded[BASE64_ENCODE_FINAL_LENGTH]; unsigned done; assert(output->coding); @@ -194,7 +194,7 @@ sexp_put_code_end(struct sexp_output *output) output->coding = NULL; - sexp_put_data(output, done, encoded); + sexp_put_data(output, done, (const uint8_t*) encoded); } void diff --git a/tools/pkcs1-conv.c b/tools/pkcs1-conv.c index 9e346858..efd6528a 100644 --- a/tools/pkcs1-conv.c +++ b/tools/pkcs1-conv.c @@ -244,6 +244,14 @@ read_pem(struct nettle_buffer *buffer, FILE *f, } } +static inline int +base64_decode_in_place (struct base64_decode_ctx *ctx, size_t *dst_length, + size_t length, uint8_t *data) +{ + return base64_decode_update (ctx, dst_length, + data, length, (const char *) data); +} + static int decode_base64(struct nettle_buffer *buffer, size_t start, size_t *length) @@ -253,9 +261,8 @@ decode_base64(struct nettle_buffer *buffer, base64_decode_init(&ctx); /* Decode in place */ - if (base64_decode_update(&ctx, - length, buffer->contents + start, - *length, buffer->contents + start) + if (base64_decode_in_place(&ctx, length, + *length, buffer->contents + start) && base64_decode_final(&ctx)) return 1; |