Compare commits

...

192 Commits

Author SHA1 Message Date
David Benjamin 7f7bd6b559 Fix typo in point_add.
Rather than writing the answer into the output, it wrote it into some
awkwardly-named temporaries. Thanks to Daniel Hirche for reporting this
issue!

Bug: chromium:825273
(cherry picked from commit 5fca613918)

Change-Id: I315087f5e7414118a6f70bf4aed76325aa4f76a0
2018-03-29 15:50:25 -04:00
Adam Langley 8df8e64205 Record whether dummy PQ padding was used.
On reflection, I think we'll need to note whether dummy PQ padding was
echoed on a given connection. Otherwise measurements in Chrome will be
mixed with cases where people have MITM proxies that ignored the
extension, or possibly Google frontends that haven't been updated.

Therefore this change will be used to filter latency measurements in
Chrome to only include those where the extension was echoed and we'll
measure at levels of 1 byte (for control), 400 bytes, and 1100 bytes.

This also makes it an error if the server didn't echo an extension of
the same length as was sent.

Change-Id: Ib2a0b29cfb8719a75a28f3cf96710c57d88eaa68
Reviewed-on: https://boringssl-review.googlesource.com/26284
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-02-28 23:38:53 +00:00
Daniel Hirche 8d4f7e5421 Remove redundant assertion in fe_mul_121666_impl.
Change-Id: Ie2368dc9f6be791b7c3ad1c610dcd603634be6e4
Reviewed-on: https://boringssl-review.googlesource.com/26244
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-27 23:50:02 +00:00
Adam Langley 4702db6306 Update dummy PQ extension for round two.
In this round, Google servers will echo the extension in order to test
the latency of both parties sending a PQ key-agreement message.

The extension is sent (and echoed) for both full and resumption
handshakes. This is intended to mirror the overhead of TLS 1.3 (even
when using TLS 1.2), as a resumption in TLS 1.3 still does a fresh key
agreement.

Change-Id: I9ad163afac4fd1d916f9c7359ec32994e283abeb
Reviewed-on: https://boringssl-review.googlesource.com/26185
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-27 20:13:53 +00:00
Martin Kreichgauer 8041d8c40e third_party: re-format METATADA files
Change-Id: Ic2e9f54f5ced053c1463d5c09a74db5b2a3ea098
Reviewed-on: https://boringssl-review.googlesource.com/26224
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-27 19:57:12 +00:00
Adam Langley c01786403f Update link to CMVP certificate.
NIST redid their website and broke all the old links.

Change-Id: I5b7cba878404bb63e49f221f6203c8e1e6545af4
Reviewed-on: https://boringssl-review.googlesource.com/26204
Reviewed-by: Adam Langley <agl@google.com>
2018-02-26 22:14:35 +00:00
Adam Langley e745b25dcb Remove trailing whitespace from ssl/.
Change-Id: Ibcb27e1e5b14294c9d877db89ae62ef138e9e061
Reviewed-on: https://boringssl-review.googlesource.com/26184
Reviewed-by: Adam Langley <agl@google.com>
2018-02-26 22:05:13 +00:00
David Benjamin 672f6fc248 Always use adr with __thumb2__.
Thumb2 addresses are a bit a mess, depending on whether a label is
interpreted as a function pointer value (for use with BX and BLX) or as
a program counter value (for use with PC-relative addressing). Clang's
integrated assembler mis-assembles this code. See
https://crbug.com/124610#c54 for details.

Instead, use the ADR pseudo-instruction which has clear semantics and
should be supported by every assembler that handles the OpenSSL Thumb2
code. (In other files, the ADR vs SUB conditionals are based on
__thumb2__ already. For some reason, this one is based on __APPLE__, I'm
guessing to deal with an older version of clang assembler.)

It's unclear to me which of clang or binutils is "correct" or if this is
even a well-defined notion beyond "whatever binutils does". But I will
note that https://github.com/openssl/openssl/pull/4669 suggests binutils
has also changed behavior around this before.

See also https://github.com/openssl/openssl/pull/5431 in OpenSSL.

Bug: chromium:124610
Change-Id: I5e7a0c8c0f54a3f65cc324ad599a41883675f368
Reviewed-on: https://boringssl-review.googlesource.com/26164
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-22 22:28:15 +00:00
Daniel Hirche 36714fc8ee Remove redundant length-check in |ec_wNAF_mul|.
Right now, |g_wNAF| and |p_wNAF| are of same size.

This change makes GCC's "-Werror=logical-op" happy and adds a compile-time
assertion in case the initial size of either array ever changes.

Change-Id: I29e39a7a121a0a9d016c53da6b7c25675ddecbdc
Reviewed-on: https://boringssl-review.googlesource.com/26104
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-21 17:03:14 +00:00
Fred Gylys-Colwell 02d696f2a1 Delete |pthread_key_t| on dlclose.
When OPENSSL_DANGEROUS_RELEASE_PTHREAD_KEY is defined during the build,
this change adds a destructor function that is called when BoringSSL is
unloaded via |dlclose| or during process exit. Using |dlclose| with
BoringSSL is not supported and will leak memory, but this change allows
some code that is already doing it to survive longer.

Change-Id: Ifc6d6aae61ed0f15d61cd3dbb4ea9f8006e43dba
Reviewed-on: https://boringssl-review.googlesource.com/25784
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Reviewed-by: Fred Gylys-Colwell <fredgc@google.com>
2018-02-20 19:53:24 +00:00
Adam Langley ed626ec99b Merge NIAP and FIPS test suites.
When we do future FIPS or NIAP runs, we'll do everything. So no need for
a -niap option any longer.

Change-Id: I2c8b71951acca0734c1a15cfb6f61ec5ecee5884
Reviewed-on: https://boringssl-review.googlesource.com/26124
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-20 19:41:45 +00:00
David Benjamin 085955c567 Actually use the u64 cast.
The point was to remove the silly moduli.

Change-Id: I48c507c9dd1fc46e38e8991ed528b02b8da3dc1d
Reviewed-on: https://boringssl-review.googlesource.com/26044
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-16 20:02:56 +00:00
Steven Valdez f16cd4278f Add AES_128_CCM AEAD.
Change-Id: I830be64209deada0f24c3b6d50dc86155085c377
Reviewed-on: https://boringssl-review.googlesource.com/25904
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-16 15:57:27 +00:00
David Benjamin 78a832d793 Document RSAZ slightly better.
Better commit such details to comments before I forget them.

Change-Id: Ie36332235c692f4369413b4340a742b5ad895ce1
Reviewed-on: https://boringssl-review.googlesource.com/25984
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-15 18:14:04 +00:00
David Benjamin c03ecb93a2 Remove SSLv3_method and friends.
SSLv3_method, SSLv3_client_method, and SSLv3_server_method produce
SSL_CTXs which fail every handshake. They appear no longer necessary for
compatibility, so remove them.

SSLv3 is still accessible to callers who explicitly re-enable SSLv3 on a
TLS_method, but that will be removed completely later this year.
Meanwhile, clear out a weird hack we had here.

Update-Note: I believe there are no more callers of these functions. Any
   that were were already non-functional as these methods haven't been
   unable to handshake for a while now.

Change-Id: I622f785b428ab0ceab77b5a9db05b2b0df28145a
Reviewed-on: https://boringssl-review.googlesource.com/26004
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-15 15:29:18 +00:00
David Benjamin 1bf2337fe1 Reject compressed ECDH coordinates in TLS.
We don't advertise compressed coordinates (and point format negotiation
was deprecated in TLS 1.3), so reject them. Both Internet Explorer and
Firefox appear to reject them already.

Later I hope to add an easier to use ECDH API that acts on bytes, not
EC_POINT. This clears the way for that API to only accept uncompressed
coordinates. Compressed coordinates never got deployed over NIST curves,
for better or worse. At this point, there is no sense in changing that
as new protocols should use curve25519.

Change-Id: Id2f1be791ddcf155d596f4eb0b79351766c5cdab
Reviewed-on: https://boringssl-review.googlesource.com/26024
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-15 01:42:54 +00:00
Aaron Green 67968895b3 Remove unused strings.h #include from crypto/mem.c
crypto/mem.c #include's <strings.h>, but doesn't use call any functions
from it.

Change-Id: If60b31be7dd6b347bcb077a59825a557a2492081
Reviewed-on: https://boringssl-review.googlesource.com/25964
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-14 01:40:23 +00:00
David Benjamin 02cca1987b clang-format RSAZ C code.
Change-Id: I7fb9b06ec89ba11641454145708e157359b07cf0
Reviewed-on: https://boringssl-review.googlesource.com/25924
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
2018-02-13 22:30:03 +00:00
David Benjamin 10443f5a6e Adjust comment on potential R^3 optimization.
It's doable, but a bit of effort due to the different radix.

Change-Id: Ibfa15c31bb37de930f155ee6d19551a2b6437073
Reviewed-on: https://boringssl-review.googlesource.com/25944
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
2018-02-13 22:19:13 +00:00
Aaron Green 862e0d2e1b Add cpu-aarch64-fuchsia.c
Fuchsia/Zircon recently added support for exposing arm64 CPU features;
this CL uses the new system call to set OPENSSL_armcap_P.

Change-Id: I045dc0b58117afe6dae315a82bf9acfd8d99be1a
Reviewed-on: https://boringssl-review.googlesource.com/25865
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-13 20:12:47 +00:00
David Benjamin 638a408cd2 Add a tuned variable-time P-256 multiplication function.
This reuses wnaf.c's window scheduling, but has access to the tuned
field arithemetic and pre-computed base point table. Unlike wnaf.c, we
do not make the points affine as it's not worth it for a single table.
(We already precomputed the base point table.)

Annoyingly, 32-bit x86 gets slower by a bit, but the other platforms are
faster. My guess is that that the generic code gets to use the
bn_mul_mont assembly and the compiler, faced with the increased 32-bit
register pressure and the extremely register-poor x86, is making
bad decisions on the otherwise P-256-tuned C code. The three platforms
that see much larger gains are significantly more important than 32-bit
x86 at this point, so go with this change.

armv7a (Nexus 5X) before/after [+14.4%]:
Did 2703 ECDSA P-256 verify operations in 5034539us (536.9 ops/sec)
Did 3127 ECDSA P-256 verify operations in 5091379us (614.2 ops/sec)

aarch64 (Nexus 5X) before/after [+9.2%]:
Did 6783 ECDSA P-256 verify operations in 5031324us (1348.2 ops/sec)
Did 7410 ECDSA P-256 verify operations in 5033291us (1472.2 ops/sec)

x86 before/after [-2.7%]:
Did 8961 ECDSA P-256 verify operations in 10075901us (889.3 ops/sec)
Did 8568 ECDSA P-256 verify operations in 10003001us (856.5 ops/sec)

x86_64 before/after [+8.6%]:
Did 29808 ECDSA P-256 verify operations in 10008662us (2978.2 ops/sec)
Did 32528 ECDSA P-256 verify operations in 10057137us (3234.3 ops/sec)

Change-Id: I5fa643149f5bfbbda9533e3008baadfee9979b93
Reviewed-on: https://boringssl-review.googlesource.com/25684
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-12 22:00:48 +00:00
David Benjamin 6e4ff114fc Merge Intel copyright notice into standard
This was done by OpenSSL with the kind permission of Intel. This change
is imported from upstream's commit
dcf6e50f48e6bab92dcd2dacb27fc17c0de34199.

Change-Id: Ie8d3b700cd527a6e8cf66e0728051b2acd8cc6b9
Reviewed-on: https://boringssl-review.googlesource.com/25588
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-12 21:44:27 +00:00
David Benjamin f6cf8bbc84 Sync up AES assembly.
This syncs up with OpenSSL master as of
50ea9d2b3521467a11559be41dcf05ee05feabd6. The non-license non-spelling
changes are CFI bits, which were added in upstream in
b84460ad3a3e4fcb22efaa0a8365b826f4264ecf.

Change-Id: I42280985f834d5b9133eacafc8ff9dbd2f0ea59a
Reviewed-on: https://boringssl-review.googlesource.com/25704
Reviewed-by: Adam Langley <agl@google.com>
2018-02-11 01:03:17 +00:00
David Benjamin 6dc994265e Sync up some perlasm license headers and easy fixes.
These files are otherwise up-to-date with OpenSSL master as of
50ea9d2b3521467a11559be41dcf05ee05feabd6, modulo a couple of spelling
fixes which I've imported.

I've also reverted the same-line label and instruction patch to
x86_64-mont*.pl. The new delocate parser handles that fine.

Change-Id: Ife35c671a8104c3cc2fb6c5a03127376fccc4402
Reviewed-on: https://boringssl-review.googlesource.com/25644
Reviewed-by: Adam Langley <agl@google.com>
2018-02-11 01:00:35 +00:00
David Benjamin 0f4f6c2e02 p256-x86_64.pl: add CFI directives.
(Imported from upstream's 86e112788e2ab9740c0cabf3ae4b1eb67b386bab.)

Change-Id: I1ba11e47f1ec9846ea00c738db737c35ce7aaab1
Reviewed-on: https://boringssl-review.googlesource.com/25587
Reviewed-by: Adam Langley <agl@google.com>
2018-02-11 00:53:41 +00:00
David Benjamin 02808ddcaa p256-x86_64-asm.pl: Win64 SEH face-lift.
This imports 384e6de4c7e35e37fb3d6fbeb32ddcb5eb0d3d3f and
79ca382d4762c58c4b92fceb4e202e90c71292ae from upstream.

Differences from upstream:

- We've removed a number of unused functions.

- We never imported 3ff08e1dde56747011a702a9a5aae06cfa8ae5fc, which was
  to give the assembly control over the memory layout in the tables. So
  our "gather" is "select" (which is implemented the same because the
  memory layout never did change) and our "scatter" is in C.

Change-Id: I90d4a17da9f5f693f4dc4706887dec15f010071b
Reviewed-on: https://boringssl-review.googlesource.com/25586
Reviewed-by: Adam Langley <agl@google.com>
2018-02-11 00:52:23 +00:00
David Benjamin 05640fd373 p256-x86_64-asm.pl: Add OpenSSL copyright
As of upstream's 6aa36e8e5a062e31543e7796f0351ff9628832ce, the
corresponding file in OpenSSL has both an Intel and OpenSSL copyright
blocks.  To properly sync up with OpenSSL, use the OpenSSL copyright
block and our version of the Intel copyright block.

Change-Id: I4dc072a11390a54d0ce38ec0b8893e48f52638de
Reviewed-on: https://boringssl-review.googlesource.com/25585
Reviewed-by: Adam Langley <agl@google.com>
2018-02-11 00:50:19 +00:00
David Benjamin 8ae929f1e9 p256-x86_64.pl: update commentary with before-after performance data.
(Imported from upstream's f0e6871df2e4641d0532e8f99d26c7a6454d03df.)

Change-Id: I2b799ff2a133839b0fe9d9093799d3a86045d709
Reviewed-on: https://boringssl-review.googlesource.com/25584
Reviewed-by: Adam Langley <agl@google.com>
2018-02-11 00:49:54 +00:00
Daniel Hirche d25e62e772 Return NULL instead of zero in |bn_resized_from_ctx|.
Change-Id: I5fc029ceddfa60b2ccc97c138b94c1826f6d75fa
Reviewed-on: https://boringssl-review.googlesource.com/25844
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-10 23:10:54 +00:00
David Benjamin 38c20fe8d5 Fix threading issues with RSA freeze_private_key.
OpenSSL's RSA API is poorly designed and does not have a single place to
properly initialize the key. See
https://github.com/openssl/openssl/issues/5158.

To workaround this flaw, we must lazily instantiate pre-computed
Montgomery bits with locking. This is a ton of complexity. More
importantly, it makes it very difficult to implement RSA without side
channels. The correct in-memory representation of d, dmp1, and dmq1
depend on n, p, and q, respectively. (Those values have private
magnitudes and must be sized relative to the respective moduli.)

08805fe279 attempted to fix up the various
widths under lock, when we set up BN_MONT_CTX. However, this introduces
threading issues because other threads may access those exposed
components (RSA_get0_* also count as exposed for these purposes because
they are get0 functions), while a private key operation is in progress.

Instead, we do the following:

- There is no actual need to minimize n, p, and q, but we have minimized
  copies in the BN_MONT_CTXs, so use those.

- Store additional copies of d, dmp1, and dmq1, at the cost of more
  memory used. These copies have the correct width and are private,
  unlike d, dmp1, and dmq1 which are sadly exposed. Fix private key
  operations to use them.

- Move the frozen bit out of rsa->flags, as that too was historically
  accessible without locking.

(Serialization still uses the original BIGNUMs, but the RSAPrivateKey
serialization format already inherently leaks the magnitude, so this
doesn't matter.)

Change-Id: Ia3a9b0629f8efef23abb30bfed110d247d1db42f
Reviewed-on: https://boringssl-review.googlesource.com/25824
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-09 22:17:11 +00:00
Adam Langley 61dedd6815 Don't crash when failing to set affine coordinates when the generator is missing.
If a caller is in the process on constructing an arbitrary |EC_GROUP|,
and they try to create an |EC_POINT| to set as the generator which is
invalid, we would previously crash.

Change-Id: Ida91354257a02bd56ac29ba3104c9782b8d70f6b
Reviewed-on: https://boringssl-review.googlesource.com/25764
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-07 23:08:17 +00:00
David Benjamin 376f3f1727 Add BN_count_low_zero_bits.
This allows a BIGNUM consumer to avoid messing around with bn->d and
bn->top/width.

Bug: 232
Change-Id: I134cf412fef24eb404ff66c84831b4591d921a17
Reviewed-on: https://boringssl-review.googlesource.com/25484
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 03:10:54 +00:00
David Benjamin d24cb22c55 Make BN_cmp constant-time.
This is a bit easier to read than BN_less_than_consttime when we must do
>= or <=, about as much work to compute, and lots of code calls BN_cmp
on secret data. This also, by extension, makes BN_cmp_word
constant-time.

BN_equal_consttime is probably a little more efficient and is perfectly
readable, so leave that one around.

Change-Id: Id2e07fe312f01cb6fd10a1306dcbf6397990cf13
Reviewed-on: https://boringssl-review.googlesource.com/25444
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 03:10:44 +00:00
David Benjamin ac383701b7 Simplify bn_mul_part_recursive.
The loop and the outermost special-cases are basically the same.

Change-Id: I5e3ca60ad9a04efa66b479eebf8c3637a11cdceb
Reviewed-on: https://boringssl-review.googlesource.com/25406
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 03:04:04 +00:00
David Benjamin 6488f4e2ba Fix over-allocated bounds on bn_mul_part_recursive.
Same mistake as bn_mul_recursive.

Change-Id: I2374d37e5da61c82ccb1ad79da55597fa3f10640
Reviewed-on: https://boringssl-review.googlesource.com/25405
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 02:57:55 +00:00
David Benjamin 2bf82975ad Make bn_mul_part_recursive constant-time.
This follows similar lines as the previous cleanups and fixes the
documentation of the preconditions.

And with that, RSA private key operations, provided p and q have the
same bit length, should be constant time, as far as I know. (Though I'm
sure I've missed something.)

bn_cmp_part_words and bn_cmp_words are no longer used and deleted.

Bug: 234
Change-Id: Iceefa39f57e466c214794c69b335c4d2c81f5577
Reviewed-on: https://boringssl-review.googlesource.com/25404
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 02:51:54 +00:00
David Benjamin 6541308ff3 Don't allocate oversized arrays for bn_mul_recursive.
The power of two computations here were extremely confusing and one of
the comments mixed && and ||. Remove the cached k = j + j value.
Optimizing the j*8, j*8, j*2, and j*4 multiplications is the compiler's
job. If it doesn't manage it, it was only a couple shifts anyway.

With that fixed, it becomes easier to tell that rr was actaully
allocated twice as large as necessary. I suspect rr is also
incorrectly-allocated in the bn_mul_part_recursive case, but I'll wait
until I've checked that function over first. (The array size
documentation on the other bn_{mul,sqr}_recursive functions have had
mistakes before.)

Change-Id: I298400b988e3bd108d01d6a7c8a5b262ddf81feb
Reviewed-on: https://boringssl-review.googlesource.com/25364
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 02:51:44 +00:00
David Benjamin 34a2c5e476 Make bn_mul_recursive constant-time.
I left the input length as int because the calling convention passes
these messy deltas around. This micro-optimization is almost certainly
pointless, but bn_sub_part_words is written in assembly, so I've left it
alone for now. The documented preconditions were also all completely
wrong, so I've fixed them. We actually only call them for even tighter
bounds (one of dna or dnb is 0 and the other is 0 or -1), at least
outside bn_mul_part_recursive which I still need to read through.

This leaves bn_mul_part_recursive, which is reachable for RSA keys which
are not a power of two in bit width.

The first iteration of this had an uncaught bug, so I added a few more
aggressive tests generated with:

  A = 0x...
  B = 0x...

  # Chop off 0, 1 and > 1 word for both 32 and 64-bit.
  for i in (0, 1, 2, 4):
    for j in (0, 1, 2, 4):
      a = A >> (32*i)
      b = B >> (32*j)
      p = a * b
      print "Product = %x" % p
      print "A = %x" % a
      print "B = %x" % b
      print

Bug: 234
Change-Id: I72848d992637c0390cdd3c4f81cb919393b59eb8
Reviewed-on: https://boringssl-review.googlesource.com/25344
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 02:51:34 +00:00
David Benjamin b01dd1c622 Make bn_sqr_recursive constant-time.
We still need BN_mul and, in particular, bn_mul_recursive will either
require bn_abs_sub_words be generalized or that we add a parallel
bn_abs_sub_part_words, but start with the easy one.

While I'm here, simplify the i and j mess in here. It's patterned after
the multiplication one, but can be much simpler.

Bug: 234
Change-Id: If936099d53304f2512262a1cbffb6c28ae30ccee
Reviewed-on: https://boringssl-review.googlesource.com/25325
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 02:47:34 +00:00
David Benjamin 3b3e12d81e Simplify BN_bn2bin_padded.
There is no more need for the "constant-time" reading beyond bn->top. We
can write the bytes out naively because RSA computations no longer call
bn_correct_top/bn_set_minimal_width.

Specifically, the final computation is a BN_mod_mul_montgomery to remove
the blinding, and that keeps the sizes correct.

Bug: 237
Change-Id: I6e90d81c323b644e179d899f411479ea16deab98
Reviewed-on: https://boringssl-review.googlesource.com/25324
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 02:41:38 +00:00
David Benjamin be837402a9 Make the rest of RSA CRT constant-time.
Alas, the existence of RSA keys with q > p is obnoxious, but we can
canonicalize it away. To my knowledge, the remaining leaks in RSA are:

- Key generation. This is kind of hopelessly non-constant-time but
  perhaps deserves a more careful ponder. Though hopefully it does not
  come in at a measurable point for practical purposes.

- Private key serialization. RSAPrivateKey inherently leaks the
  magnitudes of d, dmp1, dmq1, and iqmp. This is unavoidable but
  hopefully does not come in at a measurable point for practical
  purposes.

- If p and q have different word widths, we currently fall back to the
  variable-time BN_mod rather than Montgomery reduction at the start of
  CRT. I can think of ways to apply Montgomery reduction, but it's
  probably better to deny CRT to such keys, if not reject them outright.

- bn_mul_fixed and bn_sqr_fixed which affect the Montgomery
  multiplication bn_mul_mont-less configurations, as well as the final
  CRT multiplication. We should fix this.

Bug: 233
Change-Id: I8c2ecf8f8ec104e9f26299b66ac8cbb0cad04616
Reviewed-on: https://boringssl-review.googlesource.com/25263
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 02:40:34 +00:00
David Benjamin 150ad30d28 Split BN_uadd into a bn_uadd_fixed.
This is to be used in constant-time RSA CRT.

Bug: 233
Change-Id: Ibade5792324dc6aba38cab6971d255d41fb5eb91
Reviewed-on: https://boringssl-review.googlesource.com/25286
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 02:39:45 +00:00
David Benjamin 5b10def1cf Compute mont->RR in constant-time.
Use the now constant-time modular arithmetic functions.

Bug: 236
Change-Id: I4567d67bfe62ca82ec295f2233d1a6c9b131e5d2
Reviewed-on: https://boringssl-review.googlesource.com/25285
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 01:40:24 +00:00
David Benjamin 6f564afbdd Make BN_mod_*_quick constant-time.
As the EC code will ultimately want to use these in "words" form by way
of EC_FELEM, and because it's much easier, I've implement these as
low-level words-based functions that require all inputs have the same
width. The BIGNUM versions which RSA and, for now, EC calls are
implemented on top of that.

Unfortunately, doing such things in constant-time and accounting for
undersized inputs requires some scratch space, and these functions don't
take BN_CTX. So I've added internal bn_mod_*_quick_ctx functions that
take a BN_CTX and the old functions now allocate a bit unnecessarily.
RSA only needs lshift (for BN_MONT_CTX) and sub (for CRT), but the
generic EC code wants add as well.

The generic EC code isn't even remotely constant-time, and I hope to
ultimately use stack-allocated EC_FELEMs, so I've made the actual
implementations here implemented in "words", which is much simpler
anyway due to not having to take care of widths.

I've also gone ahead and switched the EC code to these functions,
largely as a test of their performance (an earlier iteration made the EC
code noticeably slower). These operations are otherwise not
performance-critical in RSA.

The conversion from BIGNUM to BIGNUM+BN_CTX should be dropped by the
static linker already, and the unused BIGNUM+BN_CTX functions will fall
off when EC_FELEM happens.

Update-Note: BN_mod_*_quick bounce on malloc a bit now, but they're not
    really used externally. The one caller I found was wpa_supplicant
    which bounces on malloc already. They appear to be implementing
    compressed coordinates by hand? We may be able to convince them to
    call EC_POINT_set_compressed_coordinates_GFp.

Bug: 233, 236
Change-Id: I2bf361e9c089e0211b97d95523dbc06f1168e12b
Reviewed-on: https://boringssl-review.googlesource.com/25261
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 01:16:04 +00:00
David Benjamin eaa80b7069 Remove DSA k+q kludge.
With fixed-width BIGNUMs, this is no longer a concern. With this CL, I
believe we now no longer call BN_num_bits on BIGNUMs with secret
magnitude.

Of course, DSA then turns around and calls the variable-time BN_mod
immediately afterwards anyway. But the DSA is deprecated and doomed to
be removed someday anyway.

Change-Id: Iac1dab22aa51c0e7f5ca0f7f44a026a242a4eaa2
Reviewed-on: https://boringssl-review.googlesource.com/25284
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-06 00:51:54 +00:00
David Benjamin 08805fe279 Normalize RSA private component widths.
d, dmp1, dmq1, and iqmp have private magnitudes. This is awkward because
the RSAPrivateKey serialization leaks the magnitudes. Do the best we can
and fix them up before any RSA operations.

This moves the piecemeal BN_MONT_CTX_set_locked into a common function
where we can do more complex canonicalization on the keys.  Ideally this
would be done on key import, but the exposed struct (and OpenSSL 1.1.0's
bad API design) mean there is no single point in time when key import is
finished.

Also document the constraints on RSA_set0_* functions. (These
constraints aren't new. They just were never documented before.)

Update-Note: If someone tried to use an invalid RSA key where d >= n,
   dmp1 >= p, dmq1 >= q, or iqmp >= p, this may break. Such keys would not
   have passed RSA_check_key, but it's possible to manually assemble
   keys that bypass it.
Bug: 232
Change-Id: I421f883128952f892ac0cde0d224873a625f37c5
Reviewed-on: https://boringssl-review.googlesource.com/25259
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-05 23:58:53 +00:00
David Benjamin c7b6e0a664 Don't leak widths in bn_mod_mul_montgomery_fallback.
The fallback functions still themselves leak, but I've left TODOs there.

This only affects BN_mod_mul_montgomery on platforms where we don't use
the bn_mul_mont assembly, but BN_mul additionally affects the final
multiplication in RSA CRT.

Bug: 232
Change-Id: Ia1ae16162c38e10c056b76d6b2afbed67f1a5e16
Reviewed-on: https://boringssl-review.googlesource.com/25260
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-05 23:57:03 +00:00
David Benjamin 08d774a45f Remove some easy bn_set_minimal_width calls.
Functions that deserialize from bytes and Montgomery multiplication have
no reason to minimize their inputs.

Bug: 232
Change-Id: I121cc9b388033d684057b9df4ad0c08364849f58
Reviewed-on: https://boringssl-review.googlesource.com/25258
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-05 23:47:14 +00:00
David Benjamin 09633cc34e Rename bn->top to bn->width.
This has no behavior change, but it has a semantic one. This CL is an
assertion that all BIGNUM functions tolerate non-minimal BIGNUMs now.
Specifically:

- Functions that do not touch top/width are assumed to not care.

- Functions that do touch top/width will be changed by this CL. These
  should be checked in review that they tolerate non-minimal BIGNUMs.

Subsequent CLs will start adjusting the widths that BIGNUM functions
output, to fix timing leaks.

Bug: 232
Change-Id: I3a2b41b071f2174452f8d3801bce5c78947bb8f7
Reviewed-on: https://boringssl-review.googlesource.com/25257
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-05 23:44:24 +00:00
David Benjamin 23223ebbc1 Tidy BN_bn2hex and BN_print with non-minimal inputs.
These actually work as-is, but BN_bn2hex allocates more memory than
necessary, and we may as well skip the unnecessary words where we can.
Also add a test for this.

Bug: 232
Change-Id: Ie271fe9f3901d00dd5c3d7d63c1776de81a10ec7
Reviewed-on: https://boringssl-review.googlesource.com/25304
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-05 23:18:33 +00:00
David Benjamin cb4e300f17 Store EC field and orders in minimal form.
The order (and later the field) are used to size stack-allocated fixed
width word arrays. They're also entirely public, so this is fine.

Bug: 232
Change-Id: Ie98869cdbbdfea92dcad64a300f7e0b47bef6bf2
Reviewed-on: https://boringssl-review.googlesource.com/25256
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-05 23:17:34 +00:00
David Benjamin 226b4b51b5 Make the rest of BIGNUM accept non-minimal values.
Test this by re-running bn_tests.txt tests a lot. For the most part,
this was done by scattering bn_minimal_width or bn_correct_top calls as
needed. We'll incrementally tease apart the functions that need to act
on non-minimal BIGNUMs in constant-time.

BN_sqr was switched to call bn_correct_top at the end, rather than
sample bn_minimal_width, in anticipation of later splitting it into
BN_sqr (for calculators) and BN_sqr_fixed (for BN_mod_mul_montgomery).

BN_div_word also uses bn_correct_top because it calls BN_lshift so
officially shouldn't rely on BN_lshift returning something
minimal-width, though I expect we'd want to split off a BN_lshift_fixed
than change that anyway?

The shifts sample bn_minimal_width rather than bn_correct_top because
they all seem to try to be very clever around the bit width. If we need
constant-time versions of them, we can adjust them later.

Bug: 232
Change-Id: Ie17b39034a713542dbe906cf8954c0c5483c7db7
Reviewed-on: https://boringssl-review.googlesource.com/25255
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-02-05 23:05:34 +00:00
Adam Langley 45210dd4e2 Tidy up |ec_GFp_simple_point2oct| and friend.
(Just happened to see these as I went by.)

Change-Id: I348b163e6986bfca8b58e56885c35a813efe28f6
Reviewed-on: https://boringssl-review.googlesource.com/25725
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-05 04:40:59 +00:00
Adam Langley 2044181e01 Set output point to the generator when not on the curve.
Processing off-curve points is sufficiently dangerous to worry about
code that doesn't check the return value of
|EC_POINT_set_affine_coordinates| and |EC_POINT_oct2point|. While we
have integrated on-curve checks into these functions, code that ignores
the return value will still be able to work with an invalid point
because it's already been installed in the output by the time the check
is done.

Instead, in the event of an off-curve point, set the output point to the
generator, which is certainly on the curve and hopefully safe.

Change-Id: Ibc73dceb2d8d21920e07c4f6def2c8249cb78ca0
Reviewed-on: https://boringssl-review.googlesource.com/25724
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-05 02:03:29 +00:00
Adam Langley a312391050 cavp_tlskdf_test.cc: include errno.h since errno is referenced.
Change-Id: Id2d9923b3f0984be995a8057f60e714946f0f0b2
Reviewed-on: https://boringssl-review.googlesource.com/25664
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-02 22:50:27 +00:00
Adam Langley 091b455f09 Support running CAVP tests on an Android device.
This change allows run_cavp.go to execute tests on a connected Android
device and collect the results.

Change-Id: Ica83239c58d83907b82c591c4873a3de4ba0b3c0
Reviewed-on: https://boringssl-review.googlesource.com/25604
Reviewed-by: David Benjamin <davidben@google.com>
2018-02-02 22:34:17 +00:00
Adam Langley 472ba2c2dd Require that Ed25519 |s| values be < order.
https://tools.ietf.org/html/rfc8032#section-5.1.7 adds this requirement
to prevent signature malleability.

Change-Id: Iac9a3649d97fc69e6efb4aea1ab1e002768fadc9
Reviewed-on: https://boringssl-review.googlesource.com/25564
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-02-02 20:45:08 +00:00
David Benjamin f4b708cc1e Add a function which folds BN_MONT_CTX_{new,set} together.
These empty states aren't any use to either caller or implementor.

Change-Id: If0b748afeeb79e4a1386182e61c5b5ecf838de62
Reviewed-on: https://boringssl-review.googlesource.com/25254
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 20:23:25 +00:00
David Benjamin feffb87168 Make BN_bn2bin_padded work with non-minimal BIGNUMs.
Checking the excess words for zero doesn't need to be in constant time,
but it's free. BN_bn2bin_padded is a little silly as read_word_padded
only exists to work around bn->top being minimal. Once non-minimal
BIGNUMs are turned on and the RSA code works right, we can simplify
BN_bn2bin_padded.

Bug: 232
Change-Id: Ib81e30ca1e5a8ea90ab3278bf4ded219bac481ac
Reviewed-on: https://boringssl-review.googlesource.com/25253
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 20:16:50 +00:00
David Benjamin 385e4e9d98 Handle directive arguments with * in them.
Some of the CFI directives from upstream include expressions such as:

   .cfi_adjust_cfa_offset 32*5+8

(Also the latest version of peg moves the go generate line to
delocate.peg.go.)

Change-Id: I21bdf9ae44f81e4eca7b3565c4581a670f621a80
Reviewed-on: https://boringssl-review.googlesource.com/25624
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 19:59:06 +00:00
David Benjamin 6c41465548 Remove redundant bn->top computation.
One less to worry about.

Bug: 232
Change-Id: Ib7d38e18fee02590088d76363e17f774cfefa59b
Reviewed-on: https://boringssl-review.googlesource.com/25252
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 18:54:09 +00:00
David Benjamin 7979dbede2 Use bn_resize_words in BN_from_montgomery_word.
Saves a bit of work, and we get a width sanity-check.

Bug: 232
Change-Id: I1c6bc376c9d8aaf60a078fdc39f35b6f44a688c6
Reviewed-on: https://boringssl-review.googlesource.com/25251
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 18:52:49 +00:00
David Benjamin 76ce04bec8 Fix up BN_MONT_CTX_set with non-minimal values.
Give a non-minimal modulus, there are two possible values of R we might
pick: 2^(BN_BITS2 * width) or 2^(BN_BITS2 * bn_minimal_width).
Potentially secret moduli would make the former attractive and things
might even work, but our only secret moduli (RSA) have public bit
widths. It's more cases to test and the usual BIGNUM invariant is that
widths do not affect numerical output.

Thus, settle on minimizing mont->N for now. With the top explicitly made
minimal, computing |lgBigR| is also a little simpler.

This CL also abstracts out the < R check in the RSA code, and implements
it in a width-agnostic way.

Bug: 232
Change-Id: I354643df30530db7866bb7820e34241d7614f3c2
Reviewed-on: https://boringssl-review.googlesource.com/25250
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 18:52:15 +00:00
David Benjamin 0758b6837e Reject negative numbers in BN_{mod_mul,to,from}_montgomery.
These functions already require their inputs to be reduced mod N (or, in
some cases, bounded by R or N*R), so negative numbers are nonsense.  The
code still attempted to account for them by working on the absolute
value and fiddling with the sign bit. (The output would be in range (-N,
N) instead of [0, N).)

This complicates relaxing bn_correct_top because bn_correct_top is also
used to prevent storing a negative zero. Instead, just reject negative
inputs.

Upgrade-Note: These functions are public API, so some callers may
    notice. Code search suggests there is only one caller outside
    BoringSSL, and it looks fine.

Bug: 232
Change-Id: Ieba3acbb36b0ff6b72b8ed2b14882ec9b88e4665
Reviewed-on: https://boringssl-review.googlesource.com/25249
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 18:44:54 +00:00
David Benjamin 9a5bfc0350 Tidy up BN_mod_mul_montgomery.
This matches bn_mod_mul_montgomery_small and removes a bit of
unnecessary stuttering.

Change-Id: Ife249c6e8754aef23c144dbfdea5daaf7ed9f48a
Reviewed-on: https://boringssl-review.googlesource.com/25248
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 18:44:01 +00:00
David Benjamin 2ccdf584aa Factor out BN_to_montgomery(1) optimization.
This cuts down on a duplicated place where we mess with bn->top. It also
also better abstracts away what determines the value of R.

(I ordered this wrong and rebasing will be annoying. Specifically, the
question is what happens if the modulus is non-minimal. In
https://boringssl-review.googlesource.com/c/boringssl/+/25250/, R will
be determined by the stored width of mont->N, so we want to use mont's
copy of the modulus. Though, one way or another, the important part is
that it's inside the Montgomery abstraction.)

Bug: 232
Change-Id: I74212e094c8a47f396b87982039e49048a130916
Reviewed-on: https://boringssl-review.googlesource.com/25247
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 18:42:39 +00:00
David Benjamin dc8b1abb75 Do RSA sqrt(2) business in BIGNUM.
This is actually a bit more complicated (the mismatching widths cases
will never actually happen in RSA), but it's easier to think about and
removes more width-sensitive logic.

Bug: 232
Change-Id: I85fe6e706be1f7d14ffaf587958e930f47f85b3c
Reviewed-on: https://boringssl-review.googlesource.com/25246
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 18:32:32 +00:00
David Benjamin 43cf27e7d7 Add bn_copy_words.
This makes it easier going to and from non-minimal BIGNUMs and words
without worrying about the widths which are ultimately to become less
friendly.

Bug: 232
Change-Id: Ia57cb29164c560b600573c27b112ad9375a86aad
Reviewed-on: https://boringssl-review.googlesource.com/25245
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 18:24:39 +00:00
David Benjamin ad5cfdf541 Add initial support for non-minimal BIGNUMs.
Thanks to Andres Erbsen for extremely helpful suggestions on how finally
plug this long-standing hole!

OpenSSL BIGNUMs are currently minimal-width, which means they cannot be
constant-time. We'll need to either excise BIGNUM from RSA and EC or
somehow fix BIGNUM. EC_SCALAR and later EC_FELEM work will excise it
from EC, but RSA's BIGNUMs are more transparent.  Teaching BIGNUM to
handle non-minimal word widths is probably simpler.

The main constraint is BIGNUM's large "calculator" API surface. One
could, in theory, do arbitrary math on RSA components, which means all
public functions must tolerate non-minimal inputs. This is also useful
for EC; https://boringssl-review.googlesource.com/c/boringssl/+/24445 is
silly.

As a first step, fix comparison-type functions that were assuming
minimal BIGNUMs. I've also added bn_resize_words, but it is testing-only
until the rest of the library is fixed.

bn->top is now a loose upper bound we carry around. It does not affect
numerical results, only performance and secrecy. This is a departure
from the original meaning, and compiler help in auditing everything is
nice, so the final change in this series will rename bn->top to
bn->width. Thus these new functions are named per "width", not "top".

Looking further ahead, how are output BIGNUM widths determined? There's
three notions of correctness here:

1. Do I compute the right answer for all widths?

2. Do I handle secret data in constant time?

3. Does my memory usage not balloon absurdly?

For (1), a BIGNUM function must give the same answer for all input
widths. BN_mod_add_quick may assume |a| < |m|, but |a| may still be
wider than |m| by way of leading zeres. The simplest approach is to
write code in a width-agnostic way and rely on functions to accept all
widths. Where functions need to look at bn->d, we'll a few helper
functions to smooth over funny widths.

For (2), (1) is little cumbersome. Consider constant-time modular
addition. A sane type system would guarantee input widths match. But C
is weak here, and bifurcating the internals is a lot of work. Thus, at
least for now, I do not propose we move RSA's internal computation out
of BIGNUM. (EC_SCALAR/EC_FELEM are valuable for EC because we get to
stack-allocate, curves were already specialized, and EC only has two
types with many operations on those types. None of these apply to RSA.
We've got numbers mod n, mod p, mod q, and their corresponding
exponents, each of which is used for basically one operation.)

Instead, constant-time BIGNUM functions will output non-minimal widths.
This is trivial for BN_bin2bn or modular arithmetic. But for BN_mul,
constant-time[*] would dictate r->top = a->top + b->top. A calculator
repeatedly multiplying by one would then run out of memory.  Those we'll
split into a private BN_mul_fixed for crypto, leaving BN_mul for
calculators. BN_mul is just BN_mul_fixed followed by bn_correct_top.

[*] BN_mul is not constant-time for other reasons, but that will be
fixed separately.

Bug: 232
Change-Id: Ide2258ae8c09a9a41bb71d6777908d1c27917069
Reviewed-on: https://boringssl-review.googlesource.com/25244
Reviewed-by: Adam Langley <agl@google.com>
2018-02-02 18:03:46 +00:00
David Benjamin 884086e0e2 Remove x86_64 x25519 assembly.
Now that we have 64-bit C code, courtesy of fiat-crypto, the tradeoff
for carrying the assembly changes:

Assembly:
Did 16000 Curve25519 base-point multiplication operations in 1059932us (15095.3 ops/sec)
Did 16000 Curve25519 arbitrary point multiplication operations in 1060023us (15094.0 ops/sec)

fiat64:
Did 39000 Curve25519 base-point multiplication operations in 1004712us (38817.1 ops/sec)
Did 14000 Curve25519 arbitrary point multiplication operations in 1006827us (13905.1 ops/sec)

The assembly is still about 9% faster than fiat64, but fiat64 gets to
use the Ed25519 tables for the base point multiplication, so overall it
is actually faster to disable the assembly:

>>> 1/(1/15094.0 + 1/15095.3)
7547.324986004976
>>> 1/(1/38817.1 + 1/13905.1)
10237.73016319501

(At the cost of touching a 30kB table.)

The assembly implementation is no longer pulling its weight. Remove it
and use the fiat code in all build configurations.

Change-Id: Id736873177d5568bb16ea06994b9fcb1af104e33
Reviewed-on: https://boringssl-review.googlesource.com/25524
Reviewed-by: Adam Langley <agl@google.com>
2018-02-01 21:44:58 +00:00
David Benjamin fa65113400 Push an error if custom private keys fail.
The private key callback may not push one of its own (it's possible to
register a custom error library and whatnot, but this is tedious). If
the callback does not push any, we report SSL_ERROR_SYSCALL. This is not
completely wrong, as "syscall" really means "I don't know, something you
gave me, probably the BIO, failed so I assume you know what happened",
but most callers just check errno. And indeed cert_cb pushes its own
error, so this probably should as well.

Update-Note: Custom private key callbacks which push an error code on
    failure will report both that error followed by
    SSL_R_PRIVATE_KEY_OPERATION_FAILED. Callbacks which did not push any
    error will switch from SSL_ERROR_SYSCALL to SSL_ERROR_SSL with
    SSL_R_PRIVATE_KEY_OPERATION_FAILED.

Change-Id: I7e90cd327fe0cbcff395470381a3591364a82c74
Reviewed-on: https://boringssl-review.googlesource.com/25544
Reviewed-by: Adam Langley <agl@google.com>
2018-02-01 21:43:42 +00:00
David Benjamin 48669209b7 Fix fuzzer mode suppressions.
All the patterns need to account for a possible "-Split" version now.

Change-Id: Ie1b38ce10777d61d70a4d5a8bb2d44cdc98e4bfb
Reviewed-on: https://boringssl-review.googlesource.com/25504
Reviewed-by: Adam Langley <agl@google.com>
2018-01-31 22:57:51 +00:00
Adam Langley ddb57cfb51 Add tests for split handshakes.
This change adds a couple of focused tests to ssl_test.cc, but also
programmically duplicates many runner tests in a split-handshake mode.

Change-Id: I9dafc8a394581e5daf1318722e1015de82117fd9
Reviewed-on: https://boringssl-review.googlesource.com/25388
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-01-31 22:33:42 +00:00
Adam Langley 3fe8fa74ac Add initial, experimental support for split handshakes.
Split handshakes allows the handshaking of a TLS connection to be
performed remotely. This encompasses not just the private-key and ticket
operations – support for that was already available – but also things
such as selecting the certificates and cipher suites.

The the comment block in ssl.h for details. This is highly experimental
and will change significantly before its settled.

Change-Id: I337bdfa4c3262169e9b79dd4e70b57f0d380fcad
Reviewed-on: https://boringssl-review.googlesource.com/25387
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
2018-01-31 22:24:17 +00:00
Steven Valdez 7e5dd25d47 Remove draft22 and experiment2.
Change-Id: I2486dc810ea842c534015fc04917712daa26cfde
Update-Note: Now that tls13_experiment2 is gone, the server should remove the set_tls13_variant call. To avoid further churn, we'll make the server default for future variants to be what we'd like to deploy.
Reviewed-on: https://boringssl-review.googlesource.com/25104
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-31 18:07:53 +00:00
Nick Harper 3c034b2cf3 Add support for QUIC transport params.
This adds support for sending the quic_transport_parameters
(draft-ietf-quic-tls) in ClientHello and EncryptedExtensions, as well as
reading the value sent by the peer.

Bug: boringssl:224
Change-Id: Ied633f557cb13ac87454d634f2bd81ab156f5399
Reviewed-on: https://boringssl-review.googlesource.com/24464
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-30 23:54:40 +00:00
David Benjamin a62dbf88d8 Move OPENSSL_FALLTHROUGH to internal headers.
Having it in base.h pollutes the global namespace a bit and, in
particular, causes clang to give unhelpful suggestions in consuming
projects.

Change-Id: I6ca1a88bdd1701f0c49192a0df56ac0953c7067c
Reviewed-on: https://boringssl-review.googlesource.com/25464
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-29 18:17:57 +00:00
Matthew Braithwaite 5301c10c53 ssl_verify_peer_cert: implement |SSL_VERIFY_NONE| as advertised.
Since SSL{,_CTX}_set_custom_verify take a |mode| parameter that may be
|SSL_VERIFY_NONE|, it should do what it says on the tin, which is to
perform verification and ignore the result.

Change-Id: I0d8490111fb199c6b325cc167cf205316ecd4b49
Reviewed-on: https://boringssl-review.googlesource.com/25224
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-26 22:42:17 +00:00
Adam Langley e8d2439cd3 Expose ssl_session_serialize to libssl.
This function can serialise a session to a |CBB|.

Change-Id: Icdb7aef900f03f947c3fa4625dd218401eb8eafc
Reviewed-on: https://boringssl-review.googlesource.com/25385
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-26 22:31:47 +00:00
David Benjamin 0ab3f0ca25 Notice earlier if a server echoes the TLS 1.3 compatibility session ID.
Mono's legacy TLS 1.0 stack, as a server, does not implement any form of
resumption, but blindly echos the ClientHello session ID in the
ServerHello for no particularly good reason.

This is invalid, but due to quirks of how our client checked session ID
equality, we only noticed on the second connection, rather than the
first. Flaky failures do no one any good, so break deterministically on
the first connection, when we realize something strange is going on.

Bug: chromium:796910
Change-Id: I1f255e915fcdffeafb80be481f6c0acb3c628846
Reviewed-on: https://boringssl-review.googlesource.com/25424
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
2018-01-26 21:53:27 +00:00
Adam Langley 0ab86cf6f9 Require only that the nonce be strictly monotonic in TLS's AES-GCM
Previously we required that the calls to TLS's AES-GCM use an
incrementing nonce. This change relaxes that requirement so that nonces
need only be strictly monotonic (i.e. values can now be skipped). This
still meets the uniqueness requirements of a nonce.

Change-Id: Ib649a58bb93bf4dc0e081de8a5971daefffe9c70
Reviewed-on: https://boringssl-review.googlesource.com/25384
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-26 20:09:44 +00:00
Adam Langley 449a9e6a9e Make the gdb window larger.
Running can spawn gdb in an xterm, but the default xterm is rather
small. We could have everyone set their .Xdefaults, I presume, to solve
this, but very few people are running the old xterm these days.

Change-Id: I46eb3ff22f292eb44ce8c5124e83f1ab8aef9547
Reviewed-on: https://boringssl-review.googlesource.com/24846
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-26 19:59:23 +00:00
Adam Langley ab5a947d8e Reslice TLS AEAD setup.
This change reslices how the functions that generate the key block and
initialise the TLS AEADs are cut. This makes future changes easier.

Change-Id: I7e0f7327375301bed96f33c195b80156db83ce6d
Reviewed-on: https://boringssl-review.googlesource.com/24845
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-26 19:48:03 +00:00
Adam Langley c61b577197 Add some more utility functions to bytestring.
Change-Id: I7932258890b0b2226ff6841af45926e1b11979ba
Reviewed-on: https://boringssl-review.googlesource.com/24844
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-25 23:51:36 +00:00
David Benjamin 5a869aa3e8 Documentation typo.
Change-Id: Ie2e90cba642f416d3845171c96a3743846817657
Reviewed-on: https://boringssl-review.googlesource.com/25264
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-25 14:47:06 +00:00
David Benjamin 610cdbb102 Switch some ints to bools and Spans.
Change-Id: I505b29ae20fb660229900c4e046a0b1e5606d02c
Reviewed-on: https://boringssl-review.googlesource.com/25164
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
2018-01-24 19:24:07 +00:00
David Benjamin 32b5940267 Don't leak the exponent bit width in BN_mod_exp_mont_consttime.
(See also https://github.com/openssl/openssl/pull/5154.)

The exponent here is one of d, dmp1, or dmq1 for RSA. This value and its
bit length are both secret. The only public upper bound is the bit width
of the corresponding modulus (RSA n, p, and q, respectively).

Although BN_num_bits is constant-time (sort of; see bn_correct_top notes
in preceding patch), this does not fix the root problem, which is that
the windows are based on the minimal bit width, not the upper bound. We
could use BN_num_bits(m), but BN_mod_exp_mont_consttime is public API
and may be called with larger exponents. Instead, use all top*BN_BITS2
bits in the BIGNUM. This is still sensitive to the long-standing
bn_correct_top leak, but we need to fix that regardless.

This may cause us to do a handful of extra multiplications for RSA keys
which are just above a whole number of words, but that is not a standard
RSA key size.

Change-Id: I5e2f12b70c303b27c597a7e513b7bf7288f7b0e3
Reviewed-on: https://boringssl-review.googlesource.com/25185
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 22:27:37 +00:00
David Benjamin cb1ad205d0 Use 51-bit limbs from fiat-crypto in 64-bit.
Our 64-bit performance was much lower than it could have been, since we
weren't using the 64-bit multipliers. Fortunately, fiat-crypto is
awesome, so this is just a matter of synthesizing new code and
integration work.

Functions without the signature fiat-crypto curly braces were written by
hand and warrant more review. (It's just redistributing some bits.)

These use the donna variants which takes (and proves) some of the
instruction scheduling from donna as that's significantly faster.
Glancing over things, I suspect but have not confirmed the gap is due to
this:
https://github.com/mit-plv/fiat-crypto/pull/295#issuecomment-356892413

Clang without OPENSSL_SMALL (ECDH omitted since that uses assembly and
is unaffected by this CL).

Before:
Did 105149 Ed25519 key generation operations in 5025208us (20924.3 ops/sec)
Did 125000 Ed25519 signing operations in 5024003us (24880.6 ops/sec)
Did 37642 Ed25519 verify operations in 5072539us (7420.7 ops/sec)

After:
Did 206000 Ed25519 key generation operations in 5020547us (41031.4 ops/sec)
Did 227000 Ed25519 signing operations in 5005232us (45352.5 ops/sec)
Did 69840 Ed25519 verify operations in 5004769us (13954.7 ops/sec)

Clang + OPENSSL_SMALL:

Before:
Did 68598 Ed25519 key generation operations in 5024629us (13652.4 ops/sec)
Did 73000 Ed25519 signing operations in 5067837us (14404.6 ops/sec)
Did 36765 Ed25519 verify operations in 5078684us (7239.1 ops/sec)
Did 74000 Curve25519 base-point multiplication operations in 5016465us (14751.4 ops/sec)
Did 45600 Curve25519 arbitrary point multiplication operations in 5034680us (9057.2 ops/sec)

After:
Did 117315 Ed25519 key generation operations in 5021860us (23360.9 ops/sec)
Did 126000 Ed25519 signing operations in 5003521us (25182.3 ops/sec)
Did 64974 Ed25519 verify operations in 5047790us (12871.8 ops/sec)
Did 134000 Curve25519 base-point multiplication operations in 5058946us (26487.7 ops/sec)
Did 86000 Curve25519 arbitrary point multiplication operations in 5050478us (17028.1 ops/sec)

GCC without OPENSSL_SMALL (ECDH omitted since that uses assembly and
is unaffected by this CL).

Before:
Did 35552 Ed25519 key generation operations in 5030756us (7066.9 ops/sec)
Did 38286 Ed25519 signing operations in 5001648us (7654.7 ops/sec)
Did 10584 Ed25519 verify operations in 5068158us (2088.3 ops/sec)

After:
Did 92158 Ed25519 key generation operations in 5024021us (18343.5 ops/sec)
Did 99000 Ed25519 signing operations in 5011908us (19753.0 ops/sec)
Did 31122 Ed25519 verify operations in 5069878us (6138.6 ops/sec)

Change-Id: Ic0c24d50b4ee2bbc408b94965e9d63319936107d
Reviewed-on: https://boringssl-review.googlesource.com/24805
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 22:25:07 +00:00
David Benjamin a1bc1ba47c Fix up CTR_DRBG_update comment.
The original comment was a little confusing. Also lowercase
CTR_DRBG_update to make our usual naming for static functions.

Bug: 227
Change-Id: I381c7ba12b788452d54520b7bc3b13bba8a59f2d
Reviewed-on: https://boringssl-review.googlesource.com/25204
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 22:19:03 +00:00
David Benjamin 8017cdde38 Make BN_num_bits_word constant-time.
(The BN_num_bits_word implementation was originally written by Andy
Polyakov for OpenSSL. See also
https://github.com/openssl/openssl/pull/5154.)

BN_num_bits, by way of BN_num_bits_word, currently leaks the
most-significant word of its argument via branching and memory access
pattern.

BN_num_bits is called on RSA prime factors in various places. These have
public bit lengths, but all bits beyond the high bit are secret. This
fully resolves those cases.

There are a few places where BN_num_bits is called on an input where
the bit length is also secret. The two left in BoringSSL are:

- BN_mod_exp_mont_consttime calls it on the RSA private exponent.

- The timing "fix" to add the order to k in DSA.

This does *not* fully resolve those cases as we still only look at the
top word. Today, that is guaranteed to be non-zero, but only because of
the long-standing bn_correct_top timing leak. Once that is fixed (I hope
to have patches soon), a constant-time BN_num_bits on such inputs must
count bits on each word.

Instead, those cases should not call BN_num_bits at all. The former uses
the bit width to pick windows, but it should be using the maximum bit
width. The next patch will fix this.  The latter is the same "fix" we
excised from ECDSA in a838f9dc7e.  That
should be excised from DSA after the bn_correct_top bug is fixed.

Thanks to Dinghao Wu, Danfeng Zhang, Shuai Wang, Pei Wang, and Xiao Liu
for reporting this issue.

Change-Id: Idc3da518cc5ec18bd8688b95f959b15300a57c14
Reviewed-on: https://boringssl-review.googlesource.com/25184
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 22:14:54 +00:00
David Benjamin b9f30bb6fe Unwind total_num from wNAF_mul.
The EC_POINTs are still allocated (for now), but everything else fits on
the stack nicely, which saves a lot of fiddling with cleanup and
allocations.

Change-Id: Ib8480737ecc97e6b40b2c05f217cd8d3dc82cb72
Reviewed-on: https://boringssl-review.googlesource.com/25150
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 22:04:58 +00:00
David Benjamin d86c0d2889 Pull the malloc out of compute_wNAF.
This is to simplify clearing unnecessary mallocs out of ec_wNAF_mul, and
perhaps to use it in tuned variable-time multiplication functions.

Change-Id: Ic390d2e8e20d0ee50f3643830a582e94baebba95
Reviewed-on: https://boringssl-review.googlesource.com/25149
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 21:53:58 +00:00
David Benjamin 6ca09409cc Always compute the maximum-length wNAF.
This cuts out another total_num-length array and simplifies things.
Leading zeros at the front of the schedule don't do anything, so it's
easier to just produce a fixed-length one. (I'm also hoping to
ultimately reuse this function in //third_party/fiat/p256.c and get the
best of both worlds for ECDSA verification; tuned field arithmetic
operations, precomputed table, and variable-time multiply.)

Change-Id: I771f4ff7dcfdc3ee0eff8d9038d6dc9a0be3d4e0
Reviewed-on: https://boringssl-review.googlesource.com/25148
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 21:51:25 +00:00
David Benjamin a42d7bee85 Reorganize curve25519.c slightly.
Adding 51-bit limbs will require two implementations of most of the
field operations. Group them together to make this more manageable. Also
move the representation-independent functions to the end.

Change-Id: I264e8ac64318a1d5fa72e6ad6f7ccf2f0a2c2be9
Reviewed-on: https://boringssl-review.googlesource.com/24804
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 21:42:14 +00:00
David Benjamin 0c1eafc6fe Add additional constants to make_curve25519_tables.py.
These are also constants that depend on the field representation.

Change-Id: I22333c099352ad64eb27fe15ffdc38c6ae7c07ff
Reviewed-on: https://boringssl-review.googlesource.com/24746
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 21:35:03 +00:00
David Benjamin 522ad7e8fc Use EC_SCALAR for compute_wNAF.
Note this switches from walking BN_num_bits to the full bit length of
the scalar. But that can only cause it to add a few extra zeros to the
front of the schedule, which r_is_at_infinity will skip over.

Change-Id: I91e087c9c03505566b68f75fb37dfb53db467652
Reviewed-on: https://boringssl-review.googlesource.com/25147
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 21:34:50 +00:00
David Benjamin 338eeb0c4f Remove r_is_inverted logic.
This appears to be pointless. Before, we would have a 50% chance of
doing an inversion at each non-zero bit but the first
(r_is_at_infinity), plus a 50% chance of doing an inversion at the end.
Now we would have a 50% chance of doing an inversion at each non-zero
bit. That's the same number of coin flips.

Change-Id: I8158fd48601cb041188826d4f68ac1a31a6fbbbc
Reviewed-on: https://boringssl-review.googlesource.com/25146
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-23 21:29:13 +00:00
David Benjamin 2d77d4084a Generate curve25519 tables with a script.
This is to make it easier to add new field element representations. The
Ed25519 logic in the script is partially adapted from RFC 8032's Python
code, but I replaced the point addition logic with the naive textbook
formula since this script only cares about being obviously correct.

Change-Id: I0b90bf470993c177070fd1010ac5865fedb46c82
Reviewed-on: https://boringssl-review.googlesource.com/24745
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 21:21:54 +00:00
David Benjamin 042b49cf3c Extract curve25519 tables into a separate header.
This is in preparation for writing a script to generate them. I'm
manually moving the existing tables over so it will be easier to confirm
the script didn't change the values.

Change-Id: Id83e95c80d981e19d1179d45bf47559b3e1fc86e
Reviewed-on: https://boringssl-review.googlesource.com/24744
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 21:08:49 +00:00
David Benjamin 5d9408714c Remove unnecessary window size cases.
The optimization for wsize = 1 only kicks in for 19-bit primes. The
cases for b >= 800 and cannot happen due to EC_MAX_SCALAR_BYTES.

Change-Id: If5ca908563f027172cdf31c9a22342152fecd12f
Reviewed-on: https://boringssl-review.googlesource.com/25145
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 21:08:39 +00:00
David Benjamin 4111dd2fc2 Don't compute a per-scalar window size in wNAF code.
Simplify things slightly. The probability of the scalar being small
enough to go down a window size is astronomically small. (2^-186 for
P-256 and 2^-84 for P-384.)

Change-Id: Ie879f0b06bcfd1e6e6e3bf3f54e0d7d6567525a4
Reviewed-on: https://boringssl-review.googlesource.com/25144
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 21:06:42 +00:00
David Benjamin 186df3a655 Implement fe_sq2_tt with fe_sq_tt.
fiat-crypto only generates fe_mul and fe_sq, but the original Ed25519
implementation we had also had fe_sq2 for computing 2*f^2. Previously,
we inlined a version of fe_mul.

Instead, we could implement it with fe_sq and fe_add. Performance-wise,
this seems to not regress. If anything, it makes it faster?

Before (clang, run for 10 seconds):
Did 243000 Ed25519 key generation operations in 10025910us (24237.2 ops/sec)
Did 250000 Ed25519 signing operations in 10035580us (24911.4 ops/sec)
Did 73305 Ed25519 verify operations in 10071101us (7278.7 ops/sec)
Did 184000 Curve25519 base-point multiplication operations in 10040138us (18326.4 ops/sec)
Did 186000 Curve25519 arbitrary point multiplication operations in 10052721us (18502.5 ops/sec)

After (clang, run for 10 seconds):
Did 242424 Ed25519 key generation operations in 10013117us (24210.6 ops/sec)
Did 253000 Ed25519 signing operations in 10011744us (25270.3 ops/sec)
Did 73899 Ed25519 verify operations in 10048040us (7354.6 ops/sec)
Did 194000 Curve25519 base-point multiplication operations in 10005389us (19389.6 ops/sec)
Did 195000 Curve25519 arbitrary point multiplication operations in 10028443us (19444.7 ops/sec)

Before (clang + OPENSSL_SMALL, run for 10 seconds):
Did 144000 Ed25519 key generation operations in 10019344us (14372.2 ops/sec)
Did 146000 Ed25519 signing operations in 10011653us (14583.0 ops/sec)
Did 74052 Ed25519 verify operations in 10005789us (7400.9 ops/sec)
Did 150000 Curve25519 base-point multiplication operations in 10007468us (14988.8 ops/sec)
Did 91392 Curve25519 arbitrary point multiplication operations in 10057678us (9086.8 ops/sec)

After (clang + OPENSSL_SMALL, run for 10 seconds):
Did 144000 Ed25519 key generation operations in 10066724us (14304.6 ops/sec)
Did 148000 Ed25519 signing operations in 10062043us (14708.7 ops/sec)
Did 74820 Ed25519 verify operations in 10058557us (7438.4 ops/sec)
Did 151000 Curve25519 base-point multiplication operations in 10063492us (15004.7 ops/sec)
Did 90402 Curve25519 arbitrary point multiplication operations in 10049141us (8996.0 ops/sec)

Change-Id: I31e9f61833492c3ff2dfd78e1dee5e06f43c850f
Reviewed-on: https://boringssl-review.googlesource.com/24724
Reviewed-by: Adam Langley <agl@google.com>
2018-01-23 20:49:50 +00:00
David Benjamin a7bc94489f Don't use the client_random entropy for GREASE.
No sense in tempting middleboxes unnecessarily.

Change-Id: Iec66f77195f6b8aa62be681917342e59eb7aba31
Reviewed-on: https://boringssl-review.googlesource.com/24964
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
2018-01-23 19:10:40 +00:00
David Benjamin 44fd6eeef5 Split BORINGSSL_self_test into its own file.
Some non-FIPS consumers exclude bcm.c and build each fragment file
separately. This means non-FIPS code cannot live in bcm.c.
https://boringssl-review.googlesource.com/25044 made the self-test
function exist outside of FIPS code, so it needed to be moved into is
own file.

To avoid confusing generate_build_files.py, this can't be named
self_test.c, so I went with self_check.c.

Change-Id: I337b39b158bc50d6ca0a8ad1b6e15eb851095e1e
Reviewed-on: https://boringssl-review.googlesource.com/25124
Reviewed-by: Martin Kreichgauer <martinkr@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-22 23:06:41 +00:00
Martin Kreichgauer 98e24197ee add missing #includes
Change-Id: Ib067411d4cafe1838c2dc42fc8bfd9011490f45c
Reviewed-on: https://boringssl-review.googlesource.com/25064
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-22 21:54:08 +00:00
Shenghua Zhang a4f78775b9 [ndk] Change ndk deps in src and relocate to third_party/boringssl
Because the android sdk managed by CIPD (see go/use-adjective-apis),
its deps repo ndk needs to be relocated, as well as hooked by the root
DEPS instead of recursedeps. This CL addes android ndk deps in
util/bot/DEPS.

Bug: chromium:659808
Change-Id: I270053ae56ba1caaf9c67f2240855eafd499b782
Reviewed-on: https://boringssl-review.googlesource.com/24864
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-22 21:08:28 +00:00
Steven Valdez cb15cfda29 Add draft23 tests.
Change-Id: Ic77bc2f55e1e997ea20641cae66b0deddf1ef99c
Reviewed-on: https://boringssl-review.googlesource.com/25084
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-22 20:29:38 +00:00
Adam Langley f2e7b220c0 Extract FIPS KAT tests into a function.
This change adds |BORINGSSL_self_test|, which allows applications to run
the FIPS KAT tests on demand, even in non-FIPS builds.

Change-Id: I950b30a02ab030d5e05f2d86148beb4ee1b5929c
Reviewed-on: https://boringssl-review.googlesource.com/25044
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-22 20:16:38 +00:00
Nick Harper 36fcc4ca5d Implement Token Binding
Update-Note: Token Binding can no longer be configured with the custom
  extensions API. Instead, use the new built-in implementation. (The
  internal repository should be all set.)

Bug: 183

Change-Id: I007523a638dc99582ebd1d177c38619fa7e1ac38
Reviewed-on: https://boringssl-review.googlesource.com/20645
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-22 20:08:28 +00:00
David Benjamin 8d67f6f0cf Update tools.
This is a reland 9d1f96606c, which should
hopefuly be fine after afd1cd959e. Though
I've also gone ahead and gotten the latest versions of things.
(android_tools and clang updated.)

In particular, get the new NDK. Unfortunately, the new clang picks up
an unfortunate change for clang-cl that we now must work around.

http://llvm.org/viewvc/llvm-project?view=revision&revision=319116

Bug: 109
Change-Id: If19b09c585957fefaffa8c3197a50189402a555a
Reviewed-on: https://boringssl-review.googlesource.com/25025
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-22 18:30:18 +00:00
David Benjamin 017fbf0940 Fix sort order.
Change-Id: I459637397429109a2314355b571a42a61cb9dd49
Reviewed-on: https://boringssl-review.googlesource.com/25024
Commit-Queue: David Benjamin <davidben@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-22 18:13:38 +00:00
Adam Langley 05a8434484 Support AVX-512 instructions with a writemask in delocate.
AVX-512 adds a new text instruction syntax to x86-64 assembly to specify
the writemask registers and the merge-masking vs zeroing-masking signal.

This change causes these tokens to be passed through.

Patch by Jeff McDonald.

Change-Id: Ib15b15ac684183cc5fba329a176b63b477bc24a3
Reviewed-on: https://boringssl-review.googlesource.com/24945
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-22 18:00:18 +00:00
David Benjamin bb1e5cbbe3 Use -gcv8 instead of -g cv8.
yasm accepts both, but nasm reportedly only accepts the former.

Change-Id: Iddcd33daac3f9063b4ddd50d82503b1984391c08
Reviewed-on: https://boringssl-review.googlesource.com/25004
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-22 16:11:38 +00:00
Frederik Kriewitz 5ab5484044 Support |alignof|/|alignas| in GCC 4.7.
(Note that support for GCC 4.7 ends 2018-03-23.)

Change-Id: Ia2ac6a735c8177a2b3a13f16197ff918266bc1cb
Reviewed-on: https://boringssl-review.googlesource.com/24924
Reviewed-by: Adam Langley <agl@google.com>
2018-01-20 02:04:57 +00:00
Adam Langley c7ef069ac9 Fix format-string error in delocate.go.
Errorf treats its argument as a format string and so “%rax” is a
problem.

Change-Id: I863ef361f07d0b8a348994efe45869202d0b31f1
Reviewed-on: https://boringssl-review.googlesource.com/24944
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-18 19:08:50 +00:00
Adam Langley 37c6eb4284 Support TLS KDF test for NIAP.
NIAP requires that the TLS KDF be tested by CAVP so this change moves
the PRF into crypto/fipsmodule/tls and adds a test harness for it. Like
the KAS tests, this is only triggered when “-niap” is passed to
run_cavp.go.

Change-Id: Iaa4973d915853c8e367e6106d829e44fcf1b4ce5
Reviewed-on: https://boringssl-review.googlesource.com/24666
Reviewed-by: Adam Langley <agl@google.com>
2018-01-16 22:57:17 +00:00
Adam Langley e80c7c065c Support KAS tests for NIAP.
This change adds support for two specific CAVP tests, in order to
meet NIAP requirements.

These tests are currently only run when “-niap” is passed to run_cavp.go
because they are not part of our FIPS validation (yet).

Change-Id: I511279651aae094702332130fac5ab64d11ddfdb
Reviewed-on: https://boringssl-review.googlesource.com/24665
Reviewed-by: Adam Langley <agl@google.com>
2018-01-16 22:57:01 +00:00
Adam Langley 92b8ecdd0d Change from configuring a FAX scanner function to a FAX next-line function.
In order to process some NIST FAX files, we needed to implement a custom
scanner function to skip over lines that are effectively comments, but
not marked as such.

In the near future we'll need to process KAS FAX files, for which we
need not only to skip over unmarked comment lines, but also to skip some
lines of the response which the FAX doesn't include.

For this we need a more powerful callback function, which this change
provides.

Change-Id: Ibb12b97ac65b3e85317d2e97386ef1c2ea263d4b
Reviewed-on: https://boringssl-review.googlesource.com/24664
Reviewed-by: Adam Langley <agl@google.com>
2018-01-16 22:56:50 +00:00
David Benjamin afd1cd959e Work around an NDK / Android bug.
The NDK r16 sometimes generates binaries with the DF_1_PIE, which the
runtime linker on Android N complains about. The next NDK revision
should work around this but, in the meantime, strip its error out.

https://github.com/android-ndk/ndk/issues/602
https://android-review.googlesource.com/c/platform/bionic/+/259790
https://android-review.googlesource.com/c/toolchain/binutils/+/571550

Change-Id: I99306d42f11179d5d19bd3f107a7386cc5c690db
Reviewed-on: https://boringssl-review.googlesource.com/24884
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-16 16:52:46 +00:00
Gabriel Redner 7c5e1400dd Fix reference to nonexistent function.
Change-Id: Ib02f1945117dfd7f7d46dbf0672091830c6f3481
Reviewed-on: https://boringssl-review.googlesource.com/24904
Reviewed-by: Adam Langley <agl@google.com>
2018-01-16 16:23:36 +00:00
David Benjamin 94cd196a80 Add files in third_party/fiat for Chromium to pick up.
Chromium's licenses.py is a little finicky.

Change-Id: I015a3565eb8f3cfecb357d142facc796a9c80888
Reviewed-on: https://boringssl-review.googlesource.com/24784
Reviewed-by: Adam Langley <agl@google.com>
2018-01-10 22:02:03 +00:00
David Benjamin b6317b98ee Update googletest.
The latest MSVC 2017 complains about std::tr1::tuple, which was fixed in
upstream GTest.

Upstream have also merged all our patches, we now no longer are carrying
a diff. (Thanks, Gennadiy!)

Change-Id: I6932687b8e8c1eff8c2edf42da0a12080e7b61dd
Reviewed-on: https://boringssl-review.googlesource.com/24685
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-10 12:11:44 +00:00
Alessandro Ghedini 11a5726ee3 tool: update selection of draft22 TLS 1.3 variant
Change-Id: I7085a07dd2f3d802ada049a2f771ff0c74f4f902
Reviewed-on: https://boringssl-review.googlesource.com/24764
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-10 12:08:54 +00:00
Adam Langley 512a289a8a Add support for dummy PQ padding.
This extension will be used to measure the latency impact of potentially
sending a post-quantum key share by default. At this time it's purely
measuring the impact of the client sending the key share, not the server
replying with a ciphertext.

We could use the existing padding extension for this but that extension
doesn't allow the server to echo it, so we would need a different
extension in the future anyway. Thus we just create one now.

We can assume that modern clients will be using TLS 1.3 by the time that
PQ key-exchange is established and thus the key share will be sent in
all ClientHello messages. However, since TLS 1.3 isn't quite here yet,
this extension is also sent for TLS 1.0–1.2 ClientHellos. The latency
impact should be the same either way.

Change-Id: Ie4a17551f6589b28505797e8c54cddbe3338dfe5
Reviewed-on: https://boringssl-review.googlesource.com/24585
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-10 00:27:31 +00:00
David Benjamin 3c92e80d7a Revert "Update tools."
This reverts commit 9d1f96606c.

Reason for revert: aarch64 bots are breaking for some reason.

Original change's description:
> Update tools.
> 
> In particular, get the new NDK. Unfortunately, the new clang picks up
> an unfortunate change for clang-cl that we now must work around.
> 
> http://llvm.org/viewvc/llvm-project?view=revision&revision=319116
> 
> Bug: 109
> Change-Id: I091ca7160683e70cd79b5c2b7a4267fea258ec17
> Reviewed-on: https://boringssl-review.googlesource.com/24644
> Reviewed-by: Steven Valdez <svaldez@google.com>
> Commit-Queue: David Benjamin <davidben@google.com>
> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>

TBR=davidben@google.com,svaldez@google.com

Change-Id: I98960f295987857c4e42c312059b6d5934bb5e43
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 109
Reviewed-on: https://boringssl-review.googlesource.com/24747
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-09 21:45:11 +00:00
David Benjamin 9d1f96606c Update tools.
In particular, get the new NDK. Unfortunately, the new clang picks up
an unfortunate change for clang-cl that we now must work around.

http://llvm.org/viewvc/llvm-project?view=revision&revision=319116

Bug: 109
Change-Id: I091ca7160683e70cd79b5c2b7a4267fea258ec17
Reviewed-on: https://boringssl-review.googlesource.com/24644
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-09 21:28:00 +00:00
David Benjamin 53ff70f68c Tidy up some warnings.
Updating clang seems to have upset the clang-cl build. I think because
they decided -Wall now matches MSVC's semantics, which is a little nuts.
Two of the warnings, however, weren't wrong, so fix those.

http://llvm.org/viewvc/llvm-project?view=revision&revision=319116

Change-Id: I168e52e4e70ca7b1069e0b0db241fb5305c12b1e
Reviewed-on: https://boringssl-review.googlesource.com/24684
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-09 16:01:32 +00:00
David Benjamin e2b8466fa7 Update CMake on Windows bots to 3.10.1.
The 3.10 update had to be rolled back due to a bug with clang-cl that
has since been fixed.

Change-Id: I31c28aedb533f20ab01f105f6f3f7b3ee9c91784
Reviewed-on: https://boringssl-review.googlesource.com/24324
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-09 15:56:42 +00:00
Steven Valdez 74666da5b3 Update key share extension number for draft23.
Change-Id: I7561fc7e04d726ea9e26f645da10e45b62a20627
Reviewed-on: https://boringssl-review.googlesource.com/24704
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-09 15:22:02 +00:00
David Benjamin 0c9b7b5de2 Align various point_get_affine_coordinates implementations.
The P-224 implementation was missing the optimization to avoid doing
extra work when asking for only one coordinate (ECDH and ECDSA both
involve an x-coordinate query). The P-256 implementation was missing the
optimization to do one less Montgomery reduction.

TODO - Benchmarks

Change-Id: I268d9c24737c6da9efaf1c73395b73dd97355de7
Reviewed-on: https://boringssl-review.googlesource.com/24690
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-08 20:03:42 +00:00
David Benjamin 9112631c1f Remove ftmp* comments from P-256 addition code.
These are remnants of the old code which had a bunch of ftmp variables.

Change-Id: Id14cf414cb67ff08e240970767f7a5a58e883ce4
Reviewed-on: https://boringssl-review.googlesource.com/24689
Reviewed-by: Adam Langley <agl@google.com>
2018-01-08 19:51:03 +00:00
David Benjamin 3ab6ad6abd Simplify EC_KEY_set_public_key_affine_coordinates.
EC_POINT_set_affine_coordinates_GFp already rejects coordinates which
are out of range. There's no need to double-check.

Change-Id: Id1685355c555dda66d2a14125cb0083342f37e53
Reviewed-on: https://boringssl-review.googlesource.com/24688
Reviewed-by: Adam Langley <agl@google.com>
2018-01-08 19:50:42 +00:00
David Benjamin 99084cdd76 Fold away ec_point_set_Jprojective_coordinates_GFp.
p224-64.c can just write straight into the EC_POINT, as the other files
do, which saves the mess around BN_CTX. It's also more correct.
ec_point_set_Jprojective_coordinates_GFp abstracts out field_encode, but
then we would want to abstract out field_decode too when reading.

That then allows us to inline ec_point_set_Jprojective_coordinates_GFp
into ec_GFp_simple_point_set_affine_coordinates and get rid of an
unnecessary tower of helper functions. Also we can use the precomputed
value of one rather than recompute it each time.

Change-Id: I8282dc66a4a437f5a3b6a1a59cc39be4cb71ccf9
Reviewed-on: https://boringssl-review.googlesource.com/24687
Reviewed-by: Adam Langley <agl@google.com>
2018-01-08 19:48:37 +00:00
David Benjamin 1eddb4be29 Make EC_POINT_set_compressed_coordinates_GFp use BIGNUM directly.
All the messing around with field_mul and field_sqr does the same thing
as calling EC_GROUP_get_curve_GFp. This is in preparation for ultimately
moving the field elements to an EC_FELEM type.

Where we draw the BIGNUM / EC_FELEM line determines what EC_FELEM
operations we need. Since we don't care much about the performance of
this function, leave it in BIGNUM so we don't need an EC_FELEM
BN_mod_sqrt just yet. We can push it down later if we feel so inclined.

Change-Id: Iec07240d40828df6b7a29fd1f430e3b390d5f506
Reviewed-on: https://boringssl-review.googlesource.com/24686
Reviewed-by: Adam Langley <agl@google.com>
2018-01-08 19:40:21 +00:00
Matthew Braithwaite 9770532afa Map NOT_YET_VALID errors to |certificate_expired|.
The language of RFC 5246 is "A certificate has expired or is not
currently valid", which sounds to me like |certificate_expired| should
pertain to any case where the current time is outside the
certificate's validity period.

Along the way, group the |unknown_ca| errors together.

Change-Id: I92c1fe3fc898283d0c7207625de36662cd0f784e
Reviewed-on: https://boringssl-review.googlesource.com/24624
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-05 23:40:40 +00:00
David Benjamin 92e332501a Add a function for encoding SET OF.
The Chromium certificate verifier ends up encoding a SET OF when
canonicalizing X.509 names. Requiring the caller canonicalize a SET OF
is complicated enough that we should probably sort it for folks. (We
really need to get this name canonicalization insanity out of X.509...)

This would remove the extra level of indirection in Chromium
net/cert/internal/verify_name_match.cc CBB usage.

Note this is not quite the same order as SET, but SET is kind of
useless. Since it's encoding heterogeneous values, it is reasonable to
require the caller just encode them in the correct order. In fact, a DER
SET is just SEQUENCE with a post-processing step on the definition to
fix the ordering of the fields. (Unless the SET contains an untagged
CHOICE, in which case the ordering is weird, but SETs are not really
used in the real world, much less SETs with untagged CHOICEs.)

Bug: 11
Change-Id: I51e7938a81529243e7514360f867330359ae4f2c
Reviewed-on: https://boringssl-review.googlesource.com/24444
Reviewed-by: Adam Langley <agl@google.com>
2018-01-05 23:39:02 +00:00
David Benjamin 00208b443c Use fiat-crypto's freeze function for fe_tobytes.
It requires a handful of additional intrinsics for now.

Fiat's freeze function only works on the tight bounds, so fe_isnonzero
gains an extra fe_carry. But all other calls of fe_tobytes are of tight
bounds anyway.

Change-Id: I834858cee7863c7344e456d7a7dbf4f414f04ae5
Reviewed-on: https://boringssl-review.googlesource.com/24545
Reviewed-by: Adam Langley <agl@google.com>
2018-01-05 23:38:26 +00:00
Adam Langley 2f9b47fb19 Better pack structs in ssl/internal.h
Change-Id: I632a5c9067860216f9252907b104ba605c33a50d
Reviewed-on: https://boringssl-review.googlesource.com/24584
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-04 21:08:36 +00:00
Marek Gilbert 11850d5f61 Rename all googletest CMake targets
CMake targets are visible globally but gtest_main has boringssl-specific
behavior that isn't appropriate for general use.

This change makes it possible to use boringssl and abseil-cpp in the
same project (since abseil-cpp expects gtest_main to exist and be useful
for its own tests).

Change-Id: Icc81c11b8bb4b1e21cea7c9fa725b6c082bd5369
Reviewed-on: https://boringssl-review.googlesource.com/24604
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-04 16:30:54 +00:00
David Benjamin 915c121bb5 Remove some outdated preconditions and postconditions.
These date to the old code and have been replaced by the fe and fe_loose
bounds in the header file. Also fix up a comment that the comment
converter didn't manage to convert.

Change-Id: I2e3ea867a8cea2b347d09c304a17e532b2e36545
Reviewed-on: https://boringssl-review.googlesource.com/24525
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-03 23:03:32 +00:00
David Benjamin 3144d92ab8 Add some missing array parameter length annotations.
Not that anything checks them...

Change-Id: Iae1b5dbdb3c20a9ebd841bcd32cc5c725c68eb01
Reviewed-on: https://boringssl-review.googlesource.com/24524
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-03 22:34:22 +00:00
David Benjamin d9f49974e3 Support high tag numbers in CBS/CBB.
This is a reland of https://boringssl-review.googlesource.com/2330. I
believe I've now cleared the fallout.

Android's attestion format uses some ludicrously large tag numbers:
https://developer.android.com/training/articles/security-key-attestation.html#certificate_schema

Add support for these in CBS/CBB. The public API does not change for
callers who were using the CBS_ASN1_* constants, but it is no longer the
case that tag representations match their DER encodings for small tag
numbers. When passing tags into CBS/CBB, use CBS_ASN1_* constants. When
working with DER byte arrays (most commonly test vectors), use the
numbers themselves.

Bug: 214
Update-Note: The in-memory representation of CBS/CBB tags changes.
   Additionally, we now support tag numbers above 30. I believe I've now
   actually cleared the fallout of the former. There is one test in
   Chromium and the same test in the internal repository that needs
   fixing.

Change-Id: I49b9d30df01f023c646d31156360ff69c91626a3
Reviewed-on: https://boringssl-review.googlesource.com/24404
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-03 22:28:32 +00:00
David Benjamin 5bcaa113e2 Tighten EC_KEY's association with its group.
This is to simplify
https://boringssl-review.googlesource.com/c/boringssl/+/24445/.

Setting or changing an EC_KEY's group after the public or private keys
have been configured is quite awkward w.r.t. consistency checks. It
becomes additionally messy if we mean to store private keys as
EC_SCALARs (and avoid the BIGNUM timing leak), whose size is
curve-dependent.

Instead, require that callers configure the group before setting either
half of the keypair. Additionally, reject EC_KEY_set_group calls that
change the group. This will simplify clearing one more BIGNUM timing
leak.

Update-Note: This will break code which sets the group and key in a
    weird order. I checked calls of EC_KEY_new and confirmed they all
    set the group first. If I missed any, let me know.

Change-Id: Ie89f90a318b31b6b98f71138e5ff3de5323bc9a6
Reviewed-on: https://boringssl-review.googlesource.com/24425
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-03 22:15:11 +00:00
Matthew Braithwaite e15019572b SSL_alert_from_verify_result: expose.
This function maps |X509_V_ERR_*| to SSL alarm codes.  It's used
internally when certs are verified with X509_verify_cert(), and is
helpful to callers who want to call that function, but who also want
to report its errors in a less implementation-dependent way.

Change-Id: I2900cce2eb631489f0947c317beafafd3ea57a75
Reviewed-on: https://boringssl-review.googlesource.com/24564
Commit-Queue: Matt Braithwaite <mab@google.com>
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-03 22:02:42 +00:00
Adam Langley ef16f19ef2 Support delocating vpbroadcastq.
(This can be generated with -mavx2.)

Change-Id: I6d92d9e93eb448357342ef86d050321f0ef40f9e
Reviewed-on: https://boringssl-review.googlesource.com/24504
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2018-01-02 21:06:52 +00:00
Adam Langley 380bc30f0c Fix |ASN1_INTEGER_set| when setting zero.
|ASN1_INTEGER_set| and |BN_to_ASN1_INTEGER| disagree about how to encode
zero. OpenSSL master has aligned around the behaviour of the latter
(i.e. a single zero byte) so fix |ASN1_INTEGER_set| to do that. (This is
also the form that DER requires.)

At the same time, fix undefined behaviour when negative a |long| whose
value is |LONG_MIN|.

Change-Id: I1198de35e61a286ac6472e99152f3d22fda59044
Reviewed-on: https://boringssl-review.googlesource.com/24485
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-02 16:11:31 +00:00
Adam Langley f8d05579b4 Add ASN1_INTEGET_set_uint64.
Change-Id: I3298875a376c98cbb60deb8c99b9548c84b014df
Reviewed-on: https://boringssl-review.googlesource.com/24484
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2018-01-02 16:01:31 +00:00
Andres Erbsen 0a54e99848 Add links to proofs of elliptic curve formulas.
Change-Id: I166f740185f26770b51759714efd5d634fbcc173
Reviewed-on: https://boringssl-review.googlesource.com/24424
Reviewed-by: David Benjamin <davidben@google.com>
2017-12-22 19:52:44 +00:00
David Benjamin 80ede1df8e Fix early_mac_len computation.
We would set it to block_size rather than zero. This doesn't cause
problems (the code behaves correctly with either value), but it is a
tiny missed optimization.

Change-Id: Ic751352750cc7ef74aa25a6cc96da82007199941
Reviewed-on: https://boringssl-review.googlesource.com/24364
Commit-Queue: David Benjamin <davidben@google.com>
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-21 21:41:39 +00:00
Andres Erbsen 36fce983b6 add fiat-crypto code generation readme
Change-Id: Ie4060121f6bc8da07d87db8ec8133ea17e99e1fe
Reviewed-on: https://boringssl-review.googlesource.com/24344
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-21 18:35:39 +00:00
David Benjamin 6df6540766 Add a draft TLS 1.3 anti-downgrade signal.
TLS 1.3 includes a server-random-based anti-downgrade signal, as a
workaround for TLS 1.2's ServerKeyExchange signature failing to cover
the entire handshake. However, because TLS 1.3 draft versions are each
doomed to die, we cannot deploy it until the final RFC. (Suppose a
draft-TLS-1.3 client checked the signal and spoke to a final-TLS-1.3
server. The server would correctly negotiate TLS 1.2 and send the
signal. But the client would then break. An anologous situation exists
with reversed roles.)

However, it appears that Cisco devices have non-compliant TLS 1.2
implementations[1] and copy over another server's server-random when
acting as a TLS terminator (client and server back-to-back).

Hopefully they are the only ones doing this. Implement a
measurement-only version with a different value. This sentinel must not
be enforced, but it will tell us whether enforcing it will cause
problems.

[1] https://www.ietf.org/mail-archive/web/tls/current/msg25168.html

Bug: 226
Change-Id: I976880bdb2ef26f51592b2f6b3b97664342679c8
Reviewed-on: https://boringssl-review.googlesource.com/24284
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2017-12-21 01:50:33 +00:00
David Benjamin 02e6256b16 Move early_data_accepted to ssl->s3.
This is connection state, not configuration, so it must live on
ssl->s3, otherwise SSL_clear will be confused.

Change-Id: Id7c87ced5248d3953e37946e2d0673d66bfedb08
Reviewed-on: https://boringssl-review.googlesource.com/24264
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-19 15:44:38 +00:00
David Benjamin a0c87adbf0 Add RSA_flags and RSA_METHOD_FLAG_NO_CHECK.
RSA_METHOD_FLAG_NO_CHECK is the same as our RSA_FLAG_OPAQUE. cURL uses
this to determine if it should call SSL_CTX_check_private_key.

Change-Id: Ie2953632346a31de346a4452f4eaad8435cf76e8
Reviewed-on: https://boringssl-review.googlesource.com/24245
Reviewed-by: Adam Langley <agl@google.com>
2017-12-18 23:56:15 +00:00
David Benjamin 0551feb3a1 Trim some unused RSA flags.
Update-Note: Some RSA_FLAG_* constants are gone. Code search says they
   were unused, but they can be easily restored if this breaks anything.
Change-Id: I47f642af5af9f8d80972ca8da0a0c2bd271c20eb
Reviewed-on: https://boringssl-review.googlesource.com/24244
Reviewed-by: Adam Langley <agl@google.com>
2017-12-18 23:55:27 +00:00
David Benjamin d90b8033d7 Clear the error queue in fuzzer-mode Channel ID hooks.
Otherwise it leaves something on the error queue and confuses
SSL_get_error, should the handshake state machine fail immediately
afterwards because of a BIO-level error.

Change-Id: I2c7b5e31368b9c5b2efa324166f52972430d6074
Reviewed-on: https://boringssl-review.googlesource.com/24247
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-18 21:56:32 +00:00
David Benjamin 287ac180ee Refresh fuzzer corpora.
The TLS 1.3 variants got renumbered (and many dropped).

Change-Id: I75f63e7188bb22eb115e7f4393e67dc696c013c5
Reviewed-on: https://boringssl-review.googlesource.com/24246
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
2017-12-18 21:54:26 +00:00
Steven Valdez 64cc121f41 Remove deprecated TLS 1.3 variants.
Upgrade-Note: SSL_CTX_set_tls13_variant(tls13_experiment) on the server
should switch to SSL_CTX_set_tls13_variant(tls13_experiment2).
(Configuring any TLS 1.3 variants on the server enables all variants,
so this is a no-op. We're just retiring some old experiments.)
Change-Id: I60f0ca3f96ff84bdf59e1a282a46e51d99047462
Reviewed-on: https://boringssl-review.googlesource.com/23784
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2017-12-18 21:20:32 +00:00
David Benjamin ea52ec98a5 Perform the RSA CRT reductions with Montgomery reduction.
The first step of RSA with the CRT optimization is to reduce our input
modulo p and q. We can do this in constant-time[*] with Montgomery
reduction. When p and q are the same size, Montgomery reduction's bounds
hold. We need two rounds of it because the first round gives us an
unwanted R^-1.

This does not appear to have a measurable impact on performance. Also
add a long TODO describing how to make the rest of the function
constant-time[*] which hopefully we'll get to later. RSA blinding should
protect us from it all, but make this constant-time anyway.

Since this and the follow-up work will special-case weird keys, add a
test that we don't break those unintentionally. (Though I am not above
breaking them intentionally someday...)

Thanks to Andres Erbsen for discussions on how to do this bit properly.

[*] Ignoring the pervasive bn_correct_top problem for the moment.

Change-Id: Ide099a9db8249cb6549be99c5f8791a39692ea81
Reviewed-on: https://boringssl-review.googlesource.com/24204
Reviewed-by: Adam Langley <agl@google.com>
2017-12-18 18:59:18 +00:00
David Benjamin f88242d1c1 SSL_export_keying_material should work in half-RTT.
QUIC will need to derive keys at this point. This also smooths over a
part of the server 0-RTT abstraction. Like with False Start, the SSL
object is largely in a functional state at this point.

Bug: 221
Change-Id: I4207d8cb1273a1156e728a7bff3943cc2c69e288
Reviewed-on: https://boringssl-review.googlesource.com/24224
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-18 16:53:13 +00:00
David Benjamin ebd87230ac Bring ERR_ERROR_STRING_BUF_LEN down to 120.
Originally, the only OpenSSL API to stringify errors was:

  char *ERR_error_string(unsigned long e, char *buf);

This API leaves callers a choice to either be thread unsafe (buf = NULL)
or pass in a buffer with unknown size. Indeed the original
implementation was just a bunch of unchecked sprintfs with, in the buf =
NULL case, a static 256-byte buffer.

https://github.com/openssl/openssl/blob/388f2f56f213dfada0370d48cb9bcc3c7e980b32/crypto/err/err.c#L374

Then ERR_error_string was documented that the buffer must be size 120.
Nowhere in the code was 120 significant. I expect OpenSSL just made up a
number.

https://github.com/openssl/openssl/commit/388f2f56f213dfada0370d48cb9bcc3c7e980b32

Then upstream added the ERR_error_string_n API. Although the
documentation stated 120 bytes, the internal buffer was 256, so the code
actually translates ERR_error_string to ERR_error_string_n(e, buf, 256),
not ERR_error_string_n(e, buf, 120)!

https://github.com/openssl/openssl/commit/e5c84d5152c11a3dfa436041d3336a6f403baad8

So the documentation was wrong all this time! OpenSSL 1.1.0 corrected
the documentation to 256, but, alas, a lot of code used the
documentation and sized the buffer at 120. We should fix all
ERR_error_string callers to ERR_error_string_n but, in the meantime,
using 120 is probably less effort.

Note this also affects ERR_print_errors_cb right now. We don't have
function codes, so 120 bytes leaves 60 bytes for the reason code. Our
longest one, TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST is 46 bytes,
so it's a little tight, but, if needed, we can recover 20-ish bytes by
shrinking the library names. We can also always make ERR_print_errors_cb
use a larger buffer.

Change-Id: I472a1a802f2e6281cc7515d2a452208d6bac1200
Reviewed-on: https://boringssl-review.googlesource.com/24184
Reviewed-by: Adam Langley <agl@google.com>
2017-12-14 19:47:23 +00:00
David Benjamin 875095aa7c Silence ARMv8 deprecated IT instruction warnings.
ARMv8 kindly deprecated most of its IT instructions in Thumb mode.
These files are taken from upstream and are used on both ARMv7 and ARMv8
processors. Accordingly, silence the warnings by marking the file as
targetting ARMv7. In other files, they were accidentally silenced anyway
by way of the existing .arch lines.

This can be reproduced by building with the new NDK and passing
-DCMAKE_ASM_FLAGS=-march=armv8-a. Some of our downstream code ends up
passing that to the assembly.

Note this change does not attempt to arrange for ARMv8-A/T32 to get
code which honors the constraints. It only silences the warnings and
continues to give it the same ARMv7-A/Thumb-2 code that backwards
compatibility dictates it continue to run.

Bug: chromium:575886, b/63131949
Change-Id: I24ce0b695942eaac799347922b243353b43ad7df
Reviewed-on: https://boringssl-review.googlesource.com/24166
Reviewed-by: Adam Langley <agl@google.com>
2017-12-14 01:56:22 +00:00
David Benjamin 9894ee9de2 Scope CMAKE_ASM_FLAGS workaround to the old NDK toolchain.
The one in the NDK works just fine. In particular, this means one can
pass -DCMAKE_ASM_FLAGS="-march=armv8-a" and test the ARMv8 assembler
warnings.

Additionally, make the workaround put the flags in the other order, so
-march is user-overridable.

Change-Id: I278ddd17ab688f83ee01f2aca4ff32307f5b0a2d
Reviewed-on: https://boringssl-review.googlesource.com/24164
Reviewed-by: Adam Langley <agl@google.com>
2017-12-14 01:55:26 +00:00
David Benjamin 528877962b Document the NDK's built-in toolchain file.
The third-party toolchain file doesn't actually work with newer NDKs,
and the one shipped with the NDK has fewer bugs.

Change-Id: I59e1db393f0d66b186fb71590fab14db7faa0756
Reviewed-on: https://boringssl-review.googlesource.com/24165
Reviewed-by: Adam Langley <agl@google.com>
2017-12-14 01:54:47 +00:00
David Benjamin 4358f104cf Remove clang assembler .arch workaround.
This makes it difficult to build against the NDK's toolchain file. The
problem is __clang__ just means Clang is the frontend and implies
nothing about which assembler. When using as, it is fine. When using
clang-as on Linux, one needs a clang-as from this year.

The only places where we case about clang's integrated assembler are iOS
(where perlasm strips out .arch anyway) and build environments like
Chromium which have a regularly-updated clang. Thus we can remove this
now.

Bug: 39
Update-Note: Holler if this breaks the build. If it doesn't break the
   build, you can probably remove any BORINGSSL_CLANG_SUPPORTS_DOT_ARCH
   or explicit -march armv8-a+crypto lines in your BoringSSL build.
Change-Id: I21ce54b14c659830520c2f1d51c7bd13e0980c68
Reviewed-on: https://boringssl-review.googlesource.com/24124
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-13 22:22:41 +00:00
David Benjamin a9c5b7b3fb Roll back CMake update on Windows bots.
CMake screwed up. See
https://github.com/Kitware/CMake/commit/f969f1a9ce1d0045b9d056fd08c4683c34c420fa.

It looks like CMake 3.10.1 is in the process of being released. While we
wait for them to put together that build, I'll just revert this real
quick. It's nice to keep them all at the same version, but we really
just needed a new one for Android.

Change-Id: I01b5a54b65df2194d7b84c825dfdcf0fb87fd06b
Reviewed-on: https://boringssl-review.googlesource.com/24144
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-13 21:56:50 +00:00
David Benjamin d870cbdd97 Update CMake to 3.10.0 on the bots.
The NDK toolchain file requires 3.6.0 or later. We were still using
3.5.0.

Change-Id: I216d33bed4187c7e62a2672eb4f92ce815b60b1c
Reviewed-on: https://boringssl-review.googlesource.com/24104
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-13 21:35:11 +00:00
David Benjamin 0c9c1aad35 Fix generate_build_files.py.
third_party/fiat/p256.c is weird. We need to switch everything to
sources.cmake.

Change-Id: I52e56e87a1ac5534b88a372ad68a1052fb019b67
Reviewed-on: https://boringssl-review.googlesource.com/24084
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-12 20:58:58 +00:00
Steven Valdez f98b582ded Fix tls13_variant check to check max_version.
Change-Id: I946e8903d745b0bf0c48701d16aa866464233ab7
Reviewed-on: https://boringssl-review.googlesource.com/24044
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2017-12-12 17:20:07 +00:00
David Benjamin 6fe960d174 Enable __asm__ and uint128_t code in clang-cl.
It actually works fine. I just forgot one of the typedefs last time.
This gives a roughly 2x improvement on P-256 in clang-cl +
OPENSSL_SMALL, the configuration used by Chrome.

Before:
Did 1302 ECDH P-256 operations in 1015000us (1282.8 ops/sec)
Did 4250 ECDSA P-256 signing operations in 1047000us (4059.2 ops/sec)
Did 1750 ECDSA P-256 verify operations in 1094000us (1599.6 ops/sec)

After:
Did 3250 ECDH P-256 operations in 1078000us (3014.8 ops/sec)
Did 8250 ECDSA P-256 signing operations in 1016000us (8120.1 ops/sec)
Did 3250 ECDSA P-256 verify operations in 1063000us (3057.4 ops/sec)

(These were taken on a VM, so the measurements are extremely noisy, but
this sort of improvement is visible regardless.)

Alas, we do need a little extra bit of fiddling because division does
not work (crbug.com/787617).

Bug: chromium:787617
Update-Note: This removes the MSan uint128_t workaround which does not
    appear to be necessary anymore.
Change-Id: I8361314608521e5bdaf0e7eeae7a02c33f55c69f
Reviewed-on: https://boringssl-review.googlesource.com/23984
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-11 22:46:26 +00:00
David Benjamin 650d8c393e Implement TLS 1.3 early exporters.
Bug: 222
Change-Id: I33ee56358a62afcd9c3921026d55efcc543a5c11
Reviewed-on: https://boringssl-review.googlesource.com/23945
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-11 21:33:26 +00:00
David Benjamin 8f53fc0a94 Fix fuzzer mode suppressions.
Change-Id: Ic79f189c0bb2abf5d87f59ee410cafb4fb116ab8
Reviewed-on: https://boringssl-review.googlesource.com/24004
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
2017-12-11 20:12:11 +00:00
Andres Erbsen 46304abf7d ec/p256.c: fiat-crypto field arithmetic (64, 32)
The fiat-crypto-generated code uses the Montgomery form implementation
strategy, for both 32-bit and 64-bit code.

64-bit throughput seems slower, but the difference is smaller than noise between repetitions (-2%?)

32-bit throughput has decreased significantly for ECDH (-40%). I am
attributing this to the change from varibale-time scalar multiplication
to constant-time scalar multiplication. Due to the same bottleneck,
ECDSA verification still uses the old code (otherwise there would have
been a 60% throughput decrease). On the other hand, ECDSA signing
throughput has increased slightly (+10%), perhaps due to the use of a
precomputed table of multiples of the base point.

64-bit benchmarks (Google Cloud Haswell):

with this change:
Did 9126 ECDH P-256 operations in 1009572us (9039.5 ops/sec)
Did 23000 ECDSA P-256 signing operations in 1039832us (22119.0 ops/sec)
Did 8820 ECDSA P-256 verify operations in 1024242us (8611.2 ops/sec)

master (40e8c921ca):
Did 9340 ECDH P-256 operations in 1017975us (9175.1 ops/sec)
Did 23000 ECDSA P-256 signing operations in 1039820us (22119.2 ops/sec)
Did 8688 ECDSA P-256 verify operations in 1021108us (8508.4 ops/sec)

benchmarks on ARMv7 (LG Nexus 4):

with this change:
Did 150 ECDH P-256 operations in 1029726us (145.7 ops/sec)
Did 506 ECDSA P-256 signing operations in 1065192us (475.0 ops/sec)
Did 363 ECDSA P-256 verify operations in 1033298us (351.3 ops/sec)

master (2fce1beda0):
Did 245 ECDH P-256 operations in 1017518us (240.8 ops/sec)
Did 473 ECDSA P-256 signing operations in 1086281us (435.4 ops/sec)
Did 360 ECDSA P-256 verify operations in 1003846us (358.6 ops/sec)

64-bit tables converted as follows:

import re, sys, math

p = 2**256 - 2**224 + 2**192 + 2**96 - 1
R = 2**256

def convert(t):
    x0, s1, x1, s2, x2, s3, x3 = t.groups()
    v = int(x0, 0) + 2**64 * (int(x1, 0) + 2**64*(int(x2,0) + 2**64*(int(x3, 0)) ))
    w = v*R%p
    y0 = hex(w%(2**64))
    y1 = hex((w>>64)%(2**64))
    y2 = hex((w>>(2*64))%(2**64))
    y3 = hex((w>>(3*64))%(2**64))
    ww = int(y0, 0) + 2**64 * (int(y1, 0) + 2**64*(int(y2,0) + 2**64*(int(y3, 0)) ))
    if ww != v*R%p:
        print(x0,x1,x2,x3)
        print(hex(v))
        print(y0,y1,y2,y3)
        print(hex(w))
        print(hex(ww))
        assert 0
    return '{'+y0+s1+y1+s2+y2+s3+y3+'}'

fe_re = re.compile('{'+r'(\s*,\s*)'.join(r'(\d+|0x[abcdefABCDEF0123456789]+)' for i in range(4)) + '}')
print (re.sub(fe_re, convert, sys.stdin.read()).rstrip('\n'))

32-bit tables converted from 64-bit tables

Change-Id: I52d6e5504fcb6ca2e8b0ee13727f4500c80c1799
Reviewed-on: https://boringssl-review.googlesource.com/23244
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-11 17:55:46 +00:00
David Benjamin 21baf6421a Fix CustomExtensions-Server-EarlyDataAccepted test.
It's misnamed but, more importantly, doesn't do anything because the
test client isn't sending early data to begin with. We really need to
make these tests less error-prone to write. With this fix, the test
actually notices if we remove the server-side 0-RTT check.

Also remove MaxEarlyDataSize from the other server tests which
erroneously set it. Any test with sets that was likely copy-and-pasted
incorrectly.

Change-Id: Idc24bc1590e0316946022341185285418ab8c77b
Reviewed-on: https://boringssl-review.googlesource.com/23944
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-11 15:54:15 +00:00
David Benjamin eb9232f06f Fully reduce scalars in EC_POINT_mul.
Along the way, this allows us to tidy up the invariants associated with
EC_SCALAR. They were fuzzy around ec_point_mul_scalar and some
computations starting from the digest in ECDSA. The latter I've put into
the type system with EC_LOOSE_SCALAR.

As for the former, Andres points out that particular EC implementations
are only good for scalars within a certain range, otherwise you may need
extra work to avoid the doubling case. To simplify curve
implementations, we reduce them fully rather than do the looser bit size
check, so they can have the stronger precondition to work with.

Change-Id: Iff9a0404f89adf8f7f914f8e8246c9f3136453f1
Reviewed-on: https://boringssl-review.googlesource.com/23664
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-08 17:55:54 +00:00
David Benjamin 2b63addf6a Use uint32_t for unicode code points.
The newer clang-cl is unhappy about the tautological comparison on
Windows, but the comparison itself is unnecessary anyway, since the
values will never exceed uint32_t.

I think the reason it's not firing elsewhere is because on other 64-bit
platforms, it is not tautological because long is 64-bit. On other
32-bit platforms, I'm not sure we actually have a standalone trunk clang
builder right now.

Update-Note: UTF8_getc and UTF8_putc were unexported. No one appears to
    be calling them. (We're a crypto library, not a Unicode library.)
Change-Id: I0949ddea3131dca5f55d04e672c3ccf2915c41ab
Reviewed-on: https://boringssl-review.googlesource.com/23844
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-08 17:51:34 +00:00
David Benjamin 296a61d600 bn/asm/rsaz-avx2.pl: fix digit correction bug in rsaz_1024_mul_avx2.
Credit to OSS-Fuzz for finding this.

CVE-2017-3738

(Imported from upstream's 5630661aecbea5fe3c4740f5fea744a1f07a6253 and
77d75993651b63e872244a3256e37967bb3c3e9e.)

Confirmed with Intel SDE that the fix makes the test vector pass and
that, without the fix, the test vector does not. (Well, we knew the
latter already, since it was our test vector.)

Change-Id: I167aa3407ddab3b434bacbd18e099c55aa40ac4c
Reviewed-on: https://boringssl-review.googlesource.com/23884
Reviewed-by: Adam Langley <agl@google.com>
2017-12-07 16:54:32 +00:00
David Benjamin 2bc937068d Add X509_NAME_get0_der from OpenSSL 1.1.0.
Change-Id: Iaa616a09f944ce720c11236b031d0fa9deb47db3
Reviewed-on: https://boringssl-review.googlesource.com/23864
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-06 17:49:04 +00:00
David Benjamin d8dbde79f9 Don't allow negative EC_KEY private keys.
We check that the private key is less than the order, but we forgot the
other end.

Update-Note: It's possible some caller was relying on this, but since
    that function already checked the other half of the range, I'm
    expecting this to be a no-op change.

Change-Id: I4a53357d7737735b3cfbe97d379c8ca4eca5d5ac
Reviewed-on: https://boringssl-review.googlesource.com/23665
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2017-12-05 19:46:27 +00:00
David Benjamin 6979c7e8eb Disable Clang -Wtautological-constant-compare.
This is a recent Clang warning, but it's far too aggressive. The earlier
unsigned long silliness was worth fixing, but it otherwise complains on
32-bit platforms with:

  if (some_size_t > 0xffffffff) {
    ...
  }

which is unreasonable as, on 64-bit platforms, this check is meaningful
and requiring the programmer add ifdefs is error-prone. This matches
Chromium in https://crbug.com/767059.

Bug: chromium:767059
Change-Id: I0bb0f3a4b60f222e9d1b3c569471fbcf5518caed
Reviewed-on: https://boringssl-review.googlesource.com/23845
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
2017-12-05 19:34:47 +00:00
David Benjamin 56d5d7085d Update tools.
The newer clang should hopefully fix the new linux_clang_cfi bot.

Note the VS2017 revision actually went backwards due to
https://chromium.googlesource.com/chromium/src/+/db45606398cf4389bf332b0cdcffd04e7de4a4f6

Change-Id: Icaca7a57596f063ccca490917d4b78813f2e9537
Reviewed-on: https://boringssl-review.googlesource.com/23824
Reviewed-by: Adam Langley <agl@google.com>
2017-12-04 21:39:54 +00:00
David Benjamin 494e4d0e89 Add an option for False Start without ALPN.
We can probably do this globally at this point since the cipher
requirements are much more restrict than they were in the beginning.
(Firefox, in particular, has done so far a while.) For now add a flag
since some consumer wanted this.

I'll see about connecting it to a Chrome field trial after our breakage
budget is no longer reserved for TLS 1.3.

Change-Id: Ib61dd5aae2dfd48b56e79873a7f3061a7631a5f8
Reviewed-on: https://boringssl-review.googlesource.com/23725
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-04 21:20:46 +00:00
David Benjamin a5462d3050 Actually deprecate ERR_remove_thread_state.
Change-Id: I1f22e51bff8714550fbc73b116c08894c5b24d3d
Reviewed-on: https://boringssl-review.googlesource.com/23804
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-04 17:04:27 +00:00
Michał Janiszewski d3ec6f1adb Add missing errno.h include to bio_test.cc
This fixes compilation on aarch64 and other architectures for Android.

Change-Id: I0b09ab06858c92d07e2376e244a4626a6af5037b
Reviewed-on: https://boringssl-review.googlesource.com/23764
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-04 01:32:37 +00:00
Adam Langley bc37ad91fe Fix alignment-violating cast.
Change-Id: Id8b69bb6103dd938f4c6d0d2ec24f3d50ba5513c
Update-Note: fixes b/70034392
Reviewed-on: https://boringssl-review.googlesource.com/23744
Commit-Queue: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-01 22:32:17 +00:00
Steven Valdez 9986f6b045 Fix renegotiation with TLS 1.3 draft 22.
Change-Id: I87edf7e1fee07da4bc93cc7ab524b79991a4206e
Reviewed-on: https://boringssl-review.googlesource.com/23724
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-12-01 17:56:55 +00:00
David Benjamin 48eaa28a12 Make EC_POINT_mul work with arbitrary BIGNUMs again.
Rejecting values where we'd previous called BN_nnmod may have been
overly ambitious. In the long run, all the supported ECC APIs (ECDSA*,
ECDH_compute_key, and probably some additional new ECDH API) will be
using the EC_SCALAR version anyway, so this doesn't really matter.

Change-Id: I79cd4015f2d6daf213e4413caa2a497608976f93
Reviewed-on: https://boringssl-review.googlesource.com/23584
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-11-30 21:58:17 +00:00
David Benjamin 2fc4f362cd Revert "Support high tag numbers in CBS/CBB."
This reverts commit 66801feb17. This
turned out to break a lot more than expected. Hopefully we can reland it
soon, but we need to fix up some consumers first.

Note due to work that went in later, this is not a trivial revert and
should be re-reviewed.

Change-Id: I6474b67cce9a8aa03f722f37ad45914b76466bea
Reviewed-on: https://boringssl-review.googlesource.com/23644
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-11-30 21:57:17 +00:00
David Benjamin 095b6c9baa Also add a decoupled OBJ_obj2txt.
We need it in both directions. Also I missed that in OBJ_obj2txt we
allowed uint64_t components, but in my new OBJ_txt2obj we only allowed
uint32_t. For consistency, upgrade that to uint64_t.

Bug: chromium:706445
Change-Id: I38cfeea8ff64b9acf7998e552727c6c3b2cc600f
Reviewed-on: https://boringssl-review.googlesource.com/23544
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-11-30 18:21:48 +00:00
Steven Valdez 1530ef3ec5 Add early data input from file.
Change-Id: I93a54e7a67acddb196ed53ce7fe49c718553948d
Reviewed-on: https://boringssl-review.googlesource.com/23604
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-11-30 17:29:45 +00:00
David Benjamin fb535892e5 runner: Rewrite some more parsers.
These were easy.

Change-Id: I5fc764b83d641b08b58ccbff36dbd28cb66efed0
Reviewed-on: https://boringssl-review.googlesource.com/23564
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-11-30 17:05:06 +00:00
Steven Valdez c5c31abe2b Enforce compression_method in TLS 1.3 draft 22.
Change-Id: Ic99a949258e62cad168c2c39507ca63100a8ffe5
Reviewed-on: https://boringssl-review.googlesource.com/23264
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-11-29 22:19:04 +00:00
Steven Valdez e6cefe41bb Update PR 1091 CL to use draft22 version.
Change-Id: Ifa811262fbca22222656da530f97daac3dcd6a5b
Reviewed-on: https://boringssl-review.googlesource.com/22944
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
2017-11-29 16:11:24 +00:00
1171 changed files with 26070 additions and 27874 deletions
+1
View File
@@ -5,6 +5,7 @@ ssl/test/runner/runner
doc/*.html
doc/doc.css
util/bot/android_ndk
util/bot/android_tools
util/bot/cmake-linux64
util/bot/cmake-linux64.tar.gz
+9 -16
View File
@@ -79,14 +79,15 @@ for other variables which may be used to configure the build.
### Building for Android
It's possible to build BoringSSL with the Android NDK using CMake. This has
been tested with version 10d of the NDK.
It's possible to build BoringSSL with the Android NDK using CMake. Recent
versions of the NDK include a CMake toolchain file which works with CMake 3.6.0
or later. This has been tested with version r16b of the NDK.
Unpack the Android NDK somewhere and export `ANDROID_NDK` to point to the
directory. Then make a build directory as above and run CMake like this:
cmake -DANDROID_ABI=armeabi-v7a \
-DCMAKE_TOOLCHAIN_FILE=../third_party/android-cmake/android.toolchain.cmake \
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \
-DANDROID_NATIVE_API_LEVEL=16 \
-GNinja ..
@@ -94,7 +95,11 @@ Once you've run that, Ninja should produce Android-compatible binaries. You
can replace `armeabi-v7a` in the above with `arm64-v8a` and use API level 21 or
higher to build aarch64 binaries.
For other options, see [android-cmake's documentation](./third_party/android-cmake/README.md).
For older NDK versions, BoringSSL ships a third-party CMake toolchain file. Use
`../third_party/android-cmake/android.toolchain.cmake` for
`CMAKE_TOOLCHAIN_FILE` instead.
For other options, see the documentation in the toolchain file.
### Building for iOS
@@ -145,18 +150,6 @@ corresponding ARM feature.
Note that if a feature is enabled in this way, but not actually supported at
run-time, BoringSSL will likely crash.
## Assembling ARMv8 with Clang
In order to support the ARMv8 crypto instructions, Clang requires that the
architecture be `armv8-a+crypto`. However, setting that as a general build flag
would allow the compiler to assume that crypto instructions are *always*
supported, even without testing for them.
It's possible to set the architecture in an assembly file using the `.arch`
directive, but only very recent versions of Clang support this. If
`BORINGSSL_CLANG_SUPPORTS_DOT_ARCH` is defined then `.arch` directives will be
used with Clang, otherwise you may need to craft acceptable assembler flags.
# Running tests
There are two sets of tests: the C/C++ tests and the blackbox tests. For former
+31 -12
View File
@@ -1,5 +1,11 @@
cmake_minimum_required (VERSION 2.8.11)
# Report AppleClang separately from Clang. Their version numbers are different.
# https://cmake.org/cmake/help/v3.0/policy/CMP0025.html
if(POLICY CMP0025)
cmake_policy(SET CMP0025 NEW)
endif()
# Defer enabling C and CXX languages.
project (BoringSSL NONE)
@@ -42,17 +48,18 @@ endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
# Note clang-cl is odd and sets both CLANG and MSVC. We base our configuration
# primarily on our normal Clang one because the MSVC one is mostly
# suppressions for an overaggressive -Wall.
set(C_CXX_FLAGS "-Wall -Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings")
# primarily on our normal Clang one.
set(C_CXX_FLAGS "-Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings")
if(MSVC)
# clang-cl sets different default warnings than clang.
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-unused-parameter -fmsc-version=1900")
# clang-cl sets different default warnings than clang. It also treats -Wall
# as -Weverything, to match MSVC. Instead -W3 is the alias for -Wall.
# See http://llvm.org/viewvc/llvm-project?view=revision&revision=319116
set(C_CXX_FLAGS "${C_CXX_FLAGS} -W3 -Wno-unused-parameter -fmsc-version=1900")
# googletest suppresses warning C4996 via a pragma, but clang-cl does not
# honor it. Suppress it here to compensate. See https://crbug.com/772117.
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-deprecated-declarations")
else()
set(C_CXX_FLAGS "${C_CXX_FLAGS} -ggdb -fvisibility=hidden -fno-common")
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wall -ggdb -fvisibility=hidden -fno-common")
endif()
if(CLANG)
@@ -63,6 +70,18 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-free-nonheap-object")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
NOT "6.0.0" VERSION_GREATER CMAKE_C_COMPILER_VERSION)
# Clang's -Wtautological-constant-compare is far too aggressive and does not
# account for, say, wanting the same code to work on both 32-bit and 64-bit
# platforms.
#
# Note "Clang" and "AppleClang" version differently, so we check for an
# exact match on the COMPILER_ID. As of writing, the warning is not in any
# release of AppleClang yet.
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-tautological-constant-compare -Wtautological-constant-out-of-range-compare")
endif()
if(CLANG OR NOT "7.0.0" VERSION_GREATER CMAKE_C_COMPILER_VERSION)
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wimplicit-fallthrough")
endif()
@@ -321,11 +340,11 @@ else()
message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR})
endif()
if (ANDROID AND ${ARCH} STREQUAL "arm")
# The Android-NDK CMake files somehow fail to set the -march flag for
# assembly files. Without this flag, the compiler believes that it's
if (ANDROID AND NOT ANDROID_NDK_REVISION AND ${ARCH} STREQUAL "arm")
# The third-party Android-NDK CMake files somehow fail to set the -march flag
# for assembly files. Without this flag, the compiler believes that it's
# building for ARMv5.
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR}")
set(CMAKE_ASM_FLAGS "-march=${CMAKE_SYSTEM_PROCESSOR} ${CMAKE_ASM_FLAGS}")
endif()
if (${ARCH} STREQUAL "x86" AND APPLE AND ${CMAKE_VERSION} VERSION_LESS "3.0")
@@ -337,8 +356,8 @@ endif()
# Add minimal googletest targets. The provided one has many side-effects, and
# googletest has a very straightforward build.
add_library(gtest third_party/googletest/src/gtest-all.cc)
target_include_directories(gtest PRIVATE third_party/googletest)
add_library(boringssl_gtest third_party/googletest/src/gtest-all.cc)
target_include_directories(boringssl_gtest PRIVATE third_party/googletest)
include_directories(third_party/googletest/include)
+3 -40
View File
@@ -5,10 +5,9 @@ license. This license is reproduced at the bottom of this file.
Contributors to BoringSSL are required to follow the CLA rules for Chromium:
https://cla.developers.google.com/clas
Some files from Intel are under yet another license, which is also included
underneath. Files in third_party/ have their own licenses, as described
therein. The MIT license, for third_party/fiat, which, unlike other third_party
directories, is compiled into non-test libraries, is included below.
Files in third_party/ have their own licenses, as described therein. The MIT
license, for third_party/fiat, which, unlike other third_party directories, is
compiled into non-test libraries, is included below.
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
OpenSSL License and the original SSLeay license apply to the toolkit. See below
@@ -158,42 +157,6 @@ ISC license used for completely new code in BoringSSL:
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
Some files from Intel carry the following license:
# Copyright (c) 2012, Intel Corporation
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the
# distribution.
#
# * Neither the name of the Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
#
# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The code in third_party/fiat carries the MIT license:
Copyright (c) 2015-2016 the fiat-crypto authors (see
+1 -1
View File
@@ -210,7 +210,7 @@ strings and loading algorithms, etc. All of these functions still exist in
BoringSSL for convenience, but they do nothing and are not necessary.
The one exception is `CRYPTO_library_init`. In `BORINGSSL_NO_STATIC_INITIALIZER`
builds, it must be called to query CPU capabitilies before the rest of the
builds, it must be called to query CPU capabilities before the rest of the
library. In the default configuration, this is done with a static initializer
and is also unnecessary.
+5 -3
View File
@@ -53,7 +53,7 @@ if(NOT OPENSSL_NO_ASM)
set(PERLASM_STYLE win32n)
set(PERLASM_FLAGS "-DOPENSSL_IA32_SSE2")
endif()
set(CMAKE_ASM_NASM_FLAGS "-g cv8")
set(CMAKE_ASM_NASM_FLAGS "-gcv8")
# On Windows, we use the NASM output, specifically built with Yasm.
set(ASM_EXT asm)
@@ -134,6 +134,7 @@ add_library(
OBJECT
cpu-aarch64-fuchsia.c
cpu-aarch64-linux.c
cpu-arm.c
cpu-arm-linux.c
@@ -260,6 +261,7 @@ add_executable(
pool/pool_test.cc
refcount_test.cc
rsa_extra/rsa_test.cc
self_test.cc
test/file_test_gtest.cc
thread_test.cc
x509/x509_test.cc
@@ -267,11 +269,11 @@ add_executable(
x509v3/v3name_test.cc
$<TARGET_OBJECTS:crypto_test_data>
$<TARGET_OBJECTS:gtest_main>
$<TARGET_OBJECTS:boringssl_gtest_main>
$<TARGET_OBJECTS:test_support>
)
target_link_libraries(crypto_test crypto gtest)
target_link_libraries(crypto_test crypto boringssl_gtest)
if (WIN32)
target_link_libraries(crypto_test ws2_32)
endif()
+33 -28
View File
@@ -347,40 +347,45 @@ ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
{
int j, k;
unsigned int i;
unsigned char buf[sizeof(long) + 1];
long d;
a->type = V_ASN1_INTEGER;
if (a->length < (int)(sizeof(long) + 1)) {
if (a->data != NULL)
OPENSSL_free(a->data);
if ((a->data =
(unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL)
OPENSSL_memset((char *)a->data, 0, sizeof(long) + 1);
if (v >= 0) {
return ASN1_INTEGER_set_uint64(a, (uint64_t) v);
}
if (a->data == NULL) {
if (!ASN1_INTEGER_set_uint64(a, 0 - (uint64_t) v)) {
return 0;
}
a->type = V_ASN1_NEG_INTEGER;
return 1;
}
int ASN1_INTEGER_set_uint64(ASN1_INTEGER *out, uint64_t v)
{
uint8_t *const newdata = OPENSSL_malloc(sizeof(uint64_t));
if (newdata == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
return (0);
}
d = v;
if (d < 0) {
d = -d;
a->type = V_ASN1_NEG_INTEGER;
return 0;
}
for (i = 0; i < sizeof(long); i++) {
if (d == 0)
OPENSSL_free(out->data);
out->data = newdata;
v = CRYPTO_bswap8(v);
memcpy(out->data, &v, sizeof(v));
out->type = V_ASN1_INTEGER;
size_t leading_zeros;
for (leading_zeros = 0; leading_zeros < sizeof(uint64_t) - 1;
leading_zeros++) {
if (out->data[leading_zeros] != 0) {
break;
buf[i] = (int)d & 0xff;
d >>= 8;
}
}
j = 0;
for (k = i - 1; k >= 0; k--)
a->data[j++] = buf[k];
a->length = j;
return (1);
out->length = sizeof(uint64_t) - leading_zeros;
OPENSSL_memmove(out->data, out->data + leading_zeros, out->length);
return 1;
}
long ASN1_INTEGER_get(const ASN1_INTEGER *a)
+24 -22
View File
@@ -61,17 +61,19 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "asn1_locl.h"
static int traverse_string(const unsigned char *p, int len, int inform,
int (*rfunc) (unsigned long value, void *in),
int (*rfunc) (uint32_t value, void *in),
void *arg);
static int in_utf8(unsigned long value, void *arg);
static int out_utf8(unsigned long value, void *arg);
static int type_str(unsigned long value, void *arg);
static int cpy_asc(unsigned long value, void *arg);
static int cpy_bmp(unsigned long value, void *arg);
static int cpy_univ(unsigned long value, void *arg);
static int cpy_utf8(unsigned long value, void *arg);
static int is_printable(unsigned long value);
static int in_utf8(uint32_t value, void *arg);
static int out_utf8(uint32_t value, void *arg);
static int type_str(uint32_t value, void *arg);
static int cpy_asc(uint32_t value, void *arg);
static int cpy_bmp(uint32_t value, void *arg);
static int cpy_univ(uint32_t value, void *arg);
static int cpy_utf8(uint32_t value, void *arg);
static int is_printable(uint32_t value);
/*
* These functions take a string in UTF8, ASCII or multibyte form and a mask
@@ -100,7 +102,7 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
unsigned char *p;
int nchar;
char strbuf[32];
int (*cpyfunc) (unsigned long, void *) = NULL;
int (*cpyfunc) (uint32_t, void *) = NULL;
if (len == -1)
len = strlen((const char *)in);
if (!mask)
@@ -253,10 +255,10 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
*/
static int traverse_string(const unsigned char *p, int len, int inform,
int (*rfunc) (unsigned long value, void *in),
int (*rfunc) (uint32_t value, void *in),
void *arg)
{
unsigned long value;
uint32_t value;
int ret;
while (len) {
if (inform == MBSTRING_ASC) {
@@ -267,8 +269,8 @@ static int traverse_string(const unsigned char *p, int len, int inform,
value |= *p++;
len -= 2;
} else if (inform == MBSTRING_UNIV) {
value = ((unsigned long)*p++) << 24;
value |= ((unsigned long)*p++) << 16;
value = ((uint32_t)*p++) << 24;
value |= ((uint32_t)*p++) << 16;
value |= *p++ << 8;
value |= *p++;
len -= 4;
@@ -292,7 +294,7 @@ static int traverse_string(const unsigned char *p, int len, int inform,
/* Just count number of characters */
static int in_utf8(unsigned long value, void *arg)
static int in_utf8(uint32_t value, void *arg)
{
int *nchar;
nchar = arg;
@@ -302,7 +304,7 @@ static int in_utf8(unsigned long value, void *arg)
/* Determine size of output as a UTF8 String */
static int out_utf8(unsigned long value, void *arg)
static int out_utf8(uint32_t value, void *arg)
{
int *outlen;
outlen = arg;
@@ -315,7 +317,7 @@ static int out_utf8(unsigned long value, void *arg)
* "mask".
*/
static int type_str(unsigned long value, void *arg)
static int type_str(uint32_t value, void *arg)
{
unsigned long types;
types = *((unsigned long *)arg);
@@ -335,7 +337,7 @@ static int type_str(unsigned long value, void *arg)
/* Copy one byte per character ASCII like strings */
static int cpy_asc(unsigned long value, void *arg)
static int cpy_asc(uint32_t value, void *arg)
{
unsigned char **p, *q;
p = arg;
@@ -347,7 +349,7 @@ static int cpy_asc(unsigned long value, void *arg)
/* Copy two byte per character BMPStrings */
static int cpy_bmp(unsigned long value, void *arg)
static int cpy_bmp(uint32_t value, void *arg)
{
unsigned char **p, *q;
p = arg;
@@ -360,7 +362,7 @@ static int cpy_bmp(unsigned long value, void *arg)
/* Copy four byte per character UniversalStrings */
static int cpy_univ(unsigned long value, void *arg)
static int cpy_univ(uint32_t value, void *arg)
{
unsigned char **p, *q;
p = arg;
@@ -375,7 +377,7 @@ static int cpy_univ(unsigned long value, void *arg)
/* Copy to a UTF8String */
static int cpy_utf8(unsigned long value, void *arg)
static int cpy_utf8(uint32_t value, void *arg)
{
unsigned char **p;
int ret;
@@ -387,7 +389,7 @@ static int cpy_utf8(unsigned long value, void *arg)
}
/* Return 1 if the character is permitted in a PrintableString */
static int is_printable(unsigned long value)
static int is_printable(uint32_t value)
{
int ch;
if (value > 0x7f)
+13 -11
View File
@@ -59,6 +59,8 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "asn1_locl.h"
/* UTF8 utilities */
/*
@@ -70,10 +72,10 @@
* incorrectly (not minimal length).
*/
int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
int UTF8_getc(const unsigned char *str, int len, uint32_t *val)
{
const unsigned char *p;
unsigned long value;
uint32_t value;
int ret;
if (len <= 0)
return 0;
@@ -112,7 +114,7 @@ int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
|| ((p[2] & 0xc0) != 0x80)
|| ((p[3] & 0xc0) != 0x80))
return -3;
value = ((unsigned long)(*p++ & 0x7)) << 18;
value = ((uint32_t)(*p++ & 0x7)) << 18;
value |= (*p++ & 0x3f) << 12;
value |= (*p++ & 0x3f) << 6;
value |= *p++ & 0x3f;
@@ -127,9 +129,9 @@ int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
|| ((p[3] & 0xc0) != 0x80)
|| ((p[4] & 0xc0) != 0x80))
return -3;
value = ((unsigned long)(*p++ & 0x3)) << 24;
value |= ((unsigned long)(*p++ & 0x3f)) << 18;
value |= ((unsigned long)(*p++ & 0x3f)) << 12;
value = ((uint32_t)(*p++ & 0x3)) << 24;
value |= ((uint32_t)(*p++ & 0x3f)) << 18;
value |= ((uint32_t)(*p++ & 0x3f)) << 12;
value |= (*p++ & 0x3f) << 6;
value |= *p++ & 0x3f;
if (value < 0x200000)
@@ -144,10 +146,10 @@ int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
|| ((p[4] & 0xc0) != 0x80)
|| ((p[5] & 0xc0) != 0x80))
return -3;
value = ((unsigned long)(*p++ & 0x1)) << 30;
value |= ((unsigned long)(*p++ & 0x3f)) << 24;
value |= ((unsigned long)(*p++ & 0x3f)) << 18;
value |= ((unsigned long)(*p++ & 0x3f)) << 12;
value = ((uint32_t)(*p++ & 0x1)) << 30;
value |= ((uint32_t)(*p++ & 0x3f)) << 24;
value |= ((uint32_t)(*p++ & 0x3f)) << 18;
value |= ((uint32_t)(*p++ & 0x3f)) << 12;
value |= (*p++ & 0x3f) << 6;
value |= *p++ & 0x3f;
if (value < 0x4000000)
@@ -167,7 +169,7 @@ int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
* most 6 characters.
*/
int UTF8_putc(unsigned char *str, int len, unsigned long value)
int UTF8_putc(unsigned char *str, int len, uint32_t value)
{
if (!str)
len = 6; /* Maximum we will need */
+3
View File
@@ -93,6 +93,9 @@ int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
int combine);
int UTF8_getc(const unsigned char *str, int len, uint32_t *val);
int UTF8_putc(unsigned char *str, int len, uint32_t value);
#if defined(__cplusplus)
} /* extern C */
+28
View File
@@ -15,6 +15,7 @@
#include <stdio.h>
#include <gtest/gtest.h>
#include <limits.h>
#include <openssl/asn1.h>
#include <openssl/err.h>
@@ -60,3 +61,30 @@ TEST(ASN1Test, LargeTags) {
EXPECT_EQ(Bytes(&kZero, 1), Bytes(obj->value.asn1_string->data,
obj->value.asn1_string->length));
}
TEST(ASN1Test, IntegerSetting) {
bssl::UniquePtr<ASN1_INTEGER> by_bn(M_ASN1_INTEGER_new());
bssl::UniquePtr<ASN1_INTEGER> by_long(M_ASN1_INTEGER_new());
bssl::UniquePtr<ASN1_INTEGER> by_uint64(M_ASN1_INTEGER_new());
bssl::UniquePtr<BIGNUM> bn(BN_new());
const std::vector<int64_t> kValues = {
LONG_MIN, -2, -1, 0, 1, 2, 0xff, 0x100, 0xffff, 0x10000, LONG_MAX,
};
for (const auto &i : kValues) {
SCOPED_TRACE(i);
ASSERT_EQ(1, ASN1_INTEGER_set(by_long.get(), i));
const uint64_t abs = i < 0 ? (0 - (uint64_t) i) : i;
ASSERT_TRUE(BN_set_u64(bn.get(), abs));
BN_set_negative(bn.get(), i < 0);
ASSERT_TRUE(BN_to_ASN1_INTEGER(bn.get(), by_bn.get()));
EXPECT_EQ(0, ASN1_INTEGER_cmp(by_bn.get(), by_long.get()));
if (i >= 0) {
ASSERT_EQ(1, ASN1_INTEGER_set_uint64(by_uint64.get(), i));
EXPECT_EQ(0, ASN1_INTEGER_cmp(by_bn.get(), by_uint64.get()));
}
}
}
+1
View File
@@ -27,6 +27,7 @@
#if !defined(OPENSSL_WINDOWS)
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <string.h>
+1
View File
@@ -73,6 +73,7 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
#include <openssl/mem.h>
#include "internal.h"
#include "../internal.h"
static int bio_fd_non_fatal_error(int err) {
+2
View File
@@ -81,6 +81,8 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../internal.h"
#define BIO_FP_READ 0x02
#define BIO_FP_WRITE 0x04
+6 -5
View File
@@ -77,8 +77,9 @@ int BN_bn2cbb_padded(CBB *out, size_t len, const BIGNUM *in) {
static const char hextable[] = "0123456789abcdef";
char *BN_bn2hex(const BIGNUM *bn) {
int width = bn_minimal_width(bn);
char *buf = OPENSSL_malloc(1 /* leading '-' */ + 1 /* zero is non-empty */ +
bn->top * BN_BYTES * 2 + 1 /* trailing NUL */);
width * BN_BYTES * 2 + 1 /* trailing NUL */);
if (buf == NULL) {
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
return NULL;
@@ -94,7 +95,7 @@ char *BN_bn2hex(const BIGNUM *bn) {
}
int z = 0;
for (int i = bn->top - 1; i >= 0; i--) {
for (int i = width - 1; i >= 0; i--) {
for (int j = BN_BITS2 - 8; j >= 0; j -= 8) {
// strip leading zeros
int v = ((int)(bn->d[i] >> (long)j)) & 0xff;
@@ -153,7 +154,7 @@ static int decode_hex(BIGNUM *bn, const char *in, int in_len) {
in_len -= todo;
}
assert(i <= bn->dmax);
bn->top = i;
bn->width = i;
return 1;
}
@@ -222,7 +223,7 @@ static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_
goto err;
}
bn_correct_top(ret);
bn_set_minimal_width(ret);
if (!BN_is_zero(ret)) {
ret->neg = neg;
}
@@ -347,7 +348,7 @@ int BN_print(BIO *bp, const BIGNUM *a) {
goto end;
}
for (i = a->top - 1; i >= 0; i--) {
for (i = bn_minimal_width(a) - 1; i >= 0; i--) {
for (j = BN_BITS2 - 4; j >= 0; j -= 4) {
// strip leading zeros
v = ((int)(a->d[i] >> (long)j)) & 0x0f;
+153 -42
View File
@@ -889,54 +889,165 @@ TEST(CBSTest, BitString) {
TEST(CBBTest, AddOIDFromText) {
const struct {
const char *in;
bool ok;
std::vector<uint8_t> out;
} kTests[] = {
const char *text;
std::vector<uint8_t> der;
} kValidOIDs[] = {
// Some valid values.
{"1.2.3.4", true, {0x2a, 0x3, 0x4}},
{"0.0", {0x00}},
{"0.2.3.4", {0x2, 0x3, 0x4}},
{"1.2.3.4", {0x2a, 0x3, 0x4}},
{"2.2.3.4", {0x52, 0x3, 0x4}},
{"1.2.840.113554.4.1.72585",
true,
{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09}},
// Test edge cases around the first component.
{"0.39", true, {0x27}},
{"0.40", false, {}},
{"1.0", true, {0x28}},
{"1.39", true, {0x4f}},
{"1.40", false, {}},
{"2.0", true, {0x50}},
{"2.1", true, {0x51}},
{"2.40", true, {0x78}},
// The empty string is not an OID.
{"", false, {}},
// No empty components.
{".1.2.3.4.5", false, {}},
{"1..2.3.4.5", false, {}},
{"1.2.3.4.5.", false, {}},
// There must be at least two components.
{"1", false, {}},
// No extra leading zeros.
{"00.1.2.3.4", false, {}},
{"01.1.2.3.4", false, {}},
// Check for overflow.
{"1.2.4294967295", true, {0x2a, 0x8f, 0xff, 0xff, 0xff, 0x7f}},
{"1.2.4294967296", false, {}},
// 40*A + B overflows.
{"2.4294967215", true, {0x8f, 0xff, 0xff, 0xff, 0x7f}},
{"2.4294967216", false, {}},
{"0.39", {0x27}},
{"1.0", {0x28}},
{"1.39", {0x4f}},
{"2.0", {0x50}},
{"2.1", {0x51}},
{"2.40", {0x78}},
// Edge cases near an overflow.
{"1.2.18446744073709551615",
{0x2a, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}},
{"2.18446744073709551535",
{0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}},
};
for (const auto &t : kTests) {
SCOPED_TRACE(t.in);
const char *kInvalidTexts[] = {
// Invalid second component.
"0.40",
"1.40",
// Invalid first component.
"3.1",
// The empty string is not an OID.
"",
// No empty components.
".1.2.3.4.5",
"1..2.3.4.5",
"1.2.3.4.5.",
// There must be at least two components.
"1",
// No extra leading zeros.
"00.1.2.3.4",
"01.1.2.3.4",
// Overflow for both components or 40*A + B.
"1.2.18446744073709551616",
"2.18446744073709551536",
};
const std::vector<uint8_t> kInvalidDER[] = {
// The empty string is not an OID.
{},
// Non-minimal representation.
{0x80, 0x01},
// Overflow. This is the DER representation of
// 1.2.840.113554.4.1.72585.18446744073709551616. (The final value is
// 2^64.)
{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09,
0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00},
};
for (const auto &t : kValidOIDs) {
SCOPED_TRACE(t.text);
bssl::ScopedCBB cbb;
ASSERT_TRUE(CBB_init(cbb.get(), 0));
int ok = CBB_add_asn1_oid_from_text(cbb.get(), t.in, strlen(t.in));
EXPECT_EQ(t.ok, static_cast<bool>(ok));
if (ok) {
uint8_t *out;
size_t len;
ASSERT_TRUE(CBB_finish(cbb.get(), &out, &len));
bssl::UniquePtr<uint8_t> free_out(out);
EXPECT_EQ(Bytes(t.out), Bytes(out, len));
}
ASSERT_TRUE(CBB_add_asn1_oid_from_text(cbb.get(), t.text, strlen(t.text)));
uint8_t *out;
size_t len;
ASSERT_TRUE(CBB_finish(cbb.get(), &out, &len));
bssl::UniquePtr<uint8_t> free_out(out);
EXPECT_EQ(Bytes(t.der), Bytes(out, len));
CBS cbs;
CBS_init(&cbs, t.der.data(), t.der.size());
bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs));
ASSERT_TRUE(text.get());
EXPECT_STREQ(t.text, text.get());
}
for (const char *t : kInvalidTexts) {
SCOPED_TRACE(t);
bssl::ScopedCBB cbb;
ASSERT_TRUE(CBB_init(cbb.get(), 0));
EXPECT_FALSE(CBB_add_asn1_oid_from_text(cbb.get(), t, strlen(t)));
}
for (const auto &t : kInvalidDER) {
SCOPED_TRACE(Bytes(t));
CBS cbs;
CBS_init(&cbs, t.data(), t.size());
bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs));
EXPECT_FALSE(text);
}
}
TEST(CBBTest, FlushASN1SetOf) {
const struct {
std::vector<uint8_t> in, out;
} kValidInputs[] = {
// No elements.
{{}, {}},
// One element.
{{0x30, 0x00}, {0x30, 0x00}},
// Two identical elements.
{{0x30, 0x00, 0x30, 0x00}, {0x30, 0x00, 0x30, 0x00}},
// clang-format off
{{0x30, 0x02, 0x00, 0x00,
0x30, 0x00,
0x01, 0x00,
0x30, 0x02, 0x00, 0x00,
0x30, 0x03, 0x00, 0x00, 0x00,
0x30, 0x00,
0x30, 0x03, 0x00, 0x00, 0x01,
0x30, 0x01, 0x00,
0x01, 0x01, 0x00},
{0x01, 0x00,
0x01, 0x01, 0x00,
0x30, 0x00,
0x30, 0x00,
0x30, 0x01, 0x00,
0x30, 0x02, 0x00, 0x00,
0x30, 0x02, 0x00, 0x00,
0x30, 0x03, 0x00, 0x00, 0x00,
0x30, 0x03, 0x00, 0x00, 0x01}},
// clang-format on
};
for (const auto &t : kValidInputs) {
SCOPED_TRACE(Bytes(t.in));
bssl::ScopedCBB cbb;
CBB child;
ASSERT_TRUE(CBB_init(cbb.get(), 0));
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &child, CBS_ASN1_SET));
ASSERT_TRUE(CBB_add_bytes(&child, t.in.data(), t.in.size()));
ASSERT_TRUE(CBB_flush_asn1_set_of(&child));
EXPECT_EQ(Bytes(t.out), Bytes(CBB_data(&child), CBB_len(&child)));
// Running it again should be idempotent.
ASSERT_TRUE(CBB_flush_asn1_set_of(&child));
EXPECT_EQ(Bytes(t.out), Bytes(CBB_data(&child), CBB_len(&child)));
// The ASN.1 header remain intact.
ASSERT_TRUE(CBB_flush(cbb.get()));
EXPECT_EQ(0x31, CBB_data(cbb.get())[0]);
}
const std::vector<uint8_t> kInvalidInputs[] = {
{0x30},
{0x30, 0x01},
{0x30, 0x00, 0x30, 0x00, 0x30, 0x01},
};
for (const auto &t : kInvalidInputs) {
SCOPED_TRACE(Bytes(t));
bssl::ScopedCBB cbb;
CBB child;
ASSERT_TRUE(CBB_init(cbb.get(), 0));
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &child, CBS_ASN1_SET));
ASSERT_TRUE(CBB_add_bytes(&child, t.data(), t.size()));
EXPECT_FALSE(CBB_flush_asn1_set_of(&child));
}
}
+105 -8
View File
@@ -18,6 +18,7 @@
#include <limits.h>
#include <string.h>
#include <openssl/buf.h>
#include <openssl/mem.h>
#include "../internal.h"
@@ -332,9 +333,9 @@ int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) {
// add_base128_integer encodes |v| as a big-endian base-128 integer where the
// high bit of each byte indicates where there is more data. This is the
// encoding used in DER for both high tag number form and OID components.
static int add_base128_integer(CBB *cbb, uint32_t v) {
static int add_base128_integer(CBB *cbb, uint64_t v) {
unsigned len_len = 0;
unsigned copy = v;
uint64_t copy = v;
while (copy > 0) {
len_len++;
copy >>= 7;
@@ -504,11 +505,33 @@ int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) {
return CBB_flush(cbb);
}
int CBB_add_asn1_octet_string(CBB *cbb, const uint8_t *data, size_t data_len) {
CBB child;
if (!CBB_add_asn1(cbb, &child, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child, data, data_len) ||
!CBB_flush(cbb)) {
return 0;
}
return 1;
}
int CBB_add_asn1_bool(CBB *cbb, int value) {
CBB child;
if (!CBB_add_asn1(cbb, &child, CBS_ASN1_BOOLEAN) ||
!CBB_add_u8(&child, value != 0 ? 0xff : 0) ||
!CBB_flush(cbb)) {
return 0;
}
return 1;
}
// parse_dotted_decimal parses one decimal component from |cbs|, where |cbs| is
// an OID literal, e.g., "1.2.840.113554.4.1.72585". It consumes both the
// component and the dot, so |cbs| may be passed into the function again for the
// next value.
static int parse_dotted_decimal(CBS *cbs, uint32_t *out) {
static int parse_dotted_decimal(CBS *cbs, uint64_t *out) {
*out = 0;
int seen_digit = 0;
for (;;) {
@@ -524,8 +547,8 @@ static int parse_dotted_decimal(CBS *cbs, uint32_t *out) {
// Forbid stray leading zeros.
(seen_digit && *out == 0) ||
// Check for overflow.
*out > UINT32_MAX / 10 ||
*out * 10 > UINT32_MAX - (u - '0')) {
*out > UINT64_MAX / 10 ||
*out * 10 > UINT64_MAX - (u - '0')) {
return 0;
}
*out = *out * 10 + (u - '0');
@@ -544,7 +567,7 @@ int CBB_add_asn1_oid_from_text(CBB *cbb, const char *text, size_t len) {
CBS_init(&cbs, (const uint8_t *)text, len);
// OIDs must have at least two components.
uint32_t a, b;
uint64_t a, b;
if (!parse_dotted_decimal(&cbs, &a) ||
!parse_dotted_decimal(&cbs, &b)) {
return 0;
@@ -554,8 +577,8 @@ int CBB_add_asn1_oid_from_text(CBB *cbb, const char *text, size_t len) {
// 0, 1, or 2 and that, when it is 0 or 1, |b| is at most 39.
if (a > 2 ||
(a < 2 && b > 39) ||
b > UINT32_MAX - 80 ||
!add_base128_integer(cbb, 40 * a + b)) {
b > UINT64_MAX - 80 ||
!add_base128_integer(cbb, 40u * a + b)) {
return 0;
}
@@ -569,3 +592,77 @@ int CBB_add_asn1_oid_from_text(CBB *cbb, const char *text, size_t len) {
return 1;
}
static int compare_set_of_element(const void *a_ptr, const void *b_ptr) {
// See X.690, section 11.6 for the ordering. They are sorted in ascending
// order by their DER encoding.
const CBS *a = a_ptr, *b = b_ptr;
size_t a_len = CBS_len(a), b_len = CBS_len(b);
size_t min_len = a_len < b_len ? a_len : b_len;
int ret = OPENSSL_memcmp(CBS_data(a), CBS_data(b), min_len);
if (ret != 0) {
return ret;
}
if (a_len == b_len) {
return 0;
}
// If one is a prefix of the other, the shorter one sorts first. (This is not
// actually reachable. No DER encoding is a prefix of another DER encoding.)
return a_len < b_len ? -1 : 1;
}
int CBB_flush_asn1_set_of(CBB *cbb) {
if (!CBB_flush(cbb)) {
return 0;
}
CBS cbs;
size_t num_children = 0;
CBS_init(&cbs, CBB_data(cbb), CBB_len(cbb));
while (CBS_len(&cbs) != 0) {
if (!CBS_get_any_asn1_element(&cbs, NULL, NULL, NULL)) {
return 0;
}
num_children++;
}
if (num_children < 2) {
return 1; // Nothing to do. This is the common case for X.509.
}
if (num_children > ((size_t)-1) / sizeof(CBS)) {
return 0; // Overflow.
}
// Parse out the children and sort. We alias them into a copy of so they
// remain valid as we rewrite |cbb|.
int ret = 0;
size_t buf_len = CBB_len(cbb);
uint8_t *buf = BUF_memdup(CBB_data(cbb), buf_len);
CBS *children = OPENSSL_malloc(num_children * sizeof(CBS));
if (buf == NULL || children == NULL) {
goto err;
}
CBS_init(&cbs, buf, buf_len);
for (size_t i = 0; i < num_children; i++) {
if (!CBS_get_any_asn1_element(&cbs, &children[i], NULL, NULL)) {
goto err;
}
}
qsort(children, num_children, sizeof(CBS), compare_set_of_element);
// Rewind |cbb| and write the contents back in the new order.
cbb->base->len = cbb->offset + cbb->pending_len_len;
for (size_t i = 0; i < num_children; i++) {
if (!CBB_add_bytes(cbb, CBS_data(&children[i]), CBS_len(&children[i]))) {
goto err;
}
}
assert(CBB_len(cbb) == buf_len);
ret = 1;
err:
OPENSSL_free(buf);
OPENSSL_free(children);
return ret;
}
+106 -18
View File
@@ -12,11 +12,16 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#if !defined(__STDC_FORMAT_MACROS)
#define __STDC_FORMAT_MACROS
#endif
#include <openssl/buf.h>
#include <openssl/mem.h>
#include <openssl/bytestring.h>
#include <assert.h>
#include <inttypes.h>
#include <string.h>
#include "internal.h"
@@ -175,6 +180,33 @@ int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) {
return cbs_get_length_prefixed(cbs, out, 3);
}
// parse_base128_integer reads a big-endian base-128 integer from |cbs| and sets
// |*out| to the result. This is the encoding used in DER for both high tag
// number form and OID components.
static int parse_base128_integer(CBS *cbs, uint64_t *out) {
uint64_t v = 0;
uint8_t b;
do {
if (!CBS_get_u8(cbs, &b)) {
return 0;
}
if ((v >> (64 - 7)) != 0) {
// The value is too large.
return 0;
}
if (v == 0 && b == 0x80) {
// The value must be minimally encoded.
return 0;
}
v = (v << 7) | (b & 0x7f);
// Values end at an octet with the high bit cleared.
} while (b & 0x80);
*out = v;
return 1;
}
static int parse_asn1_tag(CBS *cbs, unsigned *out) {
uint8_t tag_byte;
if (!CBS_get_u8(cbs, &tag_byte)) {
@@ -191,27 +223,15 @@ static int parse_asn1_tag(CBS *cbs, unsigned *out) {
unsigned tag = ((unsigned)tag_byte & 0xe0) << CBS_ASN1_TAG_SHIFT;
unsigned tag_number = tag_byte & 0x1f;
if (tag_number == 0x1f) {
tag_number = 0;
for (;;) {
if (!CBS_get_u8(cbs, &tag_byte) ||
((tag_number << 7) >> 7) != tag_number) {
return 0;
}
tag_number = (tag_number << 7) | (tag_byte & 0x7f);
// The tag must be represented in the minimal number of bytes.
if (tag_number == 0) {
return 0;
}
if ((tag_byte & 0x80) == 0) {
break;
}
}
if (// Check the tag number is within our supported bounds.
tag_number > CBS_ASN1_TAG_NUMBER_MASK ||
uint64_t v;
if (!parse_base128_integer(cbs, &v) ||
// Check the tag number is within our supported bounds.
v > CBS_ASN1_TAG_NUMBER_MASK ||
// Small tag numbers should have used low tag number form.
tag_number < 0x1f) {
v < 0x1f) {
return 0;
}
tag_number = (unsigned)v;
}
tag |= tag_number;
@@ -405,6 +425,22 @@ int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
return 1;
}
int CBS_get_asn1_bool(CBS *cbs, int *out) {
CBS bytes;
if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_BOOLEAN) ||
CBS_len(&bytes) != 1) {
return 0;
}
const uint8_t value = *CBS_data(&bytes);
if (value != 0 && value != 0xff) {
return 0;
}
*out = !!value;
return 1;
}
int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
int present = 0;
@@ -527,3 +563,55 @@ int CBS_asn1_bitstring_has_bit(const CBS *cbs, unsigned bit) {
return byte_num < CBS_len(cbs) &&
(CBS_data(cbs)[byte_num] & (1 << bit_num)) != 0;
}
static int add_decimal(CBB *out, uint64_t v) {
char buf[DECIMAL_SIZE(uint64_t) + 1];
BIO_snprintf(buf, sizeof(buf), "%" PRIu64, v);
return CBB_add_bytes(out, (const uint8_t *)buf, strlen(buf));
}
char *CBS_asn1_oid_to_text(const CBS *cbs) {
CBB cbb;
if (!CBB_init(&cbb, 32)) {
goto err;
}
CBS copy = *cbs;
// The first component is 40 * value1 + value2, where value1 is 0, 1, or 2.
uint64_t v;
if (!parse_base128_integer(&copy, &v)) {
goto err;
}
if (v >= 80) {
if (!CBB_add_bytes(&cbb, (const uint8_t *)"2.", 2) ||
!add_decimal(&cbb, v - 80)) {
goto err;
}
} else if (!add_decimal(&cbb, v / 40) ||
!CBB_add_u8(&cbb, '.') ||
!add_decimal(&cbb, v % 40)) {
goto err;
}
while (CBS_len(&copy) != 0) {
if (!parse_base128_integer(&copy, &v) ||
!CBB_add_u8(&cbb, '.') ||
!add_decimal(&cbb, v)) {
goto err;
}
}
uint8_t *txt;
size_t txt_len;
if (!CBB_add_u8(&cbb, '\0') ||
!CBB_finish(&cbb, &txt, &txt_len)) {
goto err;
}
return (char *)txt;
err:
CBB_cleanup(&cbb);
return NULL;
}
+4
View File
@@ -171,6 +171,10 @@ my @ret;
$code.=<<___;
#include <openssl/arm_arch.h>
@ Silence ARMv8 deprecated IT instruction warnings. This file is used by both
@ ARMv7 and ARMv8 processors and does not use ARMv8 instructions.
.arch armv7-a
.text
#if defined(__thumb2__) || defined(__clang__)
.syntax unified
+1
View File
@@ -28,6 +28,7 @@
# Denver 4.50/+82% 2.63 2.67(*)
# X-Gene 9.50/+46% 8.82 8.89(*)
# Mongoose 8.00/+44% 3.64 3.25
# Kryo 8.17/+50% 4.83 4.65
#
# (*) it's expected that doubling interleave factor doesn't help
# all processors, only those with higher NEON latency and
+8 -1
View File
@@ -1,4 +1,11 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
#
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+1
View File
@@ -22,6 +22,7 @@ add_library(
e_rc4.c
e_aesgcmsiv.c
e_aesctrhmac.c
e_aesccm.c
e_chacha20poly1305.c
tls_cbc.c
+38
View File
@@ -93,6 +93,8 @@ static const struct KnownAEAD kAEADs[] = {
"aes_128_ctr_hmac_sha256.txt", false, true, 0},
{"AES_256_CTR_HMAC_SHA256", EVP_aead_aes_256_ctr_hmac_sha256,
"aes_256_ctr_hmac_sha256.txt", false, true, 0},
{"AES_128_CCM_BLUETOOTH", EVP_aead_aes_128_ccm_bluetooth,
"aes_128_ccm_bluetooth_tests.txt", false, false, 0},
};
class PerAEADTest : public testing::TestWithParam<KnownAEAD> {
@@ -651,3 +653,39 @@ TEST(AEADTest, AESGCMEmptyNonce) {
EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
}
TEST(AEADTest, AESCCMLargeAD) {
static const std::vector<uint8_t> kKey(16, 'A');
static const std::vector<uint8_t> kNonce(13, 'N');
static const std::vector<uint8_t> kAD(65536, 'D');
static const std::vector<uint8_t> kPlaintext = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
static const std::vector<uint8_t> kCiphertext = {
0xa2, 0x12, 0x3f, 0x0b, 0x07, 0xd5, 0x02, 0xff,
0xa9, 0xcd, 0xa0, 0xf3, 0x69, 0x1c, 0x49, 0x0c};
static const std::vector<uint8_t> kTag = {0x4a, 0x31, 0x82, 0x96};
// Test AES-128-CCM-Bluetooth.
bssl::ScopedEVP_AEAD_CTX ctx;
ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_128_ccm_bluetooth(),
kKey.data(), kKey.size(),
EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
std::vector<uint8_t> out(kCiphertext.size() + kTag.size());
size_t out_len;
EXPECT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
kNonce.data(), kNonce.size(), kPlaintext.data(),
kPlaintext.size(), kAD.data(), kAD.size()));
ASSERT_EQ(out_len, kCiphertext.size() + kTag.size());
EXPECT_EQ(Bytes(kCiphertext), Bytes(out.data(), kCiphertext.size()));
EXPECT_EQ(Bytes(kTag), Bytes(out.data() + kCiphertext.size(), kTag.size()));
EXPECT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
kNonce.data(), kNonce.size(), out.data(),
out.size(), kAD.data(), kAD.size()));
ASSERT_EQ(out_len, kPlaintext.size());
EXPECT_EQ(Bytes(kPlaintext), Bytes(out.data(), kPlaintext.size()));
}
+171
View File
@@ -0,0 +1,171 @@
/* Copyright (c) 2018, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <openssl/aead.h>
#include <assert.h>
#include <openssl/cipher.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../fipsmodule/cipher/internal.h"
#define EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN 4
#define EVP_AEAD_AES_CCM_BLUETOOTH_NONCE_LEN 13
#define EVP_AEAD_AES_CCM_MAX_TAG_LEN 16
struct aead_aes_ccm_ctx {
union {
double align;
AES_KEY ks;
} ks;
CCM128_CONTEXT ccm;
};
static int aead_aes_ccm_bluetooth_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
size_t key_len, size_t tag_len) {
if (key_len != 16) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
return 0; // EVP_AEAD_CTX_init should catch this.
}
if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) {
tag_len = EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN;
}
if (tag_len != EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE);
return 0;
}
struct aead_aes_ccm_ctx *ccm_ctx =
OPENSSL_malloc(sizeof(struct aead_aes_ccm_ctx));
if (ccm_ctx == NULL) {
OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
return 0;
}
block128_f block;
ctr128_f ctr = aes_ctr_set_key(&ccm_ctx->ks.ks, NULL, &block, key, key_len);
ctx->tag_len = tag_len;
if (!CRYPTO_ccm128_init(&ccm_ctx->ccm, &ccm_ctx->ks.ks, block, ctr, tag_len,
15 - EVP_AEAD_AES_CCM_BLUETOOTH_NONCE_LEN)) {
OPENSSL_PUT_ERROR(CIPHER, ERR_R_INTERNAL_ERROR);
OPENSSL_free(ccm_ctx);
return 0;
}
ctx->aead_state = ccm_ctx;
return 1;
}
static void aead_aes_ccm_cleanup(EVP_AEAD_CTX *ctx) {
OPENSSL_free(ctx->aead_state);
}
static int aead_aes_ccm_seal_scatter(
const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
const struct aead_aes_ccm_ctx *ccm_ctx = ctx->aead_state;
if (in_len > CRYPTO_ccm128_max_input(&ccm_ctx->ccm)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
return 0;
}
if (max_out_tag_len < ctx->tag_len) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
return 0;
}
if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE);
return 0;
}
if (!CRYPTO_ccm128_encrypt(&ccm_ctx->ccm, &ccm_ctx->ks.ks, out, out_tag,
ctx->tag_len, nonce, nonce_len, in, in_len, ad,
ad_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
return 0;
}
*out_tag_len = ctx->tag_len;
return 1;
}
static int aead_aes_ccm_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *in, size_t in_len,
const uint8_t *in_tag, size_t in_tag_len,
const uint8_t *ad, size_t ad_len) {
const struct aead_aes_ccm_ctx *ccm_ctx = ctx->aead_state;
if (in_len > CRYPTO_ccm128_max_input(&ccm_ctx->ccm)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
return 0;
}
if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE);
return 0;
}
if (in_tag_len != ctx->tag_len) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
return 0;
}
uint8_t tag[EVP_AEAD_AES_CCM_MAX_TAG_LEN];
assert(ctx->tag_len <= EVP_AEAD_AES_CCM_MAX_TAG_LEN);
if (!CRYPTO_ccm128_decrypt(&ccm_ctx->ccm, &ccm_ctx->ks.ks, out, tag,
ctx->tag_len, nonce, nonce_len, in, in_len, ad,
ad_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
return 0;
}
if (CRYPTO_memcmp(tag, in_tag, ctx->tag_len) != 0) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
return 0;
}
return 1;
}
static const EVP_AEAD aead_aes_128_ccm_bluetooth = {
16,
EVP_AEAD_AES_CCM_BLUETOOTH_NONCE_LEN, // nonce length
EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN, // overhead
EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN, // max tag length
0, // seal_scatter_supports_extra_in
aead_aes_ccm_bluetooth_init,
NULL /* init_with_direction */,
aead_aes_ccm_cleanup,
NULL /* open */,
aead_aes_ccm_seal_scatter,
aead_aes_ccm_open_gather,
NULL /* get_iv */,
NULL /* tag_len */,
};
const EVP_AEAD *EVP_aead_aes_128_ccm_bluetooth(void) {
return &aead_aes_128_ccm_bluetooth;
}
+2
View File
@@ -57,6 +57,8 @@
#include <openssl/cipher.h>
#include <openssl/nid.h>
#include "../internal.h"
#define c2l(c, l) \
do { \
+1 -2
View File
@@ -191,8 +191,7 @@ static int aead_tls_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
// block from encrypting the input and split the result between |out| and
// |out_tag|. Then feed the rest.
const size_t early_mac_len =
(block_size - (in_len % block_size) % block_size);
const size_t early_mac_len = (block_size - (in_len % block_size)) % block_size;
if (early_mac_len != 0) {
assert(len + block_size - early_mac_len == in_len);
uint8_t buf[EVP_MAX_BLOCK_LENGTH];
@@ -0,0 +1,20 @@
KEY: 404142434445464748494a4b4c4d4e4f
NONCE: 101112131415161718191a1b1c
IN: 20212223
AD: 0001020304050607
CT: 69915dad
TAG: 064617ca
KEY: 404142434445464748494a4b4c4d4e4f
NONCE: 101112131415161718191a1b1c
IN: 202122232425262728292a2b2c2d2e2f
AD: 0001020304050607
CT: 69915dad1e84c6376a68c2967e4dab61
TAG: 99763ebb
KEY: 404142434445464748494a4b4c4d4e4f
NONCE: 101112131415161718191a1b1c
IN: 202122232425262728292a2b2c2d2e2f
AD:
CT: 69915dad1e84c6376a68c2967e4dab61
TAG: c4630026
+55
View File
@@ -0,0 +1,55 @@
/* Copyright (c) 2018, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <openssl/cpu.h>
#if defined(OPENSSL_AARCH64) && defined(OPENSSL_FUCHSIA) && \
!defined(OPENSSL_STATIC_ARMCAP)
#include <zircon/features.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
#include <openssl/arm_arch.h>
#include "internal.h"
extern uint32_t OPENSSL_armcap_P;
void OPENSSL_cpuid_setup(void) {
uint32_t hwcap;
zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &hwcap);
if (rc != ZX_OK || (hwcap & ZX_ARM64_FEATURE_ISA_ASIMD) == 0) {
// Matching OpenSSL, if NEON/ASIMD is missing, don't report other features
// either.
return;
}
OPENSSL_armcap_P |= ARMV7_NEON;
if (hwcap & ZX_ARM64_FEATURE_ISA_AES) {
OPENSSL_armcap_P |= ARMV8_AES;
}
if (hwcap & ZX_ARM64_FEATURE_ISA_PMULL) {
OPENSSL_armcap_P |= ARMV8_PMULL;
}
if (hwcap & ZX_ARM64_FEATURE_ISA_SHA1) {
OPENSSL_armcap_P |= ARMV8_SHA1;
}
if (hwcap & ZX_ARM64_FEATURE_ISA_SHA2) {
OPENSSL_armcap_P |= ARMV8_SHA256;
}
}
#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP
+2 -1
View File
@@ -14,7 +14,8 @@
#include <openssl/cpu.h>
#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP)
#if defined(OPENSSL_AARCH64) && defined(OPENSSL_LINUX) && \
!defined(OPENSSL_STATIC_ARMCAP)
#include <sys/auxv.h>
-9
View File
@@ -8,21 +8,12 @@ if (${ARCH} STREQUAL "arm")
)
endif()
if (${ARCH} STREQUAL "x86_64")
set(
CURVE25519_ARCH_SOURCES
asm/x25519-asm-x86_64.S
)
endif()
add_library(
curve25519
OBJECT
spake25519.c
x25519-x86_64.c
${CURVE25519_ARCH_SOURCES}
)
File diff suppressed because it is too large Load Diff
+22
View File
@@ -44,6 +44,28 @@ TEST(Ed25519Test, TestVectors) {
});
}
TEST(Ed25519Test, Malleability) {
// https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
// that s be in [0, order). This prevents someone from adding a multiple of
// order to s and obtaining a second valid signature for the same message.
static const uint8_t kMsg[] = {0x54, 0x65, 0x73, 0x74};
static const uint8_t kSig[] = {
0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
};
static const uint8_t kPub[] = {
0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
};
EXPECT_FALSE(ED25519_verify(kMsg, sizeof(kMsg), kSig, kPub));
}
TEST(Ed25519Test, KeypairFromSeed) {
uint8_t public_key1[32], private_key1[64];
ED25519_keypair(public_key1, private_key1);
-247
View File
@@ -1,247 +0,0 @@
/* Copyright (c) 2015, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
// This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
// 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as
// public domain but this file has the ISC license just to keep licencing
// simple.
//
// The field functions are shared by Ed25519 and X25519 where possible.
#include <openssl/curve25519.h>
#include <string.h>
#include "../internal.h"
#include "../../third_party/fiat/internal.h"
#if defined(BORINGSSL_X25519_X86_64)
typedef struct { uint64_t v[5]; } fe25519;
// These functions are defined in asm/x25519-x86_64.S
void x25519_x86_64_work_cswap(fe25519 *, uint64_t);
void x25519_x86_64_mul(fe25519 *out, const fe25519 *a, const fe25519 *b);
void x25519_x86_64_square(fe25519 *out, const fe25519 *a);
void x25519_x86_64_freeze(fe25519 *);
void x25519_x86_64_ladderstep(fe25519 *work);
static void fe25519_setint(fe25519 *r, unsigned v) {
r->v[0] = v;
r->v[1] = 0;
r->v[2] = 0;
r->v[3] = 0;
r->v[4] = 0;
}
// Assumes input x being reduced below 2^255
static void fe25519_pack(unsigned char r[32], const fe25519 *x) {
fe25519 t;
t = *x;
x25519_x86_64_freeze(&t);
r[0] = (uint8_t)(t.v[0] & 0xff);
r[1] = (uint8_t)((t.v[0] >> 8) & 0xff);
r[2] = (uint8_t)((t.v[0] >> 16) & 0xff);
r[3] = (uint8_t)((t.v[0] >> 24) & 0xff);
r[4] = (uint8_t)((t.v[0] >> 32) & 0xff);
r[5] = (uint8_t)((t.v[0] >> 40) & 0xff);
r[6] = (uint8_t)((t.v[0] >> 48));
r[6] ^= (uint8_t)((t.v[1] << 3) & 0xf8);
r[7] = (uint8_t)((t.v[1] >> 5) & 0xff);
r[8] = (uint8_t)((t.v[1] >> 13) & 0xff);
r[9] = (uint8_t)((t.v[1] >> 21) & 0xff);
r[10] = (uint8_t)((t.v[1] >> 29) & 0xff);
r[11] = (uint8_t)((t.v[1] >> 37) & 0xff);
r[12] = (uint8_t)((t.v[1] >> 45));
r[12] ^= (uint8_t)((t.v[2] << 6) & 0xc0);
r[13] = (uint8_t)((t.v[2] >> 2) & 0xff);
r[14] = (uint8_t)((t.v[2] >> 10) & 0xff);
r[15] = (uint8_t)((t.v[2] >> 18) & 0xff);
r[16] = (uint8_t)((t.v[2] >> 26) & 0xff);
r[17] = (uint8_t)((t.v[2] >> 34) & 0xff);
r[18] = (uint8_t)((t.v[2] >> 42) & 0xff);
r[19] = (uint8_t)((t.v[2] >> 50));
r[19] ^= (uint8_t)((t.v[3] << 1) & 0xfe);
r[20] = (uint8_t)((t.v[3] >> 7) & 0xff);
r[21] = (uint8_t)((t.v[3] >> 15) & 0xff);
r[22] = (uint8_t)((t.v[3] >> 23) & 0xff);
r[23] = (uint8_t)((t.v[3] >> 31) & 0xff);
r[24] = (uint8_t)((t.v[3] >> 39) & 0xff);
r[25] = (uint8_t)((t.v[3] >> 47));
r[25] ^= (uint8_t)((t.v[4] << 4) & 0xf0);
r[26] = (uint8_t)((t.v[4] >> 4) & 0xff);
r[27] = (uint8_t)((t.v[4] >> 12) & 0xff);
r[28] = (uint8_t)((t.v[4] >> 20) & 0xff);
r[29] = (uint8_t)((t.v[4] >> 28) & 0xff);
r[30] = (uint8_t)((t.v[4] >> 36) & 0xff);
r[31] = (uint8_t)((t.v[4] >> 44));
}
static void fe25519_unpack(fe25519 *r, const uint8_t x[32]) {
r->v[0] = x[0];
r->v[0] += (uint64_t)x[1] << 8;
r->v[0] += (uint64_t)x[2] << 16;
r->v[0] += (uint64_t)x[3] << 24;
r->v[0] += (uint64_t)x[4] << 32;
r->v[0] += (uint64_t)x[5] << 40;
r->v[0] += ((uint64_t)x[6] & 7) << 48;
r->v[1] = x[6] >> 3;
r->v[1] += (uint64_t)x[7] << 5;
r->v[1] += (uint64_t)x[8] << 13;
r->v[1] += (uint64_t)x[9] << 21;
r->v[1] += (uint64_t)x[10] << 29;
r->v[1] += (uint64_t)x[11] << 37;
r->v[1] += ((uint64_t)x[12] & 63) << 45;
r->v[2] = x[12] >> 6;
r->v[2] += (uint64_t)x[13] << 2;
r->v[2] += (uint64_t)x[14] << 10;
r->v[2] += (uint64_t)x[15] << 18;
r->v[2] += (uint64_t)x[16] << 26;
r->v[2] += (uint64_t)x[17] << 34;
r->v[2] += (uint64_t)x[18] << 42;
r->v[2] += ((uint64_t)x[19] & 1) << 50;
r->v[3] = x[19] >> 1;
r->v[3] += (uint64_t)x[20] << 7;
r->v[3] += (uint64_t)x[21] << 15;
r->v[3] += (uint64_t)x[22] << 23;
r->v[3] += (uint64_t)x[23] << 31;
r->v[3] += (uint64_t)x[24] << 39;
r->v[3] += ((uint64_t)x[25] & 15) << 47;
r->v[4] = x[25] >> 4;
r->v[4] += (uint64_t)x[26] << 4;
r->v[4] += (uint64_t)x[27] << 12;
r->v[4] += (uint64_t)x[28] << 20;
r->v[4] += (uint64_t)x[29] << 28;
r->v[4] += (uint64_t)x[30] << 36;
r->v[4] += ((uint64_t)x[31] & 127) << 44;
}
static void fe25519_invert(fe25519 *r, const fe25519 *x) {
fe25519 z2;
fe25519 z9;
fe25519 z11;
fe25519 z2_5_0;
fe25519 z2_10_0;
fe25519 z2_20_0;
fe25519 z2_50_0;
fe25519 z2_100_0;
fe25519 t;
int i;
/* 2 */ x25519_x86_64_square(&z2, x);
/* 4 */ x25519_x86_64_square(&t, &z2);
/* 8 */ x25519_x86_64_square(&t, &t);
/* 9 */ x25519_x86_64_mul(&z9, &t, x);
/* 11 */ x25519_x86_64_mul(&z11, &z9, &z2);
/* 22 */ x25519_x86_64_square(&t, &z11);
/* 2^5 - 2^0 = 31 */ x25519_x86_64_mul(&z2_5_0, &t, &z9);
/* 2^6 - 2^1 */ x25519_x86_64_square(&t, &z2_5_0);
/* 2^20 - 2^10 */ for (i = 1; i < 5; i++) { x25519_x86_64_square(&t, &t); }
/* 2^10 - 2^0 */ x25519_x86_64_mul(&z2_10_0, &t, &z2_5_0);
/* 2^11 - 2^1 */ x25519_x86_64_square(&t, &z2_10_0);
/* 2^20 - 2^10 */ for (i = 1; i < 10; i++) { x25519_x86_64_square(&t, &t); }
/* 2^20 - 2^0 */ x25519_x86_64_mul(&z2_20_0, &t, &z2_10_0);
/* 2^21 - 2^1 */ x25519_x86_64_square(&t, &z2_20_0);
/* 2^40 - 2^20 */ for (i = 1; i < 20; i++) { x25519_x86_64_square(&t, &t); }
/* 2^40 - 2^0 */ x25519_x86_64_mul(&t, &t, &z2_20_0);
/* 2^41 - 2^1 */ x25519_x86_64_square(&t, &t);
/* 2^50 - 2^10 */ for (i = 1; i < 10; i++) { x25519_x86_64_square(&t, &t); }
/* 2^50 - 2^0 */ x25519_x86_64_mul(&z2_50_0, &t, &z2_10_0);
/* 2^51 - 2^1 */ x25519_x86_64_square(&t, &z2_50_0);
/* 2^100 - 2^50 */ for (i = 1; i < 50; i++) { x25519_x86_64_square(&t, &t); }
/* 2^100 - 2^0 */ x25519_x86_64_mul(&z2_100_0, &t, &z2_50_0);
/* 2^101 - 2^1 */ x25519_x86_64_square(&t, &z2_100_0);
/* 2^200 - 2^100 */ for (i = 1; i < 100; i++) {
x25519_x86_64_square(&t, &t);
}
/* 2^200 - 2^0 */ x25519_x86_64_mul(&t, &t, &z2_100_0);
/* 2^201 - 2^1 */ x25519_x86_64_square(&t, &t);
/* 2^250 - 2^50 */ for (i = 1; i < 50; i++) { x25519_x86_64_square(&t, &t); }
/* 2^250 - 2^0 */ x25519_x86_64_mul(&t, &t, &z2_50_0);
/* 2^251 - 2^1 */ x25519_x86_64_square(&t, &t);
/* 2^252 - 2^2 */ x25519_x86_64_square(&t, &t);
/* 2^253 - 2^3 */ x25519_x86_64_square(&t, &t);
/* 2^254 - 2^4 */ x25519_x86_64_square(&t, &t);
/* 2^255 - 2^5 */ x25519_x86_64_square(&t, &t);
/* 2^255 - 21 */ x25519_x86_64_mul(r, &t, &z11);
}
static void mladder(fe25519 *xr, fe25519 *zr, const uint8_t s[32]) {
fe25519 work[5];
work[0] = *xr;
fe25519_setint(work + 1, 1);
fe25519_setint(work + 2, 0);
work[3] = *xr;
fe25519_setint(work + 4, 1);
int i, j;
uint8_t prevbit = 0;
j = 6;
for (i = 31; i >= 0; i--) {
while (j >= 0) {
const uint8_t bit = 1 & (s[i] >> j);
const uint64_t swap = bit ^ prevbit;
prevbit = bit;
x25519_x86_64_work_cswap(work + 1, swap);
x25519_x86_64_ladderstep(work);
j -= 1;
}
j = 7;
}
*xr = work[1];
*zr = work[2];
}
void x25519_x86_64(uint8_t out[32], const uint8_t scalar[32],
const uint8_t point[32]) {
uint8_t e[32];
OPENSSL_memcpy(e, scalar, sizeof(e));
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
fe25519 t;
fe25519 z;
fe25519_unpack(&t, point);
mladder(&t, &z, e);
fe25519_invert(&z, &z);
x25519_x86_64_mul(&t, &t, &z);
fe25519_pack(out, &t);
}
#endif // BORINGSSL_X25519_X86_64
+16 -54
View File
@@ -239,11 +239,6 @@ int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed_in,
}
BN_CTX_start(ctx);
mont = BN_MONT_CTX_new();
if (mont == NULL) {
goto err;
}
r0 = BN_CTX_get(ctx);
g = BN_CTX_get(ctx);
W = BN_CTX_get(ctx);
@@ -401,8 +396,9 @@ end:
goto err;
}
if (!BN_set_word(test, h) ||
!BN_MONT_CTX_set(mont, p, ctx)) {
mont = BN_MONT_CTX_new_for_modulus(p, ctx);
if (mont == NULL ||
!BN_set_word(test, h)) {
goto err;
}
@@ -839,7 +835,7 @@ int DSA_size(const DSA *dsa) {
static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
BIGNUM **out_r) {
BN_CTX *ctx;
BIGNUM k, kq, *kinv = NULL, *r = NULL;
BIGNUM k, *kinv = NULL, *r = NULL;
int ret = 0;
if (!dsa->p || !dsa->q || !dsa->g) {
@@ -848,7 +844,6 @@ static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
}
BN_init(&k);
BN_init(&kq);
ctx = ctx_in;
if (ctx == NULL) {
@@ -859,54 +854,22 @@ static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
}
r = BN_new();
if (r == NULL) {
goto err;
}
// Get random k
if (!BN_rand_range_ex(&k, 1, dsa->q)) {
goto err;
}
if (!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
kinv = BN_new();
if (r == NULL || kinv == NULL ||
// Get random k
!BN_rand_range_ex(&k, 1, dsa->q) ||
!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
(CRYPTO_MUTEX *)&dsa->method_mont_lock, dsa->p,
ctx) ||
!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_q,
(CRYPTO_MUTEX *)&dsa->method_mont_lock, dsa->q,
ctx)) {
goto err;
}
// Compute r = (g^k mod p) mod q
if (!BN_copy(&kq, &k)) {
goto err;
}
// We do not want timing information to leak the length of k,
// so we compute g^k using an equivalent exponent of fixed length.
//
// (This is a kludge that we need because the BN_mod_exp_mont()
// does not let us specify the desired timing behaviour.)
if (!BN_add(&kq, &kq, dsa->q)) {
goto err;
}
if (BN_num_bits(&kq) <= BN_num_bits(dsa->q) && !BN_add(&kq, &kq, dsa->q)) {
goto err;
}
if (!BN_mod_exp_mont_consttime(r, dsa->g, &kq, dsa->p, ctx,
dsa->method_mont_p)) {
goto err;
}
if (!BN_mod(r, r, dsa->q, ctx)) {
goto err;
}
// Compute part of 's = inv(k) (m + xr) mod q' using Fermat's Little
// Theorem.
kinv = BN_new();
if (kinv == NULL ||
ctx) ||
// Compute r = (g^k mod p) mod q
!BN_mod_exp_mont_consttime(r, dsa->g, &k, dsa->p, ctx,
dsa->method_mont_p) ||
!BN_mod(r, r, dsa->q, ctx) ||
// Compute part of 's = inv(k) (m + xr) mod q' using Fermat's Little
// Theorem.
!bn_mod_inverse_prime(kinv, &k, dsa->q, ctx, dsa->method_mont_q)) {
goto err;
}
@@ -930,7 +893,6 @@ err:
BN_CTX_free(ctx);
}
BN_clear_free(&k);
BN_clear_free(&kq);
BN_clear_free(kinv);
return ret;
}
+5
View File
@@ -52,6 +52,7 @@ SSL,254,DOWNGRADE_DETECTED
SSL,143,DTLS_MESSAGE_TOO_BIG
SSL,257,DUPLICATE_EXTENSION
SSL,264,DUPLICATE_KEY_SHARE
SSL,283,EARLY_DATA_NOT_IN_USE
SSL,144,ECC_CERT_NOT_FOR_SIGNING
SSL,282,EMPTY_HELLO_RETRY_REQUEST
SSL,145,EMS_STATE_INCONSISTENT
@@ -64,6 +65,7 @@ SSL,151,EXTRA_DATA_IN_MESSAGE
SSL,152,FRAGMENT_MISMATCH
SSL,153,GOT_NEXT_PROTO_WITHOUT_EXTENSION
SSL,154,HANDSHAKE_FAILURE_ON_CLIENT_HELLO
SSL,284,HANDSHAKE_NOT_COMPLETE
SSL,155,HTTPS_PROXY_REQUEST
SSL,156,HTTP_REQUEST
SSL,157,INAPPROPRIATE_FALLBACK
@@ -84,6 +86,7 @@ SSL,167,MISSING_TMP_ECDH_KEY
SSL,168,MIXED_SPECIAL_OPERATOR_WITH_GROUPS
SSL,169,MTU_TOO_SMALL
SSL,170,NEGOTIATED_BOTH_NPN_AND_ALPN
SSL,285,NEGOTIATED_TB_WITHOUT_EMS_OR_RI
SSL,171,NESTED_GROUP
SSL,172,NO_CERTIFICATES_RETURNED
SSL,173,NO_CERTIFICATE_ASSIGNED
@@ -114,6 +117,7 @@ SSL,191,PATH_TOO_LONG
SSL,192,PEER_DID_NOT_RETURN_A_CERTIFICATE
SSL,193,PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE
SSL,267,PRE_SHARED_KEY_MUST_BE_LAST
SSL,287,PRIVATE_KEY_OPERATION_FAILED
SSL,194,PROTOCOL_IS_SHUTDOWN
SSL,271,PSK_IDENTITY_BINDER_COUNT_MISMATCH
SSL,195,PSK_IDENTITY_NOT_FOUND
@@ -131,6 +135,7 @@ SSL,205,RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION
SSL,206,SCSV_RECEIVED_WHEN_RENEGOTIATING
SSL,207,SERVERHELLO_TLSEXT
SSL,273,SERVER_CERT_CHANGED
SSL,286,SERVER_ECHOED_INVALID_SESSION_ID
SSL,208,SESSION_ID_CONTEXT_UNINITIALIZED
SSL,209,SESSION_MAY_NOT_BE_CREATED
SSL,250,SHUTDOWN_WHILE_IN_INIT
+22
View File
@@ -545,6 +545,28 @@ OAEPLabel = 00112233445566778899aabbccddeeff
Input = "Hello World"
CheckDecrypt
# Though we will never generate such a key, test that RSA keys where p < q work
# properly.
PrivateKey = RSA-Swapped
Type = RSA
Input = 30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100ab28f98747934779011417d5bbb4095eae6f48ed09e13081616cf390aac75b10a206a98953d402647dfef7fa363be2765a303b05ec388bd9a1d75123a1205b4ecb43c33f2e37d3e30842181d694a3acfc39afc52554946e699d97d97066596a46725ce6dea322623afcafecbd2884d9a0c5eae9c4d7da8874c29c19edb762e1902030100010281800d637ea568e169f15ab6be288f6ec55edd29425c9c6dbb941b5160fa1b89cda34ef15378b5107c016d63b0f52721e71497f876dd7f3d6b1f228c4bc20c3c12384644200e91130c9195660d1e706f55b2accf00c5e2174a1d9ee289f0e763ee58860485ec97d19d7fa2df38af5b5910b1fa52087768d288e6ec4c8d5eca23c8d3024100be757a24dc2c923692d964693b2d71ca33ccb2f946f9e5232d2090b715a97dca554068fab8876105bc9ed6dccfd0917c5e0b80339306535c3eeb787e89397bc7024100e60f5c9e52434da079b8c641791a81a96daa4d9921a07e5b48292a9fce230df7c9fc2b97b5e38834ed5caaa387a0bca35c474e989a68dd65b79a6f691a74471f0240438ccf017bc5a3260ff76291a01782204136fcd344c524ebd0f997da17a8c1a09d93f6a7d602cdfa86e79f3539cfb389f4a1079b432e1f2abc762f8a51893dc9024046604ca4e1e554c9d27283b363a888219c3a8ca25b770d303f52d8872a37eefdedfc0619d2ba57e058fc0ff71676453e73ec1c4ef26d41ccebed824754a05d6102404445374d8450e753e0a42085b56b0d6d500b3e3518536dc8f12ec8fd77aa75491835327ac0e12d73b5c3f1b09d03f6a24fe63b9c551dee6559b625435ec92429
Sign = RSA-Swapped
Digest = SHA256
Input = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
Output = 07fa4e3de9c002c41c952dc292ef5a814c4c17dc1a6cf958c4c971e8089676d6661b442270ef9295c41e5385c9628aa1bdee2cc2558b8473ba212f2ba04b9ff2264c19187b9506b1d0a1cc2751844cc8dedf555d62ce81bc0e70bfe83d0184ee964593af91b9b327c0fb272c799148cd8737d412cbf36c2ad25fd66977bf805f
# Though we will never generate such a key, test that RSA keys where p and q are
# different sizes work properly.
PrivateKey = RSA-PrimeMismatch
Type = RSA
Input = 30820295020100300d06092a864886f70d01010105000482027f3082027b02010002818100c766f4fef89f5e9a8e13ed500fb38523ea94d7f8be066900eee58c913b4c6fdcb13d63d39b9108feabcefd1ffd04776403dc58f968ae817977d0809e567d8af512d604a0e9cb448fa5e402204ee519712a5ebbfd002faf8169495a782f54366b4665aac0d968bfec63c5446b6f9b13061c7f3d1f3f1b6bede8fff881b410a66f0203010001028180528c062f49485c771a0b18ca747d8a47f8941ea63c305626cb3f1f067e6861c4441c432687dbd08d484aac3b01f3ffdc3b762c719167f7cb22e565aa6acd597306ef6f7828b9720e9d440816186d940c4c5a9720dddf71fe0b59483f02a751515c8c27e43c575d6725d55f5bb77e0f977773b00afc058cfab6617ec90d0b62a9026100cb8f97c37b4fbc298b645bc3dc0526f8a4274e9a193b33c3acb76499b5b96330e4b586cbaa56368ffc12644952322253bc669496d572c0980f125fd7273739cf790d24401052b13732114d397c8c16a44716dc62d2320fb1ced99290dfd53e07022100fac51ac653609cdaba53280c6b6f209052e270be0c3c68fe8b37d6bf05fbba59026038dff2f04c58d7e2e7ae6fb1469d2de954bc22cb0d77ac1be4fb0ca1a1d39d7240c4b357de4cde4bd68b30f8077e38771af1b25c7e60e48cd7d1337402e1fc460ab57046720918b8aa4589452196669119c7ba65e602d4bdc264a9fdce7c5f2b0220773af0180bdc8bb7938fa6230191bcb1e236b7d4248d347e9242e25fc0c0874102605c4894cde334889f5b52ed8f86a2ee9c1fbe4166287e24ce44f3093bff383962f08043842f6ff3e6002104b0e29442c4a4483c5d06e2254fbe5e3930de3d0e28af10e96c6e341a4b8859382dbba24536a38ae71118e3e22413a93f298a7f744c
Sign = RSA-PrimeMismatch
Digest = SHA256
Input = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
Output = 6192b1ce630c87d02e8245fd74d4f6ecac37eef979d188c8fa48c4d355fbe814e7dd3152f42bb020d769b540d11867af5b947387b8c99158d56901ff3708e423931178213916ae1002f162c9d497aacacdcb20e6ffe7ed40138a253fc943ddf3587433df5831a3ce46aeefce358a009bf6bad12d82d77424c2755d984d7da196
# EC tests
+1 -1
View File
@@ -8,7 +8,7 @@ Please note that we cannot answer questions about FIPS, nor about using BoringSS
BoringCrypto has undergone the following validations:
1. 2017-06-15: certificate [#2964](http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/1401val2017.htm#2964), [security policy](/crypto/fipsmodule/policydocs/BoringCrypto-Security-Policy-20170615.docx) (in docx format).
1. 2017-06-15: certificate [#2964](https://csrc.nist.gov/Projects/Cryptographic-Module-Validation-Program/Certificate/2964), [security policy](/crypto/fipsmodule/policydocs/BoringCrypto-Security-Policy-20170615.docx) (in docx format).
## Running CAVP tests
+18 -11
View File
@@ -1,7 +1,14 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
#
# ====================================================================
# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
# project. The module is, however, dual licensed under OpenSSL and
# CRYPTOGAMS licenses depending on where you obtain it. For further
# details see http://www.openssl.org/~appro/cryptogams/.
@@ -32,7 +39,7 @@
# for scaling too, I [try to] avoid the latter by favoring off-by-2
# shifts and masking the result with 0xFF<<2 instead of "boring" 0xFF.
#
# As was shown by Dean Gaudet <dean@arctic.org>, the above note turned
# As was shown by Dean Gaudet, the above note turned out to be
# void. Performance improvement with off-by-2 shifts was observed on
# intermediate implementation, which was spilling yet another register
# to stack... Final offset*4 code below runs just a tad faster on P4,
@@ -48,8 +55,8 @@
# better performance on most recent µ-archs...
#
# Third version adds AES_cbc_encrypt implementation, which resulted in
# up to 40% performance imrovement of CBC benchmark results. 40% was
# observed on P4 core, where "overall" imrovement coefficient, i.e. if
# up to 40% performance improvement of CBC benchmark results. 40% was
# observed on P4 core, where "overall" improvement coefficient, i.e. if
# compared to PIC generated by GCC and in CBC mode, was observed to be
# as large as 4x:-) CBC performance is virtually identical to ECB now
# and on some platforms even better, e.g. 17.6 "small" cycles/byte on
@@ -152,7 +159,7 @@
# combinations then attack becomes infeasible. This is why revised
# AES_cbc_encrypt "dares" to switch to larger S-box when larger chunk
# of data is to be processed in one stroke. The current size limit of
# 512 bytes is chosen to provide same [diminishigly low] probability
# 512 bytes is chosen to provide same [diminishingly low] probability
# for cache-line to remain untouched in large chunk operation with
# large S-box as for single block operation with compact S-box and
# surely needs more careful consideration...
@@ -164,12 +171,12 @@
# yield execution to process performing AES just before timer fires
# off the scheduler, immediately regain control of CPU and analyze the
# cache state. For this attack to be efficient attacker would have to
# effectively slow down the operation by several *orders* of magnitute,
# effectively slow down the operation by several *orders* of magnitude,
# by ratio of time slice to duration of handful of AES rounds, which
# unlikely to remain unnoticed. Not to mention that this also means
# that he would spend correspondigly more time to collect enough
# that he would spend correspondingly more time to collect enough
# statistical data to mount the attack. It's probably appropriate to
# say that if adeversary reckons that this attack is beneficial and
# say that if adversary reckons that this attack is beneficial and
# risks to be noticed, you probably have larger problems having him
# mere opportunity. In other words suggested code design expects you
# to preclude/mitigate this attack by overall system security design.
@@ -233,7 +240,7 @@ $small_footprint=1; # $small_footprint=1 code is ~5% slower [on
# contention and in hope to "collect" 5% back
# in real-life applications...
$vertical_spin=0; # shift "verticaly" defaults to 0, because of
$vertical_spin=0; # shift "vertically" defaults to 0, because of
# its proof-of-concept status...
# Note that there is no decvert(), as well as last encryption round is
# performed with "horizontal" shifts. This is because this "vertical"
@@ -1599,7 +1606,7 @@ sub decstep()
# no instructions are reordered, as performance appears
# optimal... or rather that all attempts to reorder didn't
# result in better performance [which by the way is not a
# bit lower than ecryption].
# bit lower than encryption].
if($i==3) { &mov ($key,$__key); }
else { &mov ($out,$s[0]); }
&and ($out,0xFF);
+8 -3
View File
@@ -76,6 +76,11 @@ $code=<<___;
# define __ARM_ARCH__ __LINUX_ARM_ARCH__
#endif
@ Silence ARMv8 deprecated IT instruction warnings. This file is used by both
@ ARMv7 and ARMv8 processors and does not use ARMv8 instructions. (ARMv8 AES
@ instructions are in aesv8-armx.pl.)
.arch armv7-a
.text
#if defined(__thumb2__) && !defined(__APPLE__)
.syntax unified
@@ -203,7 +208,7 @@ asm_AES_encrypt:
adr r3,.
#endif
stmdb sp!,{r1,r4-r12,lr}
#ifdef __APPLE__
#if defined(__thumb2__) || defined(__APPLE__)
adr $tbl,AES_Te
#else
sub $tbl,r3,#asm_AES_encrypt-AES_Te @ Te
@@ -481,7 +486,7 @@ _armv4_AES_set_encrypt_key:
mov lr,r1 @ bits
mov $key,r2 @ key
#ifdef __APPLE__
#if defined(__thumb2__) || defined(__APPLE__)
adr $tbl,AES_Te+1024 @ Te4
#else
sub $tbl,r3,#_armv4_AES_set_encrypt_key-AES_Te-1024 @ Te4
@@ -979,7 +984,7 @@ asm_AES_decrypt:
adr r3,.
#endif
stmdb sp!,{r1,r4-r12,lr}
#ifdef __APPLE__
#if defined(__thumb2__) || defined(__APPLE__)
adr $tbl,AES_Td
#else
sub $tbl,r3,#asm_AES_decrypt-AES_Td @ Td
+94 -3
View File
@@ -1,7 +1,14 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
#
# ====================================================================
# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
# project. The module is, however, dual licensed under OpenSSL and
# CRYPTOGAMS licenses depending on where you obtain it. For further
# details see http://www.openssl.org/~appro/cryptogams/.
@@ -590,13 +597,21 @@ $code.=<<___;
.type asm_AES_encrypt,\@function,3
.hidden asm_AES_encrypt
asm_AES_encrypt:
.cfi_startproc
mov %rsp,%rax
.cfi_def_cfa_register %rax
push %rbx
.cfi_push %rbx
push %rbp
.cfi_push %rbp
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
# allocate frame "above" key schedule
lea -63(%rdx),%rcx # %rdx is key argument
@@ -609,6 +624,7 @@ asm_AES_encrypt:
mov %rsi,16(%rsp) # save out
mov %rax,24(%rsp) # save original stack pointer
.cfi_cfa_expression %rsp+24,deref,+8
.Lenc_prologue:
mov %rdx,$key
@@ -635,20 +651,29 @@ asm_AES_encrypt:
mov 16(%rsp),$out # restore out
mov 24(%rsp),%rsi # restore saved stack pointer
.cfi_def_cfa %rsi,8
mov $s0,0($out) # write output vector
mov $s1,4($out)
mov $s2,8($out)
mov $s3,12($out)
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lenc_epilogue:
ret
.cfi_endproc
.size asm_AES_encrypt,.-asm_AES_encrypt
___
@@ -1186,13 +1211,21 @@ $code.=<<___;
.type asm_AES_decrypt,\@function,3
.hidden asm_AES_decrypt
asm_AES_decrypt:
.cfi_startproc
mov %rsp,%rax
.cfi_def_cfa_register %rax
push %rbx
.cfi_push %rbx
push %rbp
.cfi_push %rbp
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
# allocate frame "above" key schedule
lea -63(%rdx),%rcx # %rdx is key argument
@@ -1205,6 +1238,7 @@ asm_AES_decrypt:
mov %rsi,16(%rsp) # save out
mov %rax,24(%rsp) # save original stack pointer
.cfi_cfa_expression %rsp+24,deref,+8
.Ldec_prologue:
mov %rdx,$key
@@ -1233,20 +1267,29 @@ asm_AES_decrypt:
mov 16(%rsp),$out # restore out
mov 24(%rsp),%rsi # restore saved stack pointer
.cfi_def_cfa %rsi,8
mov $s0,0($out) # write output vector
mov $s1,4($out)
mov $s2,8($out)
mov $s3,12($out)
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Ldec_epilogue:
ret
.cfi_endproc
.size asm_AES_decrypt,.-asm_AES_decrypt
___
#------------------------------------------------------------------#
@@ -1284,22 +1327,34 @@ $code.=<<___;
.globl asm_AES_set_encrypt_key
.type asm_AES_set_encrypt_key,\@function,3
asm_AES_set_encrypt_key:
.cfi_startproc
push %rbx
.cfi_push %rbx
push %rbp
.cfi_push %rbp
push %r12 # redundant, but allows to share
.cfi_push %r12
push %r13 # exception handler...
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
sub \$8,%rsp
.cfi_adjust_cfa_offset 8
.Lenc_key_prologue:
call _x86_64_AES_set_encrypt_key
mov 40(%rsp),%rbp
.cfi_restore %rbp
mov 48(%rsp),%rbx
.cfi_restore %rbx
add \$56,%rsp
.cfi_adjust_cfa_offset -56
.Lenc_key_epilogue:
ret
.cfi_endproc
.size asm_AES_set_encrypt_key,.-asm_AES_set_encrypt_key
.type _x86_64_AES_set_encrypt_key,\@abi-omnipotent
@@ -1549,13 +1604,21 @@ $code.=<<___;
.globl asm_AES_set_decrypt_key
.type asm_AES_set_decrypt_key,\@function,3
asm_AES_set_decrypt_key:
.cfi_startproc
push %rbx
.cfi_push %rbx
push %rbp
.cfi_push %rbp
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
push %rdx # save key schedule
.cfi_adjust_cfa_offset 8
.Ldec_key_prologue:
call _x86_64_AES_set_encrypt_key
@@ -1609,14 +1672,22 @@ $code.=<<___;
xor %rax,%rax
.Labort:
mov 8(%rsp),%r15
.cfi_restore %r15
mov 16(%rsp),%r14
.cfi_restore %r14
mov 24(%rsp),%r13
.cfi_restore %r13
mov 32(%rsp),%r12
.cfi_restore %r12
mov 40(%rsp),%rbp
.cfi_restore %rbp
mov 48(%rsp),%rbx
.cfi_restore %rbx
add \$56,%rsp
.cfi_adjust_cfa_offset -56
.Ldec_key_epilogue:
ret
.cfi_endproc
.size asm_AES_set_decrypt_key,.-asm_AES_set_decrypt_key
___
@@ -1645,15 +1716,23 @@ $code.=<<___;
.extern OPENSSL_ia32cap_P
.hidden asm_AES_cbc_encrypt
asm_AES_cbc_encrypt:
.cfi_startproc
cmp \$0,%rdx # check length
je .Lcbc_epilogue
pushfq
.cfi_push 49 # %rflags
push %rbx
.cfi_push %rbx
push %rbp
.cfi_push %rbp
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
.Lcbc_prologue:
cld
@@ -1699,8 +1778,10 @@ asm_AES_cbc_encrypt:
.Lcbc_te_ok:
xchg %rsp,$key
.cfi_def_cfa_register $key
#add \$8,%rsp # reserve for return address!
mov $key,$_rsp # save %rsp
.cfi_cfa_expression $_rsp,deref,+64
.Lcbc_fast_body:
mov %rdi,$_inp # save copy of inp
mov %rsi,$_out # save copy of out
@@ -1930,7 +2011,7 @@ asm_AES_cbc_encrypt:
lea ($key,%rax),%rax
mov %rax,$keyend
# pick Te4 copy which can't "overlap" with stack frame or key scdedule
# pick Te4 copy which can't "overlap" with stack frame or key schedule
lea 2048($sbox),$sbox
lea 768-8(%rsp),%rax
sub $sbox,%rax
@@ -2082,17 +2163,27 @@ asm_AES_cbc_encrypt:
.align 16
.Lcbc_exit:
mov $_rsp,%rsi
.cfi_def_cfa %rsi,64
mov (%rsi),%r15
.cfi_restore %r15
mov 8(%rsi),%r14
.cfi_restore %r14
mov 16(%rsi),%r13
.cfi_restore %r13
mov 24(%rsi),%r12
.cfi_restore %r12
mov 32(%rsi),%rbp
.cfi_restore %rbp
mov 40(%rsi),%rbx
.cfi_restore %rbx
lea 48(%rsi),%rsp
.cfi_def_cfa %rsp,16
.Lcbc_popfq:
popfq
.cfi_pop 49 # %rflags
.Lcbc_epilogue:
ret
.cfi_endproc
.size asm_AES_cbc_encrypt,.-asm_AES_cbc_encrypt
___
}
+21 -10
View File
@@ -1,4 +1,11 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2009-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -43,18 +50,22 @@
# Add aesni_xts_[en|de]crypt. Westmere spends 1.50 cycles processing
# one byte out of 8KB with 128-bit key, Sandy Bridge - 1.09.
# November 2015
#
# Add aesni_ocb_[en|de]crypt. [Removed in BoringSSL]
######################################################################
# Current large-block performance in cycles per byte processed with
# 128-bit key (less is better).
#
# CBC en-/decrypt CTR XTS ECB
# CBC en-/decrypt CTR XTS ECB OCB
# Westmere 3.77/1.37 1.37 1.52 1.27
# * Bridge 5.07/0.98 0.99 1.09 0.91
# Haswell 4.44/0.80 0.97 1.03 0.72
# Skylake 2.68/0.65 0.65 0.66 0.64
# Silvermont 5.77/3.56 3.67 4.03 3.46
# Goldmont 3.84/1.39 1.39 1.63 1.31
# Bulldozer 5.80/0.98 1.05 1.24 0.93
# * Bridge 5.07/0.98 0.99 1.09 0.91 1.10
# Haswell 4.44/0.80 0.97 1.03 0.72 0.76
# Skylake 2.68/0.65 0.65 0.66 0.64 0.66
# Silvermont 5.77/3.56 3.67 4.03 3.46 4.03
# Goldmont 3.84/1.39 1.39 1.63 1.31 1.70
# Bulldozer 5.80/0.98 1.05 1.24 0.93 1.23
$PREFIX="aesni"; # if $PREFIX is set to "AES", the script
# generates drop-in replacement for
@@ -228,7 +239,7 @@ sub aesni_generate1 # fully unrolled loop
# can schedule aes[enc|dec] every cycle optimal interleave factor
# equals to corresponding instructions latency. 8x is optimal for
# * Bridge, but it's unfeasible to accommodate such implementation
# in XMM registers addreassable in 32-bit mode and therefore maximum
# in XMM registers addressable in 32-bit mode and therefore maximum
# of 6x is used instead...
sub aesni_generate2
@@ -2425,7 +2436,7 @@ if ($PREFIX eq "aesni") {
&pxor ("xmm3","xmm3");
&aesenclast ("xmm2","xmm3");
&movdqa ("xmm3","xmm1")
&movdqa ("xmm3","xmm1");
&pslldq ("xmm1",4);
&pxor ("xmm3","xmm1");
&pslldq ("xmm1",4);
+71 -12
View File
@@ -60,7 +60,7 @@
# identical to CBC, because CBC-MAC is essentially CBC encrypt without
# saving output. CCM CTR "stays invisible," because it's neatly
# interleaved wih CBC-MAC. This provides ~30% improvement over
# "straghtforward" CCM implementation with CTR and CBC-MAC performed
# "straightforward" CCM implementation with CTR and CBC-MAC performed
# disjointly. Parallelizable modes practically achieve the theoretical
# limit.
#
@@ -143,14 +143,14 @@
# asymptotic, if it can be surpassed, isn't it? What happens there?
# Rewind to CBC paragraph for the answer. Yes, out-of-order execution
# magic is responsible for this. Processor overlaps not only the
# additional instructions with AES ones, but even AES instuctions
# additional instructions with AES ones, but even AES instructions
# processing adjacent triplets of independent blocks. In the 6x case
# additional instructions still claim disproportionally small amount
# of additional cycles, but in 8x case number of instructions must be
# a tad too high for out-of-order logic to cope with, and AES unit
# remains underutilized... As you can see 8x interleave is hardly
# justifiable, so there no need to feel bad that 32-bit aesni-x86.pl
# utilizies 6x interleave because of limited register bank capacity.
# utilizes 6x interleave because of limited register bank capacity.
#
# Higher interleave factors do have negative impact on Westmere
# performance. While for ECB mode it's negligible ~1.5%, other
@@ -1182,6 +1182,7 @@ $code.=<<___;
.type aesni_ctr32_encrypt_blocks,\@function,5
.align 16
aesni_ctr32_encrypt_blocks:
.cfi_startproc
cmp \$1,$len
jne .Lctr32_bulk
@@ -1204,7 +1205,9 @@ $code.=<<___;
.align 16
.Lctr32_bulk:
lea (%rsp),$key_ # use $key_ as frame pointer
.cfi_def_cfa_register $key_
push %rbp
.cfi_push %rbp
sub \$$frame_size,%rsp
and \$-16,%rsp # Linux kernel stack can be incorrectly seeded
___
@@ -1548,7 +1551,7 @@ $code.=<<___;
sub \$8,$len
jnc .Lctr32_loop8 # loop if $len-=8 didn't borrow
add \$8,$len # restore real remainig $len
add \$8,$len # restore real remaining $len
jz .Lctr32_done # done if ($len==0)
lea -0x80($key),$key
@@ -1665,7 +1668,7 @@ $code.=<<___;
movups $inout2,0x20($out) # $len was 3, stop store
.Lctr32_done:
xorps %xmm0,%xmm0 # clear regiser bank
xorps %xmm0,%xmm0 # clear register bank
xor $key0,$key0
pxor %xmm1,%xmm1
pxor %xmm2,%xmm2
@@ -1725,9 +1728,12 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -8($key_),%rbp
.cfi_restore %rbp
lea ($key_),%rsp
.cfi_def_cfa_register %rsp
.Lctr32_epilogue:
ret
.cfi_endproc
.size aesni_ctr32_encrypt_blocks,.-aesni_ctr32_encrypt_blocks
___
}
@@ -1749,8 +1755,11 @@ $code.=<<___;
.type aesni_xts_encrypt,\@function,6
.align 16
aesni_xts_encrypt:
.cfi_startproc
lea (%rsp),%r11 # frame pointer
.cfi_def_cfa_register %r11
push %rbp
.cfi_push %rbp
sub \$$frame_size,%rsp
and \$-16,%rsp # Linux kernel stack can be incorrectly seeded
___
@@ -1848,7 +1857,7 @@ $code.=<<___;
lea `16*6`($inp),$inp
pxor $twmask,$inout5
pxor $twres,@tweak[0] # calclulate tweaks^round[last]
pxor $twres,@tweak[0] # calculate tweaks^round[last]
aesenc $rndkey1,$inout4
pxor $twres,@tweak[1]
movdqa @tweak[0],`16*0`(%rsp) # put aside tweaks^round[last]
@@ -2215,9 +2224,12 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -8(%r11),%rbp
.cfi_restore %rbp
lea (%r11),%rsp
.cfi_def_cfa_register %rsp
.Lxts_enc_epilogue:
ret
.cfi_endproc
.size aesni_xts_encrypt,.-aesni_xts_encrypt
___
@@ -2226,8 +2238,11 @@ $code.=<<___;
.type aesni_xts_decrypt,\@function,6
.align 16
aesni_xts_decrypt:
.cfi_startproc
lea (%rsp),%r11 # frame pointer
.cfi_def_cfa_register %r11
push %rbp
.cfi_push %rbp
sub \$$frame_size,%rsp
and \$-16,%rsp # Linux kernel stack can be incorrectly seeded
___
@@ -2328,7 +2343,7 @@ $code.=<<___;
lea `16*6`($inp),$inp
pxor $twmask,$inout5
pxor $twres,@tweak[0] # calclulate tweaks^round[last]
pxor $twres,@tweak[0] # calculate tweaks^round[last]
aesdec $rndkey1,$inout4
pxor $twres,@tweak[1]
movdqa @tweak[0],`16*0`(%rsp) # put aside tweaks^last round key
@@ -2718,9 +2733,12 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -8(%r11),%rbp
.cfi_restore %rbp
lea (%r11),%rsp
.cfi_def_cfa_register %rsp
.Lxts_dec_epilogue:
ret
.cfi_endproc
.size aesni_xts_decrypt,.-aesni_xts_decrypt
___
}
@@ -2745,12 +2763,18 @@ $code.=<<___;
.type aesni_ocb_encrypt,\@function,6
.align 32
aesni_ocb_encrypt:
.cfi_startproc
lea (%rsp),%rax
push %rbx
.cfi_push %rbx
push %rbp
.cfi_push %rbp
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
___
$code.=<<___ if ($win64);
lea -0xa0(%rsp),%rsp
@@ -2945,6 +2969,7 @@ $code.=<<___ if (!$win64);
pxor %xmm14,%xmm14
pxor %xmm15,%xmm15
lea 0x28(%rsp),%rax
.cfi_def_cfa %rax,8
___
$code.=<<___ if ($win64);
movaps 0x00(%rsp),%xmm6
@@ -2972,13 +2997,20 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -40(%rax),%r14
.cfi_restore %r14
mov -32(%rax),%r13
.cfi_restore %r13
mov -24(%rax),%r12
.cfi_restore %r12
mov -16(%rax),%rbp
.cfi_restore %rbp
mov -8(%rax),%rbx
.cfi_restore %rbx
lea (%rax),%rsp
.cfi_def_cfa_register %rsp
.Locb_enc_epilogue:
ret
.cfi_endproc
.size aesni_ocb_encrypt,.-aesni_ocb_encrypt
.type __ocb_encrypt6,\@abi-omnipotent
@@ -3191,12 +3223,18 @@ __ocb_encrypt1:
.type aesni_ocb_decrypt,\@function,6
.align 32
aesni_ocb_decrypt:
.cfi_startproc
lea (%rsp),%rax
push %rbx
.cfi_push %rbx
push %rbp
.cfi_push %rbp
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
___
$code.=<<___ if ($win64);
lea -0xa0(%rsp),%rsp
@@ -3413,6 +3451,7 @@ $code.=<<___ if (!$win64);
pxor %xmm14,%xmm14
pxor %xmm15,%xmm15
lea 0x28(%rsp),%rax
.cfi_def_cfa %rax,8
___
$code.=<<___ if ($win64);
movaps 0x00(%rsp),%xmm6
@@ -3440,13 +3479,20 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -40(%rax),%r14
.cfi_restore %r14
mov -32(%rax),%r13
.cfi_restore %r13
mov -24(%rax),%r12
.cfi_restore %r12
mov -16(%rax),%rbp
.cfi_restore %rbp
mov -8(%rax),%rbx
.cfi_restore %rbx
lea (%rax),%rsp
.cfi_def_cfa_register %rsp
.Locb_dec_epilogue:
ret
.cfi_endproc
.size aesni_ocb_decrypt,.-aesni_ocb_decrypt
.type __ocb_decrypt6,\@abi-omnipotent
@@ -3659,6 +3705,7 @@ $code.=<<___;
.type ${PREFIX}_cbc_encrypt,\@function,6
.align 16
${PREFIX}_cbc_encrypt:
.cfi_startproc
test $len,$len # check length
jz .Lcbc_ret
@@ -3735,7 +3782,9 @@ $code.=<<___;
.align 16
.Lcbc_decrypt_bulk:
lea (%rsp),%r11 # frame pointer
.cfi_def_cfa_register %r11
push %rbp
.cfi_push %rbp
sub \$$frame_size,%rsp
and \$-16,%rsp # Linux kernel stack can be incorrectly seeded
___
@@ -4179,9 +4228,12 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -8(%r11),%rbp
.cfi_restore %rbp
lea (%r11),%rsp
.cfi_def_cfa_register %rsp
.Lcbc_ret:
ret
.cfi_endproc
.size ${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt
___
}
@@ -4202,7 +4254,9 @@ $code.=<<___;
.type ${PREFIX}_set_decrypt_key,\@abi-omnipotent
.align 16
${PREFIX}_set_decrypt_key:
.cfi_startproc
.byte 0x48,0x83,0xEC,0x08 # sub rsp,8
.cfi_adjust_cfa_offset 8
call __aesni_set_encrypt_key
shl \$4,$bits # rounds-1 after _aesni_set_encrypt_key
test %eax,%eax
@@ -4235,15 +4289,16 @@ ${PREFIX}_set_decrypt_key:
pxor %xmm0,%xmm0
.Ldec_key_ret:
add \$8,%rsp
.cfi_adjust_cfa_offset -8
ret
.cfi_endproc
.LSEH_end_set_decrypt_key:
.size ${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key
___
# This is based on submission by
#
# Huang Ying <ying.huang@intel.com>
# Vinodh Gopal <vinodh.gopal@intel.com>
# This is based on submission from Intel by
# Huang Ying
# Vinodh Gopal
# Kahraman Akdemir
#
# Aggressively optimized in respect to aeskeygenassist's critical path
@@ -4271,7 +4326,9 @@ $code.=<<___;
.align 16
${PREFIX}_set_encrypt_key:
__aesni_set_encrypt_key:
.cfi_startproc
.byte 0x48,0x83,0xEC,0x08 # sub rsp,8
.cfi_adjust_cfa_offset 8
mov \$-1,%rax
test $inp,$inp
jz .Lenc_key_ret
@@ -4461,7 +4518,7 @@ __aesni_set_encrypt_key:
.align 16
.L14rounds:
movups 16($inp),%xmm2 # remaning half of *userKey
movups 16($inp),%xmm2 # remaining half of *userKey
mov \$13,$bits # 14 rounds for 256
lea 16(%rax),%rax
cmp \$`1<<28`,%r10d # AVX, but no XOP
@@ -4565,7 +4622,9 @@ __aesni_set_encrypt_key:
pxor %xmm4,%xmm4
pxor %xmm5,%xmm5
add \$8,%rsp
.cfi_adjust_cfa_offset -8
ret
.cfi_endproc
.LSEH_end_set_encrypt_key:
.align 16
+3 -7
View File
@@ -58,11 +58,7 @@ $code=<<___;
#if __ARM_MAX_ARCH__>=7
.text
___
$code.=<<___ if ($flavour =~ /64/);
#if !defined(__clang__) || defined(BORINGSSL_CLANG_SUPPORTS_DOT_ARCH)
.arch armv8-a+crypto
#endif
___
$code.=".arch armv8-a+crypto\n" if ($flavour =~ /64/);
$code.=<<___ if ($flavour !~ /64/);
.arch armv7-a // don't confuse not-so-latest binutils with argv8 :-)
.fpu neon
@@ -933,7 +929,7 @@ if ($flavour =~ /64/) { ######## 64-bit code
s/^(\s+)v/$1/o or # strip off v prefix
s/\bbx\s+lr\b/ret/o;
# fix up remainig legacy suffixes
# fix up remaining legacy suffixes
s/\.[ui]?8//o;
m/\],#8/o and s/\.16b/\.8b/go;
s/\.[ui]?32//o and s/\.16b/\.4s/go;
@@ -992,7 +988,7 @@ if ($flavour =~ /64/) { ######## 64-bit code
s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go; # new->old registers
s/\/\/\s?/@ /o; # new->old style commentary
# fix up remainig new-style suffixes
# fix up remaining new-style suffixes
s/\{q([0-9]+)\},\s*\[(.+)\],#8/sprintf "{d%d},[$2]!",2*$1/eo or
s/\],#[0-9]+/]!/o;
+5 -9
View File
@@ -14,8 +14,7 @@
# details see http://www.openssl.org/~appro/cryptogams/.
#
# Specific modes and adaptation for Linux kernel by Ard Biesheuvel
# <ard.biesheuvel@linaro.org>. Permission to use under GPL terms is
# granted.
# of Linaro. Permission to use under GPL terms is granted.
# ====================================================================
# Bit-sliced AES for ARM NEON
@@ -49,10 +48,7 @@
# <appro@openssl.org>
# April-August 2013
#
# Add CBC, CTR and XTS subroutines, adapt for kernel use.
#
# <ard.biesheuvel@linaro.org>
# Add CBC, CTR and XTS subroutines and adapt for kernel use; courtesy of Ard.
$flavour = shift;
if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
@@ -746,7 +742,7 @@ $code.=<<___;
_bsaes_decrypt8:
adr $const,.
vldmia $key!, {@XMM[9]} @ round 0 key
#ifdef __APPLE__
#if defined(__thumb2__) || defined(__APPLE__)
adr $const,.LM0ISR
#else
add $const,$const,#.LM0ISR-_bsaes_decrypt8
@@ -845,7 +841,7 @@ _bsaes_const:
_bsaes_encrypt8:
adr $const,.
vldmia $key!, {@XMM[9]} @ round 0 key
#ifdef __APPLE__
#if defined(__thumb2__) || defined(__APPLE__)
adr $const,.LM0SR
#else
sub $const,$const,#_bsaes_encrypt8-.LM0SR
@@ -953,7 +949,7 @@ $code.=<<___;
_bsaes_key_convert:
adr $const,.
vld1.8 {@XMM[7]}, [$inp]! @ load round 0 key
#ifdef __APPLE__
#if defined(__thumb2__) || defined(__APPLE__)
adr $const,.LM0
#else
sub $const,$const,#_bsaes_key_convert-.LM0
+115 -1
View File
@@ -1,4 +1,11 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
###################################################################
### AES-128 [originally in CTR mode] ###
@@ -1158,15 +1165,23 @@ $code.=<<___;
.type bsaes_ecb_encrypt_blocks,\@abi-omnipotent
.align 16
bsaes_ecb_encrypt_blocks:
.cfi_startproc
mov %rsp, %rax
.Lecb_enc_prologue:
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
lea -0x48(%rsp),%rsp
.cfi_adjust_cfa_offset 0x48
___
$code.=<<___ if ($win64);
lea -0xa0(%rsp), %rsp
@@ -1184,6 +1199,7 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov %rsp,%rbp # backup %rsp
.cfi_def_cfa_register %rbp
mov 240($arg4),%eax # rounds
mov $arg1,$inp # backup arguments
mov $arg2,$out
@@ -1328,6 +1344,7 @@ $code.=<<___;
jb .Lecb_enc_bzero
lea 0x78(%rbp),%rax
.cfi_def_cfa %rax,8
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -1345,29 +1362,45 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -48(%rax), %r15
.cfi_restore %r15
mov -40(%rax), %r14
.cfi_restore %r14
mov -32(%rax), %r13
.cfi_restore %r13
mov -24(%rax), %r12
.cfi_restore %r12
mov -16(%rax), %rbx
.cfi_restore %rbx
mov -8(%rax), %rbp
.cfi_restore %rbp
lea (%rax), %rsp # restore %rsp
.cfi_def_cfa_register %rsp
.Lecb_enc_epilogue:
ret
.cfi_endproc
.size bsaes_ecb_encrypt_blocks,.-bsaes_ecb_encrypt_blocks
.globl bsaes_ecb_decrypt_blocks
.type bsaes_ecb_decrypt_blocks,\@abi-omnipotent
.align 16
bsaes_ecb_decrypt_blocks:
.cfi_startproc
mov %rsp, %rax
.Lecb_dec_prologue:
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
lea -0x48(%rsp),%rsp
.cfi_adjust_cfa_offset 0x48
___
$code.=<<___ if ($win64);
lea -0xa0(%rsp), %rsp
@@ -1385,6 +1418,7 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov %rsp,%rbp # backup %rsp
.cfi_def_cfa_register %rbp
mov 240($arg4),%eax # rounds
mov $arg1,$inp # backup arguments
mov $arg2,$out
@@ -1530,6 +1564,7 @@ $code.=<<___;
jb .Lecb_dec_bzero
lea 0x78(%rbp),%rax
.cfi_def_cfa %rax,8
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -1547,14 +1582,22 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -48(%rax), %r15
.cfi_restore %r15
mov -40(%rax), %r14
.cfi_restore %r14
mov -32(%rax), %r13
.cfi_restore %r13
mov -24(%rax), %r12
.cfi_restore %r12
mov -16(%rax), %rbx
.cfi_restore %rbx
mov -8(%rax), %rbp
.cfi_restore %rbp
lea (%rax), %rsp # restore %rsp
.cfi_def_cfa_register %rsp
.Lecb_dec_epilogue:
ret
.cfi_endproc
.size bsaes_ecb_decrypt_blocks,.-bsaes_ecb_decrypt_blocks
___
}
@@ -1564,6 +1607,7 @@ $code.=<<___;
.type bsaes_cbc_encrypt,\@abi-omnipotent
.align 16
bsaes_cbc_encrypt:
.cfi_startproc
___
$code.=<<___ if ($win64);
mov 48(%rsp),$arg6 # pull direction flag
@@ -1577,12 +1621,19 @@ $code.=<<___;
mov %rsp, %rax
.Lcbc_dec_prologue:
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
lea -0x48(%rsp), %rsp
.cfi_adjust_cfa_offset 0x48
___
$code.=<<___ if ($win64);
mov 0xa0(%rsp),$arg5 # pull ivp
@@ -1601,6 +1652,7 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov %rsp, %rbp # backup %rsp
.cfi_def_cfa_register %rbp
mov 240($arg4), %eax # rounds
mov $arg1, $inp # backup arguments
mov $arg2, $out
@@ -1820,6 +1872,7 @@ $code.=<<___;
ja .Lcbc_dec_bzero
lea 0x78(%rbp),%rax
.cfi_def_cfa %rax,8
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -1837,29 +1890,45 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -48(%rax), %r15
.cfi_restore %r15
mov -40(%rax), %r14
.cfi_restore %r14
mov -32(%rax), %r13
.cfi_restore %r13
mov -24(%rax), %r12
.cfi_restore %r12
mov -16(%rax), %rbx
.cfi_restore %rbx
mov -8(%rax), %rbp
.cfi_restore %rbp
lea (%rax), %rsp # restore %rsp
.cfi_def_cfa_register %rsp
.Lcbc_dec_epilogue:
ret
.cfi_endproc
.size bsaes_cbc_encrypt,.-bsaes_cbc_encrypt
.globl bsaes_ctr32_encrypt_blocks
.type bsaes_ctr32_encrypt_blocks,\@abi-omnipotent
.align 16
bsaes_ctr32_encrypt_blocks:
.cfi_startproc
mov %rsp, %rax
.Lctr_enc_prologue:
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
lea -0x48(%rsp), %rsp
.cfi_adjust_cfa_offset 0x48
___
$code.=<<___ if ($win64);
mov 0xa0(%rsp),$arg5 # pull ivp
@@ -1878,6 +1947,7 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov %rsp, %rbp # backup %rsp
.cfi_def_cfa_register %rbp
movdqu ($arg5), %xmm0 # load counter
mov 240($arg4), %eax # rounds
mov $arg1, $inp # backup arguments
@@ -2052,6 +2122,7 @@ $code.=<<___;
ja .Lctr_enc_bzero
lea 0x78(%rbp),%rax
.cfi_def_cfa %rax,8
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -2069,14 +2140,22 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -48(%rax), %r15
.cfi_restore %r15
mov -40(%rax), %r14
.cfi_restore %r14
mov -32(%rax), %r13
.cfi_restore %r13
mov -24(%rax), %r12
.cfi_restore %r12
mov -16(%rax), %rbx
.cfi_restore %rbx
mov -8(%rax), %rbp
.cfi_restore %rbp
lea (%rax), %rsp # restore %rsp
.cfi_def_cfa_register %rsp
.Lctr_enc_epilogue:
ret
.cfi_endproc
.size bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks
___
######################################################################
@@ -2092,15 +2171,23 @@ $code.=<<___;
.type bsaes_xts_encrypt,\@abi-omnipotent
.align 16
bsaes_xts_encrypt:
.cfi_startproc
mov %rsp, %rax
.Lxts_enc_prologue:
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
lea -0x48(%rsp), %rsp
.cfi_adjust_cfa_offset 0x48
___
$code.=<<___ if ($win64);
mov 0xa0(%rsp),$arg5 # pull key2
@@ -2120,6 +2207,7 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov %rsp, %rbp # backup %rsp
.cfi_def_cfa_register %rbp
mov $arg1, $inp # backup arguments
mov $arg2, $out
mov $arg3, $len
@@ -2442,6 +2530,7 @@ $code.=<<___;
ja .Lxts_enc_bzero
lea 0x78(%rbp),%rax
.cfi_def_cfa %rax,8
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -2459,29 +2548,45 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -48(%rax), %r15
.cfi_restore %r15
mov -40(%rax), %r14
.cfi_restore %r14
mov -32(%rax), %r13
.cfi_restore %r13
mov -24(%rax), %r12
.cfi_restore %r12
mov -16(%rax), %rbx
.cfi_restore %rbx
mov -8(%rax), %rbp
.cfi_restore %rbp
lea (%rax), %rsp # restore %rsp
.cfi_def_cfa_register %rsp
.Lxts_enc_epilogue:
ret
.cfi_endproc
.size bsaes_xts_encrypt,.-bsaes_xts_encrypt
.globl bsaes_xts_decrypt
.type bsaes_xts_decrypt,\@abi-omnipotent
.align 16
bsaes_xts_decrypt:
.cfi_startproc
mov %rsp, %rax
.Lxts_dec_prologue:
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
lea -0x48(%rsp), %rsp
.cfi_adjust_cfa_offset 0x48
___
$code.=<<___ if ($win64);
mov 0xa0(%rsp),$arg5 # pull key2
@@ -2849,6 +2954,7 @@ $code.=<<___;
ja .Lxts_dec_bzero
lea 0x78(%rbp),%rax
.cfi_def_cfa %rax,8
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -2866,14 +2972,22 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -48(%rax), %r15
.cfi_restore %r15
mov -40(%rax), %r14
.cfi_restore %r14
mov -32(%rax), %r13
.cfi_restore %r13
mov -24(%rax), %r12
.cfi_restore %r12
mov -16(%rax), %rbx
.cfi_restore %rbx
mov -8(%rax), %rbp
.cfi_restore %rbp
lea (%rax), %rsp # restore %rsp
.cfi_def_cfa_register %rsp
.Lxts_dec_epilogue:
ret
.cfi_endproc
.size bsaes_xts_decrypt,.-bsaes_xts_decrypt
___
}
+8 -1
View File
@@ -1,4 +1,11 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
######################################################################
## Constant-time SSSE3 AES core implementation.
+8 -1
View File
@@ -1,4 +1,11 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
######################################################################
## Constant-time SSSE3 AES core implementation.
+11 -542
View File
@@ -16,21 +16,15 @@
#define _GNU_SOURCE // needed for syscall() on Linux.
#endif
#include <openssl/aead.h>
#include <openssl/aes.h>
#include <openssl/base.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/des.h>
#include <openssl/ecdsa.h>
#include <openssl/ec_key.h>
#include <stdlib.h>
#include <openssl/digest.h>
#include <openssl/hmac.h>
#include <openssl/nid.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include "../internal.h"
#include "rand/internal.h"
#include "aes/aes.c"
#include "aes/key_wrap.c"
@@ -67,15 +61,16 @@
#include "ec/ec_montgomery.c"
#include "ec/oct.c"
#include "ec/p224-64.c"
#include "ec/p256-64.c"
#include "../../third_party/fiat/p256.c"
#include "ec/p256-x86_64.c"
#include "ec/simple.c"
#include "ec/util-64.c"
#include "ec/util.c"
#include "ec/wnaf.c"
#include "hmac/hmac.c"
#include "md4/md4.c"
#include "md5/md5.c"
#include "modes/cbc.c"
#include "modes/ccm.c"
#include "modes/cfb.c"
#include "modes/ctr.c"
#include "modes/gcm.c"
@@ -88,205 +83,16 @@
#include "rsa/padding.c"
#include "rsa/rsa.c"
#include "rsa/rsa_impl.c"
#include "self_check/self_check.c"
#include "sha/sha1-altivec.c"
#include "sha/sha1.c"
#include "sha/sha256.c"
#include "sha/sha512.c"
#include "tls/kdf.c"
#if defined(BORINGSSL_FIPS)
static void hexdump(const uint8_t *in, size_t len) {
for (size_t i = 0; i < len; i++) {
printf("%02x", in[i]);
}
}
static int check_test(const void *expected, const void *actual,
size_t expected_len, const char *name) {
if (OPENSSL_memcmp(actual, expected, expected_len) != 0) {
printf("%s failed.\nExpected: ", name);
hexdump(expected, expected_len);
printf("\nCalculated: ");
hexdump(actual, expected_len);
printf("\n");
return 0;
}
return 1;
}
static int set_bignum(BIGNUM **out, const uint8_t *in, size_t len) {
*out = BN_bin2bn(in, len, NULL);
return *out != NULL;
}
static RSA *self_test_rsa_key(void) {
static const uint8_t kN[] = {
0xd3, 0x3a, 0x62, 0x9f, 0x07, 0x77, 0xb0, 0x18, 0xf3, 0xff, 0xfe, 0xcc,
0xc9, 0xa2, 0xc2, 0x3a, 0xa6, 0x1d, 0xd8, 0xf0, 0x26, 0x5b, 0x38, 0x90,
0x17, 0x48, 0x15, 0xce, 0x21, 0xcd, 0xd6, 0x62, 0x99, 0xe2, 0xd7, 0xda,
0x40, 0x80, 0x3c, 0xad, 0x18, 0xb7, 0x26, 0xe9, 0x30, 0x8a, 0x23, 0x3f,
0x68, 0x9a, 0x9c, 0x31, 0x34, 0x91, 0x99, 0x06, 0x11, 0x36, 0xb2, 0x9e,
0x3a, 0xd0, 0xbc, 0xb9, 0x93, 0x4e, 0xb8, 0x72, 0xa1, 0x9f, 0xb6, 0x8c,
0xd5, 0x17, 0x1f, 0x7e, 0xaa, 0x75, 0xbb, 0xdf, 0xa1, 0x70, 0x48, 0xc4,
0xec, 0x9a, 0x51, 0xed, 0x41, 0xc9, 0x74, 0xc0, 0x3e, 0x1e, 0x85, 0x2f,
0xbe, 0x34, 0xc7, 0x65, 0x34, 0x8b, 0x4d, 0x55, 0x4b, 0xe1, 0x45, 0x54,
0x0d, 0x75, 0x7e, 0x89, 0x4d, 0x0c, 0xf6, 0x33, 0xe5, 0xfc, 0xfb, 0x56,
0x1b, 0xf2, 0x39, 0x9d, 0xe0, 0xff, 0x55, 0xcf, 0x02, 0x05, 0xb9, 0x74,
0xd2, 0x91, 0xfc, 0x87, 0xe1, 0xbb, 0x97, 0x2a, 0xe4, 0xdd, 0x20, 0xc0,
0x38, 0x47, 0xc0, 0x76, 0x3f, 0xa1, 0x9b, 0x5c, 0x20, 0xff, 0xff, 0xc7,
0x49, 0x3b, 0x4c, 0xaf, 0x99, 0xa6, 0x3e, 0x82, 0x5c, 0x58, 0x27, 0xce,
0x01, 0x03, 0xc3, 0x16, 0x35, 0x20, 0xe9, 0xf0, 0x15, 0x7a, 0x41, 0xd5,
0x1f, 0x52, 0xea, 0xdf, 0xad, 0x4c, 0xbb, 0x0d, 0xcb, 0x04, 0x91, 0xb0,
0x95, 0xa8, 0xce, 0x25, 0xfd, 0xd2, 0x62, 0x47, 0x77, 0xee, 0x13, 0xf1,
0x48, 0x72, 0x9e, 0xd9, 0x2d, 0xe6, 0x5f, 0xa4, 0xc6, 0x9e, 0x5a, 0xb2,
0xc6, 0xa2, 0xf7, 0x0a, 0x16, 0x17, 0xae, 0x6b, 0x1c, 0x30, 0x7c, 0x63,
0x08, 0x83, 0xe7, 0x43, 0xec, 0x54, 0x5e, 0x2c, 0x08, 0x0b, 0x5e, 0x46,
0xa7, 0x10, 0x93, 0x43, 0x53, 0x4e, 0xe3, 0x16, 0x73, 0x55, 0xce, 0xf2,
0x94, 0xc0, 0xbe, 0xb3,
};
static const uint8_t kE[] = {0x01, 0x00, 0x01}; // 65537
static const uint8_t kD[] = {
0x2f, 0x2c, 0x1e, 0xd2, 0x3d, 0x2c, 0xb1, 0x9b, 0x21, 0x02, 0xce, 0xb8,
0x95, 0x5f, 0x4f, 0xd9, 0x21, 0x38, 0x11, 0x36, 0xb0, 0x9a, 0x36, 0xab,
0x97, 0x47, 0x75, 0xf7, 0x2e, 0xfd, 0x75, 0x1f, 0x58, 0x16, 0x9c, 0xf6,
0x14, 0xe9, 0x8e, 0xa3, 0x69, 0x9d, 0x9d, 0x86, 0xfe, 0x5c, 0x1b, 0x3b,
0x11, 0xf5, 0x55, 0x64, 0x77, 0xc4, 0xfc, 0x53, 0xaa, 0x8c, 0x78, 0x9f,
0x75, 0xab, 0x20, 0x3a, 0xa1, 0x77, 0x37, 0x22, 0x02, 0x8e, 0x54, 0x8a,
0x67, 0x1c, 0x5e, 0xe0, 0x3e, 0xd9, 0x44, 0x37, 0xd1, 0x29, 0xee, 0x56,
0x6c, 0x30, 0x9a, 0x93, 0x4d, 0xd9, 0xdb, 0xc5, 0x03, 0x1a, 0x75, 0xcc,
0x0f, 0xc2, 0x61, 0xb5, 0x6c, 0x62, 0x9f, 0xc6, 0xa8, 0xc7, 0x8a, 0x60,
0x17, 0x11, 0x62, 0x4c, 0xef, 0x74, 0x31, 0x97, 0xad, 0x89, 0x2d, 0xe8,
0x31, 0x1d, 0x8b, 0x58, 0x82, 0xe3, 0x03, 0x1a, 0x6b, 0xdf, 0x3f, 0x3e,
0xa4, 0x27, 0x19, 0xef, 0x46, 0x7a, 0x90, 0xdf, 0xa7, 0xe7, 0xc9, 0x66,
0xab, 0x41, 0x1d, 0x65, 0x78, 0x1c, 0x18, 0x40, 0x5c, 0xd6, 0x87, 0xb5,
0xea, 0x29, 0x44, 0xb3, 0xf5, 0xb3, 0xd2, 0x4f, 0xce, 0x88, 0x78, 0x49,
0x27, 0x4e, 0x0b, 0x30, 0x85, 0xfb, 0x73, 0xfd, 0x8b, 0x32, 0x15, 0xee,
0x1f, 0xc9, 0x0e, 0x89, 0xb9, 0x43, 0x2f, 0xe9, 0x60, 0x8d, 0xda, 0xae,
0x2b, 0x30, 0x99, 0xee, 0x88, 0x81, 0x20, 0x7b, 0x4a, 0xc3, 0x18, 0xf2,
0x94, 0x02, 0x79, 0x94, 0xaa, 0x65, 0xd9, 0x1b, 0x45, 0x2a, 0xac, 0x6e,
0x30, 0x48, 0x57, 0xea, 0xbe, 0x79, 0x7d, 0xfc, 0x67, 0xaa, 0x47, 0xc0,
0xf7, 0x52, 0xfd, 0x0b, 0x63, 0x4e, 0x3d, 0x2e, 0xcc, 0x36, 0xa0, 0xdb,
0x92, 0x0b, 0xa9, 0x1b, 0xeb, 0xc2, 0xd5, 0x08, 0xd3, 0x85, 0x87, 0xf8,
0x5d, 0x1a, 0xf6, 0xc1,
};
static const uint8_t kP[] = {
0xf7, 0x06, 0xa3, 0x98, 0x8a, 0x52, 0xf8, 0x63, 0x68, 0x27, 0x4f, 0x68,
0x7f, 0x34, 0xec, 0x8e, 0x5d, 0xf8, 0x30, 0x92, 0xb3, 0x62, 0x4c, 0xeb,
0xdb, 0x19, 0x6b, 0x09, 0xc5, 0xa3, 0xf0, 0xbb, 0xff, 0x0f, 0xc2, 0xd4,
0x9b, 0xc9, 0x54, 0x4f, 0xb9, 0xf9, 0xe1, 0x4c, 0xf0, 0xe3, 0x4c, 0x90,
0xda, 0x7a, 0x01, 0xc2, 0x9f, 0xc4, 0xc8, 0x8e, 0xb1, 0x1e, 0x93, 0x75,
0x75, 0xc6, 0x13, 0x25, 0xc3, 0xee, 0x3b, 0xcc, 0xb8, 0x72, 0x6c, 0x49,
0xb0, 0x09, 0xfb, 0xab, 0x44, 0xeb, 0x4d, 0x40, 0xf0, 0x61, 0x6b, 0xe5,
0xe6, 0xfe, 0x3e, 0x0a, 0x77, 0x26, 0x39, 0x76, 0x3d, 0x4c, 0x3e, 0x9b,
0x5b, 0xc0, 0xaf, 0xa2, 0x58, 0x76, 0xb0, 0xe9, 0xda, 0x7f, 0x0e, 0x78,
0xc9, 0x76, 0x49, 0x5c, 0xfa, 0xb3, 0xb0, 0x15, 0x4b, 0x41, 0xc7, 0x27,
0xa4, 0x75, 0x28, 0x5c, 0x30, 0x69, 0x50, 0x29,
};
static const uint8_t kQ[] = {
0xda, 0xe6, 0xd2, 0xbb, 0x44, 0xff, 0x4f, 0xdf, 0x57, 0xc1, 0x11, 0xa3,
0x51, 0xba, 0x17, 0x89, 0x4c, 0x01, 0xc0, 0x0c, 0x97, 0x34, 0x50, 0xcf,
0x32, 0x1e, 0xc0, 0xbd, 0x7b, 0x35, 0xb5, 0x6a, 0x26, 0xcc, 0xea, 0x4c,
0x8e, 0x87, 0x4a, 0x67, 0x8b, 0xd3, 0xe5, 0x4f, 0x3a, 0x60, 0x48, 0x59,
0x04, 0x93, 0x39, 0xd7, 0x7c, 0xfb, 0x19, 0x1a, 0x34, 0xd5, 0xe8, 0xaf,
0xe7, 0x22, 0x2c, 0x0d, 0xc2, 0x91, 0x69, 0xb6, 0xe9, 0x2a, 0xe9, 0x1c,
0x4c, 0x6e, 0x8f, 0x40, 0xf5, 0xa8, 0x3e, 0x82, 0x69, 0x69, 0xbe, 0x9f,
0x7d, 0x5c, 0x7f, 0x92, 0x78, 0x17, 0xa3, 0x6d, 0x41, 0x2d, 0x72, 0xed,
0x3f, 0x71, 0xfa, 0x97, 0xb4, 0x63, 0xe4, 0x4f, 0xd9, 0x46, 0x03, 0xfb,
0x00, 0xeb, 0x30, 0x70, 0xb9, 0x51, 0xd9, 0x0a, 0xd2, 0xf8, 0x50, 0xd4,
0xfb, 0x43, 0x84, 0xf8, 0xac, 0x58, 0xc3, 0x7b,
};
static const uint8_t kDModPMinusOne[] = {
0xf5, 0x50, 0x8f, 0x88, 0x7d, 0xdd, 0xb5, 0xb4, 0x2a, 0x8b, 0xd7, 0x4d,
0x23, 0xfe, 0xaf, 0xe9, 0x16, 0x22, 0xd2, 0x41, 0xed, 0x88, 0xf2, 0x70,
0xcb, 0x4d, 0xeb, 0xc1, 0x71, 0x97, 0xc4, 0x0b, 0x3e, 0x5a, 0x2d, 0x96,
0xab, 0xfa, 0xfd, 0x12, 0x8b, 0xd3, 0x3e, 0x4e, 0x05, 0x6f, 0x04, 0xeb,
0x59, 0x3c, 0x0e, 0xa1, 0x73, 0xbe, 0x9d, 0x99, 0x2f, 0x05, 0xf9, 0x54,
0x8d, 0x98, 0x1e, 0x0d, 0xc4, 0x0c, 0xc3, 0x30, 0x23, 0xff, 0xe5, 0xd0,
0x2b, 0xd5, 0x4e, 0x2b, 0xa0, 0xae, 0xb8, 0x32, 0x84, 0x45, 0x8b, 0x3c,
0x6d, 0xf0, 0x10, 0x36, 0x9e, 0x6a, 0xc4, 0x67, 0xca, 0xa9, 0xfc, 0x06,
0x96, 0xd0, 0xbc, 0xda, 0xd1, 0x55, 0x55, 0x8d, 0x77, 0x21, 0xf4, 0x82,
0x39, 0x37, 0x91, 0xd5, 0x97, 0x56, 0x78, 0xc8, 0x3c, 0xcb, 0x5e, 0xf6,
0xdc, 0x58, 0x48, 0xb3, 0x7c, 0x94, 0x29, 0x39,
};
static const uint8_t kDModQMinusOne[] = {
0x64, 0x65, 0xbd, 0x7d, 0x1a, 0x96, 0x26, 0xa1, 0xfe, 0xf3, 0x94, 0x0d,
0x5d, 0xec, 0x85, 0xe2, 0xf8, 0xb3, 0x4c, 0xcb, 0xf9, 0x85, 0x8b, 0x12,
0x9c, 0xa0, 0x32, 0x32, 0x35, 0x92, 0x5a, 0x94, 0x47, 0x1b, 0x70, 0xd2,
0x90, 0x04, 0x49, 0x01, 0xd8, 0xc5, 0xe4, 0xc4, 0x43, 0xb7, 0xe9, 0x36,
0xba, 0xbc, 0x73, 0xa8, 0xfb, 0xaf, 0x86, 0xc1, 0xd8, 0x3d, 0xcb, 0xac,
0xf1, 0xcb, 0x60, 0x7d, 0x27, 0x21, 0xde, 0x64, 0x7f, 0xe8, 0xa8, 0x65,
0xcc, 0x40, 0x60, 0xff, 0xa0, 0x2b, 0xfc, 0x0f, 0x80, 0x1d, 0x79, 0xca,
0x58, 0x8a, 0xd6, 0x0f, 0xed, 0x78, 0x9a, 0x02, 0x00, 0x04, 0xc2, 0x53,
0x41, 0xe8, 0x1a, 0xd0, 0xfd, 0x71, 0x5b, 0x43, 0xac, 0x19, 0x4a, 0xb6,
0x12, 0xa3, 0xcb, 0xe1, 0xc7, 0x7d, 0x5c, 0x98, 0x74, 0x4e, 0x63, 0x74,
0x6b, 0x91, 0x7a, 0x29, 0x3b, 0x92, 0xb2, 0x85,
};
static const uint8_t kQInverseModP[] = {
0xd0, 0xde, 0x19, 0xda, 0x1e, 0xa2, 0xd8, 0x8f, 0x1c, 0x92, 0x73, 0xb0,
0xc9, 0x90, 0xc7, 0xf5, 0xec, 0xc5, 0x89, 0x01, 0x05, 0x78, 0x11, 0x2d,
0x74, 0x34, 0x44, 0xad, 0xd5, 0xf7, 0xa4, 0xfe, 0x9f, 0x25, 0x4d, 0x0b,
0x92, 0xe3, 0xb8, 0x7d, 0xd3, 0xfd, 0xa5, 0xca, 0x95, 0x60, 0xa3, 0xf9,
0x55, 0x42, 0x14, 0xb2, 0x45, 0x51, 0x9f, 0x73, 0x88, 0x43, 0x8a, 0xd1,
0x65, 0x9e, 0xd1, 0xf7, 0x82, 0x2a, 0x2a, 0x8d, 0x70, 0x56, 0xe3, 0xef,
0xc9, 0x0e, 0x2a, 0x2c, 0x15, 0xaf, 0x7f, 0x97, 0x81, 0x66, 0xf3, 0xb5,
0x00, 0xa9, 0x26, 0xcc, 0x1e, 0xc2, 0x98, 0xdd, 0xd3, 0x37, 0x06, 0x79,
0xb3, 0x60, 0x58, 0x79, 0x99, 0x3f, 0xa3, 0x15, 0x1f, 0x31, 0xe3, 0x11,
0x88, 0x4c, 0x35, 0x57, 0xfa, 0x79, 0xd7, 0xd8, 0x72, 0xee, 0x73, 0x95,
0x89, 0x29, 0xc7, 0x05, 0x27, 0x68, 0x90, 0x15,
};
RSA *rsa = RSA_new();
if (rsa == NULL ||
!set_bignum(&rsa->n, kN, sizeof(kN)) ||
!set_bignum(&rsa->e, kE, sizeof(kE)) ||
!set_bignum(&rsa->d, kD, sizeof(kD)) ||
!set_bignum(&rsa->p, kP, sizeof(kP)) ||
!set_bignum(&rsa->q, kQ, sizeof(kQ)) ||
!set_bignum(&rsa->dmp1, kDModPMinusOne, sizeof(kDModPMinusOne)) ||
!set_bignum(&rsa->dmq1, kDModQMinusOne, sizeof(kDModQMinusOne)) ||
!set_bignum(&rsa->iqmp, kQInverseModP, sizeof(kQInverseModP))) {
RSA_free(rsa);
return NULL;
}
return rsa;
}
static EC_KEY *self_test_ecdsa_key(void) {
static const uint8_t kQx[] = {
0xc8, 0x15, 0x61, 0xec, 0xf2, 0xe5, 0x4e, 0xde, 0xfe, 0x66, 0x17,
0xdb, 0x1c, 0x7a, 0x34, 0xa7, 0x07, 0x44, 0xdd, 0xb2, 0x61, 0xf2,
0x69, 0xb8, 0x3d, 0xac, 0xfc, 0xd2, 0xad, 0xe5, 0xa6, 0x81,
};
static const uint8_t kQy[] = {
0xe0, 0xe2, 0xaf, 0xa3, 0xf9, 0xb6, 0xab, 0xe4, 0xc6, 0x98, 0xef,
0x64, 0x95, 0xf1, 0xbe, 0x49, 0xa3, 0x19, 0x6c, 0x50, 0x56, 0xac,
0xb3, 0x76, 0x3f, 0xe4, 0x50, 0x7e, 0xec, 0x59, 0x6e, 0x88,
};
static const uint8_t kD[] = {
0xc6, 0xc1, 0xaa, 0xda, 0x15, 0xb0, 0x76, 0x61, 0xf8, 0x14, 0x2c,
0x6c, 0xaf, 0x0f, 0xdb, 0x24, 0x1a, 0xff, 0x2e, 0xfe, 0x46, 0xc0,
0x93, 0x8b, 0x74, 0xf2, 0xbc, 0xc5, 0x30, 0x52, 0xb0, 0x77,
};
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
BIGNUM *qx = BN_bin2bn(kQx, sizeof(kQx), NULL);
BIGNUM *qy = BN_bin2bn(kQy, sizeof(kQy), NULL);
BIGNUM *d = BN_bin2bn(kD, sizeof(kD), NULL);
if (ec_key == NULL || qx == NULL || qy == NULL || d == NULL ||
!EC_KEY_set_public_key_affine_coordinates(ec_key, qx, qy) ||
!EC_KEY_set_private_key(ec_key, d)) {
EC_KEY_free(ec_key);
ec_key = NULL;
}
BN_free(qx);
BN_free(qy);
BN_free(d);
return ec_key;
}
#if !defined(OPENSSL_ASAN)
// These symbols are filled in by delocate.go. They point to the start and end
// of the module, and the location of the integrity hash, respectively.
@@ -322,345 +128,7 @@ BORINGSSL_bcm_power_on_self_test(void) {
}
#endif
static const uint8_t kAESKey[16] = "BoringCrypto Key";
static const uint8_t kAESIV[16] = {0};
static const uint8_t kPlaintext[64] =
"BoringCryptoModule FIPS KAT Encryption and Decryption Plaintext!";
static const uint8_t kAESCBCCiphertext[64] = {
0x87, 0x2d, 0x98, 0xc2, 0xcc, 0x31, 0x5b, 0x41, 0xe0, 0xfa, 0x7b,
0x0a, 0x71, 0xc0, 0x42, 0xbf, 0x4f, 0x61, 0xd0, 0x0d, 0x58, 0x8c,
0xf7, 0x05, 0xfb, 0x94, 0x89, 0xd3, 0xbc, 0xaa, 0x1a, 0x50, 0x45,
0x1f, 0xc3, 0x8c, 0xb8, 0x98, 0x86, 0xa3, 0xe3, 0x6c, 0xfc, 0xad,
0x3a, 0xb5, 0x59, 0x27, 0x7d, 0x21, 0x07, 0xca, 0x4c, 0x1d, 0x55,
0x34, 0xdd, 0x5a, 0x2d, 0xc4, 0xb4, 0xf5, 0xa8,
#if !defined(BORINGSSL_FIPS_BREAK_AES_CBC)
0x35
#else
0x00
#endif
};
static const uint8_t kAESGCMCiphertext[80] = {
0x4a, 0xd8, 0xe7, 0x7d, 0x78, 0xd7, 0x7d, 0x5e, 0xb2, 0x11, 0xb6, 0xc9,
0xa4, 0xbc, 0xb2, 0xae, 0xbe, 0x93, 0xd1, 0xb7, 0xfe, 0x65, 0xc1, 0x82,
0x2a, 0xb6, 0x71, 0x5f, 0x1a, 0x7c, 0xe0, 0x1b, 0x2b, 0xe2, 0x53, 0xfa,
0xa0, 0x47, 0xfa, 0xd7, 0x8f, 0xb1, 0x4a, 0xc4, 0xdc, 0x89, 0xf9, 0xb4,
0x14, 0x4d, 0xde, 0x95, 0xea, 0x29, 0x69, 0x76, 0x81, 0xa3, 0x5c, 0x33,
0xd8, 0x37, 0xd8, 0xfa, 0x47, 0x19, 0x46, 0x2f, 0xf1, 0x90, 0xb7, 0x61,
0x8f, 0x6f, 0xdd, 0x31, 0x3f, 0x6a, 0x64,
#if !defined(BORINGSSL_FIPS_BREAK_AES_GCM)
0x0d
#else
0x00
#endif
};
static const DES_cblock kDESKey1 = {"BCMDESK1"};
static const DES_cblock kDESKey2 = {"BCMDESK2"};
static const DES_cblock kDESKey3 = {"BCMDESK3"};
static const DES_cblock kDESIV = {"BCMDESIV"};
static const uint8_t kDESCiphertext[64] = {
0xa4, 0x30, 0x7a, 0x4c, 0x1f, 0x60, 0x16, 0xd7, 0x4f, 0x41, 0xe1,
0xbb, 0x27, 0xc4, 0x27, 0x37, 0xd4, 0x7f, 0xb9, 0x10, 0xf8, 0xbc,
0xaf, 0x93, 0x91, 0xb8, 0x88, 0x24, 0xb1, 0xf6, 0xf8, 0xbd, 0x31,
0x96, 0x06, 0x76, 0xde, 0x32, 0xcd, 0x29, 0x29, 0xba, 0x70, 0x5f,
0xea, 0xc0, 0xcb, 0xde, 0xc7, 0x75, 0x90, 0xe0, 0x0f, 0x5e, 0x2c,
0x0d, 0x49, 0x20, 0xd5, 0x30, 0x83, 0xf8, 0x08,
#if !defined(BORINGSSL_FIPS_BREAK_DES)
0x5a
#else
0x00
#endif
};
static const uint8_t kPlaintextSHA1[20] = {
0xc6, 0xf8, 0xc9, 0x63, 0x1c, 0x14, 0x23, 0x62, 0x9b, 0xbd,
0x55, 0x82, 0xf4, 0xd6, 0x1d, 0xf2, 0xab, 0x7d, 0xc8,
#if !defined(BORINGSSL_FIPS_BREAK_SHA_1)
0x28
#else
0x00
#endif
};
static const uint8_t kPlaintextSHA256[32] = {
0x37, 0xbd, 0x70, 0x53, 0x72, 0xfc, 0xd4, 0x03, 0x79, 0x70, 0xfb,
0x06, 0x95, 0xb1, 0x2a, 0x82, 0x48, 0xe1, 0x3e, 0xf2, 0x33, 0xfb,
0xef, 0x29, 0x81, 0x22, 0x45, 0x40, 0x43, 0x70, 0xce,
#if !defined(BORINGSSL_FIPS_BREAK_SHA_256)
0x0f
#else
0x00
#endif
};
static const uint8_t kPlaintextSHA512[64] = {
0x08, 0x6a, 0x1c, 0x84, 0x61, 0x9d, 0x8e, 0xb3, 0xc0, 0x97, 0x4e,
0xa1, 0x9f, 0x9c, 0xdc, 0xaf, 0x3b, 0x5c, 0x31, 0xf0, 0xf2, 0x74,
0xc3, 0xbd, 0x6e, 0xd6, 0x1e, 0xb2, 0xbb, 0x34, 0x74, 0x72, 0x5c,
0x51, 0x29, 0x8b, 0x87, 0x3a, 0xa3, 0xf2, 0x25, 0x23, 0xd4, 0x1c,
0x82, 0x1b, 0xfe, 0xd3, 0xc6, 0xee, 0xb5, 0xd6, 0xaf, 0x07, 0x7b,
0x98, 0xca, 0xa7, 0x01, 0xf3, 0x94, 0xf3, 0x68,
#if !defined(BORINGSSL_FIPS_BREAK_SHA_512)
0x14
#else
0x00
#endif
};
static const uint8_t kRSASignature[256] = {
0x62, 0x66, 0x4b, 0xe3, 0xb1, 0xd2, 0x83, 0xf1, 0xa8, 0x56, 0x2b, 0x33,
0x60, 0x1e, 0xdb, 0x1e, 0x06, 0xf7, 0xa7, 0x1e, 0xa8, 0xef, 0x03, 0x4d,
0x0c, 0xf6, 0x83, 0x75, 0x7a, 0xf0, 0x14, 0xc7, 0xe2, 0x94, 0x3a, 0xb5,
0x67, 0x56, 0xa5, 0x48, 0x7f, 0x3a, 0xa5, 0xbf, 0xf7, 0x1d, 0x44, 0xa6,
0x34, 0xed, 0x9b, 0xd6, 0x51, 0xaa, 0x2c, 0x4e, 0xce, 0x60, 0x5f, 0xe9,
0x0e, 0xd5, 0xcd, 0xeb, 0x23, 0x27, 0xf8, 0xfb, 0x45, 0xe5, 0x34, 0x63,
0x77, 0x7f, 0x2e, 0x80, 0xcf, 0x9d, 0x2e, 0xfc, 0xe2, 0x50, 0x75, 0x29,
0x46, 0xf4, 0xaf, 0x91, 0xed, 0x36, 0xe1, 0x5e, 0xef, 0x66, 0xa1, 0xff,
0x27, 0xfc, 0x87, 0x7e, 0x60, 0x84, 0x0f, 0x54, 0x51, 0x56, 0x0f, 0x68,
0x99, 0xc0, 0x3f, 0xeb, 0xa5, 0xa0, 0x46, 0xb0, 0x86, 0x02, 0xb0, 0xc8,
0xe8, 0x46, 0x13, 0x06, 0xcd, 0xb7, 0x8a, 0xd0, 0x3b, 0x46, 0xd0, 0x14,
0x64, 0x53, 0x9b, 0x5b, 0x5e, 0x02, 0x45, 0xba, 0x6e, 0x7e, 0x0a, 0xb9,
0x9e, 0x62, 0xb7, 0xd5, 0x7a, 0x87, 0xea, 0xd3, 0x24, 0xa5, 0xef, 0xb3,
0xdc, 0x05, 0x9c, 0x04, 0x60, 0x4b, 0xde, 0xa8, 0x90, 0x08, 0x7b, 0x6a,
0x5f, 0xb4, 0x3f, 0xda, 0xc5, 0x1f, 0x6e, 0xd6, 0x15, 0xde, 0x65, 0xa4,
0x6e, 0x62, 0x9d, 0x8f, 0xa8, 0xbe, 0x86, 0xf6, 0x09, 0x90, 0x40, 0xa5,
0xf4, 0x23, 0xc5, 0xf6, 0x38, 0x86, 0x0d, 0x1c, 0xed, 0x4a, 0x0a, 0xae,
0xa4, 0x26, 0xc2, 0x2e, 0xd3, 0x13, 0x66, 0x61, 0xea, 0x35, 0x01, 0x0e,
0x13, 0xda, 0x78, 0x20, 0xae, 0x59, 0x5f, 0x9b, 0xa9, 0x6c, 0xf9, 0x1b,
0xdf, 0x76, 0x53, 0xc8, 0xa7, 0xf5, 0x63, 0x6d, 0xf3, 0xff, 0xfd, 0xaf,
0x75, 0x4b, 0xac, 0x67, 0xb1, 0x3c, 0xbf, 0x5e, 0xde, 0x73, 0x02, 0x6d,
0xd2, 0x0c, 0xb1,
#if !defined(BORINGSSL_FIPS_BREAK_RSA_SIG)
0x64
#else
0x00
#endif
};
const uint8_t kDRBGEntropy[48] =
"BCM Known Answer Test DBRG Initial Entropy ";
const uint8_t kDRBGPersonalization[18] = "BCMPersonalization";
const uint8_t kDRBGAD[16] = "BCM DRBG KAT AD ";
const uint8_t kDRBGOutput[64] = {
0x1d, 0x63, 0xdf, 0x05, 0x51, 0x49, 0x22, 0x46, 0xcd, 0x9b, 0xc5,
0xbb, 0xf1, 0x5d, 0x44, 0xae, 0x13, 0x78, 0xb1, 0xe4, 0x7c, 0xf1,
0x96, 0x33, 0x3d, 0x60, 0xb6, 0x29, 0xd4, 0xbb, 0x6b, 0x44, 0xf9,
0xef, 0xd9, 0xf4, 0xa2, 0xba, 0x48, 0xea, 0x39, 0x75, 0x59, 0x32,
0xf7, 0x31, 0x2c, 0x98, 0x14, 0x2b, 0x49, 0xdf, 0x02, 0xb6, 0x5d,
0x71, 0x09, 0x50, 0xdb, 0x23, 0xdb, 0xe5, 0x22,
#if !defined(BORINGSSL_FIPS_BREAK_DRBG)
0x95
#else
0x00
#endif
};
const uint8_t kDRBGEntropy2[48] =
"BCM Known Answer Test DBRG Reseed Entropy ";
const uint8_t kDRBGReseedOutput[64] = {
0xa4, 0x77, 0x05, 0xdb, 0x14, 0x11, 0x76, 0x71, 0x42, 0x5b, 0xd8,
0xd7, 0xa5, 0x4f, 0x8b, 0x39, 0xf2, 0x10, 0x4a, 0x50, 0x5b, 0xa2,
0xc8, 0xf0, 0xbb, 0x3e, 0xa1, 0xa5, 0x90, 0x7d, 0x54, 0xd9, 0xc6,
0xb0, 0x96, 0xc0, 0x2b, 0x7e, 0x9b, 0xc9, 0xa1, 0xdd, 0x78, 0x2e,
0xd5, 0xa8, 0x66, 0x16, 0xbd, 0x18, 0x3c, 0xf2, 0xaa, 0x7a, 0x2b,
0x37, 0xf9, 0xab, 0x35, 0x64, 0x15, 0x01, 0x3f, 0xc4,
};
const uint8_t kECDSASigR[32] = {
0x67, 0x80, 0xc5, 0xfc, 0x70, 0x27, 0x5e, 0x2c, 0x70, 0x61, 0xa0,
0xe7, 0x87, 0x7b, 0xb1, 0x74, 0xde, 0xad, 0xeb, 0x98, 0x87, 0x02,
0x7f, 0x3f, 0xa8, 0x36, 0x54, 0x15, 0x8b, 0xa7, 0xf5,
#if !defined(BORINGSSL_FIPS_BREAK_ECDSA_SIG)
0x0c,
#else
0x00,
#endif
};
const uint8_t kECDSASigS[32] = {
0xa5, 0x93, 0xe0, 0x23, 0x91, 0xe7, 0x4b, 0x8d, 0x77, 0x25, 0xa6,
0xba, 0x4d, 0xd9, 0x86, 0x77, 0xda, 0x7d, 0x8f, 0xef, 0xc4, 0x1a,
0xf0, 0xcc, 0x81, 0xe5, 0xea, 0x3f, 0xc2, 0x41, 0x7f, 0xd8,
};
AES_KEY aes_key;
uint8_t aes_iv[16];
uint8_t output[256];
// AES-CBC Encryption KAT
memcpy(aes_iv, kAESIV, sizeof(kAESIV));
if (AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) != 0) {
goto err;
}
AES_cbc_encrypt(kPlaintext, output, sizeof(kPlaintext), &aes_key, aes_iv,
AES_ENCRYPT);
if (!check_test(kAESCBCCiphertext, output, sizeof(kAESCBCCiphertext),
"AES-CBC Encryption KAT")) {
goto err;
}
// AES-CBC Decryption KAT
memcpy(aes_iv, kAESIV, sizeof(kAESIV));
if (AES_set_decrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) != 0) {
goto err;
}
AES_cbc_encrypt(kAESCBCCiphertext, output, sizeof(kAESCBCCiphertext),
&aes_key, aes_iv, AES_DECRYPT);
if (!check_test(kPlaintext, output, sizeof(kPlaintext),
"AES-CBC Decryption KAT")) {
goto err;
}
size_t out_len;
uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
OPENSSL_memset(nonce, 0, sizeof(nonce));
EVP_AEAD_CTX aead_ctx;
if (!EVP_AEAD_CTX_init(&aead_ctx, EVP_aead_aes_128_gcm(), kAESKey,
sizeof(kAESKey), 0, NULL)) {
goto err;
}
// AES-GCM Encryption KAT
if (!EVP_AEAD_CTX_seal(&aead_ctx, output, &out_len, sizeof(output), nonce,
EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()),
kPlaintext, sizeof(kPlaintext), NULL, 0) ||
!check_test(kAESGCMCiphertext, output, sizeof(kAESGCMCiphertext),
"AES-GCM Encryption KAT")) {
goto err;
}
// AES-GCM Decryption KAT
if (!EVP_AEAD_CTX_open(&aead_ctx, output, &out_len, sizeof(output), nonce,
EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()),
kAESGCMCiphertext, sizeof(kAESGCMCiphertext), NULL,
0) ||
!check_test(kPlaintext, output, sizeof(kPlaintext),
"AES-GCM Decryption KAT")) {
goto err;
}
EVP_AEAD_CTX_cleanup(&aead_ctx);
DES_key_schedule des1, des2, des3;
DES_cblock des_iv;
DES_set_key(&kDESKey1, &des1);
DES_set_key(&kDESKey2, &des2);
DES_set_key(&kDESKey3, &des3);
// 3DES Encryption KAT
memcpy(&des_iv, &kDESIV, sizeof(des_iv));
DES_ede3_cbc_encrypt(kPlaintext, output, sizeof(kPlaintext), &des1, &des2,
&des3, &des_iv, DES_ENCRYPT);
if (!check_test(kDESCiphertext, output, sizeof(kDESCiphertext),
"3DES Encryption KAT")) {
goto err;
}
// 3DES Decryption KAT
memcpy(&des_iv, &kDESIV, sizeof(des_iv));
DES_ede3_cbc_encrypt(kDESCiphertext, output, sizeof(kDESCiphertext), &des1,
&des2, &des3, &des_iv, DES_DECRYPT);
if (!check_test(kPlaintext, output, sizeof(kPlaintext),
"3DES Decryption KAT")) {
goto err;
}
// SHA-1 KAT
SHA1(kPlaintext, sizeof(kPlaintext), output);
if (!check_test(kPlaintextSHA1, output, sizeof(kPlaintextSHA1),
"SHA-1 KAT")) {
goto err;
}
// SHA-256 KAT
SHA256(kPlaintext, sizeof(kPlaintext), output);
if (!check_test(kPlaintextSHA256, output, sizeof(kPlaintextSHA256),
"SHA-256 KAT")) {
goto err;
}
// SHA-512 KAT
SHA512(kPlaintext, sizeof(kPlaintext), output);
if (!check_test(kPlaintextSHA512, output, sizeof(kPlaintextSHA512),
"SHA-512 KAT")) {
goto err;
}
RSA *rsa_key = self_test_rsa_key();
if (rsa_key == NULL) {
printf("RSA KeyGen failed\n");
goto err;
}
// RSA Sign KAT
unsigned sig_len;
// Disable blinding for the power-on tests because it's not needed and
// triggers an entropy draw.
rsa_key->flags |= RSA_FLAG_NO_BLINDING;
if (!RSA_sign(NID_sha256, kPlaintextSHA256, sizeof(kPlaintextSHA256), output,
&sig_len, rsa_key) ||
!check_test(kRSASignature, output, sizeof(kRSASignature),
"RSA Sign KAT")) {
goto err;
}
// RSA Verify KAT
if (!RSA_verify(NID_sha256, kPlaintextSHA256, sizeof(kPlaintextSHA256),
kRSASignature, sizeof(kRSASignature), rsa_key)) {
printf("RSA Verify KAT failed.\n");
goto err;
}
RSA_free(rsa_key);
EC_KEY *ec_key = self_test_ecdsa_key();
if (ec_key == NULL) {
printf("ECDSA KeyGen failed\n");
goto err;
}
// ECDSA Sign/Verify PWCT
// The 'k' value for ECDSA is fixed to avoid an entropy draw.
ec_key->fixed_k = BN_new();
if (ec_key->fixed_k == NULL ||
!BN_set_word(ec_key->fixed_k, 42)) {
printf("Out of memory\n");
goto err;
}
ECDSA_SIG *sig =
ECDSA_do_sign(kPlaintextSHA256, sizeof(kPlaintextSHA256), ec_key);
uint8_t ecdsa_r_bytes[sizeof(kECDSASigR)];
uint8_t ecdsa_s_bytes[sizeof(kECDSASigS)];
if (sig == NULL ||
BN_num_bytes(sig->r) != sizeof(ecdsa_r_bytes) ||
!BN_bn2bin(sig->r, ecdsa_r_bytes) ||
BN_num_bytes(sig->s) != sizeof(ecdsa_s_bytes) ||
!BN_bn2bin(sig->s, ecdsa_s_bytes) ||
!check_test(kECDSASigR, ecdsa_r_bytes, sizeof(kECDSASigR), "ECDSA R") ||
!check_test(kECDSASigS, ecdsa_s_bytes, sizeof(kECDSASigS), "ECDSA S")) {
printf("ECDSA KAT failed.\n");
goto err;
}
ECDSA_SIG_free(sig);
EC_KEY_free(ec_key);
// DBRG KAT
CTR_DRBG_STATE drbg;
if (!CTR_DRBG_init(&drbg, kDRBGEntropy, kDRBGPersonalization,
sizeof(kDRBGPersonalization)) ||
!CTR_DRBG_generate(&drbg, output, sizeof(kDRBGOutput), kDRBGAD,
sizeof(kDRBGAD)) ||
!check_test(kDRBGOutput, output, sizeof(kDRBGOutput),
"DBRG Generate KAT") ||
!CTR_DRBG_reseed(&drbg, kDRBGEntropy2, kDRBGAD, sizeof(kDRBGAD)) ||
!CTR_DRBG_generate(&drbg, output, sizeof(kDRBGReseedOutput), kDRBGAD,
sizeof(kDRBGAD)) ||
!check_test(kDRBGReseedOutput, output, sizeof(kDRBGReseedOutput),
"DRBG Reseed KAT")) {
goto err;
}
CTR_DRBG_clear(&drbg);
CTR_DRBG_STATE kZeroDRBG;
memset(&kZeroDRBG, 0, sizeof(kZeroDRBG));
if (!check_test(&kZeroDRBG, &drbg, sizeof(drbg), "DRBG Clear KAT")) {
if (!BORINGSSL_self_test()) {
goto err;
}
@@ -676,4 +144,5 @@ void BORINGSSL_FIPS_abort(void) {
exit(1);
}
}
#endif // BORINGSSL_FIPS
+32 -63
View File
@@ -100,61 +100,38 @@ int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
return ret;
}
int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
int max, min, dif;
BN_ULONG *ap, *bp, *rp, carry, t1, t2;
const BIGNUM *tmp;
if (a->top < b->top) {
tmp = a;
int bn_uadd_fixed(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
// Widths are public, so we normalize to make |a| the larger one.
if (a->width < b->width) {
const BIGNUM *tmp = a;
a = b;
b = tmp;
}
max = a->top;
min = b->top;
dif = max - min;
int max = a->width;
int min = b->width;
if (!bn_wexpand(r, max + 1)) {
return 0;
}
r->width = max + 1;
r->top = max;
ap = a->d;
bp = b->d;
rp = r->d;
carry = bn_add_words(rp, ap, bp, min);
rp += min;
ap += min;
bp += min;
if (carry) {
while (dif) {
dif--;
t1 = *(ap++);
t2 = t1 + 1;
*(rp++) = t2;
if (t2) {
carry = 0;
break;
}
}
if (carry) {
// carry != 0 => dif == 0
*rp = 1;
r->top++;
}
BN_ULONG carry = bn_add_words(r->d, a->d, b->d, min);
for (int i = min; i < max; i++) {
// |r| and |a| may alias, so use a temporary.
BN_ULONG tmp = carry + a->d[i];
carry = tmp < a->d[i];
r->d[i] = tmp;
}
if (dif && rp != ap) {
while (dif--) {
// copy remaining words if ap != rp
*(rp++) = *(ap++);
}
}
r->d[max] = carry;
return 1;
}
r->neg = 0;
int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
if (!bn_uadd_fixed(r, a, b)) {
return 0;
}
bn_set_minimal_width(r);
return 1;
}
@@ -182,16 +159,16 @@ int BN_add_word(BIGNUM *a, BN_ULONG w) {
return i;
}
for (i = 0; w != 0 && i < a->top; i++) {
for (i = 0; w != 0 && i < a->width; i++) {
a->d[i] = l = a->d[i] + w;
w = (w > l) ? 1 : 0;
}
if (w && i == a->top) {
if (!bn_wexpand(a, a->top + 1)) {
if (w && i == a->width) {
if (!bn_wexpand(a, a->width + 1)) {
return 0;
}
a->top++;
a->width++;
a->d[i] = w;
}
@@ -199,7 +176,6 @@ int BN_add_word(BIGNUM *a, BN_ULONG w) {
}
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
int max;
int add = 0, neg = 0;
const BIGNUM *tmp;
@@ -232,13 +208,6 @@ int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
return 1;
}
// We are actually doing a - b :-)
max = (a->top > b->top) ? a->top : b->top;
if (!bn_wexpand(r, max)) {
return 0;
}
if (BN_ucmp(a, b) < 0) {
if (!BN_usub(r, b, a)) {
return 0;
@@ -259,8 +228,8 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
register BN_ULONG t1, t2, *ap, *bp, *rp;
int i, carry;
max = a->top;
min = b->top;
max = bn_minimal_width(a);
min = bn_minimal_width(b);
dif = max - min;
if (dif < 0) // hmm... should not be happening
@@ -313,9 +282,9 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
OPENSSL_memcpy(rp, ap, sizeof(*rp) * dif);
}
r->top = max;
r->width = max;
r->neg = 0;
bn_correct_top(r);
bn_set_minimal_width(r);
return 1;
}
@@ -345,7 +314,7 @@ int BN_sub_word(BIGNUM *a, BN_ULONG w) {
return i;
}
if ((a->top == 1) && (a->d[0] < w)) {
if ((bn_minimal_width(a) == 1) && (a->d[0] < w)) {
a->d[0] = w - a->d[0];
a->neg = 1;
return 1;
@@ -363,8 +332,8 @@ int BN_sub_word(BIGNUM *a, BN_ULONG w) {
}
}
if ((a->d[i] == 0) && (i == (a->top - 1))) {
a->top--;
if ((a->d[i] == 0) && (i == (a->width - 1))) {
a->width--;
}
return 1;
+4
View File
@@ -97,6 +97,10 @@ $_num="$num,#15*4"; $_bpend=$_num;
$code=<<___;
#include <openssl/arm_arch.h>
@ Silence ARMv8 deprecated IT instruction warnings. This file is used by both
@ ARMv7 and ARMv8 processors and does not use ARMv8 instructions.
.arch armv7-a
.text
#if defined(__thumb2__)
.syntax unified
+8 -1
View File
@@ -1,4 +1,11 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../../perlasm");
+7 -1
View File
@@ -1,4 +1,10 @@
#!/usr/local/bin/perl
#! /usr/bin/env perl
# Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../../perlasm");
+34 -66
View File
@@ -1,61 +1,30 @@
#!/usr/bin/env perl
##############################################################################
# #
# Copyright (c) 2012, Intel Corporation #
# #
# All rights reserved. #
# #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions are #
# met: #
# #
# * Redistributions of source code must retain the above copyright #
# notice, this list of conditions and the following disclaimer. #
# #
# * Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions and the following disclaimer in the #
# documentation and/or other materials provided with the #
# distribution. #
# #
# * Neither the name of the Intel Corporation nor the names of its #
# contributors may be used to endorse or promote products derived from #
# this software without specific prior written permission. #
# #
# #
# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY #
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE #
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR #
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR #
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, #
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR #
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF #
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS #
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #
# #
##############################################################################
# Developers and authors: #
# Shay Gueron (1, 2), and Vlad Krasnov (1) #
# (1) Intel Corporation, Israel Development Center, Haifa, Israel #
# (2) University of Haifa, Israel #
##############################################################################
# Reference: #
# [1] S. Gueron, V. Krasnov: "Software Implementation of Modular #
# Exponentiation, Using Advanced Vector Instructions Architectures", #
# F. Ozbudak and F. Rodriguez-Henriquez (Eds.): WAIFI 2012, LNCS 7369, #
# pp. 119?135, 2012. Springer-Verlag Berlin Heidelberg 2012 #
# [2] S. Gueron: "Efficient Software Implementations of Modular #
# Exponentiation", Journal of Cryptographic Engineering 2:31-43 (2012). #
# [3] S. Gueron, V. Krasnov: "Speeding up Big-numbers Squaring",IEEE #
# Proceedings of 9th International Conference on Information Technology: #
# New Generations (ITNG 2012), pp.821-823 (2012) #
# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis #
# resistant 1024-bit modular exponentiation, for optimizing RSA2048 #
# on AVX2 capable x86_64 platforms", #
# http://rt.openssl.org/Ticket/Display.html?id=2850&user=guest&pass=guest#
##############################################################################
#! /usr/bin/env perl
# Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved.
# Copyright (c) 2012, Intel Corporation. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
#
# Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1)
# (1) Intel Corporation, Israel Development Center, Haifa, Israel
# (2) University of Haifa, Israel
#
# References:
# [1] S. Gueron, V. Krasnov: "Software Implementation of Modular
# Exponentiation, Using Advanced Vector Instructions Architectures",
# F. Ozbudak and F. Rodriguez-Henriquez (Eds.): WAIFI 2012, LNCS 7369,
# pp. 119?135, 2012. Springer-Verlag Berlin Heidelberg 2012
# [2] S. Gueron: "Efficient Software Implementations of Modular
# Exponentiation", Journal of Cryptographic Engineering 2:31-43 (2012).
# [3] S. Gueron, V. Krasnov: "Speeding up Big-numbers Squaring",IEEE
# Proceedings of 9th International Conference on Information Technology:
# New Generations (ITNG 2012), pp.821-823 (2012)
# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis
# resistant 1024-bit modular exponentiation, for optimizing RSA2048
# on AVX2 capable x86_64 platforms",
# http://rt.openssl.org/Ticket/Display.html?id=2850&user=guest&pass=guest
#
# +13% improvement over original submission by <appro@openssl.org>
#
@@ -232,7 +201,7 @@ $code.=<<___;
vmovdqu 32*8-128($ap), $ACC8
lea 192(%rsp), $tp0 # 64+128=192
vpbroadcastq .Land_mask(%rip), $AND_MASK
vmovdqu .Land_mask(%rip), $AND_MASK
jmp .LOOP_GRANDE_SQR_1024
.align 32
@@ -1082,10 +1051,10 @@ $code.=<<___;
vpmuludq 32*6-128($np),$Yi,$TEMP1
vpaddq $TEMP1,$ACC6,$ACC6
vpmuludq 32*7-128($np),$Yi,$TEMP2
vpblendd \$3, $ZERO, $ACC9, $ACC9 # correct $ACC3
vpblendd \$3, $ZERO, $ACC9, $TEMP1 # correct $ACC3
vpaddq $TEMP2,$ACC7,$ACC7
vpmuludq 32*8-128($np),$Yi,$TEMP0
vpaddq $ACC9, $ACC3, $ACC3 # correct $ACC3
vpaddq $TEMP1, $ACC3, $ACC3 # correct $ACC3
vpaddq $TEMP0,$ACC8,$ACC8
mov %rbx, %rax
@@ -1098,7 +1067,9 @@ $code.=<<___;
vmovdqu -8+32*2-128($ap),$TEMP2
mov $r1, %rax
vpblendd \$0xfc, $ZERO, $ACC9, $ACC9 # correct $ACC3
imull $n0, %eax
vpaddq $ACC9,$ACC4,$ACC4 # correct $ACC3
and \$0x1fffffff, %eax
imulq 16-128($ap),%rbx
@@ -1334,15 +1305,12 @@ ___
# But as we underutilize resources, it's possible to correct in
# each iteration with marginal performance loss. But then, as
# we do it in each iteration, we can correct less digits, and
# avoid performance penalties completely. Also note that we
# correct only three digits out of four. This works because
# most significant digit is subjected to less additions.
# avoid performance penalties completely.
$TEMP0 = $ACC9;
$TEMP3 = $Bi;
$TEMP4 = $Yi;
$code.=<<___;
vpermq \$0, $AND_MASK, $AND_MASK
vpaddq (%rsp), $TEMP1, $ACC0
vpsrlq \$29, $ACC0, $TEMP1
@@ -1790,7 +1758,7 @@ $code.=<<___;
.align 64
.Land_mask:
.quad 0x1fffffff,0x1fffffff,0x1fffffff,-1
.quad 0x1fffffff,0x1fffffff,0x1fffffff,0x1fffffff
.Lscatter_permd:
.long 0,2,4,6,7,7,7,7
.Lgather_permd:
+10 -3
View File
@@ -1,7 +1,14 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
# ====================================================================
# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
# project. The module is, however, dual licensed under OpenSSL and
# CRYPTOGAMS licenses depending on where you obtain it. For further
# details see http://www.openssl.org/~appro/cryptogams/.
@@ -71,7 +78,7 @@ $frame=32; # size of above frame rounded up to 16n
&lea ("ebp",&DWP(-$frame,"esp","edi",4)); # future alloca($frame+4*(num+2))
&neg ("edi");
# minimize cache contention by arraning 2K window between stack
# minimize cache contention by arranging 2K window between stack
# pointer and ap argument [np is also position sensitive vector,
# but it's assumed to be near ap, as it's allocated at ~same
# time].
+4 -3
View File
@@ -52,8 +52,9 @@
#include <openssl/bn.h>
// TODO(davidben): Get this file working on Windows x64.
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && defined(__GNUC__)
// TODO(davidben): Get this file working on MSVC x64.
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
(defined(__GNUC__) || defined(__clang__))
#include "../internal.h"
@@ -537,4 +538,4 @@ void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]) {
#undef mul_add_c2
#undef sqr_add_c2
#endif // !NO_ASM && X86_64 && __GNUC__
#endif // !NO_ASM && X86_64 && (__GNUC__ || __clang__)
+11 -5
View File
@@ -1,4 +1,11 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -296,12 +303,11 @@ $code.=<<___;
mov $num,$j # j=num
jmp .Lsub
.align 16
.Lsub:
sbb ($np,$i,8),%rax
.Lsub: sbb ($np,$i,8),%rax
mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i]
mov 8($ap,$i,8),%rax # tp[i+1]
lea 1($i),$i # i++
dec $j # doesnn't affect CF!
dec $j # doesn't affect CF!
jnz .Lsub
sbb \$0,%rax # handle upmost overflow bit
@@ -732,7 +738,7 @@ $code.=<<___;
mov 56($ap,$i,8),@ri[3]
sbb 40($np,$i,8),@ri[1]
lea 4($i),$i # i++
dec $j # doesnn't affect CF!
dec $j # doesn't affect CF!
jnz .Lsub4x
mov @ri[0],0($rp,$i,8) # rp[i]=tp[i]-np[i]
+11 -5
View File
@@ -1,4 +1,11 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -396,12 +403,11 @@ $code.=<<___;
mov $num,$j # j=num
jmp .Lsub
.align 16
.Lsub:
sbb ($np,$i,8),%rax
.Lsub: sbb ($np,$i,8),%rax
mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i]
mov 8($ap,$i,8),%rax # tp[i+1]
lea 1($i),$i # i++
dec $j # doesnn't affect CF!
dec $j # doesn't affect CF!
jnz .Lsub
sbb \$0,%rax # handle upmost overflow bit
@@ -2405,7 +2411,7 @@ my $N=$STRIDE/4; # should match cache line size
$code.=<<___;
movdqa 0(%rax),%xmm0 # 00000001000000010000000000000000
movdqa 16(%rax),%xmm1 # 00000002000000020000000200000002
lea 88-112(%rsp,%r10),%r10 # place the mask after tp[num+1] (+ICache optimizaton)
lea 88-112(%rsp,%r10),%r10 # place the mask after tp[num+1] (+ICache optimization)
lea 128($bp),$bptr # size optimization
pshufd \$0,%xmm5,%xmm5 # broadcast index
+121 -69
View File
@@ -148,13 +148,13 @@ BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src) {
return dest;
}
if (!bn_wexpand(dest, src->top)) {
if (!bn_wexpand(dest, src->width)) {
return NULL;
}
OPENSSL_memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top);
OPENSSL_memcpy(dest->d, src->d, sizeof(src->d[0]) * src->width);
dest->top = src->top;
dest->width = src->width;
dest->neg = src->neg;
return dest;
}
@@ -164,14 +164,14 @@ void BN_clear(BIGNUM *bn) {
OPENSSL_memset(bn->d, 0, bn->dmax * sizeof(bn->d[0]));
}
bn->top = 0;
bn->width = 0;
bn->neg = 0;
}
DEFINE_METHOD_FUNCTION(BIGNUM, BN_value_one) {
static const BN_ULONG kOneLimbs[1] = { 1 };
out->d = (BN_ULONG*) kOneLimbs;
out->top = 1;
out->width = 1;
out->dmax = 1;
out->neg = 0;
out->flags = BN_FLG_STATIC_DATA;
@@ -180,61 +180,59 @@ DEFINE_METHOD_FUNCTION(BIGNUM, BN_value_one) {
// BN_num_bits_word returns the minimum number of bits needed to represent the
// value in |l|.
unsigned BN_num_bits_word(BN_ULONG l) {
static const unsigned char bits[256] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
// |BN_num_bits| is often called on RSA prime factors. These have public bit
// lengths, but all bits beyond the high bit are secret, so count bits in
// constant time.
BN_ULONG x, mask;
int bits = (l != 0);
#if defined(OPENSSL_64_BIT)
if (l & 0xffffffff00000000L) {
if (l & 0xffff000000000000L) {
if (l & 0xff00000000000000L) {
return (bits[(int)(l >> 56)] + 56);
} else {
return (bits[(int)(l >> 48)] + 48);
}
} else {
if (l & 0x0000ff0000000000L) {
return (bits[(int)(l >> 40)] + 40);
} else {
return (bits[(int)(l >> 32)] + 32);
}
}
} else
#if BN_BITS2 > 32
x = l >> 32;
mask = 0u - x;
mask = (0u - (mask >> (BN_BITS2 - 1)));
bits += 32 & mask;
l ^= (x ^ l) & mask;
#endif
{
if (l & 0xffff0000L) {
if (l & 0xff000000L) {
return (bits[(int)(l >> 24L)] + 24);
} else {
return (bits[(int)(l >> 16L)] + 16);
}
} else {
if (l & 0xff00L) {
return (bits[(int)(l >> 8)] + 8);
} else {
return (bits[(int)(l)]);
}
}
}
x = l >> 16;
mask = 0u - x;
mask = (0u - (mask >> (BN_BITS2 - 1)));
bits += 16 & mask;
l ^= (x ^ l) & mask;
x = l >> 8;
mask = 0u - x;
mask = (0u - (mask >> (BN_BITS2 - 1)));
bits += 8 & mask;
l ^= (x ^ l) & mask;
x = l >> 4;
mask = 0u - x;
mask = (0u - (mask >> (BN_BITS2 - 1)));
bits += 4 & mask;
l ^= (x ^ l) & mask;
x = l >> 2;
mask = 0u - x;
mask = (0u - (mask >> (BN_BITS2 - 1)));
bits += 2 & mask;
l ^= (x ^ l) & mask;
x = l >> 1;
mask = 0u - x;
mask = (0u - (mask >> (BN_BITS2 - 1)));
bits += 1 & mask;
return bits;
}
unsigned BN_num_bits(const BIGNUM *bn) {
const int max = bn->top - 1;
if (BN_is_zero(bn)) {
const int width = bn_minimal_width(bn);
if (width == 0) {
return 0;
}
return max*BN_BITS2 + BN_num_bits_word(bn->d[max]);
return (width - 1) * BN_BITS2 + BN_num_bits_word(bn->d[width - 1]);
}
unsigned BN_num_bytes(const BIGNUM *bn) {
@@ -242,7 +240,7 @@ unsigned BN_num_bytes(const BIGNUM *bn) {
}
void BN_zero(BIGNUM *bn) {
bn->top = bn->neg = 0;
bn->width = bn->neg = 0;
}
int BN_one(BIGNUM *bn) {
@@ -261,7 +259,7 @@ int BN_set_word(BIGNUM *bn, BN_ULONG value) {
bn->neg = 0;
bn->d[0] = value;
bn->top = 1;
bn->width = 1;
return 1;
}
@@ -280,7 +278,7 @@ int BN_set_u64(BIGNUM *bn, uint64_t value) {
bn->neg = 0;
bn->d[0] = (BN_ULONG)value;
bn->d[1] = (BN_ULONG)(value >> 32);
bn->top = 2;
bn->width = 2;
return 1;
#else
#error "BN_BITS2 must be 32 or 64."
@@ -293,12 +291,40 @@ int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num) {
}
OPENSSL_memmove(bn->d, words, num * sizeof(BN_ULONG));
// |bn_wexpand| verified that |num| isn't too large.
bn->top = (int)num;
bn_correct_top(bn);
bn->width = (int)num;
bn->neg = 0;
return 1;
}
int bn_fits_in_words(const BIGNUM *bn, size_t num) {
// All words beyond |num| must be zero.
BN_ULONG mask = 0;
for (size_t i = num; i < (size_t)bn->width; i++) {
mask |= bn->d[i];
}
return mask == 0;
}
int bn_copy_words(BN_ULONG *out, size_t num, const BIGNUM *bn) {
if (bn->neg) {
OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
return 0;
}
size_t width = (size_t)bn->width;
if (width > num) {
if (!bn_fits_in_words(bn, num)) {
OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
return 0;
}
width = num;
}
OPENSSL_memset(out, 0, sizeof(BN_ULONG) * num);
OPENSSL_memcpy(out, bn->d, sizeof(BN_ULONG) * width);
return 1;
}
int BN_is_negative(const BIGNUM *bn) {
return bn->neg != 0;
}
@@ -334,7 +360,7 @@ int bn_wexpand(BIGNUM *bn, size_t words) {
return 0;
}
OPENSSL_memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top);
OPENSSL_memcpy(a, bn->d, sizeof(BN_ULONG) * bn->width);
OPENSSL_free(bn->d);
bn->d = a;
@@ -351,20 +377,46 @@ int bn_expand(BIGNUM *bn, size_t bits) {
return bn_wexpand(bn, (bits+BN_BITS2-1)/BN_BITS2);
}
void bn_correct_top(BIGNUM *bn) {
BN_ULONG *ftl;
int tmp_top = bn->top;
if (tmp_top > 0) {
for (ftl = &(bn->d[tmp_top - 1]); tmp_top > 0; tmp_top--) {
if (*(ftl--)) {
break;
}
int bn_resize_words(BIGNUM *bn, size_t words) {
if ((size_t)bn->width <= words) {
if (!bn_wexpand(bn, words)) {
return 0;
}
bn->top = tmp_top;
OPENSSL_memset(bn->d + bn->width, 0,
(words - bn->width) * sizeof(BN_ULONG));
bn->width = words;
return 1;
}
if (bn->top == 0) {
// All words beyond the new width must be zero.
if (!bn_fits_in_words(bn, words)) {
OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
return 0;
}
bn->width = words;
return 1;
}
void bn_select_words(BN_ULONG *r, BN_ULONG mask, const BN_ULONG *a,
const BN_ULONG *b, size_t num) {
for (size_t i = 0; i < num; i++) {
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
crypto_word_t_too_small);
r[i] = constant_time_select_w(mask, a[i], b[i]);
}
}
int bn_minimal_width(const BIGNUM *bn) {
int ret = bn->width;
while (ret > 0 && bn->d[ret - 1] == 0) {
ret--;
}
return ret;
}
void bn_set_minimal_width(BIGNUM *bn) {
bn->width = bn_minimal_width(bn);
if (bn->width == 0) {
bn->neg = 0;
}
}
+407 -150
View File
@@ -87,11 +87,13 @@
#include <gtest/gtest.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include "./internal.h"
#include "../../internal.h"
@@ -106,34 +108,62 @@ static int HexToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) {
return ret;
}
static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *attribute) {
std::string hex;
if (!t->GetAttribute(&hex, attribute)) {
return nullptr;
// A BIGNUMFileTest wraps a FileTest to give |BIGNUM| values and also allows
// injecting oversized |BIGNUM|s.
class BIGNUMFileTest {
public:
BIGNUMFileTest(FileTest *t, unsigned large_mask)
: t_(t), large_mask_(large_mask), num_bignums_(0) {}
unsigned num_bignums() const { return num_bignums_; }
bssl::UniquePtr<BIGNUM> GetBIGNUM(const char *attribute) {
return GetBIGNUMImpl(attribute, true /* resize */);
}
bssl::UniquePtr<BIGNUM> ret;
if (HexToBIGNUM(&ret, hex.c_str()) != static_cast<int>(hex.size())) {
t->PrintLine("Could not decode '%s'.", hex.c_str());
return nullptr;
}
return ret;
}
bool GetInt(int *out, const char *attribute) {
bssl::UniquePtr<BIGNUM> ret =
GetBIGNUMImpl(attribute, false /* don't resize */);
if (!ret) {
return false;
}
static bool GetInt(FileTest *t, int *out, const char *attribute) {
bssl::UniquePtr<BIGNUM> ret = GetBIGNUM(t, attribute);
if (!ret) {
return false;
BN_ULONG word = BN_get_word(ret.get());
if (word > INT_MAX) {
return false;
}
*out = static_cast<int>(word);
return true;
}
BN_ULONG word = BN_get_word(ret.get());
if (word > INT_MAX) {
return false;
private:
bssl::UniquePtr<BIGNUM> GetBIGNUMImpl(const char *attribute, bool resize) {
std::string hex;
if (!t_->GetAttribute(&hex, attribute)) {
return nullptr;
}
bssl::UniquePtr<BIGNUM> ret;
if (HexToBIGNUM(&ret, hex.c_str()) != static_cast<int>(hex.size())) {
t_->PrintLine("Could not decode '%s'.", hex.c_str());
return nullptr;
}
if (resize) {
// Test with an oversized |BIGNUM| if necessary.
if ((large_mask_ & (1 << num_bignums_)) &&
!bn_resize_words(ret.get(), ret->width * 2 + 1)) {
return nullptr;
}
num_bignums_++;
}
return ret;
}
*out = static_cast<int>(word);
return true;
}
FileTest *t_;
unsigned large_mask_;
unsigned num_bignums_;
};
static testing::AssertionResult AssertBIGNUMSEqual(
const char *operation_expr, const char *expected_expr,
@@ -159,10 +189,10 @@ static testing::AssertionResult AssertBIGNUMSEqual(
#define EXPECT_BIGNUMS_EQUAL(op, a, b) \
EXPECT_PRED_FORMAT3(AssertBIGNUMSEqual, op, a, b)
static void TestSum(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> b = GetBIGNUM(t, "B");
bssl::UniquePtr<BIGNUM> sum = GetBIGNUM(t, "Sum");
static void TestSum(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> b = t->GetBIGNUM("B");
bssl::UniquePtr<BIGNUM> sum = t->GetBIGNUM("Sum");
ASSERT_TRUE(a);
ASSERT_TRUE(b);
ASSERT_TRUE(sum);
@@ -261,9 +291,9 @@ static void TestSum(FileTest *t, BN_CTX *ctx) {
}
}
static void TestLShift1(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> lshift1 = GetBIGNUM(t, "LShift1");
static void TestLShift1(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> lshift1 = t->GetBIGNUM("LShift1");
bssl::UniquePtr<BIGNUM> zero(BN_new());
ASSERT_TRUE(a);
ASSERT_TRUE(lshift1);
@@ -307,13 +337,13 @@ static void TestLShift1(FileTest *t, BN_CTX *ctx) {
EXPECT_BIGNUMS_EQUAL("(LShift | 1) >> 1", a.get(), ret.get());
}
static void TestLShift(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> lshift = GetBIGNUM(t, "LShift");
static void TestLShift(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> lshift = t->GetBIGNUM("LShift");
ASSERT_TRUE(a);
ASSERT_TRUE(lshift);
int n = 0;
ASSERT_TRUE(GetInt(t, &n, "N"));
ASSERT_TRUE(t->GetInt(&n, "N"));
bssl::UniquePtr<BIGNUM> ret(BN_new());
ASSERT_TRUE(ret);
@@ -324,13 +354,13 @@ static void TestLShift(FileTest *t, BN_CTX *ctx) {
EXPECT_BIGNUMS_EQUAL("A >> N", a.get(), ret.get());
}
static void TestRShift(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> rshift = GetBIGNUM(t, "RShift");
static void TestRShift(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> rshift = t->GetBIGNUM("RShift");
ASSERT_TRUE(a);
ASSERT_TRUE(rshift);
int n = 0;
ASSERT_TRUE(GetInt(t, &n, "N"));
ASSERT_TRUE(t->GetInt(&n, "N"));
bssl::UniquePtr<BIGNUM> ret(BN_new());
ASSERT_TRUE(ret);
@@ -338,9 +368,9 @@ static void TestRShift(FileTest *t, BN_CTX *ctx) {
EXPECT_BIGNUMS_EQUAL("A >> N", rshift.get(), ret.get());
}
static void TestSquare(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> square = GetBIGNUM(t, "Square");
static void TestSquare(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> square = t->GetBIGNUM("Square");
bssl::UniquePtr<BIGNUM> zero(BN_new());
ASSERT_TRUE(a);
ASSERT_TRUE(square);
@@ -386,15 +416,15 @@ static void TestSquare(FileTest *t, BN_CTX *ctx) {
}
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (static_cast<size_t>(a->top) <= BN_SMALL_MAX_WORDS) {
for (size_t num_a = a->top; num_a <= BN_SMALL_MAX_WORDS; num_a++) {
int a_width = bn_minimal_width(a.get());
if (a_width <= BN_SMALL_MAX_WORDS) {
for (size_t num_a = a_width; num_a <= BN_SMALL_MAX_WORDS; num_a++) {
SCOPED_TRACE(num_a);
size_t num_r = 2 * num_a;
// Use newly-allocated buffers so ASan will catch out-of-bounds writes.
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[num_a]),
r_words(new BN_ULONG[num_r]);
OPENSSL_memset(a_words.get(), 0, num_a * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_copy_words(a_words.get(), num_a, a.get()));
ASSERT_TRUE(bn_mul_small(r_words.get(), num_r, a_words.get(), num_a,
a_words.get(), num_a));
@@ -411,10 +441,10 @@ static void TestSquare(FileTest *t, BN_CTX *ctx) {
#endif
}
static void TestProduct(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> b = GetBIGNUM(t, "B");
bssl::UniquePtr<BIGNUM> product = GetBIGNUM(t, "Product");
static void TestProduct(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> b = t->GetBIGNUM("B");
bssl::UniquePtr<BIGNUM> product = t->GetBIGNUM("Product");
bssl::UniquePtr<BIGNUM> zero(BN_new());
ASSERT_TRUE(a);
ASSERT_TRUE(b);
@@ -444,22 +474,25 @@ static void TestProduct(FileTest *t, BN_CTX *ctx) {
}
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (!BN_is_negative(product.get()) &&
static_cast<size_t>(a->top) <= BN_SMALL_MAX_WORDS &&
static_cast<size_t>(b->top) <= BN_SMALL_MAX_WORDS) {
for (size_t num_a = a->top; num_a <= BN_SMALL_MAX_WORDS; num_a++) {
BN_set_negative(a.get(), 0);
BN_set_negative(b.get(), 0);
BN_set_negative(product.get(), 0);
int a_width = bn_minimal_width(a.get());
int b_width = bn_minimal_width(b.get());
if (a_width <= BN_SMALL_MAX_WORDS && b_width <= BN_SMALL_MAX_WORDS) {
for (size_t num_a = static_cast<size_t>(a_width);
num_a <= BN_SMALL_MAX_WORDS; num_a++) {
SCOPED_TRACE(num_a);
for (size_t num_b = b->top; num_b <= BN_SMALL_MAX_WORDS; num_b++) {
for (size_t num_b = static_cast<size_t>(b_width);
num_b <= BN_SMALL_MAX_WORDS; num_b++) {
SCOPED_TRACE(num_b);
size_t num_r = num_a + num_b;
// Use newly-allocated buffers so ASan will catch out-of-bounds writes.
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[num_a]),
b_words(new BN_ULONG[num_b]), r_words(new BN_ULONG[num_r]);
OPENSSL_memset(a_words.get(), 0, num_a * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
OPENSSL_memset(b_words.get(), 0, num_b * sizeof(BN_ULONG));
OPENSSL_memcpy(b_words.get(), b->d, b->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_copy_words(a_words.get(), num_a, a.get()));
ASSERT_TRUE(bn_copy_words(b_words.get(), num_b, b.get()));
ASSERT_TRUE(bn_mul_small(r_words.get(), num_r, a_words.get(), num_a,
b_words.get(), num_b));
@@ -471,11 +504,11 @@ static void TestProduct(FileTest *t, BN_CTX *ctx) {
#endif
}
static void TestQuotient(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> b = GetBIGNUM(t, "B");
bssl::UniquePtr<BIGNUM> quotient = GetBIGNUM(t, "Quotient");
bssl::UniquePtr<BIGNUM> remainder = GetBIGNUM(t, "Remainder");
static void TestQuotient(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> b = t->GetBIGNUM("B");
bssl::UniquePtr<BIGNUM> quotient = t->GetBIGNUM("Quotient");
bssl::UniquePtr<BIGNUM> remainder = t->GetBIGNUM("Remainder");
ASSERT_TRUE(a);
ASSERT_TRUE(b);
ASSERT_TRUE(quotient);
@@ -519,11 +552,11 @@ static void TestQuotient(FileTest *t, BN_CTX *ctx) {
}
}
static void TestModMul(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> b = GetBIGNUM(t, "B");
bssl::UniquePtr<BIGNUM> m = GetBIGNUM(t, "M");
bssl::UniquePtr<BIGNUM> mod_mul = GetBIGNUM(t, "ModMul");
static void TestModMul(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> b = t->GetBIGNUM("B");
bssl::UniquePtr<BIGNUM> m = t->GetBIGNUM("M");
bssl::UniquePtr<BIGNUM> mod_mul = t->GetBIGNUM("ModMul");
ASSERT_TRUE(a);
ASSERT_TRUE(b);
ASSERT_TRUE(m);
@@ -536,12 +569,12 @@ static void TestModMul(FileTest *t, BN_CTX *ctx) {
if (BN_is_odd(m.get())) {
// Reduce |a| and |b| and test the Montgomery version.
bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
bssl::UniquePtr<BN_MONT_CTX> mont(
BN_MONT_CTX_new_for_modulus(m.get(), ctx));
bssl::UniquePtr<BIGNUM> a_tmp(BN_new()), b_tmp(BN_new());
ASSERT_TRUE(mont);
ASSERT_TRUE(a_tmp);
ASSERT_TRUE(b_tmp);
ASSERT_TRUE(BN_MONT_CTX_set(mont.get(), m.get(), ctx));
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
ASSERT_TRUE(BN_nnmod(b.get(), b.get(), m.get(), ctx));
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a.get(), mont.get(), ctx));
@@ -553,24 +586,23 @@ static void TestModMul(FileTest *t, BN_CTX *ctx) {
ret.get());
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (m->top <= BN_SMALL_MAX_WORDS) {
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[m->top]),
b_words(new BN_ULONG[m->top]), r_words(new BN_ULONG[m->top]);
OPENSSL_memset(a_words.get(), 0, m->top * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
OPENSSL_memset(b_words.get(), 0, m->top * sizeof(BN_ULONG));
OPENSSL_memcpy(b_words.get(), b->d, b->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m->top, a_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_to_montgomery_small(b_words.get(), m->top, b_words.get(),
m->top, mont.get()));
size_t m_width = static_cast<size_t>(bn_minimal_width(m.get()));
if (m_width <= BN_SMALL_MAX_WORDS) {
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[m_width]),
b_words(new BN_ULONG[m_width]), r_words(new BN_ULONG[m_width]);
ASSERT_TRUE(bn_copy_words(a_words.get(), m_width, a.get()));
ASSERT_TRUE(bn_copy_words(b_words.get(), m_width, b.get()));
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m_width, a_words.get(),
m_width, mont.get()));
ASSERT_TRUE(bn_to_montgomery_small(b_words.get(), m_width, b_words.get(),
m_width, mont.get()));
ASSERT_TRUE(bn_mod_mul_montgomery_small(
r_words.get(), m->top, a_words.get(), m->top, b_words.get(), m->top,
r_words.get(), m_width, a_words.get(), m_width, b_words.get(), m_width,
mont.get()));
// Use the second half of |tmp| so ASan will catch out-of-bounds writes.
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m_width, r_words.get(),
m_width, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m_width));
EXPECT_BIGNUMS_EQUAL("A * B (mod M) (Montgomery, words)", mod_mul.get(),
ret.get());
}
@@ -578,10 +610,10 @@ static void TestModMul(FileTest *t, BN_CTX *ctx) {
}
}
static void TestModSquare(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> m = GetBIGNUM(t, "M");
bssl::UniquePtr<BIGNUM> mod_square = GetBIGNUM(t, "ModSquare");
static void TestModSquare(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> m = t->GetBIGNUM("M");
bssl::UniquePtr<BIGNUM> mod_square = t->GetBIGNUM("ModSquare");
ASSERT_TRUE(a);
ASSERT_TRUE(m);
ASSERT_TRUE(mod_square);
@@ -600,11 +632,11 @@ static void TestModSquare(FileTest *t, BN_CTX *ctx) {
if (BN_is_odd(m.get())) {
// Reduce |a| and test the Montgomery version.
bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
bssl::UniquePtr<BN_MONT_CTX> mont(
BN_MONT_CTX_new_for_modulus(m.get(), ctx));
bssl::UniquePtr<BIGNUM> a_tmp(BN_new());
ASSERT_TRUE(mont);
ASSERT_TRUE(a_tmp);
ASSERT_TRUE(BN_MONT_CTX_set(mont.get(), m.get(), ctx));
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a.get(), mont.get(), ctx));
ASSERT_TRUE(BN_mod_mul_montgomery(ret.get(), a_tmp.get(), a_tmp.get(),
@@ -622,32 +654,32 @@ static void TestModSquare(FileTest *t, BN_CTX *ctx) {
ret.get());
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (m->top <= BN_SMALL_MAX_WORDS) {
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[m->top]),
a_copy_words(new BN_ULONG[m->top]), r_words(new BN_ULONG[m->top]);
OPENSSL_memset(a_words.get(), 0, m->top * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m->top, a_words.get(),
m->top, mont.get()));
size_t m_width = static_cast<size_t>(bn_minimal_width(m.get()));
if (m_width <= BN_SMALL_MAX_WORDS) {
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[m_width]),
a_copy_words(new BN_ULONG[m_width]), r_words(new BN_ULONG[m_width]);
ASSERT_TRUE(bn_copy_words(a_words.get(), m_width, a.get()));
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m_width, a_words.get(),
m_width, mont.get()));
ASSERT_TRUE(bn_mod_mul_montgomery_small(
r_words.get(), m->top, a_words.get(), m->top, a_words.get(), m->top,
mont.get()));
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
r_words.get(), m_width, a_words.get(), m_width, a_words.get(),
m_width, mont.get()));
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m_width,
r_words.get(), m_width, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m_width));
EXPECT_BIGNUMS_EQUAL("A * A (mod M) (Montgomery, words)",
mod_square.get(), ret.get());
// Repeat the operation with |a_copy_words|.
OPENSSL_memcpy(a_copy_words.get(), a_words.get(),
m->top * sizeof(BN_ULONG));
m_width * sizeof(BN_ULONG));
ASSERT_TRUE(bn_mod_mul_montgomery_small(
r_words.get(), m->top, a_words.get(), m->top, a_copy_words.get(),
m->top, mont.get()));
r_words.get(), m_width, a_words.get(), m_width, a_copy_words.get(),
m_width, mont.get()));
// Use the second half of |tmp| so ASan will catch out-of-bounds writes.
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m_width,
r_words.get(), m_width, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m_width));
EXPECT_BIGNUMS_EQUAL("A * A_copy (mod M) (Montgomery, words)",
mod_square.get(), ret.get());
}
@@ -655,11 +687,11 @@ static void TestModSquare(FileTest *t, BN_CTX *ctx) {
}
}
static void TestModExp(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> e = GetBIGNUM(t, "E");
bssl::UniquePtr<BIGNUM> m = GetBIGNUM(t, "M");
bssl::UniquePtr<BIGNUM> mod_exp = GetBIGNUM(t, "ModExp");
static void TestModExp(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> e = t->GetBIGNUM("E");
bssl::UniquePtr<BIGNUM> m = t->GetBIGNUM("M");
bssl::UniquePtr<BIGNUM> mod_exp = t->GetBIGNUM("ModExp");
ASSERT_TRUE(a);
ASSERT_TRUE(e);
ASSERT_TRUE(m);
@@ -682,22 +714,22 @@ static void TestModExp(FileTest *t, BN_CTX *ctx) {
ret.get());
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (m->top <= BN_SMALL_MAX_WORDS) {
bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
size_t m_width = static_cast<size_t>(bn_minimal_width(m.get()));
if (m_width <= BN_SMALL_MAX_WORDS) {
bssl::UniquePtr<BN_MONT_CTX> mont(
BN_MONT_CTX_new_for_modulus(m.get(), ctx));
ASSERT_TRUE(mont.get());
ASSERT_TRUE(BN_MONT_CTX_set(mont.get(), m.get(), ctx));
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
std::unique_ptr<BN_ULONG[]> r_words(new BN_ULONG[m->top]),
a_words(new BN_ULONG[m->top]);
OPENSSL_memset(a_words.get(), 0, m->top * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m->top, a_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_mod_exp_mont_small(r_words.get(), m->top, a_words.get(),
m->top, e->d, e->top, mont.get()));
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
std::unique_ptr<BN_ULONG[]> r_words(new BN_ULONG[m_width]),
a_words(new BN_ULONG[m_width]);
ASSERT_TRUE(bn_copy_words(a_words.get(), m_width, a.get()));
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m_width, a_words.get(),
m_width, mont.get()));
ASSERT_TRUE(bn_mod_exp_mont_small(r_words.get(), m_width, a_words.get(),
m_width, e->d, e->width, mont.get()));
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m_width,
r_words.get(), m_width, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m_width));
EXPECT_BIGNUMS_EQUAL("A ^ E (mod M) (Montgomery, words)", mod_exp.get(),
ret.get());
}
@@ -705,10 +737,10 @@ static void TestModExp(FileTest *t, BN_CTX *ctx) {
}
}
static void TestExp(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> e = GetBIGNUM(t, "E");
bssl::UniquePtr<BIGNUM> exp = GetBIGNUM(t, "Exp");
static void TestExp(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> e = t->GetBIGNUM("E");
bssl::UniquePtr<BIGNUM> exp = t->GetBIGNUM("Exp");
ASSERT_TRUE(a);
ASSERT_TRUE(e);
ASSERT_TRUE(exp);
@@ -719,10 +751,10 @@ static void TestExp(FileTest *t, BN_CTX *ctx) {
EXPECT_BIGNUMS_EQUAL("A ^ E", exp.get(), ret.get());
}
static void TestModSqrt(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> p = GetBIGNUM(t, "P");
bssl::UniquePtr<BIGNUM> mod_sqrt = GetBIGNUM(t, "ModSqrt");
static void TestModSqrt(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> p = t->GetBIGNUM("P");
bssl::UniquePtr<BIGNUM> mod_sqrt = t->GetBIGNUM("ModSqrt");
bssl::UniquePtr<BIGNUM> mod_sqrt2(BN_new());
ASSERT_TRUE(a);
ASSERT_TRUE(p);
@@ -744,9 +776,9 @@ static void TestModSqrt(FileTest *t, BN_CTX *ctx) {
}
}
static void TestNotModSquare(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> not_mod_square = GetBIGNUM(t, "NotModSquare");
bssl::UniquePtr<BIGNUM> p = GetBIGNUM(t, "P");
static void TestNotModSquare(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> not_mod_square = t->GetBIGNUM("NotModSquare");
bssl::UniquePtr<BIGNUM> p = t->GetBIGNUM("P");
bssl::UniquePtr<BIGNUM> ret(BN_new());
ASSERT_TRUE(not_mod_square);
ASSERT_TRUE(p);
@@ -761,10 +793,10 @@ static void TestNotModSquare(FileTest *t, BN_CTX *ctx) {
ERR_clear_error();
}
static void TestModInv(FileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A");
bssl::UniquePtr<BIGNUM> m = GetBIGNUM(t, "M");
bssl::UniquePtr<BIGNUM> mod_inv = GetBIGNUM(t, "ModInv");
static void TestModInv(BIGNUMFileTest *t, BN_CTX *ctx) {
bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A");
bssl::UniquePtr<BIGNUM> m = t->GetBIGNUM("M");
bssl::UniquePtr<BIGNUM> mod_inv = t->GetBIGNUM("ModInv");
ASSERT_TRUE(a);
ASSERT_TRUE(m);
ASSERT_TRUE(mod_inv);
@@ -791,7 +823,7 @@ class BNTest : public testing::Test {
TEST_F(BNTest, TestVectors) {
static const struct {
const char *name;
void (*func)(FileTest *t, BN_CTX *ctx);
void (*func)(BIGNUMFileTest *t, BN_CTX *ctx);
} kTests[] = {
{"Sum", TestSum},
{"LShift1", TestLShift1},
@@ -810,13 +842,34 @@ TEST_F(BNTest, TestVectors) {
};
FileTestGTest("crypto/fipsmodule/bn/bn_tests.txt", [&](FileTest *t) {
void (*func)(BIGNUMFileTest *t, BN_CTX *ctx) = nullptr;
for (const auto &test : kTests) {
if (t->GetType() == test.name) {
test.func(t, ctx());
return;
func = test.func;
break;
}
}
FAIL() << "Unknown test type: " << t->GetType();
if (!func) {
FAIL() << "Unknown test type: " << t->GetType();
return;
}
// Run the test with normalize-sized |BIGNUM|s.
BIGNUMFileTest bn_test(t, 0);
BN_CTX_start(ctx());
func(&bn_test, ctx());
BN_CTX_end(ctx());
unsigned num_bignums = bn_test.num_bignums();
// Repeat the test with all combinations of large and small |BIGNUM|s.
for (unsigned large_mask = 1; large_mask < (1u << num_bignums);
large_mask++) {
SCOPED_TRACE(large_mask);
BIGNUMFileTest bn_test2(t, large_mask);
BN_CTX_start(ctx());
func(&bn_test2, ctx());
BN_CTX_end(ctx());
}
});
}
@@ -861,6 +914,15 @@ TEST_F(BNTest, BN2BinPadded) {
EXPECT_EQ(Bytes(zeros, sizeof(out) - bytes),
Bytes(out, sizeof(out) - bytes));
EXPECT_EQ(Bytes(reference, bytes), Bytes(out + sizeof(out) - bytes, bytes));
// Repeat some tests with a non-minimal |BIGNUM|.
EXPECT_TRUE(bn_resize_words(n.get(), 32));
EXPECT_FALSE(BN_bn2bin_padded(out, bytes - 1, n.get()));
ASSERT_TRUE(BN_bn2bin_padded(out, bytes + 1, n.get()));
EXPECT_EQ(0u, out[0]);
EXPECT_EQ(Bytes(reference, bytes), Bytes(out + 1, bytes));
}
}
@@ -1266,11 +1328,9 @@ TEST_F(BNTest, BadModulus) {
bssl::UniquePtr<BIGNUM> a(BN_new());
bssl::UniquePtr<BIGNUM> b(BN_new());
bssl::UniquePtr<BIGNUM> zero(BN_new());
bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
ASSERT_TRUE(a);
ASSERT_TRUE(b);
ASSERT_TRUE(zero);
ASSERT_TRUE(mont);
BN_zero(zero.get());
@@ -1293,13 +1353,16 @@ TEST_F(BNTest, BadModulus) {
a.get(), BN_value_one(), BN_value_one(), zero.get(), ctx(), nullptr));
ERR_clear_error();
EXPECT_FALSE(BN_MONT_CTX_set(mont.get(), zero.get(), ctx()));
bssl::UniquePtr<BN_MONT_CTX> mont(
BN_MONT_CTX_new_for_modulus(zero.get(), ctx()));
EXPECT_FALSE(mont);
ERR_clear_error();
// Some operations also may not be used with an even modulus.
ASSERT_TRUE(BN_set_word(b.get(), 16));
EXPECT_FALSE(BN_MONT_CTX_set(mont.get(), b.get(), ctx()));
mont.reset(BN_MONT_CTX_new_for_modulus(b.get(), ctx()));
EXPECT_FALSE(mont);
ERR_clear_error();
EXPECT_FALSE(BN_mod_exp_mont(a.get(), BN_value_one(), BN_value_one(), b.get(),
@@ -1758,6 +1821,41 @@ TEST_F(BNTest, PrimeChecking) {
EXPECT_EQ(0, is_probably_prime_2);
}
TEST_F(BNTest, NumBitsWord) {
constexpr BN_ULONG kOne = 1;
// 2^(N-1) takes N bits.
for (unsigned i = 1; i < BN_BITS2; i++) {
EXPECT_EQ(i, BN_num_bits_word(kOne << (i - 1))) << i;
}
// 2^N - 1 takes N bits.
for (unsigned i = 0; i < BN_BITS2; i++) {
EXPECT_EQ(i, BN_num_bits_word((kOne << i) - 1)) << i;
}
for (unsigned i = 1; i < 100; i++) {
// Generate a random value of a random length.
uint8_t buf[1 + sizeof(BN_ULONG)];
RAND_bytes(buf, sizeof(buf));
BN_ULONG w;
memcpy(&w, &buf[1], sizeof(w));
const unsigned num_bits = buf[0] % (BN_BITS2 + 1);
if (num_bits == BN_BITS2) {
w |= kOne << (BN_BITS2 - 1);
} else if (num_bits == 0) {
w = 0;
} else {
w &= (kOne << num_bits) - 1;
w |= kOne << (num_bits - 1);
}
EXPECT_EQ(num_bits, BN_num_bits_word(w)) << w;
}
}
#if !defined(BORINGSSL_SHARED_LIBRARY)
TEST_F(BNTest, LessThanWords) {
// kTestVectors is an array of 256-bit values in sorted order.
@@ -1848,3 +1946,162 @@ TEST_F(BNTest, LessThanWords) {
EXPECT_EQ(0, bn_in_range_words(NULL, 0, NULL, 0));
}
#endif // !BORINGSSL_SHARED_LIBRARY
TEST_F(BNTest, NonMinimal) {
bssl::UniquePtr<BIGNUM> ten(BN_new());
ASSERT_TRUE(ten);
ASSERT_TRUE(BN_set_word(ten.get(), 10));
bssl::UniquePtr<BIGNUM> ten_copy(BN_dup(ten.get()));
ASSERT_TRUE(ten_copy);
bssl::UniquePtr<BIGNUM> eight(BN_new());
ASSERT_TRUE(eight);
ASSERT_TRUE(BN_set_word(eight.get(), 8));
bssl::UniquePtr<BIGNUM> forty_two(BN_new());
ASSERT_TRUE(forty_two);
ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
bssl::UniquePtr<BIGNUM> two_exp_256(BN_new());
ASSERT_TRUE(two_exp_256);
ASSERT_TRUE(BN_lshift(two_exp_256.get(), BN_value_one(), 256));
bssl::UniquePtr<BIGNUM> zero(BN_new());
ASSERT_TRUE(zero);
BN_zero(zero.get());
for (size_t width = 1; width < 10; width++) {
SCOPED_TRACE(width);
// Make |ten| and |zero| wider.
EXPECT_TRUE(bn_resize_words(ten.get(), width));
EXPECT_EQ(static_cast<int>(width), ten->width);
EXPECT_TRUE(bn_resize_words(zero.get(), width));
EXPECT_EQ(static_cast<int>(width), zero->width);
EXPECT_TRUE(BN_abs_is_word(ten.get(), 10));
EXPECT_TRUE(BN_is_word(ten.get(), 10));
EXPECT_EQ(10u, BN_get_word(ten.get()));
uint64_t v;
ASSERT_TRUE(BN_get_u64(ten.get(), &v));
EXPECT_EQ(10u, v);
EXPECT_TRUE(BN_equal_consttime(ten.get(), ten_copy.get()));
EXPECT_TRUE(BN_equal_consttime(ten_copy.get(), ten.get()));
EXPECT_EQ(BN_cmp(ten.get(), ten_copy.get()), 0);
EXPECT_EQ(BN_cmp(ten_copy.get(), ten.get()), 0);
EXPECT_FALSE(BN_equal_consttime(ten.get(), eight.get()));
EXPECT_LT(BN_cmp(eight.get(), ten.get()), 0);
EXPECT_GT(BN_cmp(ten.get(), eight.get()), 0);
EXPECT_FALSE(BN_equal_consttime(ten.get(), forty_two.get()));
EXPECT_GT(BN_cmp(forty_two.get(), ten.get()), 0);
EXPECT_LT(BN_cmp(ten.get(), forty_two.get()), 0);
EXPECT_FALSE(BN_equal_consttime(ten.get(), two_exp_256.get()));
EXPECT_GT(BN_cmp(two_exp_256.get(), ten.get()), 0);
EXPECT_LT(BN_cmp(ten.get(), two_exp_256.get()), 0);
EXPECT_EQ(4u, BN_num_bits(ten.get()));
EXPECT_EQ(1u, BN_num_bytes(ten.get()));
EXPECT_FALSE(BN_is_pow2(ten.get()));
bssl::UniquePtr<char> hex(BN_bn2hex(ten.get()));
EXPECT_STREQ("0a", hex.get());
hex.reset(BN_bn2hex(zero.get()));
EXPECT_STREQ("0", hex.get());
bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
ASSERT_TRUE(bio);
ASSERT_TRUE(BN_print(bio.get(), ten.get()));
const uint8_t *ptr;
size_t len;
ASSERT_TRUE(BIO_mem_contents(bio.get(), &ptr, &len));
// TODO(davidben): |BN_print| removes leading zeros within a byte, while
// |BN_bn2hex| rounds up to a byte, except for zero which it prints as
// "0". Fix this discrepancy?
EXPECT_EQ(Bytes("a"), Bytes(ptr, len));
bio.reset(BIO_new(BIO_s_mem()));
ASSERT_TRUE(bio);
ASSERT_TRUE(BN_print(bio.get(), zero.get()));
ASSERT_TRUE(BIO_mem_contents(bio.get(), &ptr, &len));
EXPECT_EQ(Bytes("0"), Bytes(ptr, len));
}
// |ten| may be resized back down to one word.
EXPECT_TRUE(bn_resize_words(ten.get(), 1));
EXPECT_EQ(1, ten->width);
// But not to zero words, which it does not fit.
EXPECT_FALSE(bn_resize_words(ten.get(), 0));
EXPECT_TRUE(BN_is_pow2(eight.get()));
EXPECT_TRUE(bn_resize_words(eight.get(), 4));
EXPECT_EQ(4, eight->width);
EXPECT_TRUE(BN_is_pow2(eight.get()));
// |BN_MONT_CTX| is always stored minimally and uses the same R independent of
// input width.
static const uint8_t kP[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
ASSERT_TRUE(p);
bssl::UniquePtr<BN_MONT_CTX> mont(
BN_MONT_CTX_new_for_modulus(p.get(), ctx()));
ASSERT_TRUE(mont);
ASSERT_TRUE(bn_resize_words(p.get(), 32));
bssl::UniquePtr<BN_MONT_CTX> mont2(
BN_MONT_CTX_new_for_modulus(p.get(), ctx()));
ASSERT_TRUE(mont2);
EXPECT_EQ(mont->N.width, mont2->N.width);
EXPECT_EQ(0, BN_cmp(&mont->RR, &mont2->RR));
}
TEST_F(BNTest, CountLowZeroBits) {
bssl::UniquePtr<BIGNUM> ten(BN_new());
ASSERT_TRUE(ten);
ASSERT_TRUE(BN_set_word(ten.get(), 10));
bssl::UniquePtr<BIGNUM> eight(BN_new());
ASSERT_TRUE(eight);
ASSERT_TRUE(BN_set_word(eight.get(), 8));
bssl::UniquePtr<BIGNUM> two_exp_256(BN_new());
ASSERT_TRUE(two_exp_256);
ASSERT_TRUE(BN_lshift(two_exp_256.get(), BN_value_one(), 256));
bssl::UniquePtr<BIGNUM> two_exp_256_plus_4(BN_new());
ASSERT_TRUE(two_exp_256_plus_4);
ASSERT_TRUE(BN_lshift(two_exp_256_plus_4.get(), BN_value_one(), 256));
ASSERT_TRUE(BN_add_word(two_exp_256_plus_4.get(), 4));
bssl::UniquePtr<BIGNUM> zero(BN_new());
ASSERT_TRUE(zero);
BN_zero(zero.get());
EXPECT_EQ(1, BN_count_low_zero_bits(ten.get()));
EXPECT_EQ(3, BN_count_low_zero_bits(eight.get()));
EXPECT_EQ(256, BN_count_low_zero_bits(two_exp_256.get()));
EXPECT_EQ(2, BN_count_low_zero_bits(two_exp_256_plus_4.get()));
EXPECT_EQ(0, BN_count_low_zero_bits(zero.get()));
ASSERT_TRUE(bn_resize_words(ten.get(), 16));
ASSERT_TRUE(bn_resize_words(eight.get(), 16));
ASSERT_TRUE(bn_resize_words(two_exp_256.get(), 16));
ASSERT_TRUE(bn_resize_words(two_exp_256_plus_4.get(), 16));
ASSERT_TRUE(bn_resize_words(zero.get(), 16));
EXPECT_EQ(1, BN_count_low_zero_bits(ten.get()));
EXPECT_EQ(3, BN_count_low_zero_bits(eight.get()));
EXPECT_EQ(256, BN_count_low_zero_bits(two_exp_256.get()));
EXPECT_EQ(2, BN_count_low_zero_bits(two_exp_256_plus_4.get()));
EXPECT_EQ(0, BN_count_low_zero_bits(zero.get()));
}
+70
View File
@@ -5976,6 +5976,70 @@ Product = 542fb814f45924aa09a16f2a6
A = 542fb814f45924aa09a16f2a6
B = 1
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef989b0c6121e293a817a4d8899f571f257fa81c36a868d80e7fa2bcbda68a72ca3e31db8892b94d073e006433dd7128b7bf677d2b411532e5662cdff66d657673d58e03d4a338bae1a5513296f91d4d2b5b680527a2e12318e422ec2b7f05ea4fd3ef4780576488211dad5733685a8f0e5d2ecda549a15eebb235495e70d26b194c994cf16d98d356218d08a34d1593d90bc0d3572df0e84bdb1705c6c5e64ea4895599bb21bf219abdd4329813ecc198e708cee199c22f749bdeb0c206690e8420883f6c0661e47b29969986a7a72996ef63234c31aa39b7be37995d2898063ef5c3b672c43afbc1a065dec2671ae87e17639cfcd3148145a8323e1e9dc4f9c9daf981dd6aba4e8be01344c2eda185b87
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9ffec082c58ba611f7
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954a6ea39224eed9ef1
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef989b0c6121e293a817a4d8899aa73af54a4e1825aa6714016da99d9e3d0c02eb139716db437705cd9efabf0123b0831689735f4e488f226e577d4688d30914dd50ed368939452af0a7a094c065c6718bd54f53a808585fc1728c3bd1e7c968d76c6dca32f95a8323bacad31cdd4aae544d4208262c40bcf726c2f26cf1e60341c3e1e0c8ed4542555b9bf00488680b737a245cc9b7817231f1f6f1e614cdf43ea281fb850ebbb9305b1aa441a45dfdaa1e98b9d79d9ca511be070bfa94d8cd3cc750607c93e1b451a14e32356bd48d77860b37fd2e714827e770a5648ce8579a00ba5cae034502a8b03ba754994d9e002130cfdee6bfdf078dc8f6767b927c964197664c8e32bd3d31bd461ce
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9ffec082c58ba611f7
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954a6ea3922
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef989b0c6121e293a80dbb5a46feff82a92989bca577998c68ee619d9ea9972c6f139e97f5bdde635152830bedf302873508d2ed73badb82f9e32e1f4d12ea8c8b1059aa6d15f8e17d649bf41467903ab40d220d50570b5a263f637c0fcebc0ca29f8a81e2a01bf39bcb60cb9229dfd40618f706b941836bc5c291dec45ee9193e74d3a4cc5f73054ca56fd774a359f17a687268587393b76204a37cd48dcb09d3daed57a7e6d7d93a0ca3d6de8557fc4ddbfe9cb163fd10b7fe5f270dc57aa2fb88cdca2a3795015a17fd352d85fb688a38fa54883d0cab67aab08dbabd58d307c601f0f810014d78b101ff0bddb6d550b2480782406a905b9201e70ef6c1cb9765e91c10c8f5d240c
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9ffec082c58ba611f7
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef96c826c5268b0a6788e14a9e3812764dd3ebb7489e6e66058ca6ccf9c007f8c049eda369b2889cc411bca78d4f5b0e3a9e80243e87e112072b01922b595afdef4dd562e58ce917f11e69c8fe050de54fdb2d607d05f09afd6dd140e9d195b91d85269610a1e5d5036e8c9fea2d4fa693d80ecdc819b201c0aed27dfe0b92b4b3b9ecabb3b9548f0d27dc917ffb14308c4f970863e163f375852fcd9fb115640dc40534f8f51a7b903599117dca6c80924fa9a1aeb43cf5a9a3f67ae818b484feed51d7ef60b3656720891b13a983c02c281c8a0954f13b7bfaca844d2cb66de5c11ff507e39cf774c7c93b38e296a44f04e5ecf2819b57943fb0509774ddbcfeb
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9ffec082c58ba611f7
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef989b0c6121e293a817a4d8899c7bedb01951b0f4fdb2c0fb64ad74707fda20027f4cee25da9b59be288d404cbd348f27600b87015d28f03cdf411f0e8c22deb9de5b3e0094f7820d78d59c90017cbd426297f8a32fb4b55b09362cf7cfb5910085acb24dbf618752b8b74c7e87f9cac44cb3b7486c43aa9b19a64d40a74eaf1de8b5f168b43d5750236aef753278c11294efd1adaddb6addb846f45fa55d7391898e8ec1c82bcf0008d9850c4c096571e8872e975dc8af1ba01bfbe8c8c27dc30cdaddd198936e4496579741a3a20e1b8e17241fe4abe5e98794e469180b742b2e1904940381f703f512885bda0340fe74e997ab269be00a3ca29bb937db2e06d8054e26dc13a5014ba51b175
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9ffec082c5
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954a6ea39224eed9ef1
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef989b0c6121e293a817a4d88997cc097fe3f7ace3ffb0fcee52b45551165bb02354b229788b59128489879b1a0373e9862a17692464a2dfc5d09185a0f1c67d2359ba70b52b03f21c7b24feb96e25e1a2dc7f4723952bf203979f7c9e38790f881e2b35006157825555d4c867fce9ea0a3cc6f1c94ee308a68e33f64f286247465ffe854033e9c64f5d79d6d66dcb38ad03535b20376bf4c3cf26e07ef445192ba2baf08bb5286695a61ff6b5dc7aa1832017198d61a324b8c244572157323c7bb3a2fee226133e1b0e0f2ff067cf71fc24bf38d0e172f459b0cdf0707c5bc586390faacf428bfdeb04e850ee0c35f6807eb6ca8d3a473dcc2239541115a8b0d33ea33295ff8c13b2a
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9ffec082c5
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954a6ea3922
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef989b0c6121e293a80dbb5a46fc245133c3335163cce37555d36c555182e6d9a754b9aa9305c070083d0fe806d2c5eda4a976f749d6ef40515c425e6531a7f4d11926e49907b7a8a938205e0d6fefaacb145200cbe3deec686476bcdc1f6bb3535147ecb00818f2cd666ac0dd497f0fbc087bf05c6425b7752a02e2a695655d4310f04943a6178946a74dbe4688bd1eb3f1a166aef37e39f3e1d36b6d6d422ec0db264cae8d44869f57a92952bd74a026dd7cfc672803905f029c723487d4123a7520688fc9c68b2384be32e881f64d0ed7ae555bf00e5799740dd8c6accc40f3fe573f194f4848bb05aea8a5509f2dd10fce023093f1ef20267244a990d7ffd462f4e85a4
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9ffec082c5
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef96c826c5268b0a6788e14a9e353744d86d954c06f3b84ef271b184ac9957a5f88b08b606fa6aa97afc4983a62f1e74aa3f242e14a3f4cf5ea415d1437818663556a29d117ea7df1cf1ee32f70d6d5566e25d53f892c42d3f92e481b622455fce36e400de09e2d435099695354ceee249c793b76b3c544d70164381e0420ef8b85609502afff9130729ba7851e0775dc5d8c606ba614e7607625fbc38908c88fac43e29ff9b8728f5809e63f20289246b5128016478437550a833c60edb0df43dd9a47654f2e4ef308d4a18cea57ea4b0c6d08add07f2e7adc427cf591c29dbd1f975432922e3f2b71c75e4d2557efccf626be7a0d522b658d420ae321
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9ffec082c5
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef989b0c6121e293a8126efa5e7be8e75d54e5ba9405f671d624eaf8d7a115d0479f6fb773b940525fd46b69bc43c815b6bb1798813ca95790bc68032f0b9e73fc964a9922507d8aac25f859745939b828ef5ed326b226b555e5088f13531be16272a89ad41ae82c940935b5d8fe75dc520a230cc279a887bce01bae0a79356f044af13c6f4a5e53c00b2d03cfcbb0f93b26202441a207ec91576410ac1750e257906d945bfe9204b73fc417600bd191edcf2e3eb79acbf4f84dda372405b5e98397abe85c1593543cd7a5b17cb90e299f422f0ce107d86b56474e435dbbcbb5314fb579cd68d54777aa2d0ff9b6b96de62b4676edea5b09589698ed829cad22a52aaec732b79edf6af
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9f
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954a6ea39224eed9ef1
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef989b0c6121e293a8126efa5e7739032d1f8bb68307f4adc912f1d9b83797606874d4f2c669fe0b263565c4898a07701585237aa444234719adb869c17142126611a9cbd6e689fabb2847bb9dc5e2dc89694621a7179df1fe7371deb9bbdf5fea0b271d86bcde2796a65331c27365fb97fa3647435c47e5c854a95718fa49072cc239d046ca0ac2bf453beb31070370d59483adb42b9876776e43fccb663887f1a999f625eb8e9c4cdd0a89099c42cdff06be29ad9ea66a957002925c9425a83c3e74096ca31324134f5d4a2b7d3b8d7fd8d72192049f79c670874f65201c068c5aac2008a7df4e5eba02d88be8ec23683513a9cffe06671a7c2fa5da7a7aa571914caba1e
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9f
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954a6ea3922
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef989b0c6121e293a808857c1bdb914ae0fec75b02d527263093a9d9b8a42289ec74dc73e0e46568a9e8ee117659597434048308c9b66fa7a539694285b1238a13d1163fbac33db147e5431af1c7aca5b1a118db4f6650ec6340491ef7a2d203b53e43d536639f980eb6e92a37bffb2149c5eb45d6718a9496f0784370674c1d29732b944a3c3885b68f0fd2a121f556dc82d1b942e7aabba780f087b9df359d86e2055248c3aabc568e93bba67d3ccca2c4240c876506d63bb05aad6fc4c77dfafff1731a46c6711bc60c4d23976268928bc63e1d133add0633c737bb508c81fa1ff3b452b49b992ebac930432d555ab8c62ae17357b1186e80689672f5a9f472c
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9f
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef96c826c5268b0a6783ab6c7314a43e85a92955a5fbfbffcd31ef0913ba93563dab2b7f54d90fa21ca827ad15b5b1fb399a303f94837536b2813cb563f793fb780e91f8333a2de7bb9f10efdb652a504d6f242e7c15362d3a6eb6e3d1a5abb03023dfe964656979765a14fe8fc36af3d785030ce549b92a91dcb8e2aa13f5b89eb8449b31961a0f77117c8cac79af95ee69f6594e557af7bb017cd885027ff7c0cb1d2f99d1ed5eacb788f645c25150e737cf1184b546bb2d55f2014a18015ffe647580df6fe4d528ce983309baeac0347ae8739e2b1f6d1a83e12e4dbfea1cd81b11b8628837432ad1906c70323529b718c8c6e398e1dfa73
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc95262b94a0aca2f9f
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef96ebae79ce1360c374bc58f225bca564b7e6561b56e0edbb3a7f5934f382b916ab38423221d656357ce0e9bf1e9b04c0678b9c555e8365a0f977c95bd8dca1fb2ad2268193531ca36cbe7f40da8e1afe097e451dc2931b323ce731c03cc027a92ed8ae105c5e9c1bd385e238d989fadbf3aa54c097a8666df8a66b7e2d016e65a2a632603f2c84290ccd7346ada28dff79dd06c7f7989689aca4f494b977f984650f91327ab9936cb92675932440f135e54e4abeecf255d7061482b4c8d91769e02fc94b8acc43325d69541903c3ef7a7a8a5bd19bf886506d42bcf0efcb6197a8d178d6a60516a5aa771ae238a342dc61df8c18c6ba1ed952d4e0c3409c14639
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc9
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954a6ea39224eed9ef1
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef96ebae79ce1360c374bc58f2210cc134828c520a58df29ae28863a158a044937809d7d84d2940efbdddb448c64da5f1f31977e7865fd5529eac82fee3e804064a6315936295f8cb26f0de16a47373f5e8365939e280a57dacb508166a583a630c75730c2fe54971e70a35e224e7a1a21e3bd8f417a47c4796d34148cae15068e19eec637bed8f32846dc5aa7e8f50599e840903a8129206fc384e0b4085f9f1e7e3bf2fc67b62b02566ce73cb4b22d471cde35b4f0cccb74283cdded5748d62286f7ea5c184c1308d520ecc7c7f1535b1132708298bf94c0967bc8f8541bb2f2b3c81f11e50f1d8cba4ce3746ad5f85e6bacbefada657c9b386b991b2
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc9
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954a6ea3922
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef96ebae79ce1360c36ad2daaf856508e861c7f68a2611a215a93e3a15f68f72bb80a4fe9f4cfb6c7f91639179342c633db0f70c9dd849b5b5767908b27e61b812659dcd1a0613433f2c0940be49010886bb384d4676bd523f9827c1a48c7649fbfa73e872a5160796813956979b0f3fd3af728dd48f8a7348090300e41b181c8acae08a3b3106b61f90b0421803e6eba0d68e9bc93d3b659fd6316ba2815cb4b3b6a74f1f3fd24b0c07f619d995ac2beada44188eb72d371a6894f90087eaabe148755409bbff60114bcfefbfe2182e6dc4218d0da75af80059bbb14e848c2e60790fb35bf1cb685cbb133b2baf3f2faefcc3f69e34102def4
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc9
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad1eb654821c4af954
Product = 4f993781409d730da892c8451cc47a4c5c132a2c079f6c13a2689e9552450ed0b35c5291b82aae5614c0fc34f777940798a33b8bd5e010eb3c5c88595e8668fc8fb88ccd3d0cd5eee7c88e5b0b2be4605980fea4f8f2e42457963abe7860060482cfa2291e568ea55095ae2ada1c6bf9fda228664c9e02e7f12a8da4c355af044a537dd65dbf9c5d746c3c5f05a3d4d0515a48d9434b38fcbcc485558964fd9f212cf3c4aee9c03aebc468c25740df679d17823bfb20d96620c64b29f4013f0385cdd1a40fcbec3b06132a52aee615c4dbd880d0b030d5bc6aa06801d21fabd49774cd81ef504696d9655652db220ef9518c8ddd2bbd782e5f8cb06be77fc8d0c29f12d4ce67bb2478369710d003f0cb6f40a1341a5a5f2509d2d189084ea4346a44368a54f44c2be4c7b90c4d22976a31985927d0379b2e5d715a7e67eb3228943a07325a29316c695867e8f4ff676e00ffca0a6dfe8fe24652aef9e7f12616e8a54e367b90942f543a01dc7c1b8000ff991228ae83fe0131cfc235ba12ab2bdb33bd4ab0ba1b356bdbc6da4a70eed9fbf2c704e14ed6230eb5478dac0b02f4def1d8c076d1c0c0e2c4cdadb248de4acf961cee51dc41e545bd5a605a0860fb343c28ebf3f8814a9d5a7e0f3e9c93e742db76bc5671258d1da7758b41efead5
A = f33cad5d3876f0b60a001e13043e41033ee78c29ed8528fd6f22a87fc65c8c650277fab430722fcf63b3984c35ac46883127d544e2f44a465647814e15c0ff595382eff8bdff3be862f8a57a51f27ab4af9899861240855380f5bb883476699ef9eff179a1b88c64cfd6648240a5fc68de054468dc91dac11aaebe696dc05b6b0de0f54bd365ad798f3c85bceaf6ddf976b72cdf69de58335520d358f90e9856de5357dd5d2686cd1a41293d8c2687ba2cb1504420ae2c07014521889172b30df89521e2f66142345115110adf3dc603b1ddba5d80dc6b42fb980e9994aba2dfca00a3df8ea9062f570ec7e0e94d2bc9
B = 53c66ff2bc0e0d733d26f809aeedd151406ae8f44104f4e58f99e3eb54b06d542806932966bdbf30e13d81e5d6fa96f5308fc45613894b49dc7b766af02738dd89b10ca372d6232b0cbd57dcb873dea3c7598ef69b58ea5d72a0f2aaabd71025b488824a35cc33f8068ae4cd999fbb536be54e07f26df5d3bf8705281c8e94dd3712ad7c6a88f9d7b04f6f8924e18568ea07d46e58d197984824d797dd9ca1efe9763c62cc55fff69fad60d6501765dcf4926c18c027b4f9825d53cc38e99365c1b869245e66e7792f40dabeefe63e404cffc1d2ea63a9dd3fd4643afb2ddd288c6d4737abf20cec860584a7a600b4ad
# Quotient tests.
#
@@ -10507,6 +10571,12 @@ A = -80000000000000000000000000000000000000000000000000000000000000000000000000
E = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103
M = b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965
# Regression test for CVE-2017-3738.
ModExp = d360792bd8210786607817c3dda64cc38c8d0f25569597cb1f363c7919a0c3587baff01a2283edaeb04fc288ac0ab3f279b2a89ffcb452d8bdf72422a9f9780f4aa702dc964cf033149d3a339883062cab8564aebdbfac0bf68985e522c6fe545b346044690c525ca85d3f4eb3e3c25cdf541545afc84a309e9b1d7807003461
A = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2020202020df
E = 2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020FF2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020
M = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2020202020ff
# Exp tests.
#
+32 -71
View File
@@ -77,7 +77,7 @@ BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
}
if (len == 0) {
ret->top = 0;
ret->width = 0;
return ret;
}
@@ -93,7 +93,7 @@ BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
// |bn_wexpand| must check bounds on |num_words| to write it into
// |ret->dmax|.
assert(num_words <= INT_MAX);
ret->top = (int)num_words;
ret->width = (int)num_words;
ret->neg = 0;
while (len--) {
@@ -105,9 +105,6 @@ BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
}
}
// need to call this due to clear byte at top if avoiding having the top bit
// set (-ve number)
bn_correct_top(ret);
return ret;
}
@@ -123,7 +120,7 @@ BIGNUM *BN_le2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
}
if (len == 0) {
ret->top = 0;
ret->width = 0;
ret->neg = 0;
return ret;
}
@@ -134,7 +131,7 @@ BIGNUM *BN_le2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
BN_free(bn);
return NULL;
}
ret->top = num_words;
ret->width = num_words;
// Make sure the top bytes will be zeroed.
ret->d[num_words - 1] = 0;
@@ -142,8 +139,6 @@ BIGNUM *BN_le2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
// We only support little-endian platforms, so we can simply memcpy the
// internal representation.
OPENSSL_memcpy(ret->d, in, len);
bn_correct_top(ret);
return ret;
}
@@ -159,88 +154,54 @@ size_t BN_bn2bin(const BIGNUM *in, uint8_t *out) {
return n;
}
static int fits_in_bytes(const uint8_t *bytes, size_t num_bytes, size_t len) {
uint8_t mask = 0;
for (size_t i = len; i < num_bytes; i++) {
mask |= bytes[i];
}
return mask == 0;
}
int BN_bn2le_padded(uint8_t *out, size_t len, const BIGNUM *in) {
// If we don't have enough space, fail out.
size_t num_bytes = BN_num_bytes(in);
const uint8_t *bytes = (const uint8_t *)in->d;
size_t num_bytes = in->width * BN_BYTES;
if (len < num_bytes) {
return 0;
if (!fits_in_bytes(bytes, num_bytes, len)) {
return 0;
}
num_bytes = len;
}
// We only support little-endian platforms, so we can simply memcpy into the
// internal representation.
OPENSSL_memcpy(out, in->d, num_bytes);
OPENSSL_memcpy(out, bytes, num_bytes);
// Pad out the rest of the buffer with zeroes.
OPENSSL_memset(out + num_bytes, 0, len - num_bytes);
return 1;
}
// constant_time_select_ulong returns |x| if |v| is 1 and |y| if |v| is 0. Its
// behavior is undefined if |v| takes any other value.
static BN_ULONG constant_time_select_ulong(int v, BN_ULONG x, BN_ULONG y) {
BN_ULONG mask = v;
mask--;
return (~mask & x) | (mask & y);
}
// constant_time_le_size_t returns 1 if |x| <= |y| and 0 otherwise. |x| and |y|
// must not have their MSBs set.
static int constant_time_le_size_t(size_t x, size_t y) {
return ((x - y - 1) >> (sizeof(size_t) * 8 - 1)) & 1;
}
// read_word_padded returns the |i|'th word of |in|, if it is not out of
// bounds. Otherwise, it returns 0. It does so without branches on the size of
// |in|, however it necessarily does not have the same memory access pattern. If
// the access would be out of bounds, it reads the last word of |in|. |in| must
// not be zero.
static BN_ULONG read_word_padded(const BIGNUM *in, size_t i) {
// Read |in->d[i]| if valid. Otherwise, read the last word.
BN_ULONG l = in->d[constant_time_select_ulong(
constant_time_le_size_t(in->dmax, i), in->dmax - 1, i)];
// Clamp to zero if above |d->top|.
return constant_time_select_ulong(constant_time_le_size_t(in->top, i), 0, l);
}
int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) {
// Special case for |in| = 0. Just branch as the probability is negligible.
if (BN_is_zero(in)) {
OPENSSL_memset(out, 0, len);
return 1;
}
// Check if the integer is too big. This case can exit early in non-constant
// time.
if ((size_t)in->top > (len + (BN_BYTES - 1)) / BN_BYTES) {
return 0;
}
if ((len % BN_BYTES) != 0) {
BN_ULONG l = read_word_padded(in, len / BN_BYTES);
if (l >> (8 * (len % BN_BYTES)) != 0) {
const uint8_t *bytes = (const uint8_t *)in->d;
size_t num_bytes = in->width * BN_BYTES;
if (len < num_bytes) {
if (!fits_in_bytes(bytes, num_bytes, len)) {
return 0;
}
num_bytes = len;
}
// Write the bytes out one by one. Serialization is done without branching on
// the bits of |in| or on |in->top|, but if the routine would otherwise read
// out of bounds, the memory access pattern can't be fixed. However, for an
// RSA key of size a multiple of the word size, the probability of BN_BYTES
// leading zero octets is low.
//
// See Falko Stenzke, "Manger's Attack revisited", ICICS 2010.
size_t i = len;
while (i--) {
BN_ULONG l = read_word_padded(in, i / BN_BYTES);
*(out++) = (uint8_t)(l >> (8 * (i % BN_BYTES))) & 0xff;
// We only support little-endian platforms, so we can simply write the buffer
// in reverse.
for (size_t i = 0; i < num_bytes; i++) {
out[len - i - 1] = bytes[i];
}
// Pad out the rest of the buffer with zeroes.
OPENSSL_memset(out, 0, len - num_bytes);
return 1;
}
BN_ULONG BN_get_word(const BIGNUM *bn) {
switch (bn->top) {
switch (bn_minimal_width(bn)) {
case 0:
return 0;
case 1:
@@ -251,7 +212,7 @@ BN_ULONG BN_get_word(const BIGNUM *bn) {
}
int BN_get_u64(const BIGNUM *bn, uint64_t *out) {
switch (bn->top) {
switch (bn_minimal_width(bn)) {
case 0:
*out = 0;
return 1;
+57 -111
View File
@@ -63,33 +63,43 @@
#include "../../internal.h"
int BN_ucmp(const BIGNUM *a, const BIGNUM *b) {
int i;
BN_ULONG t1, t2, *ap, *bp;
i = a->top - b->top;
if (i != 0) {
return i;
static int bn_cmp_words_consttime(const BN_ULONG *a, size_t a_len,
const BN_ULONG *b, size_t b_len) {
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
crypto_word_t_too_small);
int ret = 0;
// Process the common words in little-endian order.
size_t min = a_len < b_len ? a_len : b_len;
for (size_t i = 0; i < min; i++) {
crypto_word_t eq = constant_time_eq_w(a[i], b[i]);
crypto_word_t lt = constant_time_lt_w(a[i], b[i]);
ret =
constant_time_select_int(eq, ret, constant_time_select_int(lt, -1, 1));
}
ap = a->d;
bp = b->d;
for (i = a->top - 1; i >= 0; i--) {
t1 = ap[i];
t2 = bp[i];
if (t1 != t2) {
return (t1 > t2) ? 1 : -1;
// If |a| or |b| has non-zero words beyond |min|, they take precedence.
if (a_len < b_len) {
crypto_word_t mask = 0;
for (size_t i = a_len; i < b_len; i++) {
mask |= b[i];
}
ret = constant_time_select_int(constant_time_is_zero_w(mask), ret, -1);
} else if (b_len < a_len) {
crypto_word_t mask = 0;
for (size_t i = b_len; i < a_len; i++) {
mask |= a[i];
}
ret = constant_time_select_int(constant_time_is_zero_w(mask), ret, 1);
}
return 0;
return ret;
}
int BN_ucmp(const BIGNUM *a, const BIGNUM *b) {
return bn_cmp_words_consttime(a->d, a->width, b->d, b->width);
}
int BN_cmp(const BIGNUM *a, const BIGNUM *b) {
int i;
int gt, lt;
BN_ULONG t1, t2;
if ((a == NULL) || (b == NULL)) {
if (a != NULL) {
return -1;
@@ -100,97 +110,25 @@ int BN_cmp(const BIGNUM *a, const BIGNUM *b) {
}
}
// We do not attempt to process the sign bit in constant time. Negative
// |BIGNUM|s should never occur in crypto, only calculators.
if (a->neg != b->neg) {
if (a->neg) {
return -1;
}
return 1;
}
if (a->neg == 0) {
gt = 1;
lt = -1;
} else {
gt = -1;
lt = 1;
}
if (a->top > b->top) {
return gt;
}
if (a->top < b->top) {
return lt;
}
for (i = a->top - 1; i >= 0; i--) {
t1 = a->d[i];
t2 = b->d[i];
if (t1 > t2) {
return gt;
} if (t1 < t2) {
return lt;
}
}
return 0;
}
int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n) {
int i;
BN_ULONG aa, bb;
aa = a[n - 1];
bb = b[n - 1];
if (aa != bb) {
return (aa > bb) ? 1 : -1;
}
for (i = n - 2; i >= 0; i--) {
aa = a[i];
bb = b[i];
if (aa != bb) {
return (aa > bb) ? 1 : -1;
}
}
return 0;
}
int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) {
int n, i;
n = cl - 1;
if (dl < 0) {
for (i = dl; i < 0; i++) {
if (b[n - i] != 0) {
return -1; // a < b
}
}
}
if (dl > 0) {
for (i = dl; i > 0; i--) {
if (a[n + i] != 0) {
return 1; // a > b
}
}
}
return bn_cmp_words(a, b, cl);
int ret = BN_ucmp(a, b);
return a->neg ? -ret : ret;
}
int bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) {
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
crypto_word_t_too_small);
int ret = 0;
// Process the words in little-endian order.
for (size_t i = 0; i < len; i++) {
crypto_word_t eq = constant_time_eq_w(a[i], b[i]);
crypto_word_t lt = constant_time_lt_w(a[i], b[i]);
ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, 1, 0));
}
return ret;
return bn_cmp_words_consttime(a, len, b, len) < 0;
}
int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) {
switch (bn->top) {
switch (bn_minimal_width(bn)) {
case 1:
return bn->d[0] == w;
case 0:
@@ -205,14 +143,14 @@ int BN_cmp_word(const BIGNUM *a, BN_ULONG b) {
BN_init(&b_bn);
b_bn.d = &b;
b_bn.top = b > 0;
b_bn.width = b > 0;
b_bn.dmax = 1;
b_bn.flags = BN_FLG_STATIC_DATA;
return BN_cmp(a, &b_bn);
}
int BN_is_zero(const BIGNUM *bn) {
return bn->top == 0;
return bn_minimal_width(bn) == 0;
}
int BN_is_one(const BIGNUM *bn) {
@@ -224,31 +162,39 @@ int BN_is_word(const BIGNUM *bn, BN_ULONG w) {
}
int BN_is_odd(const BIGNUM *bn) {
return bn->top > 0 && (bn->d[0] & 1) == 1;
return bn->width > 0 && (bn->d[0] & 1) == 1;
}
int BN_is_pow2(const BIGNUM *bn) {
if (bn->top == 0 || bn->neg) {
int width = bn_minimal_width(bn);
if (width == 0 || bn->neg) {
return 0;
}
for (int i = 0; i < bn->top - 1; i++) {
for (int i = 0; i < width - 1; i++) {
if (bn->d[i] != 0) {
return 0;
}
}
return 0 == (bn->d[bn->top-1] & (bn->d[bn->top-1] - 1));
return 0 == (bn->d[width-1] & (bn->d[width-1] - 1));
}
int BN_equal_consttime(const BIGNUM *a, const BIGNUM *b) {
if (a->top != b->top) {
return 0;
BN_ULONG mask = 0;
// If |a| or |b| has more words than the other, all those words must be zero.
for (int i = a->width; i < b->width; i++) {
mask |= b->d[i];
}
int limbs_are_equal =
CRYPTO_memcmp(a->d, b->d, (size_t)a->top * sizeof(a->d[0])) == 0;
return constant_time_select_int(constant_time_eq_int(a->neg, b->neg),
limbs_are_equal, 0);
for (int i = b->width; i < a->width; i++) {
mask |= a->d[i];
}
// Common words must match.
int min = a->width < b->width ? a->width : b->width;
for (int i = 0; i < min; i++) {
mask |= (a->d[i] ^ b->d[i]);
}
// The sign bit must match.
mask |= (a->neg ^ b->neg);
return mask == 0;
}
+199 -123
View File
@@ -155,18 +155,18 @@ static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out,
//
// These issues aren't specific to x86 and x86_64, so it might be worthwhile
// to add more assembly language implementations.
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86) && defined(__GNUC__)
__asm__ volatile (
"divl %4"
: "=a"(*quotient_out), "=d"(*rem_out)
: "a"(n1), "d"(n0), "rm"(d0)
: "cc" );
#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && defined(__GNUC__)
__asm__ volatile (
"divq %4"
: "=a"(*quotient_out), "=d"(*rem_out)
: "a"(n1), "d"(n0), "rm"(d0)
: "cc" );
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86) && \
(defined(__GNUC__) || defined(__clang__))
__asm__ volatile("divl %4"
: "=a"(*quotient_out), "=d"(*rem_out)
: "a"(n1), "d"(n0), "rm"(d0)
: "cc");
#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
(defined(__GNUC__) || defined(__clang__))
__asm__ volatile("divq %4"
: "=a"(*quotient_out), "=d"(*rem_out)
: "a"(n1), "d"(n0), "rm"(d0)
: "cc");
#else
#if defined(BN_ULLONG)
BN_ULLONG n = (((BN_ULLONG)n0) << BN_BITS2) | n1;
@@ -202,10 +202,16 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
BN_ULONG d0, d1;
int num_n, div_n;
// Invalid zero-padding would have particularly bad consequences
// so don't just rely on bn_check_top() here
if ((numerator->top > 0 && numerator->d[numerator->top - 1] == 0) ||
(divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
// This function relies on the historical minimal-width |BIGNUM| invariant.
// It is already not constant-time (constant-time reductions should use
// Montgomery logic), so we shrink all inputs and intermediate values to
// retain the previous behavior.
// Invalid zero-padding would have particularly bad consequences.
int numerator_width = bn_minimal_width(numerator);
int divisor_width = bn_minimal_width(divisor);
if ((numerator_width > 0 && numerator->d[numerator_width - 1] == 0) ||
(divisor_width > 0 && divisor->d[divisor_width - 1] == 0)) {
OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED);
return 0;
}
@@ -234,46 +240,48 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
if (!BN_lshift(sdiv, divisor, norm_shift)) {
goto err;
}
bn_set_minimal_width(sdiv);
sdiv->neg = 0;
norm_shift += BN_BITS2;
if (!BN_lshift(snum, numerator, norm_shift)) {
goto err;
}
bn_set_minimal_width(snum);
snum->neg = 0;
// Since we don't want to have special-case logic for the case where snum is
// larger than sdiv, we pad snum with enough zeroes without changing its
// value.
if (snum->top <= sdiv->top + 1) {
if (!bn_wexpand(snum, sdiv->top + 2)) {
if (snum->width <= sdiv->width + 1) {
if (!bn_wexpand(snum, sdiv->width + 2)) {
goto err;
}
for (int i = snum->top; i < sdiv->top + 2; i++) {
for (int i = snum->width; i < sdiv->width + 2; i++) {
snum->d[i] = 0;
}
snum->top = sdiv->top + 2;
snum->width = sdiv->width + 2;
} else {
if (!bn_wexpand(snum, snum->top + 1)) {
if (!bn_wexpand(snum, snum->width + 1)) {
goto err;
}
snum->d[snum->top] = 0;
snum->top++;
snum->d[snum->width] = 0;
snum->width++;
}
div_n = sdiv->top;
num_n = snum->top;
div_n = sdiv->width;
num_n = snum->width;
loop = num_n - div_n;
// Lets setup a 'window' into snum
// This is the part that corresponds to the current
// 'area' being divided
wnum.neg = 0;
wnum.d = &(snum->d[loop]);
wnum.top = div_n;
// only needed when BN_ucmp messes up the values between top and max
wnum.width = div_n;
// only needed when BN_ucmp messes up the values between width and max
wnum.dmax = snum->dmax - loop; // so we don't step out of bounds
// Get the top 2 words of sdiv
// div_n=sdiv->top;
// div_n=sdiv->width;
d0 = sdiv->d[div_n - 1];
d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2];
@@ -285,7 +293,7 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
if (!bn_wexpand(res, loop + 1)) {
goto err;
}
res->top = loop - 1;
res->width = loop - 1;
resp = &(res->d[loop - 1]);
// space for temp
@@ -293,9 +301,9 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
goto err;
}
// if res->top == 0 then clear the neg value otherwise decrease
// if res->width == 0 then clear the neg value otherwise decrease
// the resp pointer
if (res->top == 0) {
if (res->width == 0) {
res->neg = 0;
} else {
resp--;
@@ -371,7 +379,7 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
*resp = q;
}
bn_correct_top(snum);
bn_set_minimal_width(snum);
if (rem != NULL) {
// Keep a copy of the neg flag in numerator because if |rem| == |numerator|
@@ -385,7 +393,7 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
}
}
bn_correct_top(res);
bn_set_minimal_width(res);
BN_CTX_end(ctx);
return 1;
@@ -406,6 +414,78 @@ int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) {
return (d->neg ? BN_sub : BN_add)(r, r, d);
}
// bn_mod_sub_words sets |r| to |a| - |b| (mod |m|), using |tmp| as scratch
// space. Each array is |num| words long. |a| and |b| must be < |m|. Any pair of
// |r|, |a|, and |b| may alias.
static void bn_mod_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
const BN_ULONG *m, BN_ULONG *tmp, size_t num) {
// r = a - b
BN_ULONG borrow = bn_sub_words(r, a, b, num);
// tmp = a - b + m
bn_add_words(tmp, r, m, num);
bn_select_words(r, 0 - borrow, tmp /* r < 0 */, r /* r >= 0 */, num);
}
// bn_mod_add_words sets |r| to |a| + |b| (mod |m|), using |tmp| as scratch
// space. Each array is |num| words long. |a| and |b| must be < |m|. Any pair of
// |r|, |a|, and |b| may alias.
static void bn_mod_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
const BN_ULONG *m, BN_ULONG *tmp, size_t num) {
// tmp = a + b. Note the result fits in |num|+1 words. We store the extra word
// in |carry|.
BN_ULONG carry = bn_add_words(tmp, a, b, num);
// r = a + b - m. We use |bn_sub_words| to perform the bulk of the
// subtraction, and then apply the borrow to |carry|.
carry -= bn_sub_words(r, tmp, m, num);
// |a| and |b| were both fully-reduced, so we know:
//
// 0 + 0 - m <= r < m + m - m
// -m <= r < m
//
// If 0 <= |r| < |m|, |r| fits in |num| words and |carry| is zero. We then
// wish to select |r| as the answer. Otherwise -m <= r < 0 and we wish to
// return |r| + |m|, or |tmp|. |carry| must then be -1 or all ones. In both
// cases, |carry| is a suitable input to |bn_select_words|.
//
// Although |carry| may be one if |bn_add_words| returns one and
// |bn_sub_words| returns zero, this would give |r| > |m|, which violates are
// input assumptions.
assert(carry == 0 || carry == (BN_ULONG)-1);
bn_select_words(r, carry, tmp /* r < 0 */, r /* r >= 0 */, num);
}
static BIGNUM *bn_scratch_space_from_ctx(size_t width, BN_CTX *ctx) {
BIGNUM *ret = BN_CTX_get(ctx);
if (ret == NULL ||
!bn_wexpand(ret, width)) {
return NULL;
}
ret->neg = 0;
ret->width = width;
return ret;
}
// bn_resized_from_ctx returns |bn| with width at least |width| or NULL on
// error. This is so it may be used with low-level "words" functions. If
// necessary, it allocates a new |BIGNUM| with a lifetime of the current scope
// in |ctx|, so the caller does not need to explicitly free it. |bn| must fit in
// |width| words.
static const BIGNUM *bn_resized_from_ctx(const BIGNUM *bn, size_t width,
BN_CTX *ctx) {
if ((size_t)bn->width >= width) {
// Any excess words must be zero.
assert(bn_fits_in_words(bn, width));
return bn;
}
BIGNUM *ret = bn_scratch_space_from_ctx(width, ctx);
if (ret == NULL ||
!BN_copy(ret, bn) ||
!bn_resize_words(ret, width)) {
return NULL;
}
return ret;
}
int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
BN_CTX *ctx) {
if (!BN_add(r, a, b)) {
@@ -416,13 +496,27 @@ int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
const BIGNUM *m) {
if (!BN_uadd(r, a, b)) {
return 0;
BN_CTX *ctx = BN_CTX_new();
int ok = ctx != NULL &&
bn_mod_add_quick_ctx(r, a, b, m, ctx);
BN_CTX_free(ctx);
return ok;
}
int bn_mod_add_quick_ctx(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
const BIGNUM *m, BN_CTX *ctx) {
BN_CTX_start(ctx);
a = bn_resized_from_ctx(a, m->width, ctx);
b = bn_resized_from_ctx(b, m->width, ctx);
BIGNUM *tmp = bn_scratch_space_from_ctx(m->width, ctx);
int ok = a != NULL && b != NULL && tmp != NULL &&
bn_wexpand(r, m->width);
if (ok) {
bn_mod_add_words(r->d, a->d, b->d, m->d, tmp->d, m->width);
r->width = m->width;
}
if (BN_ucmp(r, m) >= 0) {
return BN_usub(r, r, m);
}
return 1;
BN_CTX_end(ctx);
return ok;
}
int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
@@ -433,17 +527,29 @@ int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
return BN_nnmod(r, r, m, ctx);
}
// BN_mod_sub variant that may be used if both a and b are non-negative
// and less than m
int bn_mod_sub_quick_ctx(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
const BIGNUM *m, BN_CTX *ctx) {
BN_CTX_start(ctx);
a = bn_resized_from_ctx(a, m->width, ctx);
b = bn_resized_from_ctx(b, m->width, ctx);
BIGNUM *tmp = bn_scratch_space_from_ctx(m->width, ctx);
int ok = a != NULL && b != NULL && tmp != NULL &&
bn_wexpand(r, m->width);
if (ok) {
bn_mod_sub_words(r->d, a->d, b->d, m->d, tmp->d, m->width);
r->width = m->width;
}
BN_CTX_end(ctx);
return ok;
}
int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
const BIGNUM *m) {
if (!BN_sub(r, a, b)) {
return 0;
}
if (r->neg) {
return BN_add(r, r, m);
}
return 1;
BN_CTX *ctx = BN_CTX_new();
int ok = ctx != NULL &&
bn_mod_sub_quick_ctx(r, a, b, m, ctx);
BN_CTX_free(ctx);
return ok;
}
int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
@@ -504,58 +610,33 @@ int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
abs_m->neg = 0;
}
ret = BN_mod_lshift_quick(r, r, n, (abs_m ? abs_m : m));
ret = bn_mod_lshift_quick_ctx(r, r, n, (abs_m ? abs_m : m), ctx);
BN_free(abs_m);
return ret;
}
int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m) {
if (r != a) {
if (BN_copy(r, a) == NULL) {
int bn_mod_lshift_quick_ctx(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
BN_CTX *ctx) {
if (!BN_copy(r, a)) {
return 0;
}
for (int i = 0; i < n; i++) {
if (!bn_mod_lshift1_quick_ctx(r, r, m, ctx)) {
return 0;
}
}
while (n > 0) {
int max_shift;
// 0 < r < m
max_shift = BN_num_bits(m) - BN_num_bits(r);
// max_shift >= 0
if (max_shift < 0) {
OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED);
return 0;
}
if (max_shift > n) {
max_shift = n;
}
if (max_shift) {
if (!BN_lshift(r, r, max_shift)) {
return 0;
}
n -= max_shift;
} else {
if (!BN_lshift1(r, r)) {
return 0;
}
--n;
}
// BN_num_bits(r) <= BN_num_bits(m)
if (BN_cmp(r, m) >= 0) {
if (!BN_sub(r, r, m)) {
return 0;
}
}
}
return 1;
}
int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m) {
BN_CTX *ctx = BN_CTX_new();
int ok = ctx != NULL &&
bn_mod_lshift_quick_ctx(r, a, n, m, ctx);
BN_CTX_free(ctx);
return ok;
}
int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) {
if (!BN_lshift1(r, a)) {
return 0;
@@ -564,15 +645,17 @@ int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) {
return BN_nnmod(r, r, m, ctx);
}
int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m) {
if (!BN_lshift1(r, a)) {
return 0;
}
if (BN_cmp(r, m) >= 0) {
return BN_sub(r, r, m);
}
int bn_mod_lshift1_quick_ctx(BIGNUM *r, const BIGNUM *a, const BIGNUM *m,
BN_CTX *ctx) {
return bn_mod_add_quick_ctx(r, a, a, m, ctx);
}
return 1;
int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m) {
BN_CTX *ctx = BN_CTX_new();
int ok = ctx != NULL &&
bn_mod_lshift1_quick_ctx(r, a, m, ctx);
BN_CTX_free(ctx);
return ok;
}
BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
@@ -584,7 +667,7 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
return (BN_ULONG) - 1;
}
if (a->top == 0) {
if (a->width == 0) {
return 0;
}
@@ -595,7 +678,7 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
return (BN_ULONG) - 1;
}
for (i = a->top - 1; i >= 0; i--) {
for (i = a->width - 1; i >= 0; i--) {
BN_ULONG l = a->d[i];
BN_ULONG d;
BN_ULONG unused_rem;
@@ -604,20 +687,13 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
a->d[i] = d;
}
if ((a->top > 0) && (a->d[a->top - 1] == 0)) {
a->top--;
}
if (a->top == 0) {
a->neg = 0;
}
bn_set_minimal_width(a);
ret >>= j;
return ret;
}
BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
#ifndef BN_ULLONG
#ifndef BN_CAN_DIVIDE_ULLONG
BN_ULONG ret = 0;
#else
BN_ULLONG ret = 0;
@@ -628,9 +704,9 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
return (BN_ULONG) -1;
}
#ifndef BN_ULLONG
// If |w| is too long and we don't have |BN_ULLONG| then we need to fall back
// to using |BN_div_word|.
#ifndef BN_CAN_DIVIDE_ULLONG
// If |w| is too long and we don't have |BN_ULLONG| division then we need to
// fall back to using |BN_div_word|.
if (w > ((BN_ULONG)1 << BN_BITS4)) {
BIGNUM *tmp = BN_dup(a);
if (tmp == NULL) {
@@ -642,8 +718,8 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
}
#endif
for (i = a->top - 1; i >= 0; i--) {
#ifndef BN_ULLONG
for (i = a->width - 1; i >= 0; i--) {
#ifndef BN_CAN_DIVIDE_ULLONG
ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w;
ret = ((ret << BN_BITS4) | (a->d[i] & BN_MASK2l)) % w;
#else
@@ -654,7 +730,7 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
}
int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) {
if (e == 0 || a->top == 0) {
if (e == 0 || a->width == 0) {
BN_zero(r);
return 1;
}
@@ -662,7 +738,7 @@ int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) {
size_t num_words = 1 + ((e - 1) / BN_BITS2);
// If |a| definitely has less than |e| bits, just BN_copy.
if ((size_t) a->top < num_words) {
if ((size_t) a->width < num_words) {
return BN_copy(r, a) != NULL;
}
@@ -683,8 +759,8 @@ int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) {
// Fill in the remaining fields of |r|.
r->neg = a->neg;
r->top = (int) num_words;
bn_correct_top(r);
r->width = (int) num_words;
bn_set_minimal_width(r);
return 1;
}
@@ -706,27 +782,27 @@ int BN_nnmod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) {
}
// Clear the upper words of |r|.
OPENSSL_memset(&r->d[r->top], 0, (num_words - r->top) * BN_BYTES);
OPENSSL_memset(&r->d[r->width], 0, (num_words - r->width) * BN_BYTES);
// Set parameters of |r|.
r->neg = 0;
r->top = (int) num_words;
r->width = (int) num_words;
// Now, invert every word. The idea here is that we want to compute 2^e-|x|,
// which is actually equivalent to the twos-complement representation of |x|
// in |e| bits, which is -x = ~x + 1.
for (int i = 0; i < r->top; i++) {
for (int i = 0; i < r->width; i++) {
r->d[i] = ~r->d[i];
}
// If our exponent doesn't span the top word, we have to mask the rest.
size_t top_word_exponent = e % BN_BITS2;
if (top_word_exponent != 0) {
r->d[r->top - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1;
r->d[r->width - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1;
}
// Keep the correct_top invariant for BN_add.
bn_correct_top(r);
// Keep the minimal-width invariant for |BIGNUM|.
bn_set_minimal_width(r);
// Finally, add one, for the reason described above.
return BN_add(r, r, BN_value_one());
+31 -65
View File
@@ -622,8 +622,8 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
// Allocate a montgomery context if it was not supplied by the caller.
if (mont == NULL) {
new_mont = BN_MONT_CTX_new();
if (new_mont == NULL || !BN_MONT_CTX_set(new_mont, m, ctx)) {
new_mont = BN_MONT_CTX_new_for_modulus(m, ctx);
if (new_mont == NULL) {
goto err;
}
mont = new_mont;
@@ -666,22 +666,7 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
}
}
// Set |r| to one in Montgomery form. If the high bit of |m| is set, |m| is
// close to R and we subtract rather than perform Montgomery reduction.
if (m->d[m->top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
if (!bn_wexpand(r, m->top)) {
goto err;
}
// r = 2^(top*BN_BITS2) - m
r->d[0] = 0 - m->d[0];
for (int i = 1; i < m->top; i++) {
r->d[i] = ~m->d[i];
}
r->top = m->top;
// The upper words will be zero if the corresponding words of |m| were
// 0xfff[...], so call |bn_correct_top|.
bn_correct_top(r);
} else if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) {
if (!bn_one_to_montgomery(r, mont, ctx)) {
goto err;
}
@@ -746,8 +731,7 @@ err:
int bn_mod_exp_mont_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_ULONG *p, size_t num_p,
const BN_MONT_CTX *mont) {
const BN_ULONG *n = mont->N.d;
size_t num_n = mont->N.top;
size_t num_n = mont->N.width;
if (num_n != num_a || num_n != num_r || num_n > BN_SMALL_MAX_WORDS) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
@@ -793,16 +777,7 @@ int bn_mod_exp_mont_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
}
}
// Set |r| to one in Montgomery form. If the high bit of |m| is set, |m| is
// close to R and we subtract rather than perform Montgomery reduction.
if (n[num_n - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
// r = 2^(top*BN_BITS2) - m
r[0] = 0 - n[0];
for (size_t i = 1; i < num_n; i++) {
r[i] = ~n[i];
}
} else if (!bn_from_montgomery_small(r, num_r, mont->RR.d, mont->RR.top,
mont)) {
if (!bn_one_to_montgomery_small(r, num_r, mont)) {
goto err;
}
@@ -866,7 +841,7 @@ int bn_mod_inverse_prime_mont_small(BN_ULONG *r, size_t num_r,
const BN_ULONG *a, size_t num_a,
const BN_MONT_CTX *mont) {
const BN_ULONG *p = mont->N.d;
size_t num_p = mont->N.top;
size_t num_p = mont->N.width;
if (num_p > BN_SMALL_MAX_WORDS || num_p == 0) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
@@ -901,8 +876,8 @@ static void copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf,
const int width = 1 << window;
BN_ULONG *table = (BN_ULONG *) buf;
if (top > b->top) {
top = b->top; // this works because 'buf' is explicitly zeroed
if (top > b->width) {
top = b->width; // this works because 'buf' is explicitly zeroed
}
for (i = 0, j = idx; i < top; i++, j += width) {
@@ -955,8 +930,7 @@ static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx,
}
}
b->top = top;
bn_correct_top(b);
b->width = top;
return 1;
}
@@ -1006,8 +980,7 @@ static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx,
int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx,
const BN_MONT_CTX *mont) {
int i, bits, ret = 0, window, wvalue;
int top;
int i, ret = 0, window, wvalue;
BN_MONT_CTX *new_mont = NULL;
int numPowers;
@@ -1022,9 +995,10 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
return 0;
}
top = m->top;
bits = BN_num_bits(p);
// Use all bits stored in |p|, rather than |BN_num_bits|, so we do not leak
// whether the top bits are zero.
int max_bits = p->width * BN_BITS2;
int bits = max_bits;
if (bits == 0) {
// x**0 mod 1 is still zero.
if (BN_is_one(m)) {
@@ -1036,13 +1010,17 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
// Allocate a montgomery context if it was not supplied by the caller.
if (mont == NULL) {
new_mont = BN_MONT_CTX_new();
if (new_mont == NULL || !BN_MONT_CTX_set(new_mont, m, ctx)) {
new_mont = BN_MONT_CTX_new_for_modulus(m, ctx);
if (new_mont == NULL) {
goto err;
}
mont = new_mont;
}
// Use the width in |mont->N|, rather than the copy in |m|. The assembly
// implementation assumes it can use |top| to size R.
int top = mont->N.width;
if (a->neg || BN_ucmp(a, m) >= 0) {
new_a = BN_new();
if (new_a == NULL ||
@@ -1056,15 +1034,14 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
// If the size of the operands allow it, perform the optimized
// RSAZ exponentiation. For further information see
// crypto/bn/rsaz_exp.c and accompanying assembly modules.
if ((16 == a->top) && (16 == p->top) && (BN_num_bits(m) == 1024) &&
if ((16 == a->width) && (16 == p->width) && (BN_num_bits(m) == 1024) &&
rsaz_avx2_eligible()) {
if (!bn_wexpand(rr, 16)) {
goto err;
}
RSAZ_1024_mod_exp_avx2(rr->d, a->d, p->d, m->d, mont->RR.d, mont->n0[0]);
rr->top = 16;
rr->width = 16;
rr->neg = 0;
bn_correct_top(rr);
ret = 1;
goto err;
}
@@ -1110,21 +1087,12 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
// lay down tmp and am right after powers table
tmp.d = (BN_ULONG *)(powerbuf + sizeof(m->d[0]) * top * numPowers);
am.d = tmp.d + top;
tmp.top = am.top = 0;
tmp.width = am.width = 0;
tmp.dmax = am.dmax = top;
tmp.neg = am.neg = 0;
tmp.flags = am.flags = BN_FLG_STATIC_DATA;
// prepare a^0 in Montgomery domain
// by Shay Gueron's suggestion
if (m->d[top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
// 2^(top*BN_BITS2) - m
tmp.d[0] = 0 - m->d[0];
for (i = 1; i < top; i++) {
tmp.d[i] = ~m->d[i];
}
tmp.top = top;
} else if (!BN_to_montgomery(&tmp, BN_value_one(), mont, ctx)) {
if (!bn_one_to_montgomery(&tmp, mont, ctx)) {
goto err;
}
@@ -1148,10 +1116,10 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
// BN_to_montgomery can contaminate words above .top
// [in BN_DEBUG[_DEBUG] build]...
for (i = am.top; i < top; i++) {
for (i = am.width; i < top; i++) {
am.d[i] = 0;
}
for (i = tmp.top; i < top; i++) {
for (i = tmp.width; i < top; i++) {
tmp.d[i] = 0;
}
@@ -1161,7 +1129,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
}
bn_scatter5(tmp.d, top, powerbuf, 0);
bn_scatter5(am.d, am.top, powerbuf, 1);
bn_scatter5(am.d, am.width, powerbuf, 1);
bn_mul_mont(tmp.d, am.d, am.d, np, n0, top);
bn_scatter5(tmp.d, top, powerbuf, 2);
@@ -1217,7 +1185,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
}
} else {
const uint8_t *p_bytes = (const uint8_t *)p->d;
int max_bits = p->top * BN_BITS2;
assert(bits < max_bits);
// |p = 0| has been handled as a special case, so |max_bits| is at least
// one word.
@@ -1229,7 +1196,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
// here is the top bit, inclusive.
if (bits - 4 >= max_bits - 8) {
// Read five bits from |bits-4| through |bits|, inclusive.
wvalue = p_bytes[p->top * BN_BYTES - 1];
wvalue = p_bytes[p->width * BN_BYTES - 1];
wvalue >>= (bits - 4) & 7;
wvalue &= 0x1f;
bits -= 5;
@@ -1248,8 +1215,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
}
ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np, n0, top);
tmp.top = top;
bn_correct_top(&tmp);
tmp.width = top;
if (ret) {
if (!BN_copy(rr, &tmp)) {
ret = 0;
@@ -1363,8 +1329,8 @@ int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1,
// Allocate a montgomery context if it was not supplied by the caller.
if (mont == NULL) {
new_mont = BN_MONT_CTX_new();
if (new_mont == NULL || !BN_MONT_CTX_set(new_mont, m, ctx)) {
new_mont = BN_MONT_CTX_new_for_modulus(m, ctx);
if (new_mont == NULL) {
goto err;
}
mont = new_mont;
+2 -1
View File
@@ -64,7 +64,8 @@
// This file has two other implementations: x86 assembly language in
// asm/bn-586.pl and x86_64 inline assembly in asm/x86_64-gcc.c.
#if defined(OPENSSL_NO_ASM) || \
!(defined(OPENSSL_X86) || (defined(OPENSSL_X86_64) && defined(__GNUC__)))
!(defined(OPENSSL_X86) || \
(defined(OPENSSL_X86_64) && (defined(__GNUC__) || defined(__clang__))))
#ifdef BN_ULLONG
#define mul_add(r, a, w, c) \
+98 -15
View File
@@ -140,9 +140,12 @@ extern "C" {
#if defined(OPENSSL_64_BIT)
#if !defined(_MSC_VER)
#if defined(BORINGSSL_HAS_UINT128)
// MSVC doesn't support two-word integers on 64-bit.
#define BN_ULLONG uint128_t
#if defined(BORINGSSL_CAN_DIVIDE_UINT128)
#define BN_CAN_DIVIDE_ULLONG
#endif
#endif
#define BN_BITS2 64
@@ -160,6 +163,7 @@ extern "C" {
#elif defined(OPENSSL_32_BIT)
#define BN_ULLONG uint64_t
#define BN_CAN_DIVIDE_ULLONG
#define BN_BITS2 32
#define BN_BYTES 4
#define BN_BITS4 16
@@ -193,9 +197,13 @@ extern "C" {
#define Hw(t) ((BN_ULONG)((t) >> BN_BITS2))
#endif
// bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or
// until |top| is zero. If |bn| is zero, |bn->neg| is set to zero.
void bn_correct_top(BIGNUM *bn);
// bn_minimal_width returns the minimal value of |bn->top| which fits the
// value of |bn|.
int bn_minimal_width(const BIGNUM *bn);
// bn_set_minimal_width sets |bn->width| to |bn_minimal_width(bn)|. If |bn| is
// zero, |bn->neg| is set to zero.
void bn_set_minimal_width(BIGNUM *bn);
// bn_wexpand ensures that |bn| has at least |words| works of space without
// altering its value. It returns one on success or zero on allocation
@@ -206,10 +214,27 @@ int bn_wexpand(BIGNUM *bn, size_t words);
// than a number of words.
int bn_expand(BIGNUM *bn, size_t bits);
// bn_resize_words adjusts |bn->top| to be |words|. It returns one on success
// and zero on allocation error or if |bn|'s value is too large.
OPENSSL_EXPORT int bn_resize_words(BIGNUM *bn, size_t words);
// bn_select_words sets |r| to |a| if |mask| is all ones or |b| if |mask| is
// all zeros.
void bn_select_words(BN_ULONG *r, BN_ULONG mask, const BN_ULONG *a,
const BN_ULONG *b, size_t num);
// bn_set_words sets |bn| to the value encoded in the |num| words in |words|,
// least significant word first.
int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num);
// bn_fits_in_words returns one if |bn| may be represented in |num| words, plus
// a sign bit, and zero otherwise.
int bn_fits_in_words(const BIGNUM *bn, size_t num);
// bn_copy_words copies the value of |bn| to |out| and returns one if the value
// is representable in |num| words. Otherwise, it returns zero.
int bn_copy_words(BN_ULONG *out, size_t num, const BIGNUM *bn);
// bn_mul_add_words multiples |ap| by |w|, adds the result to |rp|, and places
// the result in |rp|. |ap| and |rp| must both be |num| words long. It returns
// the carry word of the operation. |ap| and |rp| may be equal but otherwise may
@@ -255,16 +280,6 @@ void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[4]);
// bn_sqr_comba4 sets |r| to |a|^2.
void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]);
// bn_cmp_words returns a value less than, equal to or greater than zero if
// the, length |n|, array |a| is less than, equal to or greater than |b|.
int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n);
// bn_cmp_words returns a value less than, equal to or greater than zero if the
// array |a| is less than, equal to or greater than |b|. The arrays can be of
// different lengths: |cl| gives the minimum of the two lengths and |dl| gives
// the length of |a| minus the length of |b|.
int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl);
// bn_less_than_words returns one if |a| < |b| and zero otherwise, where |a|
// and |b| both are |len| words long. It runs in constant time.
int bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len);
@@ -292,7 +307,13 @@ int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
const BN_ULONG *np, const BN_ULONG *n0, int num);
uint64_t bn_mont_n0(const BIGNUM *n);
int bn_mod_exp_base_2_vartime(BIGNUM *r, unsigned p, const BIGNUM *n);
// bn_mod_exp_base_2_consttime calculates r = 2**p (mod n). |p| must be larger
// than log_2(n); i.e. 2**p must be larger than |n|. |n| must be positive and
// odd. |p| and the bit width of |n| are assumed public, but |n| is otherwise
// treated as secret.
int bn_mod_exp_base_2_consttime(BIGNUM *r, unsigned p, const BIGNUM *n,
BN_CTX *ctx);
#if defined(OPENSSL_X86_64) && defined(_MSC_VER)
#define BN_UMULT_LOHI(low, high, a, b) ((low) = _umul128((a), (b), &(high)))
@@ -322,6 +343,61 @@ int bn_jacobi(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
// otherwise.
int bn_is_bit_set_words(const BN_ULONG *a, size_t num, unsigned bit);
// bn_one_to_montgomery sets |r| to one in Montgomery form. It returns one on
// success and zero on error. This function treats the bit width of the modulus
// as public.
int bn_one_to_montgomery(BIGNUM *r, const BN_MONT_CTX *mont, BN_CTX *ctx);
// bn_less_than_montgomery_R returns one if |bn| is less than the Montgomery R
// value for |mont| and zero otherwise.
int bn_less_than_montgomery_R(const BIGNUM *bn, const BN_MONT_CTX *mont);
// Fixed-width arithmetic.
//
// The following functions implement non-modular arithmetic in constant-time
// and pessimally set |r->width| to the largest possible word size.
//
// Note this means that, e.g., repeatedly multiplying by one will cause widths
// to increase without bound. The corresponding public API functions minimize
// their outputs to avoid regressing calculator consumers.
// bn_uadd_fixed behaves like |BN_uadd|, but it pessimally sets
// |r->width| = |a->width| + |b->width| + 1.
int bn_uadd_fixed(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
// bn_mul_fixed behaves like |BN_mul|, but it rejects negative inputs and
// pessimally sets |r->width| to |a->width| + |b->width|, to avoid leaking
// information about |a| and |b|.
int bn_mul_fixed(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
// bn_sqrt_fixed behaves like |BN_sqrt|, but it pessimally sets |r->width| to
// 2*|a->width|, to avoid leaking information about |a| and |b|.
int bn_sqr_fixed(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx);
// Constant-time modular arithmetic.
//
// The following functions implement basic constant-time modular arithemtic on
// word arrays.
// bn_mod_add_quick_ctx acts like |BN_mod_add_quick| but takes a |BN_CTX|.
int bn_mod_add_quick_ctx(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
const BIGNUM *m, BN_CTX *ctx);
// bn_mod_sub_quick_ctx acts like |BN_mod_sub_quick| but takes a |BN_CTX|.
int bn_mod_sub_quick_ctx(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
const BIGNUM *m, BN_CTX *ctx);
// bn_mod_lshift1_quick_ctx acts like |BN_mod_lshift1_quick| but takes a
// |BN_CTX|.
int bn_mod_lshift1_quick_ctx(BIGNUM *r, const BIGNUM *a, const BIGNUM *m,
BN_CTX *ctx);
// bn_mod_lshift_quick_ctx acts like |BN_mod_lshift_quick| but takes a |BN_CTX|.
int bn_mod_lshift_quick_ctx(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
BN_CTX *ctx);
// Low-level operations for small numbers.
//
@@ -368,6 +444,13 @@ int bn_to_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
int bn_from_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_MONT_CTX *mont);
// bn_one_to_montgomery_small sets |r| to one in Montgomery form. It returns one
// on success and zero on error. |num_r| must be the length of the modulus,
// which is |mont->N.top|. This function treats the bit width of the modulus as
// public.
int bn_one_to_montgomery_small(BN_ULONG *r, size_t num_r,
const BN_MONT_CTX *mont);
// bn_mod_mul_montgomery_small sets |r| to |a| * |b| mod |mont->N|. Both inputs
// and outputs are in the Montgomery domain. |num_r| must be the length of the
// modulus, which is |mont->N.top|. This function returns one on success and
+1 -1
View File
@@ -58,7 +58,7 @@
// least significant word
#define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0])
#define BN_lsw(n) (((n)->width == 0) ? (BN_ULONG) 0 : (n)->d[0])
int bn_jacobi(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
// In 'tab', only odd-indexed entries are relevant:
+124 -81
View File
@@ -126,10 +126,6 @@
#define OPENSSL_BN_ASM_MONT
#endif
static int bn_mod_mul_montgomery_fallback(BIGNUM *r, const BIGNUM *a,
const BIGNUM *b,
const BN_MONT_CTX *mont, BN_CTX *ctx);
BN_MONT_CTX *BN_MONT_CTX_new(void) {
BN_MONT_CTX *ret = OPENSSL_malloc(sizeof(BN_MONT_CTX));
@@ -193,6 +189,10 @@ int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) {
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
return 0;
}
// |mont->N| is always stored minimally. Computing RR efficiently leaks the
// size of the modulus. While the modulus may be private in RSA (one of the
// primes), their sizes are public, so this is fine.
bn_set_minimal_width(&mont->N);
// Find n0 such that n0 * N == -1 (mod r).
//
@@ -200,7 +200,7 @@ int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) {
// others, we could use a shorter R value and use faster |BN_ULONG|-based
// math instead of |uint64_t|-based math, which would be double-precision.
// However, currently only the assembler files know which is which.
uint64_t n0 = bn_mont_n0(mod);
uint64_t n0 = bn_mont_n0(&mont->N);
mont->n0[0] = (BN_ULONG)n0;
#if BN_MONT_CTX_N0_LIMBS == 2
mont->n0[1] = (BN_ULONG)(n0 >> BN_BITS2);
@@ -208,19 +208,34 @@ int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) {
mont->n0[1] = 0;
#endif
BN_CTX *new_ctx = NULL;
if (ctx == NULL) {
new_ctx = BN_CTX_new();
if (new_ctx == NULL) {
return 0;
}
ctx = new_ctx;
}
// Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS2 such that R
// > mod. Even though the assembly on some 32-bit platforms works with 64-bit
// values, using |BN_BITS2| here, rather than |BN_MONT_CTX_N0_LIMBS *
// BN_BITS2|, is correct because R**2 will still be a multiple of the latter
// as |BN_MONT_CTX_N0_LIMBS| is either one or two.
//
// XXX: This is not constant time with respect to |mont->N|, but it should be.
unsigned lgBigR = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
if (!bn_mod_exp_base_2_vartime(&mont->RR, lgBigR * 2, &mont->N)) {
return 0;
}
unsigned lgBigR = mont->N.width * BN_BITS2;
int ok = bn_mod_exp_base_2_consttime(&mont->RR, lgBigR * 2, &mont->N, ctx);
BN_CTX_free(new_ctx);
return ok;
}
return 1;
BN_MONT_CTX *BN_MONT_CTX_new_for_modulus(const BIGNUM *mod, BN_CTX *ctx) {
BN_MONT_CTX *mont = BN_MONT_CTX_new();
if (mont == NULL ||
!BN_MONT_CTX_set(mont, mod, ctx)) {
BN_MONT_CTX_free(mont);
return NULL;
}
return mont;
}
int BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
@@ -234,25 +249,12 @@ int BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
}
CRYPTO_MUTEX_lock_write(lock);
ctx = *pmont;
if (ctx) {
goto out;
if (*pmont == NULL) {
*pmont = BN_MONT_CTX_new_for_modulus(mod, bn_ctx);
}
ctx = BN_MONT_CTX_new();
if (ctx == NULL) {
goto out;
}
if (!BN_MONT_CTX_set(ctx, mod, bn_ctx)) {
BN_MONT_CTX_free(ctx);
ctx = NULL;
goto out;
}
*pmont = ctx;
out:
const int ok = *pmont != NULL;
CRYPTO_MUTEX_unlock_write(lock);
return ctx != NULL;
return ok;
}
int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
@@ -263,7 +265,7 @@ int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
static int bn_from_montgomery_in_place(BN_ULONG *r, size_t num_r, BN_ULONG *a,
size_t num_a, const BN_MONT_CTX *mont) {
const BN_ULONG *n = mont->N.d;
size_t num_n = mont->N.top;
size_t num_n = mont->N.width;
if (num_r != num_n || num_a != 2 * num_n) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
@@ -304,32 +306,26 @@ static int bn_from_montgomery_in_place(BN_ULONG *r, size_t num_r, BN_ULONG *a,
static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
const BN_MONT_CTX *mont) {
if (r->neg) {
OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
return 0;
}
const BIGNUM *n = &mont->N;
if (n->top == 0) {
ret->top = 0;
if (n->width == 0) {
ret->width = 0;
return 1;
}
int max = (2 * n->top); // carry is stored separately
if (!bn_wexpand(r, max) ||
!bn_wexpand(ret, n->top)) {
int max = 2 * n->width; // carry is stored separately
if (!bn_resize_words(r, max) ||
!bn_wexpand(ret, n->width)) {
return 0;
}
// Clear the top words of |r|.
if (max > r->top) {
OPENSSL_memset(r->d + r->top, 0, (max - r->top) * sizeof(BN_ULONG));
}
r->top = max;
ret->top = n->top;
if (!bn_from_montgomery_in_place(ret->d, ret->top, r->d, r->top, mont)) {
return 0;
}
ret->neg = r->neg;
bn_correct_top(r);
bn_correct_top(ret);
return 1;
ret->width = n->width;
ret->neg = 0;
return bn_from_montgomery_in_place(ret->d, ret->width, r->d, r->width, mont);
}
int BN_from_montgomery(BIGNUM *r, const BIGNUM *a, const BN_MONT_CTX *mont,
@@ -352,35 +348,24 @@ err:
return ret;
}
int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
const BN_MONT_CTX *mont, BN_CTX *ctx) {
#if !defined(OPENSSL_BN_ASM_MONT)
return bn_mod_mul_montgomery_fallback(r, a, b, mont, ctx);
#else
int num = mont->N.top;
// |bn_mul_mont| requires at least 128 bits of limbs, at least for x86.
if (num < (128 / BN_BITS2) ||
a->top != num ||
b->top != num) {
return bn_mod_mul_montgomery_fallback(r, a, b, mont, ctx);
int bn_one_to_montgomery(BIGNUM *r, const BN_MONT_CTX *mont, BN_CTX *ctx) {
// If the high bit of |n| is set, R = 2^(width*BN_BITS2) < 2 * |n|, so we
// compute R - |n| rather than perform Montgomery reduction.
const BIGNUM *n = &mont->N;
if (n->width > 0 && (n->d[n->width - 1] >> (BN_BITS2 - 1)) != 0) {
if (!bn_wexpand(r, n->width)) {
return 0;
}
r->d[0] = 0 - n->d[0];
for (int i = 1; i < n->width; i++) {
r->d[i] = ~n->d[i];
}
r->width = n->width;
r->neg = 0;
return 1;
}
if (!bn_wexpand(r, num)) {
return 0;
}
if (!bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
// The check above ensures this won't happen.
assert(0);
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
return 0;
}
r->neg = a->neg ^ b->neg;
r->top = num;
bn_correct_top(r);
return 1;
#endif
return BN_from_montgomery(r, &mont->RR, mont, ctx);
}
static int bn_mod_mul_montgomery_fallback(BIGNUM *r, const BIGNUM *a,
@@ -396,11 +381,11 @@ static int bn_mod_mul_montgomery_fallback(BIGNUM *r, const BIGNUM *a,
}
if (a == b) {
if (!BN_sqr(tmp, a, ctx)) {
if (!bn_sqr_fixed(tmp, a, ctx)) {
goto err;
}
} else {
if (!BN_mul(tmp, a, b, ctx)) {
if (!bn_mul_fixed(tmp, a, b, ctx)) {
goto err;
}
}
@@ -417,15 +402,51 @@ err:
return ret;
}
int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
const BN_MONT_CTX *mont, BN_CTX *ctx) {
if (a->neg || b->neg) {
OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
return 0;
}
#if defined(OPENSSL_BN_ASM_MONT)
// |bn_mul_mont| requires at least 128 bits of limbs, at least for x86.
int num = mont->N.width;
if (num >= (128 / BN_BITS2) &&
a->width == num &&
b->width == num) {
if (!bn_wexpand(r, num)) {
return 0;
}
if (!bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
// The check above ensures this won't happen.
assert(0);
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
return 0;
}
r->neg = 0;
r->width = num;
return 1;
}
#endif
return bn_mod_mul_montgomery_fallback(r, a, b, mont, ctx);
}
int bn_less_than_montgomery_R(const BIGNUM *bn, const BN_MONT_CTX *mont) {
return !BN_is_negative(bn) &&
bn_fits_in_words(bn, mont->N.width);
}
int bn_to_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_MONT_CTX *mont) {
return bn_mod_mul_montgomery_small(r, num_r, a, num_a, mont->RR.d,
mont->RR.top, mont);
mont->RR.width, mont);
}
int bn_from_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_MONT_CTX *mont) {
size_t num_n = mont->N.top;
size_t num_n = mont->N.width;
if (num_a > 2 * num_n || num_r != num_n || num_n > BN_SMALL_MAX_WORDS) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
@@ -439,10 +460,32 @@ int bn_from_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
return ret;
}
int bn_one_to_montgomery_small(BN_ULONG *r, size_t num_r,
const BN_MONT_CTX *mont) {
const BN_ULONG *n = mont->N.d;
size_t num_n = mont->N.width;
if (num_n == 0 || num_r != num_n) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
// If the high bit of |n| is set, R = 2^(num_n*BN_BITS2) < 2 * |n|, so we
// compute R - |n| rather than perform Montgomery reduction.
if (num_n > 0 && (n[num_n - 1] >> (BN_BITS2 - 1)) != 0) {
r[0] = 0 - n[0];
for (size_t i = 1; i < num_n; i++) {
r[i] = ~n[i];
}
return 1;
}
return bn_from_montgomery_small(r, num_r, mont->RR.d, mont->RR.width, mont);
}
int bn_mod_mul_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_ULONG *b, size_t num_b,
const BN_MONT_CTX *mont) {
size_t num_n = mont->N.top;
size_t num_n = mont->N.width;
if (num_r != num_n || num_a + num_b > 2 * num_n ||
num_n > BN_SMALL_MAX_WORDS) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+8 -30
View File
@@ -71,7 +71,7 @@ uint64_t bn_mont_n0(const BIGNUM *n) {
// |BN_MONT_CTX_N0_LIMBS| limbs of |n|.
uint64_t n_mod_r = n->d[0];
#if BN_MONT_CTX_N0_LIMBS == 2
if (n->top > 1) {
if (n->width > 1) {
n_mod_r |= (uint64_t)n->d[1] << BN_BITS2;
}
#endif
@@ -159,10 +159,8 @@ static uint64_t bn_neg_inv_mod_r_u64(uint64_t n) {
return v;
}
// bn_mod_exp_base_2_vartime calculates r = 2**p (mod n). |p| must be larger
// than log_2(n); i.e. 2**p must be larger than |n|. |n| must be positive and
// odd.
int bn_mod_exp_base_2_vartime(BIGNUM *r, unsigned p, const BIGNUM *n) {
int bn_mod_exp_base_2_consttime(BIGNUM *r, unsigned p, const BIGNUM *n,
BN_CTX *ctx) {
assert(!BN_is_zero(n));
assert(!BN_is_negative(n));
assert(BN_is_odd(n));
@@ -171,37 +169,17 @@ int bn_mod_exp_base_2_vartime(BIGNUM *r, unsigned p, const BIGNUM *n) {
unsigned n_bits = BN_num_bits(n);
assert(n_bits != 0);
assert(p > n_bits);
if (n_bits == 1) {
return 1;
}
// Set |r| to the smallest power of two larger than |n|.
assert(p > n_bits);
if (!BN_set_bit(r, n_bits)) {
// Set |r| to the larger power of two smaller than |n|, then shift with
// reductions the rest of the way.
if (!BN_set_bit(r, n_bits - 1) ||
!bn_mod_lshift_quick_ctx(r, r, p - (n_bits - 1), n, ctx)) {
return 0;
}
// Unconditionally reduce |r|.
assert(BN_cmp(r, n) > 0);
if (!BN_usub(r, r, n)) {
return 0;
}
assert(BN_cmp(r, n) < 0);
for (unsigned i = n_bits; i < p; ++i) {
// This is like |BN_mod_lshift1_quick| except using |BN_usub|.
//
// TODO: Replace this with the use of a constant-time variant of
// |BN_mod_lshift1_quick|.
if (!BN_lshift1(r, r)) {
return 0;
}
if (BN_cmp(r, n) >= 0) {
if (!BN_usub(r, r, n)) {
return 0;
}
}
}
return 1;
}
+301 -345
View File
@@ -61,6 +61,7 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/type_check.h>
#include "internal.h"
#include "../../internal.h"
@@ -70,6 +71,13 @@
#define BN_SQR_RECURSIVE_SIZE_NORMAL BN_MUL_RECURSIVE_SIZE_NORMAL
static void bn_abs_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
size_t num, BN_ULONG *tmp) {
BN_ULONG borrow = bn_sub_words(tmp, a, b, num);
bn_sub_words(r, b, a, num);
bn_select_words(r, 0 - borrow, r /* tmp < 0 */, tmp /* tmp >= 0 */, num);
}
static void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, size_t na,
const BN_ULONG *b, size_t nb) {
if (na < nb) {
@@ -279,25 +287,43 @@ BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
int cl, int dl);
#endif
// bn_abs_sub_part_words computes |r| = |a| - |b|, storing the absolute value
// and returning a mask of all ones if the result was negative and all zeros if
// the result was positive. |cl| and |dl| follow the |bn_sub_part_words| calling
// convention.
//
// TODO(davidben): Make this take |size_t|. The |cl| + |dl| calling convention
// is confusing. The trouble is 32-bit x86 implements |bn_sub_part_words| in
// assembly, but we can probably just delete it?
static BN_ULONG bn_abs_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
const BN_ULONG *b, int cl, int dl,
BN_ULONG *tmp) {
BN_ULONG borrow = bn_sub_part_words(tmp, a, b, cl, dl);
bn_sub_part_words(r, b, a, cl, -dl);
int r_len = cl + (dl < 0 ? -dl : dl);
borrow = 0 - borrow;
bn_select_words(r, borrow, r /* tmp < 0 */, tmp /* tmp >= 0 */, r_len);
return borrow;
}
// Karatsuba recursive multiplication algorithm
// (cf. Knuth, The Art of Computer Programming, Vol. 2)
// r is 2*n2 words in size,
// a and b are both n2 words in size.
// n2 must be a power of 2.
// We multiply and return the result.
// t must be 2*n2 words in size
// We calculate
// a[0]*b[0]
// a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
// a[1]*b[1]
// dnX may not be positive, but n2/2+dnX has to be
// bn_mul_recursive sets |r| to |a| * |b|, using |t| as scratch space. |r| has
// length 2*|n2|, |a| has length |n2| + |dna|, |b| has length |n2| + |dnb|, and
// |t| has length 4*|n2|. |n2| must be a power of two. Finally, we must have
// -|BN_MUL_RECURSIVE_SIZE_NORMAL|/2 <= |dna| <= 0 and
// -|BN_MUL_RECURSIVE_SIZE_NORMAL|/2 <= |dnb| <= 0.
//
// TODO(davidben): Simplify and |size_t| the calling convention around lengths
// here.
static void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
int n2, int dna, int dnb, BN_ULONG *t) {
int n = n2 / 2, c1, c2;
int tna = n + dna, tnb = n + dnb;
unsigned int neg, zero;
BN_ULONG ln, lo, *p;
// |n2| is a power of two.
assert(n2 != 0 && (n2 & (n2 - 1)) == 0);
// Check |dna| and |dnb| are in range.
assert(-BN_MUL_RECURSIVE_SIZE_NORMAL/2 <= dna && dna <= 0);
assert(-BN_MUL_RECURSIVE_SIZE_NORMAL/2 <= dnb && dnb <= 0);
// Only call bn_mul_comba 8 if n2 == 8 and the
// two arrays are complete [steve]
@@ -309,276 +335,212 @@ static void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
// Else do normal multiply
if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
if ((dna + dnb) < 0) {
if (dna + dnb < 0) {
OPENSSL_memset(&r[2 * n2 + dna + dnb], 0,
sizeof(BN_ULONG) * -(dna + dnb));
}
return;
}
// r=(a[0]-a[1])*(b[1]-b[0])
c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
zero = neg = 0;
switch (c1 * 3 + c2) {
case -4:
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); // -
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); // -
break;
case -3:
zero = 1;
break;
case -2:
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); // -
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); // +
neg = 1;
break;
case -1:
case 0:
case 1:
zero = 1;
break;
case 2:
bn_sub_part_words(t, a, &(a[n]), tna, n - tna); // +
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); // -
neg = 1;
break;
case 3:
zero = 1;
break;
case 4:
bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
break;
}
// Split |a| and |b| into a0,a1 and b0,b1, where a0 and b0 have size |n|.
// Split |t| into t0,t1,t2,t3, each of size |n|, with the remaining 4*|n| used
// for recursive calls.
// Split |r| into r0,r1,r2,r3. We must contribute a0*b0 to r0,r1, a0*a1+b0*b1
// to r1,r2, and a1*b1 to r2,r3. The middle term we will compute as:
//
// a0*a1 + b0*b1 = (a0 - a1)*(b1 - b0) + a1*b1 + a0*b0
//
// Note that we know |n| >= |BN_MUL_RECURSIVE_SIZE_NORMAL|/2 above, so
// |tna| and |tnb| are non-negative.
int n = n2 / 2, tna = n + dna, tnb = n + dnb;
// t0 = a0 - a1 and t1 = b1 - b0. The result will be multiplied, so we XOR
// their sign masks, giving the sign of (a0 - a1)*(b1 - b0). t0 and t1
// themselves store the absolute value.
BN_ULONG neg = bn_abs_sub_part_words(t, a, &a[n], tna, n - tna, &t[n2]);
neg ^= bn_abs_sub_part_words(&t[n], &b[n], b, tnb, tnb - n, &t[n2]);
// Compute:
// t2,t3 = t0 * t1 = |(a0 - a1)*(b1 - b0)|
// r0,r1 = a0 * b0
// r2,r3 = a1 * b1
if (n == 4 && dna == 0 && dnb == 0) {
// XXX: bn_mul_comba4 could take extra args to do this well
if (!zero) {
bn_mul_comba4(&(t[n2]), t, &(t[n]));
} else {
OPENSSL_memset(&(t[n2]), 0, 8 * sizeof(BN_ULONG));
}
bn_mul_comba4(&t[n2], t, &t[n]);
bn_mul_comba4(r, a, b);
bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n]));
bn_mul_comba4(&r[n2], &a[n], &b[n]);
} else if (n == 8 && dna == 0 && dnb == 0) {
// XXX: bn_mul_comba8 could take extra args to do this well
if (!zero) {
bn_mul_comba8(&(t[n2]), t, &(t[n]));
} else {
OPENSSL_memset(&(t[n2]), 0, 16 * sizeof(BN_ULONG));
}
bn_mul_comba8(&t[n2], t, &t[n]);
bn_mul_comba8(r, a, b);
bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n]));
bn_mul_comba8(&r[n2], &a[n], &b[n]);
} else {
p = &(t[n2 * 2]);
if (!zero) {
bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
} else {
OPENSSL_memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
}
BN_ULONG *p = &t[n2 * 2];
bn_mul_recursive(&t[n2], t, &t[n], n, 0, 0, p);
bn_mul_recursive(r, a, b, n, 0, 0, p);
bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p);
bn_mul_recursive(&r[n2], &a[n], &b[n], n, dna, dnb, p);
}
// t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
// r[10] holds (a[0]*b[0])
// r[32] holds (b[1]*b[1])
// t0,t1,c = r0,r1 + r2,r3 = a0*b0 + a1*b1
BN_ULONG c = bn_add_words(t, r, &r[n2], n2);
c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
// t2,t3,c = t0,t1,c + neg*t2,t3 = (a0 - a1)*(b1 - b0) + a1*b1 + a0*b0.
// The second term is stored as the absolute value, so we do this with a
// constant-time select.
BN_ULONG c_neg = c - bn_sub_words(&t[n2 * 2], t, &t[n2], n2);
BN_ULONG c_pos = c + bn_add_words(&t[n2], t, &t[n2], n2);
bn_select_words(&t[n2], neg, &t[n2 * 2], &t[n2], n2);
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
crypto_word_t_too_small);
c = constant_time_select_w(neg, c_neg, c_pos);
if (neg) {
// if t[32] is negative
c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
} else {
// Might have a carry
c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
// We now have our three components. Add them together.
// r1,r2,c = r1,r2 + t2,t3,c
c += bn_add_words(&r[n], &r[n], &t[n2], n2);
// Propagate the carry bit to the end.
for (int i = n + n2; i < n2 + n2; i++) {
BN_ULONG old = r[i];
r[i] = old + c;
c = r[i] < old;
}
// t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
// r[10] holds (a[0]*b[0])
// r[32] holds (b[1]*b[1])
// c1 holds the carry bits
c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
if (c1) {
p = &(r[n + n2]);
lo = *p;
ln = lo + c1;
*p = ln;
// The overflow will stop before we over write
// words we should not overwrite
if (ln < (BN_ULONG)c1) {
do {
p++;
lo = *p;
ln = lo + 1;
*p = ln;
} while (ln == 0);
}
}
// The product should fit without carries.
assert(c == 0);
}
// n+tn is the word length
// t needs to be n*4 is size, as does r
// tnX may not be negative but less than n
// bn_mul_part_recursive sets |r| to |a| * |b|, using |t| as scratch space. |r|
// has length 4*|n|, |a| has length |n| + |tna|, |b| has length |n| + |tnb|, and
// |t| has length 8*|n|. |n| must be a power of two. Additionally, we must have
// 0 <= tna < n and 0 <= tnb < n, and |tna| and |tnb| must differ by at most
// one.
//
// TODO(davidben): Make this take |size_t| and perhaps the actual lengths of |a|
// and |b|.
static void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a,
const BN_ULONG *b, int n, int tna, int tnb,
BN_ULONG *t) {
int i, j, n2 = n * 2;
int c1, c2, neg;
BN_ULONG ln, lo, *p;
// |n| is a power of two.
assert(n != 0 && (n & (n - 1)) == 0);
// Check |tna| and |tnb| are in range.
assert(0 <= tna && tna < n);
assert(0 <= tnb && tnb < n);
assert(-1 <= tna - tnb && tna - tnb <= 1);
int n2 = n * 2;
if (n < 8) {
bn_mul_normal(r, a, n + tna, b, n + tnb);
OPENSSL_memset(r + n2 + tna + tnb, 0, n2 - tna - tnb);
return;
}
// r=(a[0]-a[1])*(b[1]-b[0])
c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
neg = 0;
switch (c1 * 3 + c2) {
case -4:
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); // -
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); // -
break;
case -3:
// break;
case -2:
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); // -
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); // +
neg = 1;
break;
case -1:
case 0:
case 1:
// break;
case 2:
bn_sub_part_words(t, a, &(a[n]), tna, n - tna); // +
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); // -
neg = 1;
break;
case 3:
// break;
case 4:
bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
break;
}
// Split |a| and |b| into a0,a1 and b0,b1, where a0 and b0 have size |n|. |a1|
// and |b1| have size |tna| and |tnb|, respectively.
// Split |t| into t0,t1,t2,t3, each of size |n|, with the remaining 4*|n| used
// for recursive calls.
// Split |r| into r0,r1,r2,r3. We must contribute a0*b0 to r0,r1, a0*a1+b0*b1
// to r1,r2, and a1*b1 to r2,r3. The middle term we will compute as:
//
// a0*a1 + b0*b1 = (a0 - a1)*(b1 - b0) + a1*b1 + a0*b0
// t0 = a0 - a1 and t1 = b1 - b0. The result will be multiplied, so we XOR
// their sign masks, giving the sign of (a0 - a1)*(b1 - b0). t0 and t1
// themselves store the absolute value.
BN_ULONG neg = bn_abs_sub_part_words(t, a, &a[n], tna, n - tna, &t[n2]);
neg ^= bn_abs_sub_part_words(&t[n], &b[n], b, tnb, tnb - n, &t[n2]);
// Compute:
// t2,t3 = t0 * t1 = |(a0 - a1)*(b1 - b0)|
// r0,r1 = a0 * b0
// r2,r3 = a1 * b1
if (n == 8) {
bn_mul_comba8(&(t[n2]), t, &(t[n]));
bn_mul_comba8(&t[n2], t, &t[n]);
bn_mul_comba8(r, a, b);
bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
OPENSSL_memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
} else {
p = &(t[n2 * 2]);
bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
bn_mul_recursive(r, a, b, n, 0, 0, p);
i = n / 2;
// If there is only a bottom half to the number,
// just do it
if (tna > tnb) {
j = tna - i;
} else {
j = tnb - i;
}
if (j == 0) {
bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p);
OPENSSL_memset(&(r[n2 + i * 2]), 0, sizeof(BN_ULONG) * (n2 - i * 2));
} else if (j > 0) {
// eg, n == 16, i == 8 and tn == 11
bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p);
OPENSSL_memset(&(r[n2 + tna + tnb]), 0,
sizeof(BN_ULONG) * (n2 - tna - tnb));
bn_mul_normal(&r[n2], &a[n], tna, &b[n], tnb);
// |bn_mul_normal| only writes |tna| + |tna| words. Zero the rest.
OPENSSL_memset(&r[n2 + tna + tnb], 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
} else {
BN_ULONG *p = &t[n2 * 2];
bn_mul_recursive(&t[n2], t, &t[n], n, 0, 0, p);
bn_mul_recursive(r, a, b, n, 0, 0, p);
OPENSSL_memset(&r[n2], 0, sizeof(BN_ULONG) * n2);
if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL &&
tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
bn_mul_normal(&r[n2], &a[n], tna, &b[n], tnb);
} else {
// (j < 0) eg, n == 16, i == 8 and tn == 5
OPENSSL_memset(&(r[n2]), 0, sizeof(BN_ULONG) * n2);
if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL &&
tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
} else {
for (;;) {
i /= 2;
// these simplified conditions work
// exclusively because difference
// between tna and tnb is 1 or 0
if (i < tna || i < tnb) {
bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i,
tnb - i, p);
break;
} else if (i == tna || i == tnb) {
bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i,
p);
break;
}
int i = n;
for (;;) {
i /= 2;
if (i < tna || i < tnb) {
// E.g., n == 16, i == 8 and tna == 11. |tna| and |tnb| are within one
// of each other, so if |tna| is larger and tna > i, then we know
// tnb >= i, and this call is valid.
bn_mul_part_recursive(&r[n2], &a[n], &b[n], i, tna - i, tnb - i, p);
break;
}
if (i == tna || i == tnb) {
// If there is only a bottom half to the number, just do it. We know
// the larger of |tna - i| and |tnb - i| is zero. The other is zero or
// -1 by because of |tna| and |tnb| differ by at most one.
bn_mul_recursive(&r[n2], &a[n], &b[n], i, tna - i, tnb - i, p);
break;
}
// This loop will eventually terminate when |i| falls below
// |BN_MUL_RECURSIVE_SIZE_NORMAL| because we know one of |tna| and |tnb|
// exceeds that.
}
}
}
// t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
// r[10] holds (a[0]*b[0])
// r[32] holds (b[1]*b[1])
// t0,t1,c = r0,r1 + r2,r3 = a0*b0 + a1*b1
BN_ULONG c = bn_add_words(t, r, &r[n2], n2);
c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
// t2,t3,c = t0,t1,c + neg*t2,t3 = (a0 - a1)*(b1 - b0) + a1*b1 + a0*b0.
// The second term is stored as the absolute value, so we do this with a
// constant-time select.
BN_ULONG c_neg = c - bn_sub_words(&t[n2 * 2], t, &t[n2], n2);
BN_ULONG c_pos = c + bn_add_words(&t[n2], t, &t[n2], n2);
bn_select_words(&t[n2], neg, &t[n2 * 2], &t[n2], n2);
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
crypto_word_t_too_small);
c = constant_time_select_w(neg, c_neg, c_pos);
if (neg) {
// if t[32] is negative
c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
} else {
// Might have a carry
c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
// We now have our three components. Add them together.
// r1,r2,c = r1,r2 + t2,t3,c
c += bn_add_words(&r[n], &r[n], &t[n2], n2);
// Propagate the carry bit to the end.
for (int i = n + n2; i < n2 + n2; i++) {
BN_ULONG old = r[i];
r[i] = old + c;
c = r[i] < old;
}
// t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
// r[10] holds (a[0]*b[0])
// r[32] holds (b[1]*b[1])
// c1 holds the carry bits
c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
if (c1) {
p = &(r[n + n2]);
lo = *p;
ln = lo + c1;
*p = ln;
// The overflow will stop before we over write
// words we should not overwrite
if (ln < (BN_ULONG)c1) {
do {
p++;
lo = *p;
ln = lo + 1;
*p = ln;
} while (ln == 0);
}
}
// The product should fit without carries.
assert(c == 0);
}
int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
int ret = 0;
int top, al, bl;
BIGNUM *rr;
int i;
BIGNUM *t = NULL;
int j = 0, k;
al = a->top;
bl = b->top;
if ((al == 0) || (bl == 0)) {
// bn_mul_impl implements |BN_mul| and |bn_mul_fixed|. Note this function breaks
// |BIGNUM| invariants and may return a negative zero. This is handled by the
// callers.
static int bn_mul_impl(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
BN_CTX *ctx) {
int al = a->width;
int bl = b->width;
if (al == 0 || bl == 0) {
BN_zero(r);
return 1;
}
top = al + bl;
int ret = 0;
BIGNUM *rr;
BN_CTX_start(ctx);
if ((r == a) || (r == b)) {
if ((rr = BN_CTX_get(ctx)) == NULL) {
if (r == a || r == b) {
rr = BN_CTX_get(ctx);
if (r == NULL) {
goto err;
}
} else {
@@ -586,55 +548,55 @@ int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
}
rr->neg = a->neg ^ b->neg;
i = al - bl;
int i = al - bl;
if (i == 0) {
if (al == 8) {
if (!bn_wexpand(rr, 16)) {
goto err;
}
rr->top = 16;
rr->width = 16;
bn_mul_comba8(rr->d, a->d, b->d);
goto end;
}
}
int top = al + bl;
static const int kMulNormalSize = 16;
if (al >= kMulNormalSize && bl >= kMulNormalSize) {
if (i >= -1 && i <= 1) {
/* Find out the power of two lower or equal
to the longest of the two numbers */
if (-1 <= i && i <= 1) {
// Find the larger power of two less than or equal to the larger length.
int j;
if (i >= 0) {
j = BN_num_bits_word((BN_ULONG)al);
}
if (i == -1) {
} else {
j = BN_num_bits_word((BN_ULONG)bl);
}
j = 1 << (j - 1);
assert(j <= al || j <= bl);
k = j + j;
t = BN_CTX_get(ctx);
BIGNUM *t = BN_CTX_get(ctx);
if (t == NULL) {
goto err;
}
if (al > j || bl > j) {
if (!bn_wexpand(t, k * 4)) {
goto err;
}
if (!bn_wexpand(rr, k * 4)) {
// We know |al| and |bl| are at most one from each other, so if al > j,
// bl >= j, and vice versa. Thus we can use |bn_mul_part_recursive|.
assert(al >= j && bl >= j);
if (!bn_wexpand(t, j * 8) ||
!bn_wexpand(rr, j * 4)) {
goto err;
}
bn_mul_part_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
} else {
// al <= j || bl <= j
if (!bn_wexpand(t, k * 2)) {
goto err;
}
if (!bn_wexpand(rr, k * 2)) {
// al <= j && bl <= j. Additionally, we know j <= al or j <= bl, so one
// of al - j or bl - j is zero. The other, by the bound on |i| above, is
// zero or -1. Thus, we can use |bn_mul_recursive|.
if (!bn_wexpand(t, j * 4) ||
!bn_wexpand(rr, j * 2)) {
goto err;
}
bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
}
rr->top = top;
rr->width = top;
goto end;
}
}
@@ -642,11 +604,10 @@ int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
if (!bn_wexpand(rr, top)) {
goto err;
}
rr->top = top;
rr->width = top;
bn_mul_normal(rr->d, a->d, al, b->d, bl);
end:
bn_correct_top(rr);
if (r != rr && !BN_copy(r, rr)) {
goto err;
}
@@ -657,6 +618,26 @@ err:
return ret;
}
int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
if (!bn_mul_impl(r, a, b, ctx)) {
return 0;
}
// This additionally fixes any negative zeros created by |bn_mul_impl|.
bn_set_minimal_width(r);
return 1;
}
int bn_mul_fixed(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
// Prevent negative zeros.
if (a->neg || b->neg) {
OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
return 0;
}
return bn_mul_impl(r, a, b, ctx);
}
int bn_mul_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a,
const BN_ULONG *b, size_t num_b) {
if (num_r != num_a + num_b) {
@@ -711,25 +692,19 @@ static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, size_t n,
bn_add_words(r, r, tmp, max);
}
// r is 2*n words in size,
// a and b are both n words in size. (There's not actually a 'b' here ...)
// n must be a power of 2.
// We multiply and return the result.
// t must be 2*n words in size
// We calculate
// a[0]*b[0]
// a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
// a[1]*b[1]
static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2,
// bn_sqr_recursive sets |r| to |a|^2, using |t| as scratch space. |r| has
// length 2*|n2|, |a| has length |n2|, and |t| has length 4*|n2|. |n2| must be
// a power of two.
static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, size_t n2,
BN_ULONG *t) {
int n = n2 / 2;
int zero, c1;
BN_ULONG ln, lo, *p;
// |n2| is a power of two.
assert(n2 != 0 && (n2 & (n2 - 1)) == 0);
if (n2 == 4) {
bn_sqr_comba4(r, a);
return;
} else if (n2 == 8) {
}
if (n2 == 8) {
bn_sqr_comba8(r, a);
return;
}
@@ -737,63 +712,48 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2,
bn_sqr_normal(r, a, n2, t);
return;
}
// r=(a[0]-a[1])*(a[1]-a[0])
c1 = bn_cmp_words(a, &(a[n]), n);
zero = 0;
if (c1 > 0) {
bn_sub_words(t, a, &(a[n]), n);
} else if (c1 < 0) {
bn_sub_words(t, &(a[n]), a, n);
} else {
zero = 1;
// Split |a| into a0,a1, each of size |n|.
// Split |t| into t0,t1,t2,t3, each of size |n|, with the remaining 4*|n| used
// for recursive calls.
// Split |r| into r0,r1,r2,r3. We must contribute a0^2 to r0,r1, 2*a0*a1 to
// r1,r2, and a1^2 to r2,r3.
size_t n = n2 / 2;
BN_ULONG *t_recursive = &t[n2 * 2];
// t0 = |a0 - a1|.
bn_abs_sub_words(t, a, &a[n], n, &t[n]);
// t2,t3 = t0^2 = |a0 - a1|^2 = a0^2 - 2*a0*a1 + a1^2
bn_sqr_recursive(&t[n2], t, n, t_recursive);
// r0,r1 = a0^2
bn_sqr_recursive(r, a, n, t_recursive);
// r2,r3 = a1^2
bn_sqr_recursive(&r[n2], &a[n], n, t_recursive);
// t0,t1,c = r0,r1 + r2,r3 = a0^2 + a1^2
BN_ULONG c = bn_add_words(t, r, &r[n2], n2);
// t2,t3,c = t0,t1,c - t2,t3 = 2*a0*a1
c -= bn_sub_words(&t[n2], t, &t[n2], n2);
// We now have our three components. Add them together.
// r1,r2,c = r1,r2 + t2,t3,c
c += bn_add_words(&r[n], &r[n], &t[n2], n2);
// Propagate the carry bit to the end.
for (size_t i = n + n2; i < n2 + n2; i++) {
BN_ULONG old = r[i];
r[i] = old + c;
c = r[i] < old;
}
// The result will always be negative unless it is zero
p = &(t[n2 * 2]);
if (!zero) {
bn_sqr_recursive(&(t[n2]), t, n, p);
} else {
OPENSSL_memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
}
bn_sqr_recursive(r, a, n, p);
bn_sqr_recursive(&(r[n2]), &(a[n]), n, p);
// t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero
// r[10] holds (a[0]*b[0])
// r[32] holds (b[1]*b[1])
c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
// t[32] is negative
c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
// t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1])
// r[10] holds (a[0]*a[0])
// r[32] holds (a[1]*a[1])
// c1 holds the carry bits
c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
if (c1) {
p = &(r[n + n2]);
lo = *p;
ln = lo + c1;
*p = ln;
// The overflow will stop before we over write
// words we should not overwrite
if (ln < (BN_ULONG)c1) {
do {
p++;
lo = *p;
ln = lo + 1;
*p = ln;
} while (ln == 0);
}
}
// The square should fit without carries.
assert(c == 0);
}
int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
if (!bn->top) {
if (!bn->width) {
return 1;
}
@@ -802,37 +762,34 @@ int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
return 1;
}
BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->top, w);
BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->width, w);
if (ll) {
if (!bn_wexpand(bn, bn->top + 1)) {
if (!bn_wexpand(bn, bn->width + 1)) {
return 0;
}
bn->d[bn->top++] = ll;
bn->d[bn->width++] = ll;
}
return 1;
}
int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
int max, al;
int ret = 0;
BIGNUM *tmp, *rr;
al = a->top;
int bn_sqr_fixed(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
int al = a->width;
if (al <= 0) {
r->top = 0;
r->width = 0;
r->neg = 0;
return 1;
}
int ret = 0;
BN_CTX_start(ctx);
rr = (a != r) ? r : BN_CTX_get(ctx);
tmp = BN_CTX_get(ctx);
BIGNUM *rr = (a != r) ? r : BN_CTX_get(ctx);
BIGNUM *tmp = BN_CTX_get(ctx);
if (!rr || !tmp) {
goto err;
}
max = 2 * al; // Non-zero (from above)
int max = 2 * al; // Non-zero (from above)
if (!bn_wexpand(rr, max)) {
goto err;
}
@@ -846,13 +803,9 @@ int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2];
bn_sqr_normal(rr->d, a->d, al, t);
} else {
int j, k;
j = BN_num_bits_word((BN_ULONG)al);
j = 1 << (j - 1);
k = j + j;
if (al == j) {
if (!bn_wexpand(tmp, k * 2)) {
// If |al| is a power of two, we can use |bn_sqr_recursive|.
if (al != 0 && (al & (al - 1)) == 0) {
if (!bn_wexpand(tmp, al * 4)) {
goto err;
}
bn_sqr_recursive(rr->d, a->d, al, tmp->d);
@@ -866,13 +819,7 @@ int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
}
rr->neg = 0;
// If the most-significant half of the top word of 'a' is zero, then
// the square of 'a' will max-1 words.
if (a->d[al - 1] == (a->d[al - 1] & BN_MASK2l)) {
rr->top = max - 1;
} else {
rr->top = max;
}
rr->width = max;
if (rr != r && !BN_copy(r, rr)) {
goto err;
@@ -884,6 +831,15 @@ err:
return ret;
}
int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
if (!bn_sqr_fixed(r, a, ctx)) {
return 0;
}
bn_set_minimal_width(r);
return 1;
}
int bn_sqr_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a) {
if (num_r != 2 * num_a || num_a > BN_SMALL_MAX_WORDS) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+2 -3
View File
@@ -586,9 +586,8 @@ int BN_enhanced_miller_rabin_primality_test(
}
// Montgomery setup for computations mod A
mont = BN_MONT_CTX_new();
if (mont == NULL ||
!BN_MONT_CTX_set(mont, w, ctx)) {
mont = BN_MONT_CTX_new_for_modulus(w, ctx);
if (mont == NULL) {
goto err;
}
+3 -4
View File
@@ -278,15 +278,14 @@ int bn_rand_range_words(BN_ULONG *out, BN_ULONG min_inclusive,
int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive,
const BIGNUM *max_exclusive) {
if (!bn_wexpand(r, max_exclusive->top) ||
if (!bn_wexpand(r, max_exclusive->width) ||
!bn_rand_range_words(r->d, min_inclusive, max_exclusive->d,
max_exclusive->top, kDefaultAdditionalData)) {
max_exclusive->width, kDefaultAdditionalData)) {
return 0;
}
r->neg = 0;
r->top = max_exclusive->top;
bn_correct_top(r);
r->width = max_exclusive->width;
return 1;
}
+186 -209
View File
@@ -1,44 +1,16 @@
/*****************************************************************************
* *
* Copyright (c) 2012, Intel Corporation *
* *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions are *
* met: *
* *
* * Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the *
* distribution. *
* *
* * Neither the name of the Intel Corporation nor the names of its *
* contributors may be used to endorse or promote products derived from *
* this software without specific prior written permission. *
* *
* *
* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY *
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE *
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR *
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* *
******************************************************************************
* Developers and authors: *
* Shay Gueron (1, 2), and Vlad Krasnov (1) *
* (1) Intel Corporation, Israel Development Center, Haifa, Israel *
* (2) University of Haifa, Israel *
*****************************************************************************/
/*
* Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2012, Intel Corporation. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*
* Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1)
* (1) Intel Corporation, Israel Development Center, Haifa, Israel
* (2) University of Haifa, Israel
*/
#include <openssl/base.h>
@@ -51,204 +23,209 @@
#include "../../internal.h"
/*
* See crypto/bn/asm/rsaz-avx2.pl for further details.
*/
void rsaz_1024_norm2red_avx2(void *red,const void *norm);
void rsaz_1024_mul_avx2(void *ret,const void *a,const void *b,const void *n,BN_ULONG k);
void rsaz_1024_sqr_avx2(void *ret,const void *a,const void *n,BN_ULONG k,int cnt);
void rsaz_1024_scatter5_avx2(void *tbl,const void *val,int i);
void rsaz_1024_gather5_avx2(void *val,const void *tbl,int i);
void rsaz_1024_red2norm_avx2(void *norm,const void *red);
// See crypto/bn/asm/rsaz-avx2.pl for further details.
void rsaz_1024_norm2red_avx2(void *red, const void *norm);
void rsaz_1024_mul_avx2(void *ret, const void *a, const void *b, const void *n,
BN_ULONG k);
void rsaz_1024_sqr_avx2(void *ret, const void *a, const void *n, BN_ULONG k,
int cnt);
void rsaz_1024_scatter5_avx2(void *tbl, const void *val, int i);
void rsaz_1024_gather5_avx2(void *val, const void *tbl, int i);
void rsaz_1024_red2norm_avx2(void *norm, const void *red);
alignas(64) static const BN_ULONG one[40] =
{1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
alignas(64) static const BN_ULONG two80[40] =
{0,0,1<<22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// one is 1 in RSAZ's representation.
alignas(64) static const BN_ULONG one[40] = {
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// two80 is 2^80 in RSAZ's representation. Note RSAZ uses base 2^29, so this is
// 2^(29*2 + 22) = 2^80, not 2^(64*2 + 22).
alignas(64) static const BN_ULONG two80[40] = {
0, 0, 1 << 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16],
const BN_ULONG base_norm[16], const BN_ULONG exponent[16],
const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0)
{
alignas(64) uint8_t storage[(320 * 3) + (32 * 9 * 16)]; /* 5.5KB */
unsigned char *a_inv, *m, *result,
*table_s = storage + (320 * 3),
*R2 = table_s; /* borrow */
int index;
int wvalue;
const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0) {
alignas(64) uint8_t storage[(320 * 3) + (32 * 9 * 16)]; // 5.5KB
unsigned char *a_inv, *m, *result, *table_s = storage + (320 * 3),
*R2 = table_s; // borrow
if (((((uintptr_t)storage & 4095) + 320) >> 12) != 0) {
result = storage;
a_inv = storage + 320;
m = storage + (320 * 2); // should not cross page
} else {
m = storage; // should not cross page
result = storage + 320;
a_inv = storage + (320 * 2);
}
if (((((uintptr_t)storage & 4095) + 320) >> 12) != 0) {
result = storage;
a_inv = storage + 320;
m = storage + (320 * 2); /* should not cross page */
} else {
m = storage; /* should not cross page */
result = storage + 320;
a_inv = storage + (320 * 2);
}
rsaz_1024_norm2red_avx2(m, m_norm);
rsaz_1024_norm2red_avx2(a_inv, base_norm);
rsaz_1024_norm2red_avx2(R2, RR);
rsaz_1024_norm2red_avx2(m, m_norm);
rsaz_1024_norm2red_avx2(a_inv, base_norm);
rsaz_1024_norm2red_avx2(R2, RR);
// Convert |R2| from the usual radix, giving R = 2^1024, to RSAZ's radix,
// giving R = 2^(36*29) = 2^1044.
rsaz_1024_mul_avx2(R2, R2, R2, m, k0);
// R2 = 2^2048 * 2^2048 / 2^1044 = 2^3052
rsaz_1024_mul_avx2(R2, R2, two80, m, k0);
// R2 = 2^3052 * 2^80 / 2^1044 = 2^2088 = (2^1044)^2
rsaz_1024_mul_avx2(R2, R2, R2, m, k0);
rsaz_1024_mul_avx2(R2, R2, two80, m, k0);
// table[0] = 1
rsaz_1024_mul_avx2(result, R2, one, m, k0);
// table[1] = a_inv^1
rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0);
/* table[0] = 1 */
rsaz_1024_mul_avx2(result, R2, one, m, k0);
/* table[1] = a_inv^1 */
rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 0);
rsaz_1024_scatter5_avx2(table_s, a_inv, 1);
rsaz_1024_scatter5_avx2(table_s,result,0);
rsaz_1024_scatter5_avx2(table_s,a_inv,1);
/* table[2] = a_inv^2 */
rsaz_1024_sqr_avx2(result, a_inv, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,2);
// table[2] = a_inv^2
rsaz_1024_sqr_avx2(result, a_inv, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 2);
#if 0
/* this is almost 2x smaller and less than 1% slower */
for (index=3; index<32; index++) {
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s,result,index);
}
// This is almost 2x smaller and less than 1% slower.
for (int index = 3; index < 32; index++) {
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, index);
}
#else
/* table[4] = a_inv^4 */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,4);
/* table[8] = a_inv^8 */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,8);
/* table[16] = a_inv^16 */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,16);
/* table[17] = a_inv^17 */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s,result,17);
// table[4] = a_inv^4
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 4);
// table[8] = a_inv^8
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 8);
// table[16] = a_inv^16
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 16);
// table[17] = a_inv^17
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 17);
/* table[3] */
rsaz_1024_gather5_avx2(result,table_s,2);
rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
rsaz_1024_scatter5_avx2(table_s,result,3);
/* table[6] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,6);
/* table[12] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,12);
/* table[24] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,24);
/* table[25] */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s,result,25);
// table[3]
rsaz_1024_gather5_avx2(result, table_s, 2);
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 3);
// table[6]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 6);
// table[12]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 12);
// table[24]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 24);
// table[25]
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 25);
/* table[5] */
rsaz_1024_gather5_avx2(result,table_s,4);
rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
rsaz_1024_scatter5_avx2(table_s,result,5);
/* table[10] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,10);
/* table[20] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,20);
/* table[21] */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s,result,21);
// table[5]
rsaz_1024_gather5_avx2(result, table_s, 4);
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 5);
// table[10]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 10);
// table[20]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 20);
// table[21]
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 21);
/* table[7] */
rsaz_1024_gather5_avx2(result,table_s,6);
rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
rsaz_1024_scatter5_avx2(table_s,result,7);
/* table[14] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,14);
/* table[28] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,28);
/* table[29] */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s,result,29);
// table[7]
rsaz_1024_gather5_avx2(result, table_s, 6);
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 7);
// table[14]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 14);
// table[28]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 28);
// table[29]
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 29);
/* table[9] */
rsaz_1024_gather5_avx2(result,table_s,8);
rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
rsaz_1024_scatter5_avx2(table_s,result,9);
/* table[18] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,18);
/* table[19] */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s,result,19);
// table[9]
rsaz_1024_gather5_avx2(result, table_s, 8);
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 9);
// table[18]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 18);
// table[19]
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 19);
/* table[11] */
rsaz_1024_gather5_avx2(result,table_s,10);
rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
rsaz_1024_scatter5_avx2(table_s,result,11);
/* table[22] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,22);
/* table[23] */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s,result,23);
// table[11]
rsaz_1024_gather5_avx2(result, table_s, 10);
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 11);
// table[22]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 22);
// table[23]
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 23);
/* table[13] */
rsaz_1024_gather5_avx2(result,table_s,12);
rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
rsaz_1024_scatter5_avx2(table_s,result,13);
/* table[26] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,26);
/* table[27] */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s,result,27);
// table[13]
rsaz_1024_gather5_avx2(result, table_s, 12);
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 13);
// table[26]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 26);
// table[27]
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 27);
/* table[15] */
rsaz_1024_gather5_avx2(result,table_s,14);
rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
rsaz_1024_scatter5_avx2(table_s,result,15);
/* table[30] */
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s,result,30);
/* table[31] */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s,result,31);
// table[15]
rsaz_1024_gather5_avx2(result, table_s, 14);
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 15);
// table[30]
rsaz_1024_sqr_avx2(result, result, m, k0, 1);
rsaz_1024_scatter5_avx2(table_s, result, 30);
// table[31]
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 31);
#endif
const uint8_t *p_str = (const uint8_t *)exponent;
const uint8_t *p_str = (const uint8_t *)exponent;
/* load first window */
wvalue = p_str[127] >> 3;
rsaz_1024_gather5_avx2(result,table_s,wvalue);
// load first window
int wvalue = p_str[127] >> 3;
rsaz_1024_gather5_avx2(result, table_s, wvalue);
index = 1014;
int index = 1014;
while (index > -1) { // Loop for the remaining 127 windows.
while(index > -1) { /* loop for the remaining 127 windows */
rsaz_1024_sqr_avx2(result, result, m, k0, 5);
rsaz_1024_sqr_avx2(result, result, m, k0, 5);
uint16_t wvalue_16;
memcpy(&wvalue_16, &p_str[index / 8], sizeof(wvalue_16));
wvalue = wvalue_16;
wvalue = (wvalue >> (index % 8)) & 31;
index -= 5;
wvalue = *((const unsigned short*)&p_str[index / 8]);
wvalue = (wvalue>> (index%8)) & 31;
index-=5;
rsaz_1024_gather5_avx2(a_inv, table_s, wvalue); // Borrow |a_inv|.
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
}
rsaz_1024_gather5_avx2(a_inv,table_s,wvalue); /* borrow a_inv */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
}
// Square four times.
rsaz_1024_sqr_avx2(result, result, m, k0, 4);
/* square four times */
rsaz_1024_sqr_avx2(result, result, m, k0, 4);
wvalue = p_str[0] & 15;
wvalue = p_str[0] & 15;
rsaz_1024_gather5_avx2(a_inv, table_s, wvalue); // Borrow |a_inv|.
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
rsaz_1024_gather5_avx2(a_inv,table_s,wvalue); /* borrow a_inv */
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
// Convert from Montgomery.
rsaz_1024_mul_avx2(result, result, one, m, k0);
/* from Montgomery */
rsaz_1024_mul_avx2(result, result, one, m, k0);
rsaz_1024_red2norm_avx2(result_norm, result);
rsaz_1024_red2norm_avx2(result_norm, result);
OPENSSL_cleanse(storage,sizeof(storage));
OPENSSL_cleanse(storage, sizeof(storage));
}
#endif /* OPENSSL_X86_64 */
#endif // OPENSSL_X86_64
+27 -47
View File
@@ -1,53 +1,33 @@
/*****************************************************************************
* *
* Copyright (c) 2012, Intel Corporation *
* *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions are *
* met: *
* *
* * Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the *
* distribution. *
* *
* * Neither the name of the Intel Corporation nor the names of its *
* contributors may be used to endorse or promote products derived from *
* this software without specific prior written permission. *
* *
* *
* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY *
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE *
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR *
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* *
******************************************************************************
* Developers and authors: *
* Shay Gueron (1, 2), and Vlad Krasnov (1) *
* (1) Intel Corporation, Israel Development Center, Haifa, Israel *
* (2) University of Haifa, Israel *
*****************************************************************************/
/*
* Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2012, Intel Corporation. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*
* Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1)
* (1) Intel Corporation, Israel Development Center, Haifa, Israel
* (2) University of Haifa, Israel
*/
#ifndef RSAZ_EXP_H
#define RSAZ_EXP_H
#ifndef OPENSSL_HEADER_BN_RSAZ_EXP_H
#define OPENSSL_HEADER_BN_RSAZ_EXP_H
#include <openssl/bn.h>
void RSAZ_1024_mod_exp_avx2(BN_ULONG result[16],
const BN_ULONG base_norm[16], const BN_ULONG exponent[16],
const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0);
// RSAZ_1024_mod_exp_avx2 sets |result| to |base_norm| raised to |exponent|
// modulo |m_norm|. |base_norm| must be fully-reduced and |exponent| must have
// the high bit set (it is 1024 bits wide). |RR| and |k0| must be |RR| and |n0|,
// respectively, extracted from |m_norm|'s |BN_MONT_CTX|.
void RSAZ_1024_mod_exp_avx2(BN_ULONG result[16], const BN_ULONG base_norm[16],
const BN_ULONG exponent[16],
const BN_ULONG m_norm[16], const BN_ULONG RR[16],
BN_ULONG k0);
// rsaz_avx2_eligible returns one if |RSAZ_1024_mod_exp_avx2| should be used and
// zero otherwise.
int rsaz_avx2_eligible(void);
#endif
#endif // OPENSSL_HEADER_BN_RSAZ_EXP_H
+45 -28
View File
@@ -75,28 +75,28 @@ int BN_lshift(BIGNUM *r, const BIGNUM *a, int n) {
r->neg = a->neg;
nw = n / BN_BITS2;
if (!bn_wexpand(r, a->top + nw + 1)) {
if (!bn_wexpand(r, a->width + nw + 1)) {
return 0;
}
lb = n % BN_BITS2;
rb = BN_BITS2 - lb;
f = a->d;
t = r->d;
t[a->top + nw] = 0;
t[a->width + nw] = 0;
if (lb == 0) {
for (i = a->top - 1; i >= 0; i--) {
for (i = a->width - 1; i >= 0; i--) {
t[nw + i] = f[i];
}
} else {
for (i = a->top - 1; i >= 0; i--) {
for (i = a->width - 1; i >= 0; i--) {
l = f[i];
t[nw + i + 1] |= l >> rb;
t[nw + i] = l << lb;
}
}
OPENSSL_memset(t, 0, nw * sizeof(t[0]));
r->top = a->top + nw + 1;
bn_correct_top(r);
r->width = a->width + nw + 1;
bn_set_minimal_width(r);
return 1;
}
@@ -107,26 +107,26 @@ int BN_lshift1(BIGNUM *r, const BIGNUM *a) {
if (r != a) {
r->neg = a->neg;
if (!bn_wexpand(r, a->top + 1)) {
if (!bn_wexpand(r, a->width + 1)) {
return 0;
}
r->top = a->top;
r->width = a->width;
} else {
if (!bn_wexpand(r, a->top + 1)) {
if (!bn_wexpand(r, a->width + 1)) {
return 0;
}
}
ap = a->d;
rp = r->d;
c = 0;
for (i = 0; i < a->top; i++) {
for (i = 0; i < a->width; i++) {
t = *(ap++);
*(rp++) = (t << 1) | c;
c = t >> (BN_BITS2 - 1);
}
if (c) {
*rp = 1;
r->top++;
r->width++;
}
return 1;
@@ -142,10 +142,11 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) {
return 0;
}
int a_width = bn_minimal_width(a);
nw = n / BN_BITS2;
rb = n % BN_BITS2;
lb = BN_BITS2 - rb;
if (nw >= a->top || a->top == 0) {
if (nw >= a_width || a_width == 0) {
BN_zero(r);
return 1;
}
@@ -163,8 +164,8 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) {
f = &(a->d[nw]);
t = r->d;
j = a->top - nw;
r->top = i;
j = a_width - nw;
r->width = i;
if (rb == 0) {
for (i = j; i != 0; i--) {
@@ -183,7 +184,7 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) {
}
}
if (r->top == 0) {
if (r->width == 0) {
r->neg = 0;
}
@@ -198,7 +199,7 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) {
BN_zero(r);
return 1;
}
i = a->top;
i = bn_minimal_width(a);
ap = a->d;
j = i - (ap[i - 1] == 1);
if (a != r) {
@@ -218,9 +219,9 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) {
rp[i] = (t >> 1) | c;
c = t << (BN_BITS2 - 1);
}
r->top = j;
r->width = j;
if (r->top == 0) {
if (r->width == 0) {
r->neg = 0;
}
@@ -234,14 +235,14 @@ int BN_set_bit(BIGNUM *a, int n) {
int i = n / BN_BITS2;
int j = n % BN_BITS2;
if (a->top <= i) {
if (a->width <= i) {
if (!bn_wexpand(a, i + 1)) {
return 0;
}
for (int k = a->top; k < i + 1; k++) {
for (int k = a->width; k < i + 1; k++) {
a->d[k] = 0;
}
a->top = i + 1;
a->width = i + 1;
}
a->d[i] |= (((BN_ULONG)1) << j);
@@ -258,12 +259,12 @@ int BN_clear_bit(BIGNUM *a, int n) {
i = n / BN_BITS2;
j = n % BN_BITS2;
if (a->top <= i) {
if (a->width <= i) {
return 0;
}
a->d[i] &= (~(((BN_ULONG)1) << j));
bn_correct_top(a);
bn_set_minimal_width(a);
return 1;
}
@@ -280,7 +281,7 @@ int BN_is_bit_set(const BIGNUM *a, int n) {
if (n < 0) {
return 0;
}
return bn_is_bit_set_words(a->d, a->top, n);
return bn_is_bit_set_words(a->d, a->width, n);
}
int BN_mask_bits(BIGNUM *a, int n) {
@@ -290,16 +291,32 @@ int BN_mask_bits(BIGNUM *a, int n) {
int w = n / BN_BITS2;
int b = n % BN_BITS2;
if (w >= a->top) {
if (w >= a->width) {
return 0;
}
if (b == 0) {
a->top = w;
a->width = w;
} else {
a->top = w + 1;
a->width = w + 1;
a->d[w] &= ~(BN_MASK2 << b);
}
bn_correct_top(a);
bn_set_minimal_width(a);
return 1;
}
int BN_count_low_zero_bits(const BIGNUM *bn) {
for (int i = 0; i < bn->width; i++) {
if (bn->d[i] != 0) {
int bits = 0;
for (BN_ULONG w = bn->d[i]; (w & 1) == 0; w >>= 1) {
bits++;
}
return i * BN_BITS2 + bits;
}
}
// We got to the end of |bn| and saw no non-zero words. |bn| is zero, so
// return zero.
return 0;
}
+1 -1
View File
@@ -184,7 +184,7 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) {
// November 1992.)
// t := 2*a
if (!BN_mod_lshift1_quick(t, A, p)) {
if (!bn_mod_lshift1_quick_ctx(t, A, p, ctx)) {
goto end;
}
+10 -10
View File
@@ -1148,7 +1148,7 @@ struct aead_aes_gcm_ctx {
struct aead_aes_gcm_tls12_ctx {
struct aead_aes_gcm_ctx gcm_ctx;
uint64_t counter;
uint64_t min_next_nonce;
};
static int aead_aes_gcm_init_impl(struct aead_aes_gcm_ctx *gcm_ctx,
@@ -1349,7 +1349,7 @@ static int aead_aes_gcm_tls12_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
return 0;
}
gcm_ctx->counter = 0;
gcm_ctx->min_next_nonce = 0;
size_t actual_tag_len;
if (!aead_aes_gcm_init_impl(&gcm_ctx->gcm_ctx, &actual_tag_len, key, key_len,
@@ -1373,23 +1373,23 @@ static int aead_aes_gcm_tls12_seal_scatter(
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
struct aead_aes_gcm_tls12_ctx *gcm_ctx = ctx->aead_state;
if (gcm_ctx->counter == UINT64_MAX) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE);
return 0;
}
if (nonce_len != 12) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
return 0;
}
const uint64_t be_counter = CRYPTO_bswap8(gcm_ctx->counter);
if (OPENSSL_memcmp((uint8_t *)&be_counter, nonce + nonce_len - 8, 8) != 0) {
// The given nonces must be strictly monotonically increasing.
uint64_t given_counter;
OPENSSL_memcpy(&given_counter, nonce + nonce_len - sizeof(given_counter),
sizeof(given_counter));
given_counter = CRYPTO_bswap8(given_counter);
if (given_counter == UINT64_MAX ||
given_counter < gcm_ctx->min_next_nonce) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE);
return 0;
}
gcm_ctx->counter++;
gcm_ctx->min_next_nonce = given_counter + 1;
return aead_aes_gcm_seal_scatter(ctx, out, out_tag, out_tag_len,
max_out_tag_len, nonce, nonce_len, in,
+2
View File
@@ -59,6 +59,8 @@
#include <openssl/base.h>
#include "../../internal.h"
#if defined(__cplusplus)
extern "C" {
#endif
+489 -97
View File
@@ -1,44 +1,40 @@
#!/usr/bin/env perl
# Copyright (c) 2014, Intel Corporation.
#! /usr/bin/env perl
# Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
# Copyright (c) 2014, Intel Corporation. All Rights Reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# Developers and authors:
# Shay Gueron (1, 2), and Vlad Krasnov (1)
# (1) Intel Corporation, Israel Development Center
# (2) University of Haifa
# Reference:
# S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with
# 256 Bit Primes"
# Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1)
# (1) Intel Corporation, Israel Development Center, Haifa, Israel
# (2) University of Haifa, Israel
#
# Reference:
# S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with
# 256 Bit Primes"
# Further optimization by <appro@openssl.org>:
#
# this/original
# Opteron +12-49%
# Bulldozer +14-45%
# P4 +18-46%
# Westmere +12-34%
# Sandy Bridge +9-35%
# Ivy Bridge +9-35%
# Haswell +8-37%
# Broadwell +18-58%
# Atom +15-50%
# VIA Nano +43-160%
# this/original with/without -DECP_NISTZ256_ASM(*)
# Opteron +12-49% +110-150%
# Bulldozer +14-45% +175-210%
# P4 +18-46% n/a :-(
# Westmere +12-34% +80-87%
# Sandy Bridge +9-35% +110-120%
# Ivy Bridge +9-35% +110-125%
# Haswell +8-37% +140-160%
# Broadwell +18-58% +145-210%
# Atom +15-50% +130-180%
# VIA Nano +43-160% +300-480%
#
# (*) "without -DECP_NISTZ256_ASM" refers to build with
# "enable-ec_nistp_64_gcc_128";
#
# Ranges denote minimum and maximum improvement coefficients depending
# on benchmark.
# on benchmark. Lower coefficients are for ECDSA sign, relatively fastest
# server-side operation. Keep in mind that +100% means 2x improvement.
$flavour = shift;
$output = shift;
@@ -90,8 +86,12 @@ $code.=<<___;
.type ecp_nistz256_neg,\@function,2
.align 32
ecp_nistz256_neg:
.cfi_startproc
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
.Lneg_body:
xor $a0, $a0
xor $a1, $a1
@@ -125,9 +125,15 @@ ecp_nistz256_neg:
mov $a2, 8*2($r_ptr)
mov $a3, 8*3($r_ptr)
pop %r13
pop %r12
mov 0(%rsp),%r13
.cfi_restore %r13
mov 8(%rsp),%r12
.cfi_restore %r12
lea 16(%rsp),%rsp
.cfi_adjust_cfa_offset -16
.Lneg_epilogue:
ret
.cfi_endproc
.size ecp_nistz256_neg,.-ecp_nistz256_neg
___
}
@@ -148,6 +154,7 @@ $code.=<<___;
.type ecp_nistz256_mul_mont,\@function,3
.align 32
ecp_nistz256_mul_mont:
.cfi_startproc
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -157,11 +164,18 @@ ___
$code.=<<___;
.Lmul_mont:
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
.Lmul_body:
___
$code.=<<___ if ($addx);
cmp \$0x80100, %ecx
@@ -194,13 +208,23 @@ $code.=<<___ if ($addx);
___
$code.=<<___;
.Lmul_mont_done:
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
mov 0(%rsp),%r15
.cfi_restore %r15
mov 8(%rsp),%r14
.cfi_restore %r14
mov 16(%rsp),%r13
.cfi_restore %r13
mov 24(%rsp),%r12
.cfi_restore %r12
mov 32(%rsp),%rbx
.cfi_restore %rbx
mov 40(%rsp),%rbp
.cfi_restore %rbp
lea 48(%rsp),%rsp
.cfi_adjust_cfa_offset -48
.Lmul_epilogue:
ret
.cfi_endproc
.size ecp_nistz256_mul_mont,.-ecp_nistz256_mul_mont
.type __ecp_nistz256_mul_montq,\@abi-omnipotent
@@ -430,6 +454,7 @@ __ecp_nistz256_mul_montq:
.type ecp_nistz256_sqr_mont,\@function,2
.align 32
ecp_nistz256_sqr_mont:
.cfi_startproc
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -438,11 +463,18 @@ $code.=<<___ if ($addx);
___
$code.=<<___;
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
.Lsqr_body:
___
$code.=<<___ if ($addx);
cmp \$0x80100, %ecx
@@ -471,13 +503,23 @@ $code.=<<___ if ($addx);
___
$code.=<<___;
.Lsqr_mont_done:
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
mov 0(%rsp),%r15
.cfi_restore %r15
mov 8(%rsp),%r14
.cfi_restore %r14
mov 16(%rsp),%r13
.cfi_restore %r13
mov 24(%rsp),%r12
.cfi_restore %r12
mov 32(%rsp),%rbx
.cfi_restore %rbx
mov 40(%rsp),%rbp
.cfi_restore %rbp
lea 48(%rsp),%rsp
.cfi_adjust_cfa_offset -48
.Lsqr_epilogue:
ret
.cfi_endproc
.size ecp_nistz256_sqr_mont,.-ecp_nistz256_sqr_mont
.type __ecp_nistz256_sqr_montq,\@abi-omnipotent
@@ -1041,10 +1083,10 @@ $code.=<<___ if ($win64);
movaps 0x80(%rsp), %xmm14
movaps 0x90(%rsp), %xmm15
lea 0xa8(%rsp), %rsp
.LSEH_end_ecp_nistz256_select_w5:
___
$code.=<<___;
ret
.LSEH_end_ecp_nistz256_select_w5:
.size ecp_nistz256_select_w5,.-ecp_nistz256_select_w5
################################################################################
@@ -1128,10 +1170,10 @@ $code.=<<___ if ($win64);
movaps 0x80(%rsp), %xmm14
movaps 0x90(%rsp), %xmm15
lea 0xa8(%rsp), %rsp
.LSEH_end_ecp_nistz256_select_w7:
___
$code.=<<___;
ret
.LSEH_end_ecp_nistz256_select_w7:
.size ecp_nistz256_select_w7,.-ecp_nistz256_select_w7
___
}
@@ -1152,18 +1194,19 @@ ecp_nistz256_avx2_select_w5:
___
$code.=<<___ if ($win64);
lea -0x88(%rsp), %rax
mov %rsp,%r11
.LSEH_begin_ecp_nistz256_avx2_select_w5:
.byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax), %rsp
.byte 0xc5,0xf8,0x29,0x70,0xe0 #vmovaps %xmm6, -0x20(%rax)
.byte 0xc5,0xf8,0x29,0x78,0xf0 #vmovaps %xmm7, -0x10(%rax)
.byte 0xc5,0x78,0x29,0x40,0x00 #vmovaps %xmm8, 8(%rax)
.byte 0xc5,0x78,0x29,0x48,0x10 #vmovaps %xmm9, 0x10(%rax)
.byte 0xc5,0x78,0x29,0x50,0x20 #vmovaps %xmm10, 0x20(%rax)
.byte 0xc5,0x78,0x29,0x58,0x30 #vmovaps %xmm11, 0x30(%rax)
.byte 0xc5,0x78,0x29,0x60,0x40 #vmovaps %xmm12, 0x40(%rax)
.byte 0xc5,0x78,0x29,0x68,0x50 #vmovaps %xmm13, 0x50(%rax)
.byte 0xc5,0x78,0x29,0x70,0x60 #vmovaps %xmm14, 0x60(%rax)
.byte 0xc5,0x78,0x29,0x78,0x70 #vmovaps %xmm15, 0x70(%rax)
.byte 0x48,0x8d,0x60,0xe0 # lea -0x20(%rax), %rsp
.byte 0xc5,0xf8,0x29,0x70,0xe0 # vmovaps %xmm6, -0x20(%rax)
.byte 0xc5,0xf8,0x29,0x78,0xf0 # vmovaps %xmm7, -0x10(%rax)
.byte 0xc5,0x78,0x29,0x40,0x00 # vmovaps %xmm8, 8(%rax)
.byte 0xc5,0x78,0x29,0x48,0x10 # vmovaps %xmm9, 0x10(%rax)
.byte 0xc5,0x78,0x29,0x50,0x20 # vmovaps %xmm10, 0x20(%rax)
.byte 0xc5,0x78,0x29,0x58,0x30 # vmovaps %xmm11, 0x30(%rax)
.byte 0xc5,0x78,0x29,0x60,0x40 # vmovaps %xmm12, 0x40(%rax)
.byte 0xc5,0x78,0x29,0x68,0x50 # vmovaps %xmm13, 0x50(%rax)
.byte 0xc5,0x78,0x29,0x70,0x60 # vmovaps %xmm14, 0x60(%rax)
.byte 0xc5,0x78,0x29,0x78,0x70 # vmovaps %xmm15, 0x70(%rax)
___
$code.=<<___;
vmovdqa .LTwo(%rip), $TWO
@@ -1229,11 +1272,11 @@ $code.=<<___ if ($win64);
movaps 0x70(%rsp), %xmm13
movaps 0x80(%rsp), %xmm14
movaps 0x90(%rsp), %xmm15
lea 0xa8(%rsp), %rsp
.LSEH_end_ecp_nistz256_avx2_select_w5:
lea (%r11), %rsp
___
$code.=<<___;
ret
.LSEH_end_ecp_nistz256_avx2_select_w5:
.size ecp_nistz256_avx2_select_w5,.-ecp_nistz256_avx2_select_w5
___
}
@@ -1256,19 +1299,20 @@ ecp_nistz256_avx2_select_w7:
vzeroupper
___
$code.=<<___ if ($win64);
mov %rsp,%r11
lea -0x88(%rsp), %rax
.LSEH_begin_ecp_nistz256_avx2_select_w7:
.byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax), %rsp
.byte 0xc5,0xf8,0x29,0x70,0xe0 #vmovaps %xmm6, -0x20(%rax)
.byte 0xc5,0xf8,0x29,0x78,0xf0 #vmovaps %xmm7, -0x10(%rax)
.byte 0xc5,0x78,0x29,0x40,0x00 #vmovaps %xmm8, 8(%rax)
.byte 0xc5,0x78,0x29,0x48,0x10 #vmovaps %xmm9, 0x10(%rax)
.byte 0xc5,0x78,0x29,0x50,0x20 #vmovaps %xmm10, 0x20(%rax)
.byte 0xc5,0x78,0x29,0x58,0x30 #vmovaps %xmm11, 0x30(%rax)
.byte 0xc5,0x78,0x29,0x60,0x40 #vmovaps %xmm12, 0x40(%rax)
.byte 0xc5,0x78,0x29,0x68,0x50 #vmovaps %xmm13, 0x50(%rax)
.byte 0xc5,0x78,0x29,0x70,0x60 #vmovaps %xmm14, 0x60(%rax)
.byte 0xc5,0x78,0x29,0x78,0x70 #vmovaps %xmm15, 0x70(%rax)
.byte 0x48,0x8d,0x60,0xe0 # lea -0x20(%rax), %rsp
.byte 0xc5,0xf8,0x29,0x70,0xe0 # vmovaps %xmm6, -0x20(%rax)
.byte 0xc5,0xf8,0x29,0x78,0xf0 # vmovaps %xmm7, -0x10(%rax)
.byte 0xc5,0x78,0x29,0x40,0x00 # vmovaps %xmm8, 8(%rax)
.byte 0xc5,0x78,0x29,0x48,0x10 # vmovaps %xmm9, 0x10(%rax)
.byte 0xc5,0x78,0x29,0x50,0x20 # vmovaps %xmm10, 0x20(%rax)
.byte 0xc5,0x78,0x29,0x58,0x30 # vmovaps %xmm11, 0x30(%rax)
.byte 0xc5,0x78,0x29,0x60,0x40 # vmovaps %xmm12, 0x40(%rax)
.byte 0xc5,0x78,0x29,0x68,0x50 # vmovaps %xmm13, 0x50(%rax)
.byte 0xc5,0x78,0x29,0x70,0x60 # vmovaps %xmm14, 0x60(%rax)
.byte 0xc5,0x78,0x29,0x78,0x70 # vmovaps %xmm15, 0x70(%rax)
___
$code.=<<___;
vmovdqa .LThree(%rip), $THREE
@@ -1349,11 +1393,11 @@ $code.=<<___ if ($win64);
movaps 0x70(%rsp), %xmm13
movaps 0x80(%rsp), %xmm14
movaps 0x90(%rsp), %xmm15
lea 0xa8(%rsp), %rsp
.LSEH_end_ecp_nistz256_avx2_select_w7:
lea (%r11), %rsp
___
$code.=<<___;
ret
.LSEH_end_ecp_nistz256_avx2_select_w7:
.size ecp_nistz256_avx2_select_w7,.-ecp_nistz256_avx2_select_w7
___
} else {
@@ -1557,6 +1601,7 @@ $code.=<<___;
.type ecp_nistz256_point_double,\@function,2
.align 32
ecp_nistz256_point_double:
.cfi_startproc
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -1574,17 +1619,26 @@ $code.=<<___;
.type ecp_nistz256_point_doublex,\@function,2
.align 32
ecp_nistz256_point_doublex:
.cfi_startproc
.Lpoint_doublex:
___
}
$code.=<<___;
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
sub \$32*5+8, %rsp
.cfi_adjust_cfa_offset 32*5+8
.Lpoint_double${x}_body:
.Lpoint_double_shortcut$x:
movdqu 0x00($a_ptr), %xmm0 # copy *(P256_POINT *)$a_ptr.x
@@ -1755,14 +1809,25 @@ $code.=<<___;
movq %xmm1, $r_ptr
call __ecp_nistz256_sub_from$x # p256_sub(res_y, S, res_y);
add \$32*5+8, %rsp
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
lea 32*5+56(%rsp), %rsi
.cfi_def_cfa %rsi,8
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbx
.cfi_restore %rbx
mov -8(%rsi),%rbp
.cfi_restore %rbp
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lpoint_double${x}_epilogue:
ret
.cfi_endproc
.size ecp_nistz256_point_double$sfx,.-ecp_nistz256_point_double$sfx
___
}
@@ -1788,6 +1853,7 @@ $code.=<<___;
.type ecp_nistz256_point_add,\@function,3
.align 32
ecp_nistz256_point_add:
.cfi_startproc
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -1805,17 +1871,26 @@ $code.=<<___;
.type ecp_nistz256_point_addx,\@function,3
.align 32
ecp_nistz256_point_addx:
.cfi_startproc
.Lpoint_addx:
___
}
$code.=<<___;
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
sub \$32*18+8, %rsp
.cfi_adjust_cfa_offset 32*18+8
.Lpoint_add${x}_body:
movdqu 0x00($a_ptr), %xmm0 # copy *(P256_POINT *)$a_ptr
movdqu 0x10($a_ptr), %xmm1
@@ -2124,14 +2199,25 @@ $code.=<<___;
movdqu %xmm3, 0x30($r_ptr)
.Ladd_done$x:
add \$32*18+8, %rsp
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
lea 32*18+56(%rsp), %rsi
.cfi_def_cfa %rsi,8
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbx
.cfi_restore %rbx
mov -8(%rsi),%rbp
.cfi_restore %rbp
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lpoint_add${x}_epilogue:
ret
.cfi_endproc
.size ecp_nistz256_point_add$sfx,.-ecp_nistz256_point_add$sfx
___
}
@@ -2156,6 +2242,7 @@ $code.=<<___;
.type ecp_nistz256_point_add_affine,\@function,3
.align 32
ecp_nistz256_point_add_affine:
.cfi_startproc
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -2173,17 +2260,26 @@ $code.=<<___;
.type ecp_nistz256_point_add_affinex,\@function,3
.align 32
ecp_nistz256_point_add_affinex:
.cfi_startproc
.Lpoint_add_affinex:
___
}
$code.=<<___;
push %rbp
.cfi_push %rbp
push %rbx
.cfi_push %rbx
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
sub \$32*15+8, %rsp
.cfi_adjust_cfa_offset 32*15+8
.Ladd_affine${x}_body:
movdqu 0x00($a_ptr), %xmm0 # copy *(P256_POINT *)$a_ptr
mov $b_org, $b_ptr # reassign
@@ -2428,14 +2524,25 @@ $code.=<<___;
movdqu %xmm2, 0x20($r_ptr)
movdqu %xmm3, 0x30($r_ptr)
add \$32*15+8, %rsp
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
lea 32*15+56(%rsp), %rsi
.cfi_def_cfa %rsi,8
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbx
.cfi_restore %rbx
mov -8(%rsi),%rbp
.cfi_restore %rbp
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Ladd_affine${x}_epilogue:
ret
.cfi_endproc
.size ecp_nistz256_point_add_affine$sfx,.-ecp_nistz256_point_add_affine$sfx
___
}
@@ -2586,6 +2693,291 @@ ___
}
}}}
# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
# CONTEXT *context,DISPATCHER_CONTEXT *disp)
if ($win64) {
$rec="%rcx";
$frame="%rdx";
$context="%r8";
$disp="%r9";
$code.=<<___;
.extern __imp_RtlVirtualUnwind
.type short_handler,\@abi-omnipotent
.align 16
short_handler:
push %rsi
push %rdi
push %rbx
push %rbp
push %r12
push %r13
push %r14
push %r15
pushfq
sub \$64,%rsp
mov 120($context),%rax # pull context->Rax
mov 248($context),%rbx # pull context->Rip
mov 8($disp),%rsi # disp->ImageBase
mov 56($disp),%r11 # disp->HandlerData
mov 0(%r11),%r10d # HandlerData[0]
lea (%rsi,%r10),%r10 # end of prologue label
cmp %r10,%rbx # context->Rip<end of prologue label
jb .Lcommon_seh_tail
mov 152($context),%rax # pull context->Rsp
mov 4(%r11),%r10d # HandlerData[1]
lea (%rsi,%r10),%r10 # epilogue label
cmp %r10,%rbx # context->Rip>=epilogue label
jae .Lcommon_seh_tail
lea 16(%rax),%rax
mov -8(%rax),%r12
mov -16(%rax),%r13
mov %r12,216($context) # restore context->R12
mov %r13,224($context) # restore context->R13
jmp .Lcommon_seh_tail
.size short_handler,.-short_handler
.type full_handler,\@abi-omnipotent
.align 16
full_handler:
push %rsi
push %rdi
push %rbx
push %rbp
push %r12
push %r13
push %r14
push %r15
pushfq
sub \$64,%rsp
mov 120($context),%rax # pull context->Rax
mov 248($context),%rbx # pull context->Rip
mov 8($disp),%rsi # disp->ImageBase
mov 56($disp),%r11 # disp->HandlerData
mov 0(%r11),%r10d # HandlerData[0]
lea (%rsi,%r10),%r10 # end of prologue label
cmp %r10,%rbx # context->Rip<end of prologue label
jb .Lcommon_seh_tail
mov 152($context),%rax # pull context->Rsp
mov 4(%r11),%r10d # HandlerData[1]
lea (%rsi,%r10),%r10 # epilogue label
cmp %r10,%rbx # context->Rip>=epilogue label
jae .Lcommon_seh_tail
mov 8(%r11),%r10d # HandlerData[2]
lea (%rax,%r10),%rax
mov -8(%rax),%rbp
mov -16(%rax),%rbx
mov -24(%rax),%r12
mov -32(%rax),%r13
mov -40(%rax),%r14
mov -48(%rax),%r15
mov %rbx,144($context) # restore context->Rbx
mov %rbp,160($context) # restore context->Rbp
mov %r12,216($context) # restore context->R12
mov %r13,224($context) # restore context->R13
mov %r14,232($context) # restore context->R14
mov %r15,240($context) # restore context->R15
.Lcommon_seh_tail:
mov 8(%rax),%rdi
mov 16(%rax),%rsi
mov %rax,152($context) # restore context->Rsp
mov %rsi,168($context) # restore context->Rsi
mov %rdi,176($context) # restore context->Rdi
mov 40($disp),%rdi # disp->ContextRecord
mov $context,%rsi # context
mov \$154,%ecx # sizeof(CONTEXT)
.long 0xa548f3fc # cld; rep movsq
mov $disp,%rsi
xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
mov 8(%rsi),%rdx # arg2, disp->ImageBase
mov 0(%rsi),%r8 # arg3, disp->ControlPc
mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
mov 40(%rsi),%r10 # disp->ContextRecord
lea 56(%rsi),%r11 # &disp->HandlerData
lea 24(%rsi),%r12 # &disp->EstablisherFrame
mov %r10,32(%rsp) # arg5
mov %r11,40(%rsp) # arg6
mov %r12,48(%rsp) # arg7
mov %rcx,56(%rsp) # arg8, (NULL)
call *__imp_RtlVirtualUnwind(%rip)
mov \$1,%eax # ExceptionContinueSearch
add \$64,%rsp
popfq
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbp
pop %rbx
pop %rdi
pop %rsi
ret
.size full_handler,.-full_handler
.section .pdata
.align 4
.rva .LSEH_begin_ecp_nistz256_neg
.rva .LSEH_end_ecp_nistz256_neg
.rva .LSEH_info_ecp_nistz256_neg
.rva .LSEH_begin_ecp_nistz256_mul_mont
.rva .LSEH_end_ecp_nistz256_mul_mont
.rva .LSEH_info_ecp_nistz256_mul_mont
.rva .LSEH_begin_ecp_nistz256_sqr_mont
.rva .LSEH_end_ecp_nistz256_sqr_mont
.rva .LSEH_info_ecp_nistz256_sqr_mont
.rva .LSEH_begin_ecp_nistz256_select_w5
.rva .LSEH_end_ecp_nistz256_select_w5
.rva .LSEH_info_ecp_nistz256_select_wX
.rva .LSEH_begin_ecp_nistz256_select_w7
.rva .LSEH_end_ecp_nistz256_select_w7
.rva .LSEH_info_ecp_nistz256_select_wX
___
$code.=<<___ if ($avx>1);
.rva .LSEH_begin_ecp_nistz256_avx2_select_w5
.rva .LSEH_end_ecp_nistz256_avx2_select_w5
.rva .LSEH_info_ecp_nistz256_avx2_select_wX
.rva .LSEH_begin_ecp_nistz256_avx2_select_w7
.rva .LSEH_end_ecp_nistz256_avx2_select_w7
.rva .LSEH_info_ecp_nistz256_avx2_select_wX
___
$code.=<<___;
.rva .LSEH_begin_ecp_nistz256_point_double
.rva .LSEH_end_ecp_nistz256_point_double
.rva .LSEH_info_ecp_nistz256_point_double
.rva .LSEH_begin_ecp_nistz256_point_add
.rva .LSEH_end_ecp_nistz256_point_add
.rva .LSEH_info_ecp_nistz256_point_add
.rva .LSEH_begin_ecp_nistz256_point_add_affine
.rva .LSEH_end_ecp_nistz256_point_add_affine
.rva .LSEH_info_ecp_nistz256_point_add_affine
___
$code.=<<___ if ($addx);
.rva .LSEH_begin_ecp_nistz256_point_doublex
.rva .LSEH_end_ecp_nistz256_point_doublex
.rva .LSEH_info_ecp_nistz256_point_doublex
.rva .LSEH_begin_ecp_nistz256_point_addx
.rva .LSEH_end_ecp_nistz256_point_addx
.rva .LSEH_info_ecp_nistz256_point_addx
.rva .LSEH_begin_ecp_nistz256_point_add_affinex
.rva .LSEH_end_ecp_nistz256_point_add_affinex
.rva .LSEH_info_ecp_nistz256_point_add_affinex
___
$code.=<<___;
.section .xdata
.align 8
.LSEH_info_ecp_nistz256_neg:
.byte 9,0,0,0
.rva short_handler
.rva .Lneg_body,.Lneg_epilogue # HandlerData[]
.LSEH_info_ecp_nistz256_mul_mont:
.byte 9,0,0,0
.rva full_handler
.rva .Lmul_body,.Lmul_epilogue # HandlerData[]
.long 48,0
.LSEH_info_ecp_nistz256_sqr_mont:
.byte 9,0,0,0
.rva full_handler
.rva .Lsqr_body,.Lsqr_epilogue # HandlerData[]
.long 48,0
.LSEH_info_ecp_nistz256_select_wX:
.byte 0x01,0x33,0x16,0x00
.byte 0x33,0xf8,0x09,0x00 #movaps 0x90(rsp),xmm15
.byte 0x2e,0xe8,0x08,0x00 #movaps 0x80(rsp),xmm14
.byte 0x29,0xd8,0x07,0x00 #movaps 0x70(rsp),xmm13
.byte 0x24,0xc8,0x06,0x00 #movaps 0x60(rsp),xmm12
.byte 0x1f,0xb8,0x05,0x00 #movaps 0x50(rsp),xmm11
.byte 0x1a,0xa8,0x04,0x00 #movaps 0x40(rsp),xmm10
.byte 0x15,0x98,0x03,0x00 #movaps 0x30(rsp),xmm9
.byte 0x10,0x88,0x02,0x00 #movaps 0x20(rsp),xmm8
.byte 0x0c,0x78,0x01,0x00 #movaps 0x10(rsp),xmm7
.byte 0x08,0x68,0x00,0x00 #movaps 0x00(rsp),xmm6
.byte 0x04,0x01,0x15,0x00 #sub rsp,0xa8
.align 8
___
$code.=<<___ if ($avx>1);
.LSEH_info_ecp_nistz256_avx2_select_wX:
.byte 0x01,0x36,0x17,0x0b
.byte 0x36,0xf8,0x09,0x00 # vmovaps 0x90(rsp),xmm15
.byte 0x31,0xe8,0x08,0x00 # vmovaps 0x80(rsp),xmm14
.byte 0x2c,0xd8,0x07,0x00 # vmovaps 0x70(rsp),xmm13
.byte 0x27,0xc8,0x06,0x00 # vmovaps 0x60(rsp),xmm12
.byte 0x22,0xb8,0x05,0x00 # vmovaps 0x50(rsp),xmm11
.byte 0x1d,0xa8,0x04,0x00 # vmovaps 0x40(rsp),xmm10
.byte 0x18,0x98,0x03,0x00 # vmovaps 0x30(rsp),xmm9
.byte 0x13,0x88,0x02,0x00 # vmovaps 0x20(rsp),xmm8
.byte 0x0e,0x78,0x01,0x00 # vmovaps 0x10(rsp),xmm7
.byte 0x09,0x68,0x00,0x00 # vmovaps 0x00(rsp),xmm6
.byte 0x04,0x01,0x15,0x00 # sub rsp,0xa8
.byte 0x00,0xb3,0x00,0x00 # set_frame r11
.align 8
___
$code.=<<___;
.LSEH_info_ecp_nistz256_point_double:
.byte 9,0,0,0
.rva full_handler
.rva .Lpoint_doubleq_body,.Lpoint_doubleq_epilogue # HandlerData[]
.long 32*5+56,0
.LSEH_info_ecp_nistz256_point_add:
.byte 9,0,0,0
.rva full_handler
.rva .Lpoint_addq_body,.Lpoint_addq_epilogue # HandlerData[]
.long 32*18+56,0
.LSEH_info_ecp_nistz256_point_add_affine:
.byte 9,0,0,0
.rva full_handler
.rva .Ladd_affineq_body,.Ladd_affineq_epilogue # HandlerData[]
.long 32*15+56,0
___
$code.=<<___ if ($addx);
.align 8
.LSEH_info_ecp_nistz256_point_doublex:
.byte 9,0,0,0
.rva full_handler
.rva .Lpoint_doublex_body,.Lpoint_doublex_epilogue # HandlerData[]
.long 32*5+56,0
.LSEH_info_ecp_nistz256_point_addx:
.byte 9,0,0,0
.rva full_handler
.rva .Lpoint_addx_body,.Lpoint_addx_epilogue # HandlerData[]
.long 32*18+56,0
.LSEH_info_ecp_nistz256_point_add_affinex:
.byte 9,0,0,0
.rva full_handler
.rva .Ladd_affinex_body,.Ladd_affinex_epilogue # HandlerData[]
.long 32*15+56,0
___
}
$code =~ s/\`([^\`]*)\`/eval $1/gem;
print $code;
close STDOUT;
+79 -48
View File
@@ -215,13 +215,6 @@ static const uint8_t kP521Params[6 * 66] = {
0xB7, 0x1E, 0x91, 0x38, 0x64, 0x09,
};
// MSan appears to have a bug that causes code to be miscompiled in opt mode.
// While that is being looked at, don't run the uint128_t code under MSan.
#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS) && \
!defined(MEMORY_SANITIZER)
#define BORINGSSL_USE_INT128_CODE
#endif
DEFINE_METHOD_FUNCTION(struct built_in_curves, OPENSSL_built_in_curves) {
// 1.3.132.0.35
static const uint8_t kOIDP521[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
@@ -253,16 +246,12 @@ DEFINE_METHOD_FUNCTION(struct built_in_curves, OPENSSL_built_in_curves) {
out->curves[2].param_len = 32;
out->curves[2].params = kP256Params;
out->curves[2].method =
#if defined(BORINGSSL_USE_INT128_CODE)
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
!defined(OPENSSL_SMALL)
EC_GFp_nistz256_method();
#else
EC_GFp_nistp256_method();
#endif
#else
EC_GFp_mont_method();
#endif
// 1.3.132.0.33
static const uint8_t kOIDP224[] = {0x2b, 0x81, 0x04, 0x00, 0x21};
@@ -273,7 +262,7 @@ DEFINE_METHOD_FUNCTION(struct built_in_curves, OPENSSL_built_in_curves) {
out->curves[3].param_len = 28;
out->curves[3].params = kP224Params;
out->curves[3].method =
#if defined(BORINGSSL_USE_INT128_CODE) && !defined(OPENSSL_SMALL)
#if defined(BORINGSSL_HAS_UINT128) && !defined(OPENSSL_SMALL)
EC_GFp_nistp224_method();
#else
EC_GFp_mont_method();
@@ -398,11 +387,12 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
EC_POINT_free(copy);
return 0;
}
// Store the order in minimal form, so it can be used with |BN_ULONG| arrays.
bn_set_minimal_width(&group->order);
BN_MONT_CTX_free(group->order_mont);
group->order_mont = BN_MONT_CTX_new();
if (group->order_mont == NULL ||
!BN_MONT_CTX_set(group->order_mont, &group->order, NULL)) {
group->order_mont = BN_MONT_CTX_new_for_modulus(&group->order, NULL);
if (group->order_mont == NULL) {
return 0;
}
@@ -459,9 +449,8 @@ static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) {
goto err;
}
group->order_mont = BN_MONT_CTX_new();
if (group->order_mont == NULL ||
!BN_MONT_CTX_set(group->order_mont, &group->order, ctx)) {
group->order_mont = BN_MONT_CTX_new_for_modulus(&group->order, ctx);
if (group->order_mont == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
@@ -779,6 +768,15 @@ int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
}
if (!EC_POINT_is_on_curve(group, point, ctx)) {
// In the event of an error, defend against the caller not checking the
// return value by setting a known safe value: the base point.
const EC_POINT *generator = EC_GROUP_get0_generator(group);
// The generator can be missing if the caller is in the process of
// constructing an arbitrary group. In this, we give up and hope they're
// checking the return value.
if (generator) {
EC_POINT_copy(point, generator);
}
OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE);
return 0;
}
@@ -817,6 +815,25 @@ int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) {
return ec_GFp_simple_invert(group, a, ctx);
}
static int arbitrary_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
const BIGNUM *in, BN_CTX *ctx) {
if (ec_bignum_to_scalar(group, out, in)) {
return 1;
}
ERR_clear_error();
// This is an unusual input, so we do not guarantee constant-time processing.
const BIGNUM *order = &group->order;
BN_CTX_start(ctx);
BIGNUM *tmp = BN_CTX_get(ctx);
int ok = tmp != NULL &&
BN_nnmod(tmp, in, order, ctx) &&
ec_bignum_to_scalar_unchecked(group, out, tmp);
BN_CTX_end(ctx);
return ok;
}
int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) {
// Previously, this function set |r| to the point at infinity if there was
@@ -828,30 +845,27 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
return 0;
}
// We cannot easily process arbitrary scalars in constant-time, and there is
// no need to do so. Require that scalars be the same size as the order.
//
// One could require they be fully reduced, but some consumers try to check
// that |order| * |pubkey| is the identity. This comes from following NIST SP
// 800-56A section 5.6.2.3.2. (Though all our curves have cofactor one, so
// this check isn't useful.)
int ret = 0;
EC_SCALAR g_scalar_storage, p_scalar_storage;
EC_SCALAR *g_scalar_arg = NULL, *p_scalar_arg = NULL;
unsigned order_bits = BN_num_bits(&group->order);
BN_CTX *new_ctx = NULL;
if (ctx == NULL) {
new_ctx = BN_CTX_new();
if (new_ctx == NULL) {
goto err;
}
ctx = new_ctx;
}
if (g_scalar != NULL) {
if (BN_is_negative(g_scalar) || BN_num_bits(g_scalar) > order_bits ||
!ec_bignum_to_scalar(group, &g_scalar_storage, g_scalar)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
if (!arbitrary_bignum_to_scalar(group, &g_scalar_storage, g_scalar, ctx)) {
goto err;
}
g_scalar_arg = &g_scalar_storage;
}
if (p_scalar != NULL) {
if (BN_is_negative(p_scalar) || BN_num_bits(p_scalar) > order_bits ||
!ec_bignum_to_scalar(group, &p_scalar_storage, p_scalar)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
if (!arbitrary_bignum_to_scalar(group, &p_scalar_storage, p_scalar, ctx)) {
goto err;
}
p_scalar_arg = &p_scalar_storage;
@@ -860,11 +874,30 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
ret = ec_point_mul_scalar(group, r, g_scalar_arg, p, p_scalar_arg, ctx);
err:
BN_CTX_free(new_ctx);
OPENSSL_cleanse(&g_scalar_storage, sizeof(g_scalar_storage));
OPENSSL_cleanse(&p_scalar_storage, sizeof(p_scalar_storage));
return ret;
}
int ec_point_mul_scalar_public(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar, const EC_POINT *p,
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
if ((g_scalar == NULL && p_scalar == NULL) ||
(p == NULL) != (p_scalar == NULL)) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (EC_GROUP_cmp(group, r->group, NULL) != 0 ||
(p != NULL && EC_GROUP_cmp(group, p->group, NULL) != 0)) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
return group->meth->mul_public(group, r, g_scalar, p, p_scalar, ctx);
}
int ec_point_mul_scalar(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar, const EC_POINT *p,
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
@@ -883,18 +916,6 @@ int ec_point_mul_scalar(const EC_GROUP *group, EC_POINT *r,
return group->meth->mul(group, r, g_scalar, p, p_scalar, ctx);
}
int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
const BIGNUM *y, const BIGNUM *z,
BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
return ec_GFp_simple_set_Jprojective_coordinates_GFp(group, point, x, y, z,
ctx);
}
void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag) {}
const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group) {
@@ -927,17 +948,27 @@ size_t EC_get_builtin_curves(EC_builtin_curve *out_curves,
int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
const BIGNUM *in) {
if (BN_is_negative(in) || in->top > group->order.top) {
if (!ec_bignum_to_scalar_unchecked(group, out, in)) {
return 0;
}
if (!bn_less_than_words(out->words, group->order.d, group->order.width)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
return 0;
}
return 1;
}
int ec_bignum_to_scalar_unchecked(const EC_GROUP *group, EC_SCALAR *out,
const BIGNUM *in) {
if (!bn_copy_words(out->words, group->order.width, in)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
return 0;
}
OPENSSL_memset(out->words, 0, group->order.top * sizeof(BN_ULONG));
OPENSSL_memcpy(out->words, in->d, in->top * sizeof(BN_ULONG));
return 1;
}
int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
const uint8_t additional_data[32]) {
return bn_rand_range_words(out->words, 1, group->order.d, group->order.top,
return bn_rand_range_words(out->words, 1, group->order.d, group->order.width,
additional_data);
}
+35 -54
View File
@@ -233,19 +233,21 @@ int EC_KEY_is_opaque(const EC_KEY *key) {
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; }
int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) {
// If |key| already has a group, it is an error to switch to another one.
if (key->group != NULL) {
if (EC_GROUP_cmp(key->group, group, NULL) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
return 1;
}
assert(key->priv_key == NULL);
assert(key->pub_key == NULL);
EC_GROUP_free(key->group);
// TODO(fork): duplicating the group seems wasteful but see
// |EC_KEY_set_conv_form|.
key->group = EC_GROUP_dup(group);
if (key->group == NULL) {
return 0;
}
// XXX: |BN_cmp| is not constant time.
if (key->priv_key != NULL &&
BN_cmp(key->priv_key, EC_GROUP_get0_order(group)) >= 0) {
return 0;
}
return 1;
return key->group != NULL;
}
const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
@@ -253,8 +255,12 @@ const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
}
int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) {
// XXX: |BN_cmp| is not constant time.
if (key->group != NULL &&
if (key->group == NULL) {
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
return 0;
}
if (BN_is_negative(priv_key) ||
BN_cmp(priv_key, EC_GROUP_get0_order(key->group)) >= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
return 0;
@@ -269,6 +275,16 @@ const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) {
}
int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) {
if (key->group == NULL) {
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
return 0;
}
if (EC_GROUP_cmp(key->group, pub_key->group, NULL) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
EC_POINT_free(key->pub_key);
key->pub_key = EC_POINT_dup(pub_key, key->group);
return (key->pub_key == NULL) ? 0 : 1;
@@ -317,8 +333,8 @@ int EC_KEY_check_key(const EC_KEY *eckey) {
// in case the priv_key is present :
// check if generator * priv_key == pub_key
if (eckey->priv_key) {
// XXX: |BN_cmp| is not constant time.
if (BN_cmp(eckey->priv_key, EC_GROUP_get0_order(eckey->group)) >= 0) {
if (BN_is_negative(eckey->priv_key) ||
BN_cmp(eckey->priv_key, EC_GROUP_get0_order(eckey->group)) >= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
goto err;
}
@@ -372,8 +388,6 @@ int EC_KEY_check_fips(const EC_KEY *key) {
int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x,
BIGNUM *y) {
BN_CTX *ctx = NULL;
BIGNUM *tx, *ty;
EC_POINT *point = NULL;
int ok = 0;
@@ -381,51 +395,18 @@ int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x,
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
ctx = BN_CTX_new();
if (ctx == NULL) {
return 0;
}
BN_CTX_start(ctx);
point = EC_POINT_new(key->group);
if (point == NULL) {
goto err;
}
tx = BN_CTX_get(ctx);
ty = BN_CTX_get(ctx);
if (tx == NULL ||
ty == NULL) {
goto err;
}
if (!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, ctx) ||
!EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, ctx)) {
goto err;
}
// Check if retrieved coordinates match originals: if not values
// are out of range.
if (BN_cmp(x, tx) || BN_cmp(y, ty)) {
OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
goto err;
}
if (!EC_KEY_set_public_key(key, point)) {
goto err;
}
if (EC_KEY_check_key(key) == 0) {
if (point == NULL ||
!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, NULL) ||
!EC_KEY_set_public_key(key, point) ||
!EC_KEY_check_key(key)) {
goto err;
}
ok = 1;
err:
BN_CTX_end(ctx);
BN_CTX_free(ctx);
EC_POINT_free(point);
return ok;
}
+3 -10
View File
@@ -93,7 +93,6 @@ void ec_GFp_mont_group_finish(EC_GROUP *group) {
int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
BN_CTX *new_ctx = NULL;
BN_MONT_CTX *mont = NULL;
int ret = 0;
BN_MONT_CTX_free(group->mont);
@@ -106,18 +105,12 @@ int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
}
}
mont = BN_MONT_CTX_new();
if (mont == NULL) {
goto err;
}
if (!BN_MONT_CTX_set(mont, p, ctx)) {
group->mont = BN_MONT_CTX_new_for_modulus(p, ctx);
if (group->mont == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
group->mont = mont;
mont = NULL;
ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
if (!ret) {
@@ -127,7 +120,6 @@ int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
err:
BN_CTX_free(new_ctx);
BN_MONT_CTX_free(mont);
return ret;
}
@@ -270,6 +262,7 @@ DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_mont_method) {
out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates = ec_GFp_mont_point_get_affine_coordinates;
out->mul = ec_wNAF_mul /* XXX: Not constant time. */;
out->mul_public = ec_wNAF_mul;
out->field_mul = ec_GFp_mont_field_mul;
out->field_sqr = ec_GFp_mont_field_sqr;
out->field_encode = ec_GFp_mont_field_encode;
+255 -53
View File
@@ -29,6 +29,8 @@
#include <openssl/obj.h>
#include "../../test/test_util.h"
#include "../bn/internal.h"
#include "internal.h"
// kECKeyWithoutPublic is an ECPrivateKey with the optional publicKey field
@@ -303,9 +305,73 @@ TEST(ECTest, ArbitraryCurve) {
order.get(), BN_value_one()));
EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL));
#if !defined(BORINGSSL_SHARED_LIBRARY)
// group4 has non-minimal components that do not fit in |EC_SCALAR| and the
// future |EC_FELEM|.
ASSERT_TRUE(bn_resize_words(p.get(), 32));
ASSERT_TRUE(bn_resize_words(a.get(), 32));
ASSERT_TRUE(bn_resize_words(b.get(), 32));
ASSERT_TRUE(bn_resize_words(gx.get(), 32));
ASSERT_TRUE(bn_resize_words(gy.get(), 32));
ASSERT_TRUE(bn_resize_words(order.get(), 32));
bssl::UniquePtr<EC_GROUP> group4(
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
ASSERT_TRUE(group4);
bssl::UniquePtr<EC_POINT> generator4(EC_POINT_new(group4.get()));
ASSERT_TRUE(generator4);
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
group4.get(), generator4.get(), gx.get(), gy.get(), ctx.get()));
ASSERT_TRUE(EC_GROUP_set_generator(group4.get(), generator4.get(),
order.get(), BN_value_one()));
EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group4.get(), NULL));
#endif
}
class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
TEST(ECTest, SetKeyWithoutGroup) {
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
ASSERT_TRUE(key);
// Private keys may not be configured without a group.
EXPECT_FALSE(EC_KEY_set_private_key(key.get(), BN_value_one()));
// Public keys may not be configured without a group.
bssl::UniquePtr<EC_GROUP> group(
EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
ASSERT_TRUE(group);
EXPECT_FALSE(
EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(group.get())));
}
TEST(ECTest, GroupMismatch) {
bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_secp384r1));
ASSERT_TRUE(key);
bssl::UniquePtr<EC_GROUP> p256(
EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
ASSERT_TRUE(p256);
// Changing a key's group is invalid.
EXPECT_FALSE(EC_KEY_set_group(key.get(), p256.get()));
// Configuring a public key with the wrong group is invalid.
EXPECT_FALSE(
EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(p256.get())));
}
class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {
public:
const EC_GROUP *group() const { return group_.get(); }
void SetUp() override {
group_.reset(EC_GROUP_new_by_curve_name(GetParam().nid));
ASSERT_TRUE(group_);
}
private:
bssl::UniquePtr<EC_GROUP> group_;
};
TEST_P(ECCurveTest, SetAffine) {
// Generate an EC_KEY.
@@ -313,32 +379,44 @@ TEST_P(ECCurveTest, SetAffine) {
ASSERT_TRUE(key);
ASSERT_TRUE(EC_KEY_generate_key(key.get()));
const EC_GROUP *const group = EC_KEY_get0_group(key.get());
EXPECT_TRUE(
EC_POINT_is_on_curve(group, EC_KEY_get0_public_key(key.get()), nullptr));
EXPECT_TRUE(EC_POINT_is_on_curve(group(), EC_KEY_get0_public_key(key.get()),
nullptr));
// Get the public key's coordinates.
bssl::UniquePtr<BIGNUM> x(BN_new());
ASSERT_TRUE(x);
bssl::UniquePtr<BIGNUM> y(BN_new());
ASSERT_TRUE(y);
bssl::UniquePtr<BIGNUM> p(BN_new());
ASSERT_TRUE(p);
EXPECT_TRUE(EC_POINT_get_affine_coordinates_GFp(
group, EC_KEY_get0_public_key(key.get()), x.get(), y.get(), nullptr));
group(), EC_KEY_get0_public_key(key.get()), x.get(), y.get(), nullptr));
EXPECT_TRUE(
EC_GROUP_get_curve_GFp(group(), p.get(), nullptr, nullptr, nullptr));
// Points on the curve should be accepted.
auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group));
auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group()));
ASSERT_TRUE(point);
EXPECT_TRUE(EC_POINT_set_affine_coordinates_GFp(group, point.get(), x.get(),
EXPECT_TRUE(EC_POINT_set_affine_coordinates_GFp(group(), point.get(), x.get(),
y.get(), nullptr));
// Subtract one from |y| to make the point no longer on the curve.
EXPECT_TRUE(BN_sub(y.get(), y.get(), BN_value_one()));
// Points not on the curve should be rejected.
bssl::UniquePtr<EC_POINT> invalid_point(EC_POINT_new(group));
bssl::UniquePtr<EC_POINT> invalid_point(EC_POINT_new(group()));
ASSERT_TRUE(invalid_point);
EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(),
EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group(), invalid_point.get(),
x.get(), y.get(), nullptr));
// Coordinates out of range should be rejected.
EXPECT_TRUE(BN_add(y.get(), y.get(), BN_value_one()));
EXPECT_TRUE(BN_add(y.get(), y.get(), p.get()));
EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group(), invalid_point.get(),
x.get(), y.get(), nullptr));
EXPECT_FALSE(
EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get()));
}
TEST_P(ECCurveTest, GenerateFIPS) {
@@ -353,57 +431,52 @@ TEST_P(ECCurveTest, AddingEqualPoints) {
ASSERT_TRUE(key);
ASSERT_TRUE(EC_KEY_generate_key(key.get()));
const EC_GROUP *const group = EC_KEY_get0_group(key.get());
bssl::UniquePtr<EC_POINT> p1(EC_POINT_new(group));
bssl::UniquePtr<EC_POINT> p1(EC_POINT_new(group()));
ASSERT_TRUE(p1);
ASSERT_TRUE(EC_POINT_copy(p1.get(), EC_KEY_get0_public_key(key.get())));
bssl::UniquePtr<EC_POINT> p2(EC_POINT_new(group));
bssl::UniquePtr<EC_POINT> p2(EC_POINT_new(group()));
ASSERT_TRUE(p2);
ASSERT_TRUE(EC_POINT_copy(p2.get(), EC_KEY_get0_public_key(key.get())));
bssl::UniquePtr<EC_POINT> double_p1(EC_POINT_new(group));
bssl::UniquePtr<EC_POINT> double_p1(EC_POINT_new(group()));
ASSERT_TRUE(double_p1);
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
ASSERT_TRUE(ctx);
ASSERT_TRUE(EC_POINT_dbl(group, double_p1.get(), p1.get(), ctx.get()));
ASSERT_TRUE(EC_POINT_dbl(group(), double_p1.get(), p1.get(), ctx.get()));
bssl::UniquePtr<EC_POINT> p1_plus_p2(EC_POINT_new(group));
bssl::UniquePtr<EC_POINT> p1_plus_p2(EC_POINT_new(group()));
ASSERT_TRUE(p1_plus_p2);
ASSERT_TRUE(
EC_POINT_add(group, p1_plus_p2.get(), p1.get(), p2.get(), ctx.get()));
EC_POINT_add(group(), p1_plus_p2.get(), p1.get(), p2.get(), ctx.get()));
EXPECT_EQ(0,
EC_POINT_cmp(group, double_p1.get(), p1_plus_p2.get(), ctx.get()))
EC_POINT_cmp(group(), double_p1.get(), p1_plus_p2.get(), ctx.get()))
<< "A+A != 2A";
}
TEST_P(ECCurveTest, MulZero) {
bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
ASSERT_TRUE(group);
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
ASSERT_TRUE(point);
bssl::UniquePtr<BIGNUM> zero(BN_new());
ASSERT_TRUE(zero);
BN_zero(zero.get());
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), zero.get(), nullptr,
nullptr, nullptr));
ASSERT_TRUE(EC_POINT_mul(group(), point.get(), zero.get(), nullptr, nullptr,
nullptr));
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
<< "g * 0 did not return point at infinity.";
// Test that zero times an arbitrary point is also infinity. The generator is
// used as the arbitrary point.
bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group()));
ASSERT_TRUE(generator);
ASSERT_TRUE(EC_POINT_mul(group.get(), generator.get(), BN_value_one(),
nullptr, nullptr, nullptr));
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, generator.get(),
ASSERT_TRUE(EC_POINT_mul(group(), generator.get(), BN_value_one(), nullptr,
nullptr, nullptr));
ASSERT_TRUE(EC_POINT_mul(group(), point.get(), nullptr, generator.get(),
zero.get(), nullptr));
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
<< "p * 0 did not return point at infinity.";
}
@@ -413,55 +486,184 @@ TEST_P(ECCurveTest, MulZero) {
// 5.6.2.3.2. (Though all our curves have cofactor one, so this check isn't
// useful.)
TEST_P(ECCurveTest, MulOrder) {
bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
ASSERT_TRUE(group);
// Test that g × order = ∞.
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
ASSERT_TRUE(point);
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(),
EC_GROUP_get0_order(group.get()), nullptr, nullptr,
nullptr));
ASSERT_TRUE(EC_POINT_mul(group(), point.get(), EC_GROUP_get0_order(group()),
nullptr, nullptr, nullptr));
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
<< "g * order did not return point at infinity.";
// Test that p × order = ∞, for some arbitrary p.
bssl::UniquePtr<BIGNUM> forty_two(BN_new());
ASSERT_TRUE(forty_two);
ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), forty_two.get(), nullptr,
ASSERT_TRUE(EC_POINT_mul(group(), point.get(), forty_two.get(), nullptr,
nullptr, nullptr));
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, point.get(),
EC_GROUP_get0_order(group.get()), nullptr));
ASSERT_TRUE(EC_POINT_mul(group(), point.get(), nullptr, point.get(),
EC_GROUP_get0_order(group()), nullptr));
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
<< "p * order did not return point at infinity.";
}
// Test that |EC_POINT_mul| works with out-of-range scalars. The operation will
// not be constant-time, but we'll compute the right answer.
TEST_P(ECCurveTest, MulOutOfRange) {
bssl::UniquePtr<BIGNUM> n_minus_one(BN_dup(EC_GROUP_get0_order(group())));
ASSERT_TRUE(n_minus_one);
ASSERT_TRUE(BN_sub_word(n_minus_one.get(), 1));
bssl::UniquePtr<BIGNUM> minus_one(BN_new());
ASSERT_TRUE(minus_one);
ASSERT_TRUE(BN_one(minus_one.get()));
BN_set_negative(minus_one.get(), 1);
bssl::UniquePtr<BIGNUM> seven(BN_new());
ASSERT_TRUE(seven);
ASSERT_TRUE(BN_set_word(seven.get(), 7));
bssl::UniquePtr<BIGNUM> ten_n_plus_seven(
BN_dup(EC_GROUP_get0_order(group())));
ASSERT_TRUE(ten_n_plus_seven);
ASSERT_TRUE(BN_mul_word(ten_n_plus_seven.get(), 10));
ASSERT_TRUE(BN_add_word(ten_n_plus_seven.get(), 7));
bssl::UniquePtr<EC_POINT> point1(EC_POINT_new(group())),
point2(EC_POINT_new(group()));
ASSERT_TRUE(point1);
ASSERT_TRUE(point2);
ASSERT_TRUE(EC_POINT_mul(group(), point1.get(), n_minus_one.get(), nullptr,
nullptr, nullptr));
ASSERT_TRUE(EC_POINT_mul(group(), point2.get(), minus_one.get(), nullptr,
nullptr, nullptr));
EXPECT_EQ(0, EC_POINT_cmp(group(), point1.get(), point2.get(), nullptr))
<< "-1 * G and (n-1) * G did not give the same result";
ASSERT_TRUE(EC_POINT_mul(group(), point1.get(), seven.get(), nullptr, nullptr,
nullptr));
ASSERT_TRUE(EC_POINT_mul(group(), point2.get(), ten_n_plus_seven.get(),
nullptr, nullptr, nullptr));
EXPECT_EQ(0, EC_POINT_cmp(group(), point1.get(), point2.get(), nullptr))
<< "7 * G and (10n + 7) * G did not give the same result";
}
// Test that 10×∞ + G = G.
TEST_P(ECCurveTest, Mul) {
bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
ASSERT_TRUE(group);
bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group.get()));
bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group()));
ASSERT_TRUE(p);
bssl::UniquePtr<EC_POINT> result(EC_POINT_new(group.get()));
bssl::UniquePtr<EC_POINT> result(EC_POINT_new(group()));
ASSERT_TRUE(result);
bssl::UniquePtr<BIGNUM> n(BN_new());
ASSERT_TRUE(n);
ASSERT_TRUE(EC_POINT_set_to_infinity(group.get(), p.get()));
ASSERT_TRUE(EC_POINT_set_to_infinity(group(), p.get()));
ASSERT_TRUE(BN_set_word(n.get(), 10));
// First check that 10×∞ = ∞.
ASSERT_TRUE(EC_POINT_mul(group.get(), result.get(), nullptr, p.get(), n.get(),
nullptr));
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), result.get()));
ASSERT_TRUE(
EC_POINT_mul(group(), result.get(), nullptr, p.get(), n.get(), nullptr));
EXPECT_TRUE(EC_POINT_is_at_infinity(group(), result.get()));
// Now check that 10×∞ + G = G.
const EC_POINT *generator = EC_GROUP_get0_generator(group.get());
ASSERT_TRUE(EC_POINT_mul(group.get(), result.get(), BN_value_one(), p.get(),
const EC_POINT *generator = EC_GROUP_get0_generator(group());
ASSERT_TRUE(EC_POINT_mul(group(), result.get(), BN_value_one(), p.get(),
n.get(), nullptr));
EXPECT_EQ(0, EC_POINT_cmp(group.get(), result.get(), generator, nullptr));
EXPECT_EQ(0, EC_POINT_cmp(group(), result.get(), generator, nullptr));
}
TEST_P(ECCurveTest, MulNonMinimal) {
bssl::UniquePtr<BIGNUM> forty_two(BN_new());
ASSERT_TRUE(forty_two);
ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
// Compute g × 42.
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
ASSERT_TRUE(point);
ASSERT_TRUE(EC_POINT_mul(group(), point.get(), forty_two.get(), nullptr,
nullptr, nullptr));
// Compute it again with a non-minimal 42, much larger than the scalar.
ASSERT_TRUE(bn_resize_words(forty_two.get(), 64));
bssl::UniquePtr<EC_POINT> point2(EC_POINT_new(group()));
ASSERT_TRUE(point2);
ASSERT_TRUE(EC_POINT_mul(group(), point2.get(), forty_two.get(), nullptr,
nullptr, nullptr));
EXPECT_EQ(0, EC_POINT_cmp(group(), point.get(), point2.get(), nullptr));
}
// Test that EC_KEY_set_private_key rejects invalid values.
TEST_P(ECCurveTest, SetInvalidPrivateKey) {
bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
ASSERT_TRUE(key);
bssl::UniquePtr<BIGNUM> bn(BN_new());
ASSERT_TRUE(BN_one(bn.get()));
BN_set_negative(bn.get(), 1);
EXPECT_FALSE(EC_KEY_set_private_key(key.get(), bn.get()))
<< "Unexpectedly set a key of -1";
ERR_clear_error();
ASSERT_TRUE(
BN_copy(bn.get(), EC_GROUP_get0_order(EC_KEY_get0_group(key.get()))));
EXPECT_FALSE(EC_KEY_set_private_key(key.get(), bn.get()))
<< "Unexpectedly set a key of the group order.";
ERR_clear_error();
}
TEST_P(ECCurveTest, IgnoreOct2PointReturnValue) {
bssl::UniquePtr<BIGNUM> forty_two(BN_new());
ASSERT_TRUE(forty_two);
ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
// Compute g × 42.
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
ASSERT_TRUE(point);
ASSERT_TRUE(EC_POINT_mul(group(), point.get(), forty_two.get(), nullptr,
nullptr, nullptr));
// Serialize the point.
size_t serialized_len = EC_POINT_point2oct(
group(), point.get(), POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
ASSERT_NE(0u, serialized_len);
std::vector<uint8_t> serialized(serialized_len);
ASSERT_EQ(
serialized_len,
EC_POINT_point2oct(group(), point.get(), POINT_CONVERSION_UNCOMPRESSED,
serialized.data(), serialized_len, nullptr));
// Create a serialized point that is not on the curve.
serialized[serialized_len - 1]++;
ASSERT_FALSE(EC_POINT_oct2point(group(), point.get(), serialized.data(),
serialized.size(), nullptr));
// After a failure, |point| should have been set to the generator to defend
// against code that doesn't check the return value.
ASSERT_EQ(0, EC_POINT_cmp(group(), point.get(),
EC_GROUP_get0_generator(group()), nullptr));
}
TEST_P(ECCurveTest, DoubleSpecialCase) {
const EC_POINT *g = EC_GROUP_get0_generator(group());
bssl::UniquePtr<EC_POINT> two_g(EC_POINT_new(group()));
ASSERT_TRUE(two_g);
ASSERT_TRUE(EC_POINT_dbl(group(), two_g.get(), g, nullptr));
bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group()));
ASSERT_TRUE(p);
ASSERT_TRUE(EC_POINT_mul(group(), p.get(), BN_value_one(), g, BN_value_one(),
nullptr));
EXPECT_EQ(0, EC_POINT_cmp(group(), p.get(), two_g.get(), nullptr));
EC_SCALAR one;
ASSERT_TRUE(ec_bignum_to_scalar(group(), &one, BN_value_one()));
ASSERT_TRUE(
ec_point_mul_scalar_public(group(), p.get(), &one, g, &one, nullptr));
EXPECT_EQ(0, EC_POINT_cmp(group(), p.get(), two_g.get(), nullptr));
}
static std::vector<EC_builtin_curve> AllCurves() {
+36 -22
View File
@@ -91,10 +91,9 @@ extern "C" {
OPENSSL_COMPILE_ASSERT(EC_MAX_SCALAR_WORDS <= BN_SMALL_MAX_WORDS,
bn_small_functions_applicable);
// An EC_SCALAR is a |BN_num_bits(order)|-bit integer. Only the first
// |order->top| words are used. An |EC_SCALAR| is specific to an |EC_GROUP| and
// must not be mixed between groups. Unless otherwise specified, it is fully
// reduced modulo the |order|.
// An EC_SCALAR is an integer fully reduced modulo the order. Only the first
// |order->width| words are used. An |EC_SCALAR| is specific to an |EC_GROUP|
// and must not be mixed between groups.
typedef union {
// bytes is the representation of the scalar in little-endian order.
uint8_t bytes[EC_MAX_SCALAR_BYTES];
@@ -116,6 +115,12 @@ struct ec_method_st {
// non-null.
int (*mul)(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx);
// mul_public performs the same computation as mul. It further assumes that
// the inputs are public so there is no concern about leaking their values
// through timing.
int (*mul_public)(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar, const EC_POINT *p,
const EC_SCALAR *p_scalar, BN_CTX *ctx);
// 'field_mul' and 'field_sqr' can be used by 'add' and 'dbl' so that the
// same implementations of point operations can be used with different
@@ -173,12 +178,15 @@ struct ec_point_st {
EC_GROUP *ec_group_new(const EC_METHOD *meth);
// ec_bignum_to_scalar converts |in| to an |EC_SCALAR| and writes it to |*out|.
// |in| must be non-negative and have at most |BN_num_bits(&group->order)| bits.
// It returns one on success and zero on error. It does not ensure |in| is fully
// reduced.
int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
const BIGNUM *in);
// ec_bignum_to_scalar converts |in| to an |EC_SCALAR| and writes it to
// |*out|. It returns one on success and zero if |in| is out of range.
OPENSSL_EXPORT int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
const BIGNUM *in);
// ec_bignum_to_scalar_unchecked behaves like |ec_bignum_to_scalar| but does not
// check |in| is fully reduced.
int ec_bignum_to_scalar_unchecked(const EC_GROUP *group, EC_SCALAR *out,
const BIGNUM *in);
// ec_random_nonzero_scalar sets |out| to a uniformly selected random value from
// 1 to |group->order| - 1. It returns one on success and zero on error.
@@ -193,6 +201,24 @@ int ec_point_mul_scalar(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar, const EC_POINT *p,
const EC_SCALAR *p_scalar, BN_CTX *ctx);
// ec_point_mul_scalar_public performs the same computation as
// ec_point_mul_scalar. It further assumes that the inputs are public so
// there is no concern about leaking their values through timing.
OPENSSL_EXPORT int ec_point_mul_scalar_public(
const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx);
// ec_compute_wNAF writes the modified width-(w+1) Non-Adjacent Form (wNAF) of
// |scalar| to |out| and returns one on success or zero on internal error. |out|
// must have room for |bits| + 1 elements, each of which will be either zero or
// odd with an absolute value less than 2^w satisfying
// scalar = \sum_j out[j]*2^j
// where at most one of any w+1 consecutive digits is non-zero
// with the exception that the most significant digit may be only
// w-1 zeros away from that next non-zero digit.
int ec_compute_wNAF(const EC_GROUP *group, int8_t *out, const EC_SCALAR *scalar,
size_t bits, int w);
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx);
@@ -208,16 +234,9 @@ int ec_GFp_simple_point_init(EC_POINT *);
void ec_GFp_simple_point_finish(EC_POINT *);
int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *);
int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *,
const BIGNUM *x,
const BIGNUM *y,
const BIGNUM *z, BN_CTX *);
int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
const BIGNUM *x, const BIGNUM *y,
BN_CTX *);
int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *,
const BIGNUM *x, int y_bit,
BN_CTX *);
int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
const EC_POINT *b, BN_CTX *);
int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
@@ -249,11 +268,6 @@ int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
BN_CTX *);
int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
const BIGNUM *y, const BIGNUM *z,
BN_CTX *ctx);
void ec_GFp_nistp_recode_scalar_bits(uint8_t *sign, uint8_t *digit, uint8_t in);
const EC_METHOD *EC_GFp_nistp224_method(void);
+59 -90
View File
@@ -77,11 +77,9 @@ static size_t ec_GFp_simple_point2oct(const EC_GROUP *group,
const EC_POINT *point,
point_conversion_form_t form,
uint8_t *buf, size_t len, BN_CTX *ctx) {
size_t ret;
size_t ret = 0;
BN_CTX *new_ctx = NULL;
int used_ctx = 0;
BIGNUM *x, *y;
size_t field_len, i;
if ((form != POINT_CONVERSION_COMPRESSED) &&
(form != POINT_CONVERSION_UNCOMPRESSED)) {
@@ -94,14 +92,16 @@ static size_t ec_GFp_simple_point2oct(const EC_GROUP *group,
goto err;
}
// ret := required output buffer length
field_len = BN_num_bytes(&group->field);
ret =
(form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
const size_t field_len = BN_num_bytes(&group->field);
size_t output_len = 1 /* type byte */ + field_len;
if (form == POINT_CONVERSION_UNCOMPRESSED) {
// Uncompressed points have a second coordinate.
output_len += field_len;
}
// if 'buf' is NULL, just return required length
if (buf != NULL) {
if (len < ret) {
if (len < output_len) {
OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
goto err;
}
@@ -115,8 +115,8 @@ static size_t ec_GFp_simple_point2oct(const EC_GROUP *group,
BN_CTX_start(ctx);
used_ctx = 1;
x = BN_CTX_get(ctx);
y = BN_CTX_get(ctx);
BIGNUM *x = BN_CTX_get(ctx);
BIGNUM *y = BN_CTX_get(ctx);
if (y == NULL) {
goto err;
}
@@ -131,7 +131,7 @@ static size_t ec_GFp_simple_point2oct(const EC_GROUP *group,
} else {
buf[0] = form;
}
i = 1;
size_t i = 1;
if (!BN_bn2bin_padded(buf + i, field_len, x)) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
@@ -147,70 +147,66 @@ static size_t ec_GFp_simple_point2oct(const EC_GROUP *group,
i += field_len;
}
if (i != ret) {
if (i != output_len) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
goto err;
}
}
if (used_ctx) {
BN_CTX_end(ctx);
}
BN_CTX_free(new_ctx);
return ret;
ret = output_len;
err:
if (used_ctx) {
BN_CTX_end(ctx);
}
BN_CTX_free(new_ctx);
return 0;
return ret;
}
static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
const uint8_t *buf, size_t len,
BN_CTX *ctx) {
point_conversion_form_t form;
int y_bit;
BN_CTX *new_ctx = NULL;
BIGNUM *x, *y;
size_t field_len, enc_len;
int ret = 0;
int ret = 0, used_ctx = 0;
if (len == 0) {
OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
return 0;
goto err;
}
form = buf[0];
y_bit = form & 1;
point_conversion_form_t form = buf[0];
const int y_bit = form & 1;
form = form & ~1U;
if ((form != POINT_CONVERSION_COMPRESSED &&
form != POINT_CONVERSION_UNCOMPRESSED) ||
(form == POINT_CONVERSION_UNCOMPRESSED && y_bit)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
return 0;
goto err;
}
field_len = BN_num_bytes(&group->field);
enc_len =
(form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
const size_t field_len = BN_num_bytes(&group->field);
size_t enc_len = 1 /* type byte */ + field_len;
if (form == POINT_CONVERSION_UNCOMPRESSED) {
// Uncompressed points have a second coordinate.
enc_len += field_len;
}
if (len != enc_len) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
return 0;
goto err;
}
if (ctx == NULL) {
ctx = new_ctx = BN_CTX_new();
if (ctx == NULL) {
return 0;
goto err;
}
}
BN_CTX_start(ctx);
x = BN_CTX_get(ctx);
y = BN_CTX_get(ctx);
used_ctx = 1;
BIGNUM *x = BN_CTX_get(ctx);
BIGNUM *y = BN_CTX_get(ctx);
if (x == NULL || y == NULL) {
goto err;
}
@@ -244,7 +240,9 @@ static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
ret = 1;
err:
BN_CTX_end(ctx);
if (used_ctx) {
BN_CTX_end(ctx);
}
BN_CTX_free(new_ctx);
return ret;
}
@@ -268,16 +266,20 @@ size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point,
return ec_GFp_simple_point2oct(group, point, form, buf, len, ctx);
}
int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
int y_bit, BN_CTX *ctx) {
int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
int y_bit, BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
if (BN_is_negative(x) || BN_cmp(x, &group->field) >= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT);
return 0;
}
BN_CTX *new_ctx = NULL;
BIGNUM *tmp1, *tmp2, *y;
int ret = 0;
ERR_clear_error();
@@ -292,10 +294,13 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
y_bit = (y_bit != 0);
BN_CTX_start(ctx);
tmp1 = BN_CTX_get(ctx);
tmp2 = BN_CTX_get(ctx);
y = BN_CTX_get(ctx);
if (y == NULL) {
BIGNUM *tmp1 = BN_CTX_get(ctx);
BIGNUM *tmp2 = BN_CTX_get(ctx);
BIGNUM *a = BN_CTX_get(ctx);
BIGNUM *b = BN_CTX_get(ctx);
BIGNUM *y = BN_CTX_get(ctx);
if (y == NULL ||
!EC_GROUP_get_curve_GFp(group, NULL, a, b, ctx)) {
goto err;
}
@@ -304,54 +309,28 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
// so y is one of the square roots of x^3 + a*x + b.
// tmp1 := x^3
if (group->meth->field_decode == 0) {
// field_{sqr,mul} work on standard representation
if (!group->meth->field_sqr(group, tmp2, x, ctx) ||
!group->meth->field_mul(group, tmp1, tmp2, x, ctx)) {
goto err;
}
} else {
if (!BN_mod_sqr(tmp2, x, &group->field, ctx) ||
!BN_mod_mul(tmp1, tmp2, x, &group->field, ctx)) {
goto err;
}
if (!BN_mod_sqr(tmp2, x, &group->field, ctx) ||
!BN_mod_mul(tmp1, tmp2, x, &group->field, ctx)) {
goto err;
}
// tmp1 := tmp1 + a*x
if (group->a_is_minus3) {
if (!BN_mod_lshift1_quick(tmp2, x, &group->field) ||
!BN_mod_add_quick(tmp2, tmp2, x, &group->field) ||
!BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) {
if (!bn_mod_lshift1_quick_ctx(tmp2, x, &group->field, ctx) ||
!bn_mod_add_quick_ctx(tmp2, tmp2, x, &group->field, ctx) ||
!bn_mod_sub_quick_ctx(tmp1, tmp1, tmp2, &group->field, ctx)) {
goto err;
}
} else {
if (group->meth->field_decode) {
if (!group->meth->field_decode(group, tmp2, &group->a, ctx) ||
!BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) {
goto err;
}
} else {
// field_mul works on standard representation
if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) {
goto err;
}
}
if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) {
if (!BN_mod_mul(tmp2, a, x, &group->field, ctx) ||
!bn_mod_add_quick_ctx(tmp1, tmp1, tmp2, &group->field, ctx)) {
goto err;
}
}
// tmp1 := tmp1 + b
if (group->meth->field_decode) {
if (!group->meth->field_decode(group, tmp2, &group->b, ctx) ||
!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) {
goto err;
}
} else {
if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) {
goto err;
}
if (!bn_mod_add_quick_ctx(tmp1, tmp1, b, &group->field, ctx)) {
goto err;
}
if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) {
@@ -392,13 +371,3 @@ err:
BN_CTX_free(new_ctx);
return ret;
}
int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
int y_bit, BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
return ec_GFp_simple_set_compressed_coordinates(group, point, x, y_bit, ctx);
}
+29 -48
View File
@@ -19,9 +19,6 @@
#include <openssl/base.h>
#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS) && \
!defined(OPENSSL_SMALL)
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/err.h>
@@ -34,6 +31,8 @@
#include "../../internal.h"
#if defined(BORINGSSL_HAS_UINT128) && !defined(OPENSSL_SMALL)
// Field elements are represented as a_0 + 2^56*a_1 + 2^112*a_2 + 2^168*a_3
// using 64-bit coefficients called 'limbs', and sometimes (for multiplication
// results) as b_0 + 2^56*b_1 + 2^112*b_2 + 2^168*b_3 + 2^224*b_4 + 2^280*b_5 +
@@ -1016,22 +1015,27 @@ static int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
p224_felem_inv(z2, z1);
p224_felem_square(tmp, z2);
p224_felem_reduce(z1, tmp);
p224_felem_mul(tmp, x_in, z1);
p224_felem_reduce(x_in, tmp);
p224_felem_contract(x_out, x_in);
if (x != NULL && !p224_felem_to_BN(x, x_out)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
return 0;
if (x != NULL) {
p224_felem_mul(tmp, x_in, z1);
p224_felem_reduce(x_in, tmp);
p224_felem_contract(x_out, x_in);
if (!p224_felem_to_BN(x, x_out)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
return 0;
}
}
p224_felem_mul(tmp, z1, z2);
p224_felem_reduce(z1, tmp);
p224_felem_mul(tmp, y_in, z1);
p224_felem_reduce(y_in, tmp);
p224_felem_contract(y_out, y_in);
if (y != NULL && !p224_felem_to_BN(y, y_out)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
return 0;
if (y != NULL) {
p224_felem_mul(tmp, z1, z2);
p224_felem_reduce(z1, tmp);
p224_felem_mul(tmp, y_in, z1);
p224_felem_reduce(y_in, tmp);
p224_felem_contract(y_out, y_in);
if (!p224_felem_to_BN(y, y_out)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
return 0;
}
}
return 1;
@@ -1041,28 +1045,9 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar,
const EC_POINT *p,
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
int ret = 0;
BN_CTX *new_ctx = NULL;
BIGNUM *x, *y, *z, *tmp_scalar;
p224_felem p_pre_comp[17][3];
p224_felem x_in, y_in, z_in, x_out, y_out, z_out;
if (ctx == NULL) {
ctx = BN_CTX_new();
new_ctx = ctx;
if (ctx == NULL) {
return 0;
}
}
BN_CTX_start(ctx);
if ((x = BN_CTX_get(ctx)) == NULL ||
(y = BN_CTX_get(ctx)) == NULL ||
(z = BN_CTX_get(ctx)) == NULL ||
(tmp_scalar = BN_CTX_get(ctx)) == NULL) {
goto err;
}
if (p != NULL && p_scalar != NULL) {
// We treat NULL scalars as 0, and NULL points as points at infinity, i.e.,
// they contribute nothing to the linear combination.
@@ -1071,7 +1056,7 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
if (!p224_BN_to_felem(x_out, &p->X) ||
!p224_BN_to_felem(y_out, &p->Y) ||
!p224_BN_to_felem(z_out, &p->Z)) {
goto err;
return 0;
}
p224_felem_assign(p_pre_comp[1][0], x_out);
@@ -1101,18 +1086,13 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
p224_felem_contract(x_in, x_out);
p224_felem_contract(y_in, y_out);
p224_felem_contract(z_in, z_out);
if (!p224_felem_to_BN(x, x_in) ||
!p224_felem_to_BN(y, y_in) ||
!p224_felem_to_BN(z, z_in)) {
if (!p224_felem_to_BN(&r->X, x_in) ||
!p224_felem_to_BN(&r->Y, y_in) ||
!p224_felem_to_BN(&r->Z, z_in)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
return 0;
}
ret = ec_point_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx);
err:
BN_CTX_end(ctx);
BN_CTX_free(new_ctx);
return ret;
return 1;
}
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp224_method) {
@@ -1122,10 +1102,11 @@ DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp224_method) {
out->point_get_affine_coordinates =
ec_GFp_nistp224_point_get_affine_coordinates;
out->mul = ec_GFp_nistp224_points_mul;
out->mul_public = ec_GFp_nistp224_points_mul;
out->field_mul = ec_GFp_simple_field_mul;
out->field_sqr = ec_GFp_simple_field_sqr;
out->field_encode = NULL;
out->field_decode = NULL;
};
#endif // 64_BIT && !WINDOWS && !SMALL
#endif // BORINGSSL_HAS_UINT128 && !SMALL
File diff suppressed because it is too large Load Diff
+17 -26
View File
@@ -1,24 +1,20 @@
/* Copyright (c) 2014, Intel Corporation.
/*
* Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2014, Intel Corporation. All Rights Reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
// Developers and authors:
// Shay Gueron (1, 2), and Vlad Krasnov (1)
// (1) Intel Corporation, Israel Development Center
// (2) University of Haifa
// Reference:
// S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with
// 256 Bit Primes"
* Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1)
* (1) Intel Corporation, Israel Development Center, Haifa, Israel
* (2) University of Haifa, Israel
*
* Reference:
* S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with
* 256 Bit Primes"
*/
#include <openssl/ec.h>
@@ -205,13 +201,7 @@ static void ecp_nistz256_mod_inverse_mont(BN_ULONG r[P256_LIMBS],
// returns one if it fits. Otherwise it returns zero.
static int ecp_nistz256_bignum_to_field_elem(BN_ULONG out[P256_LIMBS],
const BIGNUM *in) {
if (in->top > P256_LIMBS) {
return 0;
}
OPENSSL_memset(out, 0, sizeof(BN_ULONG) * P256_LIMBS);
OPENSSL_memcpy(out, in->d, sizeof(BN_ULONG) * in->top);
return 1;
return bn_copy_words(out, P256_LIMBS, in);
}
// r = p * p_scalar
@@ -446,6 +436,7 @@ DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistz256_method) {
out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates = ecp_nistz256_get_affine;
out->mul = ecp_nistz256_points_mul;
out->mul_public = ecp_nistz256_points_mul;
out->field_mul = ec_GFp_mont_field_mul;
out->field_sqr = ec_GFp_mont_field_sqr;
out->field_encode = ec_GFp_mont_field_encode;
+15 -11
View File
@@ -1,16 +1,20 @@
/* Copyright (c) 2014, Intel Corporation.
/*
* Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2014, Intel Corporation. All Rights Reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
* Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1)
* (1) Intel Corporation, Israel Development Center, Haifa, Israel
* (2) University of Haifa, Israel
*
* Reference:
* S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with
* 256 Bit Primes"
*/
#ifndef OPENSSL_HEADER_EC_P256_X86_64_H
#define OPENSSL_HEADER_EC_P256_X86_64_H
+6 -8
View File
@@ -160,17 +160,16 @@ static bool PointToAffine(P256_POINT_AFFINE *out, const P256_POINT *in) {
return false;
}
OPENSSL_memset(out, 0, sizeof(P256_POINT_AFFINE));
if (BN_is_zero(z.get())) {
// The point at infinity is represented as (0, 0).
OPENSSL_memset(out, 0, sizeof(P256_POINT_AFFINE));
return true;
}
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
bssl::UniquePtr<BN_MONT_CTX> mont(
BN_MONT_CTX_new_for_modulus(p.get(), ctx.get()));
if (!ctx || !mont ||
!BN_MONT_CTX_set(mont.get(), p.get(), ctx.get()) ||
// Invert Z.
!BN_from_montgomery(z.get(), z.get(), mont.get(), ctx.get()) ||
!BN_mod_inverse(z.get(), z.get(), p.get(), ctx.get()) ||
@@ -185,12 +184,11 @@ static bool PointToAffine(P256_POINT_AFFINE *out, const P256_POINT *in) {
!BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
ctx.get()) ||
!BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
ctx.get())) {
ctx.get()) ||
!bn_copy_words(out->X, P256_LIMBS, x.get()) ||
!bn_copy_words(out->Y, P256_LIMBS, y.get())) {
return false;
}
OPENSSL_memcpy(out->X, x->d, sizeof(BN_ULONG) * x->top);
OPENSSL_memcpy(out->Y, y->d, sizeof(BN_ULONG) * y->top);
return true;
}
+45 -51
View File
@@ -135,9 +135,11 @@ int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
goto err;
}
BN_set_negative(&group->field, 0);
// Store the field in minimal form, so it can be used with |BN_ULONG| arrays.
bn_set_minimal_width(&group->field);
// group->a
if (!BN_nnmod(tmp_a, a, p, ctx)) {
if (!BN_nnmod(tmp_a, a, &group->field, ctx)) {
goto err;
}
if (group->meth->field_encode) {
@@ -149,7 +151,7 @@ int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
}
// group->b
if (!BN_nnmod(&group->b, b, p, ctx)) {
if (!BN_nnmod(&group->b, b, &group->field, ctx)) {
goto err;
}
if (group->meth->field_encode &&
@@ -269,9 +271,14 @@ static int set_Jprojective_coordinate_GFp(const EC_GROUP *group, BIGNUM *out,
return BN_copy(out, in) != NULL;
}
int ec_GFp_simple_set_Jprojective_coordinates_GFp(
const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y,
const BIGNUM *z, BN_CTX *ctx) {
int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
const BIGNUM *y, BN_CTX *ctx) {
if (x == NULL || y == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
BN_CTX *new_ctx = NULL;
int ret = 0;
@@ -284,7 +291,7 @@ int ec_GFp_simple_set_Jprojective_coordinates_GFp(
if (!set_Jprojective_coordinate_GFp(group, &point->X, x, ctx) ||
!set_Jprojective_coordinate_GFp(group, &point->Y, y, ctx) ||
!set_Jprojective_coordinate_GFp(group, &point->Z, z, ctx)) {
!BN_copy(&point->Z, &group->one)) {
goto err;
}
@@ -295,19 +302,6 @@ err:
return ret;
}
int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
const BIGNUM *y, BN_CTX *ctx) {
if (x == NULL || y == NULL) {
// unlike for projective coordinates, we do not tolerate this
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
return ec_point_set_Jprojective_coordinates_GFp(group, point, x, y,
BN_value_one(), ctx);
}
int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
const EC_POINT *b, BN_CTX *ctx) {
int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
@@ -401,8 +395,8 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
}
// n5, n6
if (!BN_mod_sub_quick(n5, n1, n3, p) ||
!BN_mod_sub_quick(n6, n2, n4, p)) {
if (!bn_mod_sub_quick_ctx(n5, n1, n3, p, ctx) ||
!bn_mod_sub_quick_ctx(n6, n2, n4, p, ctx)) {
goto end;
}
// n5 = n1 - n3
@@ -424,8 +418,8 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
}
// 'n7', 'n8'
if (!BN_mod_add_quick(n1, n1, n3, p) ||
!BN_mod_add_quick(n2, n2, n4, p)) {
if (!bn_mod_add_quick_ctx(n1, n1, n3, p, ctx) ||
!bn_mod_add_quick_ctx(n2, n2, n4, p, ctx)) {
goto end;
}
// 'n7' = n1 + n3
@@ -459,14 +453,14 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
if (!field_sqr(group, n0, n6, ctx) ||
!field_sqr(group, n4, n5, ctx) ||
!field_mul(group, n3, n1, n4, ctx) ||
!BN_mod_sub_quick(&r->X, n0, n3, p)) {
!bn_mod_sub_quick_ctx(&r->X, n0, n3, p, ctx)) {
goto end;
}
// X_r = n6^2 - n5^2 * 'n7'
// 'n9'
if (!BN_mod_lshift1_quick(n0, &r->X, p) ||
!BN_mod_sub_quick(n0, n3, n0, p)) {
if (!bn_mod_lshift1_quick_ctx(n0, &r->X, p, ctx) ||
!bn_mod_sub_quick_ctx(n0, n3, n0, p, ctx)) {
goto end;
}
// n9 = n5^2 * 'n7' - 2 * X_r
@@ -477,7 +471,7 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
goto end; // now n5 is n5^3
}
if (!field_mul(group, n1, n2, n5, ctx) ||
!BN_mod_sub_quick(n0, n0, n1, p)) {
!bn_mod_sub_quick_ctx(n0, n0, n1, p, ctx)) {
goto end;
}
if (BN_is_odd(n0) && !BN_add(n0, n0, p)) {
@@ -542,31 +536,31 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
// n1
if (BN_cmp(&a->Z, &group->one) == 0) {
if (!field_sqr(group, n0, &a->X, ctx) ||
!BN_mod_lshift1_quick(n1, n0, p) ||
!BN_mod_add_quick(n0, n0, n1, p) ||
!BN_mod_add_quick(n1, n0, &group->a, p)) {
!bn_mod_lshift1_quick_ctx(n1, n0, p, ctx) ||
!bn_mod_add_quick_ctx(n0, n0, n1, p, ctx) ||
!bn_mod_add_quick_ctx(n1, n0, &group->a, p, ctx)) {
goto err;
}
// n1 = 3 * X_a^2 + a_curve
} else if (group->a_is_minus3) {
if (!field_sqr(group, n1, &a->Z, ctx) ||
!BN_mod_add_quick(n0, &a->X, n1, p) ||
!BN_mod_sub_quick(n2, &a->X, n1, p) ||
!bn_mod_add_quick_ctx(n0, &a->X, n1, p, ctx) ||
!bn_mod_sub_quick_ctx(n2, &a->X, n1, p, ctx) ||
!field_mul(group, n1, n0, n2, ctx) ||
!BN_mod_lshift1_quick(n0, n1, p) ||
!BN_mod_add_quick(n1, n0, n1, p)) {
!bn_mod_lshift1_quick_ctx(n0, n1, p, ctx) ||
!bn_mod_add_quick_ctx(n1, n0, n1, p, ctx)) {
goto err;
}
// n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
// = 3 * X_a^2 - 3 * Z_a^4
} else {
if (!field_sqr(group, n0, &a->X, ctx) ||
!BN_mod_lshift1_quick(n1, n0, p) ||
!BN_mod_add_quick(n0, n0, n1, p) ||
!bn_mod_lshift1_quick_ctx(n1, n0, p, ctx) ||
!bn_mod_add_quick_ctx(n0, n0, n1, p, ctx) ||
!field_sqr(group, n1, &a->Z, ctx) ||
!field_sqr(group, n1, n1, ctx) ||
!field_mul(group, n1, n1, &group->a, ctx) ||
!BN_mod_add_quick(n1, n1, n0, p)) {
!bn_mod_add_quick_ctx(n1, n1, n0, p, ctx)) {
goto err;
}
// n1 = 3 * X_a^2 + a_curve * Z_a^4
@@ -580,7 +574,7 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
} else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) {
goto err;
}
if (!BN_mod_lshift1_quick(&r->Z, n0, p)) {
if (!bn_mod_lshift1_quick_ctx(&r->Z, n0, p, ctx)) {
goto err;
}
// Z_r = 2 * Y_a * Z_a
@@ -588,30 +582,30 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
// n2
if (!field_sqr(group, n3, &a->Y, ctx) ||
!field_mul(group, n2, &a->X, n3, ctx) ||
!BN_mod_lshift_quick(n2, n2, 2, p)) {
!bn_mod_lshift_quick_ctx(n2, n2, 2, p, ctx)) {
goto err;
}
// n2 = 4 * X_a * Y_a^2
// X_r
if (!BN_mod_lshift1_quick(n0, n2, p) ||
if (!bn_mod_lshift1_quick_ctx(n0, n2, p, ctx) ||
!field_sqr(group, &r->X, n1, ctx) ||
!BN_mod_sub_quick(&r->X, &r->X, n0, p)) {
!bn_mod_sub_quick_ctx(&r->X, &r->X, n0, p, ctx)) {
goto err;
}
// X_r = n1^2 - 2 * n2
// n3
if (!field_sqr(group, n0, n3, ctx) ||
!BN_mod_lshift_quick(n3, n0, 3, p)) {
!bn_mod_lshift_quick_ctx(n3, n0, 3, p, ctx)) {
goto err;
}
// n3 = 8 * Y_a^4
// Y_r
if (!BN_mod_sub_quick(n0, n2, &r->X, p) ||
if (!bn_mod_sub_quick_ctx(n0, n2, &r->X, p, ctx) ||
!field_mul(group, n0, n1, n0, ctx) ||
!BN_mod_sub_quick(&r->Y, n0, n3, p)) {
!bn_mod_sub_quick_ctx(&r->Y, n0, n3, p, ctx)) {
goto err;
}
// Y_r = n1 * (n2 - X_r) - n3
@@ -694,15 +688,15 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
// rh := (rh + a*Z^4)*X
if (group->a_is_minus3) {
if (!BN_mod_lshift1_quick(tmp, Z4, p) ||
!BN_mod_add_quick(tmp, tmp, Z4, p) ||
!BN_mod_sub_quick(rh, rh, tmp, p) ||
if (!bn_mod_lshift1_quick_ctx(tmp, Z4, p, ctx) ||
!bn_mod_add_quick_ctx(tmp, tmp, Z4, p, ctx) ||
!bn_mod_sub_quick_ctx(rh, rh, tmp, p, ctx) ||
!field_mul(group, rh, rh, &point->X, ctx)) {
goto err;
}
} else {
if (!field_mul(group, tmp, Z4, &group->a, ctx) ||
!BN_mod_add_quick(rh, rh, tmp, p) ||
!bn_mod_add_quick_ctx(rh, rh, tmp, p, ctx) ||
!field_mul(group, rh, rh, &point->X, ctx)) {
goto err;
}
@@ -710,17 +704,17 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
// rh := rh + b*Z^6
if (!field_mul(group, tmp, &group->b, Z6, ctx) ||
!BN_mod_add_quick(rh, rh, tmp, p)) {
!bn_mod_add_quick_ctx(rh, rh, tmp, p, ctx)) {
goto err;
}
} else {
// rh := (rh + a)*X
if (!BN_mod_add_quick(rh, rh, &group->a, p) ||
if (!bn_mod_add_quick_ctx(rh, rh, &group->a, p, ctx) ||
!field_mul(group, rh, rh, &point->X, ctx)) {
goto err;
}
// rh := rh + b
if (!BN_mod_add_quick(rh, rh, &group->b, p)) {
if (!bn_mod_add_quick_ctx(rh, rh, &group->b, p, ctx)) {
goto err;
}
}
@@ -14,9 +14,6 @@
#include <openssl/base.h>
#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS)
#include <openssl/ec.h>
#include "internal.h"
@@ -105,5 +102,3 @@ void ec_GFp_nistp_recode_scalar_bits(uint8_t *sign, uint8_t *digit,
*sign = s & 1;
*digit = d;
}
#endif // 64_BIT && !WINDOWS
+156 -276
View File
@@ -73,8 +73,10 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/thread.h>
#include <openssl/type_check.h>
#include "internal.h"
#include "../bn/internal.h"
#include "../../internal.h"
@@ -83,58 +85,21 @@
// http://link.springer.com/chapter/10.1007%2F3-540-45537-X_13
// http://www.bmoeller.de/pdf/TI-01-08.multiexp.pdf
// Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'.
// This is an array r[] of values that are either zero or odd with an
// absolute value less than 2^w satisfying
// scalar = \sum_j r[j]*2^j
// where at most one of any w+1 consecutive digits is non-zero
// with the exception that the most significant digit may be only
// w-1 zeros away from that next non-zero digit.
static int8_t *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) {
int window_val;
int ok = 0;
int8_t *r = NULL;
int sign = 1;
int bit, next_bit, mask;
size_t len = 0, j;
if (BN_is_zero(scalar)) {
r = OPENSSL_malloc(1);
if (!r) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
r[0] = 0;
*ret_len = 1;
return r;
}
int ec_compute_wNAF(const EC_GROUP *group, int8_t *out, const EC_SCALAR *scalar,
size_t bits, int w) {
// 'int8_t' can represent integers with absolute values less than 2^7.
if (w <= 0 || w > 7) {
if (w <= 0 || w > 7 || bits == 0) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
goto err;
return 0;
}
bit = 1 << w; // at most 128
next_bit = bit << 1; // at most 256
mask = next_bit - 1; // at most 255
int bit = 1 << w; // at most 128
int next_bit = bit << 1; // at most 256
int mask = next_bit - 1; // at most 255
if (BN_is_negative(scalar)) {
sign = -1;
}
len = BN_num_bits(scalar);
// The modified wNAF may be one digit longer than binary representation
// (*ret_len will be set to the actual length, i.e. at most
// BN_num_bits(scalar) + 1).
r = OPENSSL_malloc(len + 1);
if (r == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
window_val = scalar->d[0] & mask;
j = 0;
// If j+w+1 >= len, window_val will not increase.
while (window_val != 0 || j + w + 1 < len) {
int window_val = scalar->words[0] & mask;
size_t j = 0;
// If j+w+1 >= bits, window_val will not increase.
while (window_val != 0 || j + w + 1 < bits) {
int digit = 0;
// 0 <= window_val <= 2^(w+1)
@@ -146,7 +111,7 @@ static int8_t *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) {
digit = window_val - next_bit; // -2^w < digit < 0
#if 1 // modified wNAF
if (j + w + 1 >= len) {
if (j + w + 1 >= bits) {
// special case for generating modified wNAFs:
// no new bits will be added into window_val,
// so using a positive digit here will decrease
@@ -161,7 +126,7 @@ static int8_t *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) {
if (digit <= -bit || digit >= bit || !(digit & 1)) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
goto err;
return 0;
}
window_val -= digit;
@@ -170,52 +135,38 @@ static int8_t *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) {
// for modified window NAFs, it may also be 2^w.
if (window_val != 0 && window_val != next_bit && window_val != bit) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
goto err;
return 0;
}
}
r[j++] = sign * digit;
out[j++] = digit;
window_val >>= 1;
window_val += bit * BN_is_bit_set(scalar, j + w);
window_val +=
bit * bn_is_bit_set_words(scalar->words, group->order.width, j + w);
if (window_val > next_bit) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
goto err;
return 0;
}
}
if (j > len + 1) {
// Fill the rest of the wNAF with zeros.
if (j > bits + 1) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
goto err;
return 0;
}
for (size_t i = j; i < bits + 1; i++) {
out[i] = 0;
}
len = j;
ok = 1;
err:
if (!ok) {
OPENSSL_free(r);
r = NULL;
}
if (ok) {
*ret_len = len;
}
return r;
return 1;
}
// TODO: table should be optimised for the wNAF-based implementation,
// sometimes smaller windows will give better performance
// (thus the boundaries should be increased)
static size_t window_bits_for_scalar_size(size_t b) {
if (b >= 2000) {
return 6;
}
if (b >= 800) {
return 5;
}
if (b >= 300) {
return 4;
}
@@ -231,25 +182,62 @@ static size_t window_bits_for_scalar_size(size_t b) {
return 1;
}
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar_raw, const EC_POINT *p,
const EC_SCALAR *p_scalar_raw, BN_CTX *ctx) {
// EC_WNAF_MAX_WINDOW_BITS is the largest value returned by
// |window_bits_for_scalar_size|.
#define EC_WNAF_MAX_WINDOW_BITS 4
// compute_precomp sets |out[i]| to a newly-allocated |EC_POINT| containing
// (2*i+1)*p, for i from 0 to |len|. It returns one on success and
// zero on error.
static int compute_precomp(const EC_GROUP *group, EC_POINT **out,
const EC_POINT *p, size_t len, BN_CTX *ctx) {
out[0] = EC_POINT_new(group);
if (out[0] == NULL ||
!EC_POINT_copy(out[0], p)) {
return 0;
}
int ret = 0;
EC_POINT *two_p = EC_POINT_new(group);
if (two_p == NULL ||
!EC_POINT_dbl(group, two_p, p, ctx)) {
goto err;
}
for (size_t i = 1; i < len; i++) {
out[i] = EC_POINT_new(group);
if (out[i] == NULL ||
!EC_POINT_add(group, out[i], out[i - 1], two_p, ctx)) {
goto err;
}
}
ret = 1;
err:
EC_POINT_free(two_p);
return ret;
}
static int lookup_precomp(const EC_GROUP *group, EC_POINT *out,
EC_POINT *const *precomp, int digit, BN_CTX *ctx) {
if (digit < 0) {
digit = -digit;
return EC_POINT_copy(out, precomp[digit >> 1]) &&
EC_POINT_invert(group, out, ctx);
}
return EC_POINT_copy(out, precomp[digit >> 1]);
}
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx) {
BN_CTX *new_ctx = NULL;
const EC_POINT *generator = NULL;
EC_POINT *precomp_storage[2 * (1 << (EC_WNAF_MAX_WINDOW_BITS - 1))] = {NULL};
EC_POINT **g_precomp = NULL, **p_precomp = NULL;
int8_t g_wNAF[EC_MAX_SCALAR_BYTES * 8 + 1];
int8_t p_wNAF[EC_MAX_SCALAR_BYTES * 8 + 1];
EC_POINT *tmp = NULL;
size_t total_num = 0;
size_t i, j;
int k;
int r_is_inverted = 0;
int r_is_at_infinity = 1;
size_t *wsize = NULL; // individual window sizes
int8_t **wNAF = NULL; // individual wNAFs
size_t *wNAF_len = NULL;
size_t max_len = 0;
size_t num_val = 0;
EC_POINT **val = NULL; // precomputation
EC_POINT **v;
EC_POINT ***val_sub = NULL; // pointers to sub-arrays of 'val'
int ret = 0;
if (ctx == NULL) {
@@ -258,217 +246,109 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r,
goto err;
}
}
BN_CTX_start(ctx);
// Convert from |EC_SCALAR| to |BIGNUM|. |BIGNUM| is not constant-time, but
// neither is the rest of this function.
BIGNUM *g_scalar = NULL, *p_scalar = NULL;
if (g_scalar_raw != NULL) {
g_scalar = BN_CTX_get(ctx);
if (g_scalar == NULL ||
!bn_set_words(g_scalar, g_scalar_raw->words, group->order.top)) {
goto err;
}
}
if (p_scalar_raw != NULL) {
p_scalar = BN_CTX_get(ctx);
if (p_scalar == NULL ||
!bn_set_words(p_scalar, p_scalar_raw->words, group->order.top)) {
goto err;
}
}
size_t bits = BN_num_bits(&group->order);
size_t wsize = window_bits_for_scalar_size(bits);
size_t wNAF_len = bits + 1;
size_t precomp_len = (size_t)1 << (wsize - 1);
// TODO: This function used to take |points| and |scalars| as arrays of
// |num| elements. The code below should be simplified to work in terms of |p|
// and |p_scalar|.
size_t num = p != NULL ? 1 : 0;
const EC_POINT **points = p != NULL ? &p : NULL;
BIGNUM **scalars = p != NULL ? &p_scalar : NULL;
OPENSSL_COMPILE_ASSERT(
OPENSSL_ARRAY_SIZE(g_wNAF) == OPENSSL_ARRAY_SIZE(p_wNAF),
g_wNAF_and_p_wNAF_are_different_sizes);
total_num = num;
if (g_scalar != NULL) {
generator = EC_GROUP_get0_generator(group);
if (generator == NULL) {
OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR);
goto err;
}
++total_num; // treat 'g_scalar' like 'num'-th element of 'scalars'
}
wsize = OPENSSL_malloc(total_num * sizeof(wsize[0]));
wNAF_len = OPENSSL_malloc(total_num * sizeof(wNAF_len[0]));
wNAF = OPENSSL_malloc(total_num * sizeof(wNAF[0]));
val_sub = OPENSSL_malloc(total_num * sizeof(val_sub[0]));
// Ensure wNAF is initialised in case we end up going to err.
if (wNAF != NULL) {
OPENSSL_memset(wNAF, 0, total_num * sizeof(wNAF[0]));
}
if (!wsize || !wNAF_len || !wNAF || !val_sub) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
// num_val will be the total number of temporarily precomputed points
num_val = 0;
for (i = 0; i < total_num; i++) {
size_t bits;
bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(g_scalar);
wsize[i] = window_bits_for_scalar_size(bits);
num_val += (size_t)1 << (wsize[i] - 1);
wNAF[i] =
compute_wNAF((i < num ? scalars[i] : g_scalar), wsize[i], &wNAF_len[i]);
if (wNAF[i] == NULL) {
goto err;
}
if (wNAF_len[i] > max_len) {
max_len = wNAF_len[i];
}
}
// All points we precompute now go into a single array 'val'. 'val_sub[i]' is
// a pointer to the subarray for the i-th point.
val = OPENSSL_malloc(num_val * sizeof(val[0]));
if (val == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
OPENSSL_memset(val, 0, num_val * sizeof(val[0]));
// allocate points for precomputation
v = val;
for (i = 0; i < total_num; i++) {
val_sub[i] = v;
for (j = 0; j < ((size_t)1 << (wsize[i] - 1)); j++) {
*v = EC_POINT_new(group);
if (*v == NULL) {
goto err;
}
v++;
}
}
if (!(v == val + num_val)) {
if (wNAF_len > OPENSSL_ARRAY_SIZE(g_wNAF) ||
2 * precomp_len > OPENSSL_ARRAY_SIZE(precomp_storage)) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
goto err;
}
if (!(tmp = EC_POINT_new(group))) {
// TODO(davidben): |mul_public| is for ECDSA verification which can assume
// non-NULL inputs, but this code is also used for |mul| which cannot. It's
// not constant-time, so replace the generic |mul| and remove the NULL checks.
size_t total_precomp = 0;
if (g_scalar != NULL) {
const EC_POINT *g = EC_GROUP_get0_generator(group);
if (g == NULL) {
OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR);
goto err;
}
g_precomp = precomp_storage + total_precomp;
total_precomp += precomp_len;
if (!ec_compute_wNAF(group, g_wNAF, g_scalar, bits, wsize) ||
!compute_precomp(group, g_precomp, g, precomp_len, ctx)) {
goto err;
}
}
if (p_scalar != NULL) {
p_precomp = precomp_storage + total_precomp;
total_precomp += precomp_len;
if (!ec_compute_wNAF(group, p_wNAF, p_scalar, bits, wsize) ||
!compute_precomp(group, p_precomp, p, precomp_len, ctx)) {
goto err;
}
}
tmp = EC_POINT_new(group);
if (tmp == NULL ||
// |window_bits_for_scalar_size| assumes we do this step.
!EC_POINTs_make_affine(group, total_precomp, precomp_storage, ctx)) {
goto err;
}
// prepare precomputed values:
// val_sub[i][0] := points[i]
// val_sub[i][1] := 3 * points[i]
// val_sub[i][2] := 5 * points[i]
// ...
for (i = 0; i < total_num; i++) {
if (i < num) {
if (!EC_POINT_copy(val_sub[i][0], points[i])) {
goto err;
}
} else if (!EC_POINT_copy(val_sub[i][0], generator)) {
int r_is_at_infinity = 1;
for (size_t k = wNAF_len - 1; k < wNAF_len; k--) {
if (!r_is_at_infinity && !EC_POINT_dbl(group, r, r, ctx)) {
goto err;
}
if (wsize[i] > 1) {
if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx)) {
goto err;
if (g_scalar != NULL) {
if (g_wNAF[k] != 0) {
if (!lookup_precomp(group, tmp, g_precomp, g_wNAF[k], ctx)) {
goto err;
}
if (r_is_at_infinity) {
if (!EC_POINT_copy(r, tmp)) {
goto err;
}
r_is_at_infinity = 0;
} else if (!EC_POINT_add(group, r, r, tmp, ctx)) {
goto err;
}
}
for (j = 1; j < ((size_t)1 << (wsize[i] - 1)); j++) {
if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) {
}
if (p_scalar != NULL) {
if (p_wNAF[k] != 0) {
if (!lookup_precomp(group, tmp, p_precomp, p_wNAF[k], ctx)) {
goto err;
}
if (r_is_at_infinity) {
if (!EC_POINT_copy(r, tmp)) {
goto err;
}
r_is_at_infinity = 0;
} else if (!EC_POINT_add(group, r, r, tmp, ctx)) {
goto err;
}
}
}
}
#if 1 // optional; window_bits_for_scalar_size assumes we do this step
if (!EC_POINTs_make_affine(group, num_val, val, ctx)) {
goto err;
}
#endif
r_is_at_infinity = 1;
for (k = max_len - 1; k >= 0; k--) {
if (!r_is_at_infinity && !EC_POINT_dbl(group, r, r, ctx)) {
goto err;
}
for (i = 0; i < total_num; i++) {
if (wNAF_len[i] > (size_t)k) {
int digit = wNAF[i][k];
int is_neg;
if (digit) {
is_neg = digit < 0;
if (is_neg) {
digit = -digit;
}
if (is_neg != r_is_inverted) {
if (!r_is_at_infinity && !EC_POINT_invert(group, r, ctx)) {
goto err;
}
r_is_inverted = !r_is_inverted;
}
// digit > 0
if (r_is_at_infinity) {
if (!EC_POINT_copy(r, val_sub[i][digit >> 1])) {
goto err;
}
r_is_at_infinity = 0;
} else {
if (!EC_POINT_add(group, r, r, val_sub[i][digit >> 1], ctx)) {
goto err;
}
}
}
}
}
}
if (r_is_at_infinity) {
if (!EC_POINT_set_to_infinity(group, r)) {
goto err;
}
} else if (r_is_inverted && !EC_POINT_invert(group, r, ctx)) {
if (r_is_at_infinity &&
!EC_POINT_set_to_infinity(group, r)) {
goto err;
}
ret = 1;
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
}
BN_CTX_free(new_ctx);
EC_POINT_free(tmp);
OPENSSL_free(wsize);
OPENSSL_free(wNAF_len);
if (wNAF != NULL) {
for (i = 0; i < total_num; i++) {
OPENSSL_free(wNAF[i]);
}
OPENSSL_free(wNAF);
OPENSSL_cleanse(&g_wNAF, sizeof(g_wNAF));
OPENSSL_cleanse(&p_wNAF, sizeof(p_wNAF));
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(precomp_storage); i++) {
EC_POINT_free(precomp_storage[i]);
}
if (val != NULL) {
for (i = 0; i < num_val; i++) {
EC_POINT_free(val[i]);
}
OPENSSL_free(val);
}
OPENSSL_free(val_sub);
return ret;
}
+78 -56
View File
@@ -66,10 +66,52 @@
#include "../../internal.h"
// EC_LOOSE_SCALAR is like |EC_SCALAR| but is bounded by 2^|BN_num_bits(order)|
// rather than |order|.
typedef union {
// bytes is the representation of the scalar in little-endian order.
uint8_t bytes[EC_MAX_SCALAR_BYTES];
BN_ULONG words[EC_MAX_SCALAR_WORDS];
} EC_LOOSE_SCALAR;
static void scalar_add_loose(const EC_GROUP *group, EC_LOOSE_SCALAR *r,
const EC_LOOSE_SCALAR *a, const EC_SCALAR *b) {
// Add and subtract one copy of |order| if necessary. We have:
// |a| + |b| < 2^BN_num_bits(order) + order
// so this leaves |r| < 2^BN_num_bits(order).
const BIGNUM *order = &group->order;
BN_ULONG carry = bn_add_words(r->words, a->words, b->words, order->width);
EC_LOOSE_SCALAR tmp;
BN_ULONG v =
bn_sub_words(tmp.words, r->words, order->d, order->width) - carry;
bn_select_words(r->words, 0u - v, r->words /* tmp < 0 */,
tmp.words /* tmp >= 0 */, order->width);
}
static int scalar_mod_mul_montgomery(const EC_GROUP *group, EC_SCALAR *r,
const EC_SCALAR *a, const EC_SCALAR *b) {
const BIGNUM *order = &group->order;
return bn_mod_mul_montgomery_small(r->words, order->width, a->words,
order->width, b->words, order->width,
group->order_mont);
}
static int scalar_mod_mul_montgomery_loose(const EC_GROUP *group, EC_SCALAR *r,
const EC_LOOSE_SCALAR *a,
const EC_SCALAR *b) {
// Although |a| is loose, |bn_mod_mul_montgomery_small| only requires the
// product not exceed R * |order|. |b| is fully reduced and |a| <
// 2^BN_num_bits(order) <= R, so this holds.
const BIGNUM *order = &group->order;
return bn_mod_mul_montgomery_small(r->words, order->width, a->words,
order->width, b->words, order->width,
group->order_mont);
}
// digest_to_scalar interprets |digest_len| bytes from |digest| as a scalar for
// ECDSA. Note this value is not fully reduced modulo the order, only the
// correct number of bits.
static void digest_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
static void digest_to_scalar(const EC_GROUP *group, EC_LOOSE_SCALAR *out,
const uint8_t *digest, size_t digest_len) {
const BIGNUM *order = &group->order;
size_t num_bits = BN_num_bits(order);
@@ -85,11 +127,11 @@ static void digest_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
// If still too long truncate remaining bits with a shift
if (8 * digest_len > num_bits) {
size_t shift = 8 - (num_bits & 0x7);
for (int i = 0; i < order->top - 1; i++) {
for (int i = 0; i < order->width - 1; i++) {
out->words[i] =
(out->words[i] >> shift) | (out->words[i + 1] << (BN_BITS2 - shift));
}
out->words[order->top - 1] >>= shift;
out->words[order->width - 1] >>= shift;
}
}
@@ -195,15 +237,12 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
goto err;
}
EC_SCALAR r, s, m, u1, u2, s_inv_mont;
EC_SCALAR r, s, u1, u2, s_inv_mont;
EC_LOOSE_SCALAR m;
const BIGNUM *order = EC_GROUP_get0_order(group);
if (BN_is_zero(sig->r) ||
BN_is_negative(sig->r) ||
BN_ucmp(sig->r, order) >= 0 ||
!ec_bignum_to_scalar(group, &r, sig->r) ||
BN_is_zero(sig->s) ||
BN_is_negative(sig->s) ||
BN_ucmp(sig->s, order) >= 0 ||
!ec_bignum_to_scalar(group, &s, sig->s)) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
goto err;
@@ -212,26 +251,21 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
// the products below.
int no_inverse;
if (!BN_mod_inverse_odd(X, &no_inverse, sig->s, order, ctx) ||
!ec_bignum_to_scalar(group, &s_inv_mont, X) ||
!bn_to_montgomery_small(s_inv_mont.words, order->top, s_inv_mont.words,
order->top, group->order_mont)) {
// TODO(davidben): Add a words version of |BN_mod_inverse_odd| and write
// into |s_inv_mont| directly.
!ec_bignum_to_scalar_unchecked(group, &s_inv_mont, X) ||
!bn_to_montgomery_small(s_inv_mont.words, order->width, s_inv_mont.words,
order->width, group->order_mont)) {
goto err;
}
// u1 = m * s_inv_mont mod order
// u2 = r * s_inv_mont mod order
// u1 = m * s^-1 mod order
// u2 = r * s^-1 mod order
//
// |s_inv_mont| is in Montgomery form while |m| and |r| are not, so |u1| and
// |u2| will be taken out of Montgomery form, as desired. Note that, although
// |m| is not fully reduced, |bn_mod_mul_montgomery_small| only requires the
// product not exceed R * |order|. |s_inv_mont| is fully reduced and |m| <
// 2^BN_num_bits(order) <= R, so this holds.
// |u2| will be taken out of Montgomery form, as desired.
digest_to_scalar(group, &m, digest, digest_len);
if (!bn_mod_mul_montgomery_small(u1.words, order->top, m.words, order->top,
s_inv_mont.words, order->top,
group->order_mont) ||
!bn_mod_mul_montgomery_small(u2.words, order->top, r.words, order->top,
s_inv_mont.words, order->top,
group->order_mont)) {
if (!scalar_mod_mul_montgomery_loose(group, &u1, &m, &s_inv_mont) ||
!scalar_mod_mul_montgomery(group, &u2, &r, &s_inv_mont)) {
goto err;
}
@@ -240,7 +274,7 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!ec_point_mul_scalar(group, point, &u1, pub_key, &u2, ctx)) {
if (!ec_point_mul_scalar_public(group, point, &u1, pub_key, &u2, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
goto err;
}
@@ -308,7 +342,7 @@ static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx,
SHA512_CTX sha;
uint8_t additional_data[SHA512_DIGEST_LENGTH];
SHA512_Init(&sha);
SHA512_Update(&sha, priv_key->words, order->top * sizeof(BN_ULONG));
SHA512_Update(&sha, priv_key->words, order->width * sizeof(BN_ULONG));
SHA512_Update(&sha, digest, digest_len);
SHA512_Final(additional_data, &sha);
if (!ec_random_nonzero_scalar(group, &k, additional_data)) {
@@ -318,10 +352,10 @@ static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx,
// Compute k^-1. We leave it in the Montgomery domain as an optimization for
// later operations.
if (!bn_to_montgomery_small(out_kinv_mont->words, order->top, k.words,
order->top, group->order_mont) ||
!bn_mod_inverse_prime_mont_small(out_kinv_mont->words, order->top,
out_kinv_mont->words, order->top,
if (!bn_to_montgomery_small(out_kinv_mont->words, order->width, k.words,
order->width, group->order_mont) ||
!bn_mod_inverse_prime_mont_small(out_kinv_mont->words, order->width,
out_kinv_mont->words, order->width,
group->order_mont)) {
goto err;
}
@@ -368,14 +402,17 @@ ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
int ok = 0;
ECDSA_SIG *ret = ECDSA_SIG_new();
BN_CTX *ctx = BN_CTX_new();
EC_SCALAR kinv_mont, priv_key, r_mont, s, tmp, m;
EC_SCALAR kinv_mont, priv_key, r_mont, s;
EC_LOOSE_SCALAR m, tmp;
if (ret == NULL || ctx == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
return NULL;
}
digest_to_scalar(group, &m, digest, digest_len);
if (!ec_bignum_to_scalar(group, &priv_key, priv_key_bn)) {
// TODO(davidben): Store the private key as an |EC_SCALAR| so this is obvious
// via the type system.
if (!ec_bignum_to_scalar_unchecked(group, &priv_key, priv_key_bn)) {
goto err;
}
for (;;) {
@@ -385,37 +422,22 @@ ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
}
// Compute priv_key * r (mod order). Note if only one parameter is in the
// Montgomery domain, |bn_mod_mul_montgomery_small| will compute the answer
// in the normal domain.
// Montgomery domain, |scalar_mod_mul_montgomery| will compute the answer in
// the normal domain.
if (!ec_bignum_to_scalar(group, &r_mont, ret->r) ||
!bn_to_montgomery_small(r_mont.words, order->top, r_mont.words,
order->top, group->order_mont) ||
!bn_mod_mul_montgomery_small(s.words, order->top, priv_key.words,
order->top, r_mont.words, order->top,
group->order_mont)) {
!bn_to_montgomery_small(r_mont.words, order->width, r_mont.words,
order->width, group->order_mont) ||
!scalar_mod_mul_montgomery(group, &s, &priv_key, &r_mont)) {
goto err;
}
// Compute s += m in constant time. Reduce one copy of |order| if necessary.
// Note this does not leave |s| fully reduced. We have
// |m| < 2^BN_num_bits(order), so subtracting |order| leaves
// 0 <= |s| < 2^BN_num_bits(order).
BN_ULONG carry = bn_add_words(s.words, s.words, m.words, order->top);
BN_ULONG v = bn_sub_words(tmp.words, s.words, order->d, order->top) - carry;
v = 0u - v;
for (int i = 0; i < order->top; i++) {
s.words[i] = constant_time_select_w(v, s.words[i], tmp.words[i]);
}
// Compute tmp = m + priv_key * r.
scalar_add_loose(group, &tmp, &m, &s);
// Finally, multiply s by k^-1. That was retained in Montgomery form, so the
// same technique as the previous multiplication works. Although the
// previous step did not fully reduce |s|, |bn_mod_mul_montgomery_small|
// only requires the product not exceed R * |order|. |kinv_mont| is fully
// reduced and |s| < 2^BN_num_bits(order) <= R, so this holds.
if (!bn_mod_mul_montgomery_small(s.words, order->top, s.words, order->top,
kinv_mont.words, order->top,
group->order_mont) ||
!bn_set_words(ret->s, s.words, order->top)) {
// same technique as the previous multiplication works.
if (!scalar_mod_mul_montgomery_loose(group, &s, &tmp, &kinv_mont) ||
!bn_set_words(ret->s, s.words, order->width)) {
goto err;
}
if (!BN_is_zero(ret->s)) {
@@ -142,6 +142,11 @@ ___
$code=<<___;
#include <openssl/arm_arch.h>
@ Silence ARMv8 deprecated IT instruction warnings. This file is used by both
@ ARMv7 and ARMv8 processors and does not use ARMv8 instructions. (ARMv8 PMULL
@ instructions are in aesv8-armx.pl.)
.arch armv7-a
.text
#if defined(__thumb2__) || defined(__clang__)
.syntax unified
+11 -5
View File
@@ -1,4 +1,11 @@
#!/usr/bin/env perl
#! /usr/bin/env perl
# Copyright 2010-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
#
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -96,14 +103,13 @@
#
# Does it make sense to increase Naggr? To start with it's virtually
# impossible in 32-bit mode, because of limited register bank
# capacity. Otherwise improvement has to be weighed agiainst slower
# capacity. Otherwise improvement has to be weighed against slower
# setup, as well as code size and complexity increase. As even
# optimistic estimate doesn't promise 30% performance improvement,
# there are currently no plans to increase Naggr.
#
# Special thanks to David Woodhouse <dwmw2@infradead.org> for
# providing access to a Westmere-based system on behalf of Intel
# Open Source Technology Centre.
# Special thanks to David Woodhouse for providing access to a
# Westmere-based system on behalf of Intel Open Source Technology Centre.
# January 2010
#
+1 -5
View File
@@ -66,11 +66,7 @@ $code=<<___;
.text
___
$code.=<<___ if ($flavour =~ /64/);
#if !defined(__clang__) || defined(BORINGSSL_CLANG_SUPPORTS_DOT_ARCH)
.arch armv8-a+crypto
#endif
___
$code.=".arch armv8-a+crypto\n" if ($flavour =~ /64/);
$code.=<<___ if ($flavour !~ /64/);
.fpu neon
.code 32
+258
View File
@@ -0,0 +1,258 @@
/* ====================================================================
* Copyright (c) 2011 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <assert.h>
#include <string.h>
#include <openssl/cpu.h>
#include <openssl/mem.h>
#include "../../internal.h"
#include "internal.h"
struct ccm128_state {
union {
uint64_t u[2];
uint8_t c[16];
} nonce, cmac;
};
int CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, const void *key, block128_f block,
ctr128_f ctr, unsigned M, unsigned L) {
if (M < 4 || M > 16 || (M & 1) != 0 || L < 2 || L > 8) {
return 0;
}
ctx->block = block;
ctx->ctr = ctr;
ctx->M = M;
ctx->L = L;
return 1;
}
size_t CRYPTO_ccm128_max_input(const CCM128_CONTEXT *ctx) {
return ctx->L >= sizeof(size_t) ? (size_t)-1
: (((size_t)1) << (ctx->L * 8)) - 1;
}
static int ccm128_init_state(const CCM128_CONTEXT *ctx,
struct ccm128_state *state, const void *key,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *aad, size_t aad_len,
size_t plaintext_len) {
const block128_f block = ctx->block;
const unsigned M = ctx->M;
const unsigned L = ctx->L;
// |L| determines the expected |nonce_len| and the limit for |plaintext_len|.
if (plaintext_len > CRYPTO_ccm128_max_input(ctx) ||
nonce_len != 15 - L) {
return 0;
}
// Assemble the first block for computing the MAC.
OPENSSL_memset(state, 0, sizeof(*state));
state->nonce.c[0] = (uint8_t)((L - 1) | ((M - 2) / 2) << 3);
if (aad_len != 0) {
state->nonce.c[0] |= 0x40; // Set AAD Flag
}
OPENSSL_memcpy(&state->nonce.c[1], nonce, nonce_len);
for (unsigned i = 0; i < L; i++) {
state->nonce.c[15 - i] = (uint8_t)(plaintext_len >> (8 * i));
}
(*block)(state->nonce.c, state->cmac.c, key);
size_t blocks = 1;
if (aad_len != 0) {
unsigned i;
// Cast to u64 to avoid the compiler complaining about invalid shifts.
uint64_t aad_len_u64 = aad_len;
if (aad_len_u64 < 0x10000 - 0x100) {
state->cmac.c[0] ^= (uint8_t)(aad_len_u64 >> 8);
state->cmac.c[1] ^= (uint8_t)aad_len_u64;
i = 2;
} else if (aad_len_u64 <= 0xffffffff) {
state->cmac.c[0] ^= 0xff;
state->cmac.c[1] ^= 0xfe;
state->cmac.c[2] ^= (uint8_t)(aad_len_u64 >> 24);
state->cmac.c[3] ^= (uint8_t)(aad_len_u64 >> 16);
state->cmac.c[4] ^= (uint8_t)(aad_len_u64 >> 8);
state->cmac.c[5] ^= (uint8_t)aad_len_u64;
i = 6;
} else {
state->cmac.c[0] ^= 0xff;
state->cmac.c[1] ^= 0xff;
state->cmac.c[2] ^= (uint8_t)(aad_len_u64 >> 56);
state->cmac.c[3] ^= (uint8_t)(aad_len_u64 >> 48);
state->cmac.c[4] ^= (uint8_t)(aad_len_u64 >> 40);
state->cmac.c[5] ^= (uint8_t)(aad_len_u64 >> 32);
state->cmac.c[6] ^= (uint8_t)(aad_len_u64 >> 24);
state->cmac.c[7] ^= (uint8_t)(aad_len_u64 >> 16);
state->cmac.c[8] ^= (uint8_t)(aad_len_u64 >> 8);
state->cmac.c[9] ^= (uint8_t)aad_len_u64;
i = 10;
}
do {
for (; i < 16 && aad_len != 0; i++) {
state->cmac.c[i] ^= *aad;
aad++;
aad_len--;
}
(*block)(state->cmac.c, state->cmac.c, key);
blocks++;
i = 0;
} while (aad_len != 0);
}
// Per RFC 3610, section 2.6, the total number of block cipher operations done
// must not exceed 2^61. There are two block cipher operations remaining per
// message block, plus one block at the end to encrypt the MAC.
size_t remaining_blocks = 2 * ((plaintext_len + 15) / 16) + 1;
if (plaintext_len + 15 < plaintext_len ||
remaining_blocks + blocks < blocks ||
// Silence Clang's unhelpful -Wtautological-constant-out-of-range-compare
// warning.
(sizeof(size_t) > 4 && remaining_blocks + blocks > UINT64_C(1) << 61)) {
return 0;
}
// Assemble the first block for encrypting and decrypting. The bottom |L|
// bytes are replaced with a counter and all bit the encoding of |L| is
// cleared in the first byte.
state->nonce.c[0] &= 7;
return 1;
}
static int ccm128_encrypt(const CCM128_CONTEXT *ctx, struct ccm128_state *state,
const void *key, uint8_t *out, const uint8_t *in,
size_t len) {
// The counter for encryption begins at one.
for (unsigned i = 0; i < ctx->L; i++) {
state->nonce.c[15 - i] = 0;
}
state->nonce.c[15] = 1;
uint8_t partial_buf[16];
unsigned num = 0;
if (ctx->ctr != NULL) {
CRYPTO_ctr128_encrypt_ctr32(in, out, len, key, state->nonce.c, partial_buf,
&num, ctx->ctr);
} else {
CRYPTO_ctr128_encrypt(in, out, len, key, state->nonce.c, partial_buf, &num,
ctx->block);
}
return 1;
}
static int ccm128_compute_mac(const CCM128_CONTEXT *ctx,
struct ccm128_state *state, const void *key,
uint8_t *out_tag, size_t tag_len,
const uint8_t *in, size_t len) {
block128_f block = ctx->block;
if (tag_len != ctx->M) {
return 0;
}
// Incorporate |in| into the MAC.
union {
uint64_t u[2];
uint8_t c[16];
} tmp;
while (len >= 16) {
OPENSSL_memcpy(tmp.c, in, 16);
state->cmac.u[0] ^= tmp.u[0];
state->cmac.u[1] ^= tmp.u[1];
(*block)(state->cmac.c, state->cmac.c, key);
in += 16;
len -= 16;
}
if (len > 0) {
for (size_t i = 0; i < len; i++) {
state->cmac.c[i] ^= in[i];
}
(*block)(state->cmac.c, state->cmac.c, key);
}
// Encrypt the MAC with counter zero.
for (unsigned i = 0; i < ctx->L; i++) {
state->nonce.c[15 - i] = 0;
}
(*block)(state->nonce.c, tmp.c, key);
state->cmac.u[0] ^= tmp.u[0];
state->cmac.u[1] ^= tmp.u[1];
OPENSSL_memcpy(out_tag, state->cmac.c, tag_len);
return 1;
}
int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const void *key,
uint8_t *out, uint8_t *out_tag, size_t tag_len,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *in, size_t len, const uint8_t *aad,
size_t aad_len) {
struct ccm128_state state;
return ccm128_init_state(ctx, &state, key, nonce, nonce_len, aad, aad_len,
len) &&
ccm128_compute_mac(ctx, &state, key, out_tag, tag_len, in, len) &&
ccm128_encrypt(ctx, &state, key, out, in, len);
}
int CRYPTO_ccm128_decrypt(const CCM128_CONTEXT *ctx, const void *key,
uint8_t *out, uint8_t *out_tag, size_t tag_len,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *in, size_t len, const uint8_t *aad,
size_t aad_len) {
struct ccm128_state state;
return ccm128_init_state(ctx, &state, key, nonce, nonce_len, aad, aad_len,
len) &&
ccm128_encrypt(ctx, &state, key, out, in, len) &&
ccm128_compute_mac(ctx, &state, key, out_tag, tag_len, out, len);
}
+36 -32
View File
@@ -66,38 +66,6 @@ extern "C" {
#define STRICT_ALIGNMENT 0
#endif
#if defined(__GNUC__) && __GNUC__ >= 2
static inline uint32_t CRYPTO_bswap4(uint32_t x) {
return __builtin_bswap32(x);
}
static inline uint64_t CRYPTO_bswap8(uint64_t x) {
return __builtin_bswap64(x);
}
#elif defined(_MSC_VER)
OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <intrin.h>
OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma intrinsic(_byteswap_uint64, _byteswap_ulong)
static inline uint32_t CRYPTO_bswap4(uint32_t x) {
return _byteswap_ulong(x);
}
static inline uint64_t CRYPTO_bswap8(uint64_t x) {
return _byteswap_uint64(x);
}
#else
static inline uint32_t CRYPTO_bswap4(uint32_t x) {
x = (x >> 16) | (x << 16);
x = ((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8);
return x;
}
static inline uint64_t CRYPTO_bswap8(uint64_t x) {
return CRYPTO_bswap4(x >> 32) | (((uint64_t)CRYPTO_bswap4(x)) << 32);
}
#endif
static inline uint32_t GETU32(const void *in) {
uint32_t v;
OPENSSL_memcpy(&v, in, sizeof(v));
@@ -281,6 +249,42 @@ OPENSSL_EXPORT void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, uint8_t *tag,
size_t len);
// CCM.
typedef struct ccm128_context {
block128_f block;
ctr128_f ctr;
unsigned M, L;
} CCM128_CONTEXT;
// CRYPTO_ccm128_init initialises |ctx| to use |block| (typically AES) with the
// specified |M| and |L| parameters. It returns one on success and zero if |M|
// or |L| is invalid.
int CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, const void *key, block128_f block,
ctr128_f ctr, unsigned M, unsigned L);
// CRYPTO_ccm128_max_input returns the maximum input length accepted by |ctx|.
size_t CRYPTO_ccm128_max_input(const CCM128_CONTEXT *ctx);
// CRYPTO_ccm128_encrypt encrypts |len| bytes from |in| to |out| writing the tag
// to |out_tag|. |key| must be the same key that was passed to
// |CRYPTO_ccm128_init|. It returns one on success and zero otherwise.
int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const void *key,
uint8_t *out, uint8_t *out_tag, size_t tag_len,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *in, size_t len, const uint8_t *aad,
size_t aad_len);
// CRYPTO_ccm128_decrypt decrypts |len| bytes from |in| to |out|, writing the
// expected tag to |out_tag|. |key| must be the same key that was passed to
// |CRYPTO_ccm128_init|. It returns one on success and zero otherwise.
int CRYPTO_ccm128_decrypt(const CCM128_CONTEXT *ctx, const void *key,
uint8_t *out, uint8_t *out_tag, size_t tag_len,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *in, size_t len, const uint8_t *aad,
size_t aad_len);
// CBC.
// cbc128_f is the type of a function that performs CBC-mode encryption.
+9 -7
View File
@@ -74,11 +74,11 @@ static void ctr32_add(CTR_DRBG_STATE *drbg, uint32_t n) {
CRYPTO_bswap4(CRYPTO_bswap4(drbg->counter.words[3]) + n);
}
static int CTR_DRBG_update(CTR_DRBG_STATE *drbg, const uint8_t *data,
static int ctr_drbg_update(CTR_DRBG_STATE *drbg, const uint8_t *data,
size_t data_len) {
// Section 10.2.1.2. A value of |data_len| which less than
// |CTR_DRBG_ENTROPY_LEN| is permitted and acts the same as right-padding
// with zeros. This can save a copy.
// Per section 10.2.1.2, |data_len| must be |CTR_DRBG_ENTROPY_LEN|. Here, we
// allow shorter inputs and right-pad them with zeros. This is equivalent to
// the specified algorithm but saves a copy in |CTR_DRBG_generate|.
if (data_len > CTR_DRBG_ENTROPY_LEN) {
return 0;
}
@@ -119,7 +119,7 @@ int CTR_DRBG_reseed(CTR_DRBG_STATE *drbg,
entropy = entropy_copy;
}
if (!CTR_DRBG_update(drbg, entropy, CTR_DRBG_ENTROPY_LEN)) {
if (!ctr_drbg_update(drbg, entropy, CTR_DRBG_ENTROPY_LEN)) {
return 0;
}
@@ -142,7 +142,7 @@ int CTR_DRBG_generate(CTR_DRBG_STATE *drbg, uint8_t *out, size_t out_len,
}
if (additional_data_len != 0 &&
!CTR_DRBG_update(drbg, additional_data, additional_data_len)) {
!ctr_drbg_update(drbg, additional_data, additional_data_len)) {
return 0;
}
@@ -187,7 +187,9 @@ int CTR_DRBG_generate(CTR_DRBG_STATE *drbg, uint8_t *out, size_t out_len,
OPENSSL_memcpy(out, block, out_len);
}
if (!CTR_DRBG_update(drbg, additional_data, additional_data_len)) {
// Right-padding |additional_data| in step 2.2 is handled implicitly by
// |ctr_drbg_update|, to save a copy.
if (!ctr_drbg_update(drbg, additional_data, additional_data_len)) {
return 0;
}

Some files were not shown because too many files have changed in this diff Show More