Conversation
…fuse a negative length
Contributor
|
Thanks for the patch, merged with revisions, up on https://www.bouncycastle.org/betas |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
XofUtils.encode(byte[] in, int inOff, int len)builds theencode_stringprefix of NIST SP 800-185 sec. 2.3.3 for a TupleHash element, but computes the bit length in int arithmetic:core/src/main/java/org/bouncycastle/crypto/digests/XofUtils.java:60and:62readleftEncode(len * 8)withlenan int, so the product wraps before widening to thelongparameter. Its only caller isTupleHash.update(TupleHash.java:98). The other call sites (CSHAKEDigest.java:112,KMAC.java:148/:169/:242,TupleHash.java:104,ParallelHash.java:178) already use* 8L.From 2^28 bytes the product is negative, and
leftEncodesizes its output bywhile ((v >>= 8) != 0)(XofUtils.java:12), an arithmetic shift that converges to -1, so the call never returns;rightEncodehas the same loop at:34. From 2^29 bytes the product wraps non-negative and the element is prefixed at the wrong length: it gets0100, the prefix of an empty element, so two different tuples can absorb the same byte string, which the tuple encoding of sec. 5.3 exists to prevent.A second argument reaches the same loop: a negative
outLenindoFinal(out, off, outLen)entersrightEncodeviaTupleHash.wrapUp,ParallelHash.wrapUpandKMAC.doFinal, and does not return. Issue #431 raised the negative argument in 2018; the reply fixed the endianness only.Reproduced on the released bcprov-jdk18on-1.86.jar:
MessageDigest.getInstance("TupleHash256-512", "BC").update(new byte[1 << 28])is RUNNABLE after 20 s withXofUtils.leftEncodeon top, where the same object over 1 MiB returns in 8 ms and JCA SHA-256 over that array in 973 ms; at 2^29 bytes two distinct tuples both digest to7d362b64...dc1aea82. Currentorigin/mainand the 1.87-SNAPSHOT beta (1.87.0.20718) are byte-identical here and reproduce both.This change:
len * 8L; andleftEncodeandrightEncodethrowIllegalArgumentExceptionwith'strLen' cannot be negativeinstead of spinning, so a negative output length is reported rather than hanging; andXofUtilsTest(encode vectors either side of the int boundary, and the negative cases) andTupleHashLargeInputTest(a 2^28-byte element checked against cSHAKE driven per sec. 5.3), registered inRegressionTest.testsandslowTests. Both hang without the change and pass with it;TupleHashTest,CSHAKETest,KMACTestandParallelHashTestpass either way.A digest over an element of 2^29 bytes or more changes, its old prefix not having conformed; below 2^28 the two arithmetics agree. Separately,
encodedoes not checklenagainstin.length, soupdate(byte[]{0x7f}, 0, 8)digests seven zero bytesArrays.copyOfRangefabricated, whereSHA256Digestthrows. Different cause, so it is left out; happy to raise it separately.Base tree only: one
XofUtils.java, noMETA-INF/versionscopy, nomodule-infoor OSGi change. A release-note entry is included, happy to move it to another block.