Browse Source

SHA-1: collision detection support

Update SHA1 class to include a Java port of sha1dc[1]'s ubc_check,
which can detect the attack pattern used by the SHAttered[2] authors.

Given the shattered example files that have the same SHA-1, this
modified implementation can identify there is risk of collision given
only one file in the pair:

  $ jgit ...
  [main] WARN org.eclipse.jgit.util.sha1.SHA1 - SHA-1 collision 38762cf7f5

When JGit detects probability of a collision the SHA1 class now warns
on the logger, reporting the object's SHA-1 hash, and then throws a
Sha1CollisionException to the caller.

From the paper[3] by Marc Stevens, the probability of a false positive
identification of a collision is about 14 * 2^(-160), sufficiently low
enough for any detected collision to likely be a real collision.

git-core[4] may adopt sha1dc before the system migrates to an entirely
new hash function.  This commit enables JGit to remain compatible with
that move to sha1dc, and help protect users by warning if similar
attacks as SHAttered are identified.

Performance declined about 8% (detection off), now:

  MessageDigest        238.41 MiB/s
  MessageDigest        244.52 MiB/s
  MessageDigest        244.06 MiB/s
  MessageDigest        242.58 MiB/s

  SHA1                 216.77 MiB/s (was ~240.83 MiB/s)
  SHA1                 220.98 MiB/s
  SHA1                 221.76 MiB/s
  SHA1                 221.34 MiB/s

This decline in throughput is attributed to the step loop unrolling in
compress(), which was necessary to easily fit the UbcCheck logic into
the hash function.  Using helper functions s1-s4 reduces the code
explosion, providing acceptable throughput.

With detection enabled (default):

  SHA1 detectCollision 180.12 MiB/s
  SHA1 detectCollision 181.59 MiB/s
  SHA1 detectCollision 181.64 MiB/s
  SHA1 detectCollision 182.24 MiB/s

  sha1dc (native C)   ~206.28 MiB/s
  sha1dc (native C)   ~204.47 MiB/s
  sha1dc (native C)   ~203.74 MiB/s

Average time across 100,000 calls to hash 4100 bytes (such as a commit
or tree) for the various algorithms available to JGit also shows SHA1
is slower than MessageDigest, but by an acceptable margin:

  MessageDigest        17 usec
  SHA1                 18 usec
  SHA1 detectCollision 22 usec

Time to index-pack for git.git (217982 objects, 69 MiB) has increased:

  MessageDigest   SHA1 w/ detectCollision
  -------------   -----------------------
         20.12s   25.25s
         19.87s   25.48s
         20.04s   25.26s

    avg  20.01s   25.33s    +26%

Being implemented in Java with these additional safety checks is
clearly a penalty, but throughput is still acceptable given the
increased security against object name collisions.

[1] https://github.com/cr-marcstevens/sha1collisiondetection
[2] https://shattered.it/
[3] https://marc-stevens.nl/research/papers/C13-S.pdf
[4] https://public-inbox.org/git/20170223230621.43anex65ndoqbgnf@sigill.intra.peff.net/

Change-Id: I9fe4c6d8fc5e5a661af72cd3246c9e67b1b9fee6
tags/v4.7.0.201704051617-r
Shawn Pearce 7 years ago
parent
commit
83ad74b6b9

BIN
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/util/sha1/shattered-1.pdf View File


BIN
org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/util/sha1/shattered-2.pdf View File


+ 111
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/sha1/SHA1Test.java View File

@@ -44,12 +44,20 @@
package org.eclipse.jgit.util.sha1;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.IO;
import org.junit.Test;

public class SHA1Test {
@@ -124,4 +132,107 @@ public class SHA1Test {
assertEquals(exp, s1);
assertEquals(exp, s2);
}

@Test
public void shatteredCollision()
throws IOException, NoSuchAlgorithmException {
byte[] pdf1 = read("shattered-1.pdf", 422435);
byte[] pdf2 = read("shattered-2.pdf", 422435);
MessageDigest md;
SHA1 s;

// SHAttered attack generated these PDFs to have identical SHA-1.
ObjectId bad = ObjectId
.fromString("38762cf7f55934b34d179ae6a4c80cadccbb7f0a");
md = MessageDigest.getInstance("SHA-1");
md.update(pdf1);
assertEquals("shattered-1 collides", bad,
ObjectId.fromRaw(md.digest()));
s = SHA1.newInstance().setDetectCollision(false);
s.update(pdf1);
assertEquals("shattered-1 collides", bad, s.toObjectId());

md = MessageDigest.getInstance("SHA-1");
md.update(pdf2);
assertEquals("shattered-2 collides", bad,
ObjectId.fromRaw(md.digest()));
s = SHA1.newInstance().setDetectCollision(false);
s.update(pdf2);
assertEquals("shattered-2 collides", bad, s.toObjectId());

// SHA1 with detectCollision shouldn't be fooled.
s = SHA1.newInstance().setDetectCollision(true);
s.update(pdf1);
try {
s.digest();
fail("expected " + Sha1CollisionException.class.getSimpleName());
} catch (Sha1CollisionException e) {
assertEquals(e.getMessage(),
"SHA-1 collision detected on " + bad.name());
}

s = SHA1.newInstance().setDetectCollision(true);
s.update(pdf2);
try {
s.digest();
fail("expected " + Sha1CollisionException.class.getSimpleName());
} catch (Sha1CollisionException e) {
assertEquals(e.getMessage(),
"SHA-1 collision detected on " + bad.name());
}
}

@Test
public void shatteredStoredInGitBlob() throws IOException {
byte[] pdf1 = read("shattered-1.pdf", 422435);
byte[] pdf2 = read("shattered-2.pdf", 422435);

// Although the prior test detects the chance of a collision, adding
// the Git blob header permutes the data enough for this specific
// attack example to not be detected as a collision. (A different file
// pair that takes the Git header into account however, would.)
ObjectId id1 = blob(pdf1, SHA1.newInstance().setDetectCollision(true));
ObjectId id2 = blob(pdf2, SHA1.newInstance().setDetectCollision(true));

assertEquals(
ObjectId.fromString("ba9aaa145ccd24ef760cf31c74d8f7ca1a2e47b0"),
id1);
assertEquals(
ObjectId.fromString("b621eeccd5c7edac9b7dcba35a8d5afd075e24f2"),
id2);
}

@Test
public void detectsShatteredByDefault() throws IOException {
assumeTrue(System.getProperty("org.eclipse.jgit.util.sha1.detectCollision") == null);
assumeTrue(System.getProperty("org.eclipse.jgit.util.sha1.safeHash") == null);

byte[] pdf1 = read("shattered-1.pdf", 422435);
SHA1 s = SHA1.newInstance();
s.update(pdf1);
try {
s.digest();
fail("expected " + Sha1CollisionException.class.getSimpleName());
} catch (Sha1CollisionException e) {
assertTrue("shattered-1 detected", true);
}
}

private static ObjectId blob(byte[] pdf1, SHA1 s) {
s.update(Constants.encodedTypeString(Constants.OBJ_BLOB));
s.update((byte) ' ');
s.update(Constants.encodeASCII(pdf1.length));
s.update((byte) 0);
s.update(pdf1);
return s.toObjectId();
}

private byte[] read(String name, int sizeHint) throws IOException {
try (InputStream in = getClass().getResourceAsStream(name)) {
ByteBuffer buf = IO.readWholeStream(in, sizeHint);
byte[] r = new byte[buf.remaining()];
buf.get(r);
return r;
}
}
}

+ 37
- 0
org.eclipse.jgit/about.html View File

@@ -21,6 +21,10 @@
margin-top: 0.05em;
margin-bottom: 0.05em;
}
.ubc-name {
margin-left: 0.5in;
white-space: pre;
}
</style>

</head>
@@ -54,6 +58,39 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.</p>

<hr>
<p><b>SHA-1 UbcCheck - MIT</b></p>

<p>Copyright (c) 2017:</p>
<div class="ubc-name">
Marc Stevens
Cryptology Group
Centrum Wiskunde & Informatica
P.O. Box 94079, 1090 GB Amsterdam, Netherlands
marc@marc-stevens.nl
</div>
<div class="ubc-name">
Dan Shumow
Microsoft Research
danshu@microsoft.com
</div>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
</p>
<ul><li>The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.</li></ul>
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.</p>

</body>

</html>

+ 1
- 0
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties View File

@@ -564,6 +564,7 @@ selectingCommits=Selecting commits
sequenceTooLargeForDiffAlgorithm=Sequence too large for difference algorithm.
serviceNotEnabledNoName=Service not enabled
serviceNotPermitted={0} not permitted
sha1CollisionDetected1=SHA-1 collision detected on {0}
shallowCommitsAlreadyInitialized=Shallow commits have already been initialized
shallowPacksRequireDepthWalk=Shallow packs require a DepthWalk
shortCompressedStreamAt=Short compressed stream at {0}

+ 1
- 0
org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java View File

@@ -623,6 +623,7 @@ public class JGitText extends TranslationBundle {
/***/ public String sequenceTooLargeForDiffAlgorithm;
/***/ public String serviceNotEnabledNoName;
/***/ public String serviceNotPermitted;
/***/ public String sha1CollisionDetected1;
/***/ public String shallowCommitsAlreadyInitialized;
/***/ public String shallowPacksRequireDepthWalk;
/***/ public String shortCompressedStreamAt;

+ 92
- 0
org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.compress View File

@@ -0,0 +1,92 @@
/* Template for compress method; run through cpp. */

#define ROUND1_STEP(a, b, c, d, e, T) e += s1(a,b,c,d,w[T]); b = rotateLeft(b, 30)
#define ROUND2_STEP(a, b, c, d, e, T) e += s2(a,b,c,d,w[T]); b = rotateLeft(b, 30)
#define ROUND3_STEP(a, b, c, d, e, T) e += s3(a,b,c,d,w[T]); b = rotateLeft(b, 30)
#define ROUND4_STEP(a, b, c, d, e, T) e += s4(a,b,c,d,w[T]); b = rotateLeft(b, 30)

ROUND1_STEP(a, b, c, d, e, 0);
ROUND1_STEP(e, a, b, c, d, 1);
ROUND1_STEP(d, e, a, b, c, 2);
ROUND1_STEP(c, d, e, a, b, 3);
ROUND1_STEP(b, c, d, e, a, 4);
ROUND1_STEP(a, b, c, d, e, 5);
ROUND1_STEP(e, a, b, c, d, 6);
ROUND1_STEP(d, e, a, b, c, 7);
ROUND1_STEP(c, d, e, a, b, 8);
ROUND1_STEP(b, c, d, e, a, 9);
ROUND1_STEP(a, b, c, d, e, 10);
ROUND1_STEP(e, a, b, c, d, 11);
ROUND1_STEP(d, e, a, b, c, 12);
ROUND1_STEP(c, d, e, a, b, 13);
ROUND1_STEP(b, c, d, e, a, 14);
ROUND1_STEP(a, b, c, d, e, 15);
ROUND1_STEP(e, a, b, c, d, 16);
ROUND1_STEP(d, e, a, b, c, 17);
ROUND1_STEP(c, d, e, a, b, 18);
ROUND1_STEP(b, c, d, e, a, 19);

ROUND2_STEP(a, b, c, d, e, 20);
ROUND2_STEP(e, a, b, c, d, 21);
ROUND2_STEP(d, e, a, b, c, 22);
ROUND2_STEP(c, d, e, a, b, 23);
ROUND2_STEP(b, c, d, e, a, 24);
ROUND2_STEP(a, b, c, d, e, 25);
ROUND2_STEP(e, a, b, c, d, 26);
ROUND2_STEP(d, e, a, b, c, 27);
ROUND2_STEP(c, d, e, a, b, 28);
ROUND2_STEP(b, c, d, e, a, 29);
ROUND2_STEP(a, b, c, d, e, 30);
ROUND2_STEP(e, a, b, c, d, 31);
ROUND2_STEP(d, e, a, b, c, 32);
ROUND2_STEP(c, d, e, a, b, 33);
ROUND2_STEP(b, c, d, e, a, 34);
ROUND2_STEP(a, b, c, d, e, 35);
ROUND2_STEP(e, a, b, c, d, 36);
ROUND2_STEP(d, e, a, b, c, 37);
ROUND2_STEP(c, d, e, a, b, 38);
ROUND2_STEP(b, c, d, e, a, 39);

ROUND3_STEP(a, b, c, d, e, 40);
ROUND3_STEP(e, a, b, c, d, 41);
ROUND3_STEP(d, e, a, b, c, 42);
ROUND3_STEP(c, d, e, a, b, 43);
ROUND3_STEP(b, c, d, e, a, 44);
ROUND3_STEP(a, b, c, d, e, 45);
ROUND3_STEP(e, a, b, c, d, 46);
ROUND3_STEP(d, e, a, b, c, 47);
ROUND3_STEP(c, d, e, a, b, 48);
ROUND3_STEP(b, c, d, e, a, 49);
ROUND3_STEP(a, b, c, d, e, 50);
ROUND3_STEP(e, a, b, c, d, 51);
ROUND3_STEP(d, e, a, b, c, 52);
ROUND3_STEP(c, d, e, a, b, 53);
ROUND3_STEP(b, c, d, e, a, 54);
ROUND3_STEP(a, b, c, d, e, 55);
ROUND3_STEP(e, a, b, c, d, 56);
ROUND3_STEP(d, e, a, b, c, 57);
state58.save(a, b, c, d, e);
ROUND3_STEP(c, d, e, a, b, 58);
ROUND3_STEP(b, c, d, e, a, 59);

ROUND4_STEP(a, b, c, d, e, 60);
ROUND4_STEP(e, a, b, c, d, 61);
ROUND4_STEP(d, e, a, b, c, 62);
ROUND4_STEP(c, d, e, a, b, 63);
ROUND4_STEP(b, c, d, e, a, 64);
state65.save(a, b, c, d, e);
ROUND4_STEP(a, b, c, d, e, 65);
ROUND4_STEP(e, a, b, c, d, 66);
ROUND4_STEP(d, e, a, b, c, 67);
ROUND4_STEP(c, d, e, a, b, 68);
ROUND4_STEP(b, c, d, e, a, 69);
ROUND4_STEP(a, b, c, d, e, 70);
ROUND4_STEP(e, a, b, c, d, 71);
ROUND4_STEP(d, e, a, b, c, 72);
ROUND4_STEP(c, d, e, a, b, 73);
ROUND4_STEP(b, c, d, e, a, 74);
ROUND4_STEP(a, b, c, d, e, 75);
ROUND4_STEP(e, a, b, c, d, 76);
ROUND4_STEP(d, e, a, b, c, 77);
ROUND4_STEP(c, d, e, a, b, 78);
ROUND4_STEP(b, c, d, e, a, 79);

+ 385
- 93
org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java View File

@@ -43,31 +43,54 @@

package org.eclipse.jgit.util.sha1;

import static java.lang.Integer.lowestOneBit;
import static java.lang.Integer.numberOfTrailingZeros;
import static java.lang.Integer.rotateLeft;
import static java.lang.Integer.rotateRight;

import java.util.Arrays;

import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.NB;
import org.eclipse.jgit.util.SystemReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Pure Java implementation of SHA-1 from FIPS 180-1 / RFC 3174.
*
* <p>
* See <a href="https://tools.ietf.org/html/rfc3174">RFC 3174</a>.
* <p>
* Unlike MessageDigest, this implementation includes the algorithm used by
* {@code sha1dc} to detect cryptanalytic collision attacks against SHA-1, such
* as the one used by <a href="https://shattered.it/">SHAttered</a>. See
* <a href="https://github.com/cr-marcstevens/sha1collisiondetection">
* sha1collisiondetection</a> for more information.
* <p>
* When detectCollision is true (default), this implementation throws
* {@link Sha1CollisionException} from any digest method if a potential
* collision was detected.
*
* @since 4.7
*/
public class SHA1 {
private static Logger LOG = LoggerFactory.getLogger(SHA1.class);
private static final boolean DETECT_COLLISIONS;

static {
SystemReader sr = SystemReader.getInstance();
String v = sr.getProperty("org.eclipse.jgit.util.sha1.detectCollision"); //$NON-NLS-1$
DETECT_COLLISIONS = v != null ? Boolean.parseBoolean(v) : true;
}

/** @return a new context to compute a SHA-1 hash of data. */
public static SHA1 newInstance() {
return new SHA1();
}

private int h0;
private int h1;
private int h2;
private int h3;
private int h4;
private final State h = new State();
private final int[] w = new int[80];

/** Buffer to accumulate partial blocks to 64 byte alignment. */
@@ -76,30 +99,35 @@ public class SHA1 {
/** Total number of bytes in the message. */
private long length;

private boolean detectCollision = DETECT_COLLISIONS;
private boolean foundCollision;

private final int[] w2 = new int[80];
private final State state58 = new State();
private final State state65 = new State();
private final State hIn = new State();
private final State hTmp = new State();

private SHA1() {
init();
h.init();
}

/**
* Reset this instance to compute another hash.
* Enable likely collision detection.
* <p>
* Default is {@code true}.
* <p>
* May also be set by system property:
* {@code -Dorg.eclipse.jgit.util.sha1.detectCollision=true}.
*
* @return {@code this}.
* @param detect
* @return {@code this}
*/
public SHA1 reset() {
init();
length = 0;
public SHA1 setDetectCollision(boolean detect) {
detectCollision = detect;
return this;
}

private void init() {
// Magic initialization constants defined by FIPS180.
h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;
}

/**
* Update the digest computation by adding a byte.
*
@@ -161,83 +189,283 @@ public class SHA1 {
}

private void compress(byte[] block, int p) {
// Method 1 from RFC 3174 section 6.1.
// Method 2 (circular queue of 16 words) is slower.
int a = h0, b = h1, c = h2, d = h3, e = h4;
initBlock(block, p);
int ubcDvMask = detectCollision ? UbcCheck.check(w) : 0;
compress();

// Round 1: 0 <= t <= 15 comes from the input block.
while (ubcDvMask != 0) {
int b = numberOfTrailingZeros(lowestOneBit(ubcDvMask));
UbcCheck.DvInfo dv = UbcCheck.DV[b];
for (int i = 0; i < 80; i++) {
w2[i] = w[i] ^ dv.dm[i];
}
recompress(dv.testt);
if (eq(hTmp, h)) {
foundCollision = true;
break;
}
ubcDvMask &= ~(1 << b);
}
}

private void initBlock(byte[] block, int p) {
for (int t = 0; t < 16; t++) {
int temp = NB.decodeInt32(block, p + (t << 2));
w[t] = temp;
temp += ((a << 5) | (a >>> 27)) // S^5(A)
+ (((c ^ d) & b) ^ d) // f: 0 <= t <= 19
+ e + 0x5A827999;
e = d;
d = c;
c = (b << 30) | (b >>> 2); // S^30(B)
b = a;
a = temp;
w[t] = NB.decodeInt32(block, p + (t << 2));
}

// RFC 3174 6.1.b, extend state vector to 80 words.
for (int t = 16; t < 80; t++) {
int x = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
w[t] = (x << 1) | (x >>> 31); // S^1(...)
w[t] = rotateLeft(x, 1); // S^1(...)
}
}

// Round 1: tail
for (int t = 16; t < 20; t++) {
int temp = ((a << 5) | (a >>> 27)) // S^5(A)
+ (((c ^ d) & b) ^ d) // f: 0 <= t <= 19
+ e + w[t] + 0x5A827999;
e = d;
d = c;
c = (b << 30) | (b >>> 2); // S^30(B)
b = a;
a = temp;
}
private void compress() {
// Method 1 from RFC 3174 section 6.1.
// Method 2 (circular queue of 16 words) is slower.
int a = h.a, b = h.b, c = h.c, d = h.d, e = h.e;

// Round 2
for (int t = 20; t < 40; t++) {
int temp = ((a << 5) | (a >>> 27)) // S^5(A)
+ (b ^ c ^ d) // f: 20 <= t <= 39
+ e + w[t] + 0x6ED9EBA1;
e = d;
d = c;
c = (b << 30) | (b >>> 2); // S^30(B)
b = a;
a = temp;
}
// @formatter:off
e += s1(a, b, c, d,w[ 0]); b = rotateLeft( b, 30);
d += s1(e, a, b, c,w[ 1]); a = rotateLeft( a, 30);
c += s1(d, e, a, b,w[ 2]); e = rotateLeft( e, 30);
b += s1(c, d, e, a,w[ 3]); d = rotateLeft( d, 30);
a += s1(b, c, d, e,w[ 4]); c = rotateLeft( c, 30);
e += s1(a, b, c, d,w[ 5]); b = rotateLeft( b, 30);
d += s1(e, a, b, c,w[ 6]); a = rotateLeft( a, 30);
c += s1(d, e, a, b,w[ 7]); e = rotateLeft( e, 30);
b += s1(c, d, e, a,w[ 8]); d = rotateLeft( d, 30);
a += s1(b, c, d, e,w[ 9]); c = rotateLeft( c, 30);
e += s1(a, b, c, d,w[ 10]); b = rotateLeft( b, 30);
d += s1(e, a, b, c,w[ 11]); a = rotateLeft( a, 30);
c += s1(d, e, a, b,w[ 12]); e = rotateLeft( e, 30);
b += s1(c, d, e, a,w[ 13]); d = rotateLeft( d, 30);
a += s1(b, c, d, e,w[ 14]); c = rotateLeft( c, 30);
e += s1(a, b, c, d,w[ 15]); b = rotateLeft( b, 30);
d += s1(e, a, b, c,w[ 16]); a = rotateLeft( a, 30);
c += s1(d, e, a, b,w[ 17]); e = rotateLeft( e, 30);
b += s1(c, d, e, a,w[ 18]); d = rotateLeft( d, 30);
a += s1(b, c, d, e,w[ 19]); c = rotateLeft( c, 30);

// Round 3
for (int t = 40; t < 60; t++) {
int temp = ((a << 5) | (a >>> 27)) // S^5(A)
+ ((b & c) | (d & (b | c))) // f: 40 <= t <= 59
+ e + w[t] + 0x8F1BBCDC;
e = d;
d = c;
c = (b << 30) | (b >>> 2); // S^30(B)
b = a;
a = temp;
}
e += s2(a, b, c, d,w[ 20]); b = rotateLeft( b, 30);
d += s2(e, a, b, c,w[ 21]); a = rotateLeft( a, 30);
c += s2(d, e, a, b,w[ 22]); e = rotateLeft( e, 30);
b += s2(c, d, e, a,w[ 23]); d = rotateLeft( d, 30);
a += s2(b, c, d, e,w[ 24]); c = rotateLeft( c, 30);
e += s2(a, b, c, d,w[ 25]); b = rotateLeft( b, 30);
d += s2(e, a, b, c,w[ 26]); a = rotateLeft( a, 30);
c += s2(d, e, a, b,w[ 27]); e = rotateLeft( e, 30);
b += s2(c, d, e, a,w[ 28]); d = rotateLeft( d, 30);
a += s2(b, c, d, e,w[ 29]); c = rotateLeft( c, 30);
e += s2(a, b, c, d,w[ 30]); b = rotateLeft( b, 30);
d += s2(e, a, b, c,w[ 31]); a = rotateLeft( a, 30);
c += s2(d, e, a, b,w[ 32]); e = rotateLeft( e, 30);
b += s2(c, d, e, a,w[ 33]); d = rotateLeft( d, 30);
a += s2(b, c, d, e,w[ 34]); c = rotateLeft( c, 30);
e += s2(a, b, c, d,w[ 35]); b = rotateLeft( b, 30);
d += s2(e, a, b, c,w[ 36]); a = rotateLeft( a, 30);
c += s2(d, e, a, b,w[ 37]); e = rotateLeft( e, 30);
b += s2(c, d, e, a,w[ 38]); d = rotateLeft( d, 30);
a += s2(b, c, d, e,w[ 39]); c = rotateLeft( c, 30);

e += s3(a, b, c, d,w[ 40]); b = rotateLeft( b, 30);
d += s3(e, a, b, c,w[ 41]); a = rotateLeft( a, 30);
c += s3(d, e, a, b,w[ 42]); e = rotateLeft( e, 30);
b += s3(c, d, e, a,w[ 43]); d = rotateLeft( d, 30);
a += s3(b, c, d, e,w[ 44]); c = rotateLeft( c, 30);
e += s3(a, b, c, d,w[ 45]); b = rotateLeft( b, 30);
d += s3(e, a, b, c,w[ 46]); a = rotateLeft( a, 30);
c += s3(d, e, a, b,w[ 47]); e = rotateLeft( e, 30);
b += s3(c, d, e, a,w[ 48]); d = rotateLeft( d, 30);
a += s3(b, c, d, e,w[ 49]); c = rotateLeft( c, 30);
e += s3(a, b, c, d,w[ 50]); b = rotateLeft( b, 30);
d += s3(e, a, b, c,w[ 51]); a = rotateLeft( a, 30);
c += s3(d, e, a, b,w[ 52]); e = rotateLeft( e, 30);
b += s3(c, d, e, a,w[ 53]); d = rotateLeft( d, 30);
a += s3(b, c, d, e,w[ 54]); c = rotateLeft( c, 30);
e += s3(a, b, c, d,w[ 55]); b = rotateLeft( b, 30);
d += s3(e, a, b, c,w[ 56]); a = rotateLeft( a, 30);
c += s3(d, e, a, b,w[ 57]); e = rotateLeft( e, 30);
state58.save(a, b, c, d, e);
b += s3(c, d, e, a,w[ 58]); d = rotateLeft( d, 30);
a += s3(b, c, d, e,w[ 59]); c = rotateLeft( c, 30);

// Round 4
for (int t = 60; t < 80; t++) {
int temp = ((a << 5) | (a >>> 27)) // S^5(A)
+ (b ^ c ^ d) // f: 60 <= t <= 79
+ e + w[t] + 0xCA62C1D6;
e = d;
d = c;
c = (b << 30) | (b >>> 2); // S^30(B)
b = a;
a = temp;
e += s4(a, b, c, d,w[ 60]); b = rotateLeft( b, 30);
d += s4(e, a, b, c,w[ 61]); a = rotateLeft( a, 30);
c += s4(d, e, a, b,w[ 62]); e = rotateLeft( e, 30);
b += s4(c, d, e, a,w[ 63]); d = rotateLeft( d, 30);
a += s4(b, c, d, e,w[ 64]); c = rotateLeft( c, 30);
state65.save(a, b, c, d, e);
e += s4(a, b, c, d,w[ 65]); b = rotateLeft( b, 30);
d += s4(e, a, b, c,w[ 66]); a = rotateLeft( a, 30);
c += s4(d, e, a, b,w[ 67]); e = rotateLeft( e, 30);
b += s4(c, d, e, a,w[ 68]); d = rotateLeft( d, 30);
a += s4(b, c, d, e,w[ 69]); c = rotateLeft( c, 30);
e += s4(a, b, c, d,w[ 70]); b = rotateLeft( b, 30);
d += s4(e, a, b, c,w[ 71]); a = rotateLeft( a, 30);
c += s4(d, e, a, b,w[ 72]); e = rotateLeft( e, 30);
b += s4(c, d, e, a,w[ 73]); d = rotateLeft( d, 30);
a += s4(b, c, d, e,w[ 74]); c = rotateLeft( c, 30);
e += s4(a, b, c, d,w[ 75]); b = rotateLeft( b, 30);
d += s4(e, a, b, c,w[ 76]); a = rotateLeft( a, 30);
c += s4(d, e, a, b,w[ 77]); e = rotateLeft( e, 30);
b += s4(c, d, e, a,w[ 78]); d = rotateLeft( d, 30);
a += s4(b, c, d, e,w[ 79]); c = rotateLeft( c, 30);

// @formatter:on
h.save(h.a + a, h.b + b, h.c + c, h.d + d, h.e + e);
}

private void recompress(int t) {
State s;
if (t == 58) {
s = state58;
} else if (t == 65) {
s = state65;
} else {
throw new IllegalStateException();
}
int a = s.a, b = s.b, c = s.c, d = s.d, e = s.e;

// @formatter:off
if (t == 65) {
{ c = rotateRight( c, 30); a -= s4(b, c, d, e,w2[ 64]);}
{ d = rotateRight( d, 30); b -= s4(c, d, e, a,w2[ 63]);}
{ e = rotateRight( e, 30); c -= s4(d, e, a, b,w2[ 62]);}
{ a = rotateRight( a, 30); d -= s4(e, a, b, c,w2[ 61]);}
{ b = rotateRight( b, 30); e -= s4(a, b, c, d,w2[ 60]);}

{ c = rotateRight( c, 30); a -= s3(b, c, d, e,w2[ 59]);}
{ d = rotateRight( d, 30); b -= s3(c, d, e, a,w2[ 58]);}
}
{ e = rotateRight( e, 30); c -= s3(d, e, a, b,w2[ 57]);}
{ a = rotateRight( a, 30); d -= s3(e, a, b, c,w2[ 56]);}
{ b = rotateRight( b, 30); e -= s3(a, b, c, d,w2[ 55]);}
{ c = rotateRight( c, 30); a -= s3(b, c, d, e,w2[ 54]);}
{ d = rotateRight( d, 30); b -= s3(c, d, e, a,w2[ 53]);}
{ e = rotateRight( e, 30); c -= s3(d, e, a, b,w2[ 52]);}
{ a = rotateRight( a, 30); d -= s3(e, a, b, c,w2[ 51]);}
{ b = rotateRight( b, 30); e -= s3(a, b, c, d,w2[ 50]);}
{ c = rotateRight( c, 30); a -= s3(b, c, d, e,w2[ 49]);}
{ d = rotateRight( d, 30); b -= s3(c, d, e, a,w2[ 48]);}
{ e = rotateRight( e, 30); c -= s3(d, e, a, b,w2[ 47]);}
{ a = rotateRight( a, 30); d -= s3(e, a, b, c,w2[ 46]);}
{ b = rotateRight( b, 30); e -= s3(a, b, c, d,w2[ 45]);}
{ c = rotateRight( c, 30); a -= s3(b, c, d, e,w2[ 44]);}
{ d = rotateRight( d, 30); b -= s3(c, d, e, a,w2[ 43]);}
{ e = rotateRight( e, 30); c -= s3(d, e, a, b,w2[ 42]);}
{ a = rotateRight( a, 30); d -= s3(e, a, b, c,w2[ 41]);}
{ b = rotateRight( b, 30); e -= s3(a, b, c, d,w2[ 40]);}

{ c = rotateRight( c, 30); a -= s2(b, c, d, e,w2[ 39]);}
{ d = rotateRight( d, 30); b -= s2(c, d, e, a,w2[ 38]);}
{ e = rotateRight( e, 30); c -= s2(d, e, a, b,w2[ 37]);}
{ a = rotateRight( a, 30); d -= s2(e, a, b, c,w2[ 36]);}
{ b = rotateRight( b, 30); e -= s2(a, b, c, d,w2[ 35]);}
{ c = rotateRight( c, 30); a -= s2(b, c, d, e,w2[ 34]);}
{ d = rotateRight( d, 30); b -= s2(c, d, e, a,w2[ 33]);}
{ e = rotateRight( e, 30); c -= s2(d, e, a, b,w2[ 32]);}
{ a = rotateRight( a, 30); d -= s2(e, a, b, c,w2[ 31]);}
{ b = rotateRight( b, 30); e -= s2(a, b, c, d,w2[ 30]);}
{ c = rotateRight( c, 30); a -= s2(b, c, d, e,w2[ 29]);}
{ d = rotateRight( d, 30); b -= s2(c, d, e, a,w2[ 28]);}
{ e = rotateRight( e, 30); c -= s2(d, e, a, b,w2[ 27]);}
{ a = rotateRight( a, 30); d -= s2(e, a, b, c,w2[ 26]);}
{ b = rotateRight( b, 30); e -= s2(a, b, c, d,w2[ 25]);}
{ c = rotateRight( c, 30); a -= s2(b, c, d, e,w2[ 24]);}
{ d = rotateRight( d, 30); b -= s2(c, d, e, a,w2[ 23]);}
{ e = rotateRight( e, 30); c -= s2(d, e, a, b,w2[ 22]);}
{ a = rotateRight( a, 30); d -= s2(e, a, b, c,w2[ 21]);}
{ b = rotateRight( b, 30); e -= s2(a, b, c, d,w2[ 20]);}

{ c = rotateRight( c, 30); a -= s1(b, c, d, e,w2[ 19]);}
{ d = rotateRight( d, 30); b -= s1(c, d, e, a,w2[ 18]);}
{ e = rotateRight( e, 30); c -= s1(d, e, a, b,w2[ 17]);}
{ a = rotateRight( a, 30); d -= s1(e, a, b, c,w2[ 16]);}
{ b = rotateRight( b, 30); e -= s1(a, b, c, d,w2[ 15]);}
{ c = rotateRight( c, 30); a -= s1(b, c, d, e,w2[ 14]);}
{ d = rotateRight( d, 30); b -= s1(c, d, e, a,w2[ 13]);}
{ e = rotateRight( e, 30); c -= s1(d, e, a, b,w2[ 12]);}
{ a = rotateRight( a, 30); d -= s1(e, a, b, c,w2[ 11]);}
{ b = rotateRight( b, 30); e -= s1(a, b, c, d,w2[ 10]);}
{ c = rotateRight( c, 30); a -= s1(b, c, d, e,w2[ 9]);}
{ d = rotateRight( d, 30); b -= s1(c, d, e, a,w2[ 8]);}
{ e = rotateRight( e, 30); c -= s1(d, e, a, b,w2[ 7]);}
{ a = rotateRight( a, 30); d -= s1(e, a, b, c,w2[ 6]);}
{ b = rotateRight( b, 30); e -= s1(a, b, c, d,w2[ 5]);}
{ c = rotateRight( c, 30); a -= s1(b, c, d, e,w2[ 4]);}
{ d = rotateRight( d, 30); b -= s1(c, d, e, a,w2[ 3]);}
{ e = rotateRight( e, 30); c -= s1(d, e, a, b,w2[ 2]);}
{ a = rotateRight( a, 30); d -= s1(e, a, b, c,w2[ 1]);}
{ b = rotateRight( b, 30); e -= s1(a, b, c, d,w2[ 0]);}

hIn.save(a, b, c, d, e);
a = s.a; b = s.b; c = s.c; d = s.d; e = s.e;

h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
if (t == 58) {
{ b += s3(c, d, e, a,w2[ 58]); d = rotateLeft( d, 30);}
{ a += s3(b, c, d, e,w2[ 59]); c = rotateLeft( c, 30);}

{ e += s4(a, b, c, d,w2[ 60]); b = rotateLeft( b, 30);}
{ d += s4(e, a, b, c,w2[ 61]); a = rotateLeft( a, 30);}
{ c += s4(d, e, a, b,w2[ 62]); e = rotateLeft( e, 30);}
{ b += s4(c, d, e, a,w2[ 63]); d = rotateLeft( d, 30);}
{ a += s4(b, c, d, e,w2[ 64]); c = rotateLeft( c, 30);}
}
{ e += s4(a, b, c, d,w2[ 65]); b = rotateLeft( b, 30);}
{ d += s4(e, a, b, c,w2[ 66]); a = rotateLeft( a, 30);}
{ c += s4(d, e, a, b,w2[ 67]); e = rotateLeft( e, 30);}
{ b += s4(c, d, e, a,w2[ 68]); d = rotateLeft( d, 30);}
{ a += s4(b, c, d, e,w2[ 69]); c = rotateLeft( c, 30);}
{ e += s4(a, b, c, d,w2[ 70]); b = rotateLeft( b, 30);}
{ d += s4(e, a, b, c,w2[ 71]); a = rotateLeft( a, 30);}
{ c += s4(d, e, a, b,w2[ 72]); e = rotateLeft( e, 30);}
{ b += s4(c, d, e, a,w2[ 73]); d = rotateLeft( d, 30);}
{ a += s4(b, c, d, e,w2[ 74]); c = rotateLeft( c, 30);}
{ e += s4(a, b, c, d,w2[ 75]); b = rotateLeft( b, 30);}
{ d += s4(e, a, b, c,w2[ 76]); a = rotateLeft( a, 30);}
{ c += s4(d, e, a, b,w2[ 77]); e = rotateLeft( e, 30);}
{ b += s4(c, d, e, a,w2[ 78]); d = rotateLeft( d, 30);}
{ a += s4(b, c, d, e,w2[ 79]); c = rotateLeft( c, 30);}

// @formatter:on
hTmp.save(hIn.a + a, hIn.b + b, hIn.c + c, hIn.d + d, hIn.e + e);
}

private static int s1(int a, int b, int c, int d, int w_t) {
return rotateLeft(a, 5)
// f: 0 <= t <= 19
+ ((b & c) | ((~b) & d))
+ 0x5A827999 + w_t;
}

private static int s2(int a, int b, int c, int d, int w_t) {
return rotateLeft(a, 5)
// f: 20 <= t <= 39
+ (b ^ c ^ d)
+ 0x6ED9EBA1 + w_t;
}

private static int s3(int a, int b, int c, int d, int w_t) {
return rotateLeft(a, 5)
// f: 40 <= t <= 59
+ ((b & c) | (b & d) | (c & d))
+ 0x8F1BBCDC + w_t;
}

private static int s4(int a, int b, int c, int d, int w_t) {
return rotateLeft(a, 5)
// f: 60 <= t <= 79
+ (b ^ c ^ d)
+ 0xCA62C1D6 + w_t;
}

private static boolean eq(State q, State r) {
return q.a == r.a
&& q.b == r.b
&& q.c == r.c
&& q.d == r.d
&& q.e == r.e;
}

private void finish() {
@@ -261,6 +489,12 @@ public class SHA1 {
NB.encodeInt32(buffer, 56, (int) (length >>> (32 - 3)));
NB.encodeInt32(buffer, 60, (int) (length << 3));
compress(buffer, 0);

if (foundCollision) {
ObjectId id = h.toObjectId();
LOG.warn("possible SHA-1 collision " + id.name()); //$NON-NLS-1$
throw new Sha1CollisionException(id);
}
}

/**
@@ -269,16 +503,18 @@ public class SHA1 {
* Once {@code digest()} is called, this instance should be discarded.
*
* @return the bytes for the resulting hash.
* @throws Sha1CollisionException
* if a collision was detected and safeHash is false.
*/
public byte[] digest() {
public byte[] digest() throws Sha1CollisionException {
finish();

byte[] b = new byte[20];
NB.encodeInt32(b, 0, h0);
NB.encodeInt32(b, 4, h1);
NB.encodeInt32(b, 8, h2);
NB.encodeInt32(b, 12, h3);
NB.encodeInt32(b, 16, h4);
NB.encodeInt32(b, 0, h.a);
NB.encodeInt32(b, 4, h.b);
NB.encodeInt32(b, 8, h.c);
NB.encodeInt32(b, 12, h.d);
NB.encodeInt32(b, 16, h.e);
return b;
}

@@ -288,10 +524,12 @@ public class SHA1 {
* Once {@code digest()} is called, this instance should be discarded.
*
* @return the ObjectId for the resulting hash.
* @throws Sha1CollisionException
* if a collision was detected and safeHash is false.
*/
public ObjectId toObjectId() {
public ObjectId toObjectId() throws Sha1CollisionException {
finish();
return new ObjectId(h0, h1, h2, h3, h4);
return h.toObjectId();
}

/**
@@ -301,9 +539,63 @@ public class SHA1 {
*
* @param id
* destination to copy the digest to.
* @throws Sha1CollisionException
* if a collision was detected and safeHash is false.
*/
public void digest(MutableObjectId id) {
public void digest(MutableObjectId id) throws Sha1CollisionException {
finish();
id.set(h0, h1, h2, h3, h4);
id.set(h.a, h.b, h.c, h.d, h.e);
}

/**
* Check if a collision was detected.
*
* <p>
* This method only returns an accurate result after the digest was obtained
* through {@link #digest()}, {@link #digest(MutableObjectId)} or
* {@link #toObjectId()}, as the hashing function must finish processing to
* know the final state.
*
* @return {@code true} if a likely collision was detected.
*/
public boolean hasCollision() {
return foundCollision;
}

/**
* Reset this instance to compute another hash.
*
* @return {@code this}.
*/
public SHA1 reset() {
h.init();
length = 0;
foundCollision = false;
return this;
}

private static final class State {
int a;
int b;
int c;
int d;
int e;

final void init() {
// Magic initialization constants defined by FIPS180.
save(0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0);
}

final void save(int a1, int b1, int c1, int d1, int e1) {
a = a1;
b = b1;
c = c1;
d = d1;
e = e1;
}

ObjectId toObjectId() {
return new ObjectId(a, b, c, d, e);
}
}
}

+ 192
- 0
org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.recompress View File

@@ -0,0 +1,192 @@
/* Template for recompress method; run through cpp. */

#define ROUND1_STEP(a, b, c, d, e, T) {e += s1(a,b,c,d,w2[T]); b = rotateLeft(b, 30);}
#define ROUND2_STEP(a, b, c, d, e, T) {e += s2(a,b,c,d,w2[T]); b = rotateLeft(b, 30);}
#define ROUND3_STEP(a, b, c, d, e, T) {e += s3(a,b,c,d,w2[T]); b = rotateLeft(b, 30);}
#define ROUND4_STEP(a, b, c, d, e, T) {e += s4(a,b,c,d,w2[T]); b = rotateLeft(b, 30);}

#define ROUND1_STEP_BW(a, b, c, d, e, T) {b = rotateRight(b, 30); e -= s1(a,b,c,d,w2[T]);}
#define ROUND2_STEP_BW(a, b, c, d, e, T) {b = rotateRight(b, 30); e -= s2(a,b,c,d,w2[T]);}
#define ROUND3_STEP_BW(a, b, c, d, e, T) {b = rotateRight(b, 30); e -= s3(a,b,c,d,w2[T]);}
#define ROUND4_STEP_BW(a, b, c, d, e, T) {b = rotateRight(b, 30); e -= s4(a,b,c,d,w2[T]);}

/* Condition to go backwards: if (t > step) */
/* t=80-66 have no identified DV; skip.
ROUND4_STEP_BW(b, c, d, e, a, 79)
ROUND4_STEP_BW(c, d, e, a, b, 78)
ROUND4_STEP_BW(d, e, a, b, c, 77)
ROUND4_STEP_BW(e, a, b, c, d, 76)
ROUND4_STEP_BW(a, b, c, d, e, 75)
ROUND4_STEP_BW(b, c, d, e, a, 74)
ROUND4_STEP_BW(c, d, e, a, b, 73)
ROUND4_STEP_BW(d, e, a, b, c, 72)
ROUND4_STEP_BW(e, a, b, c, d, 71)
ROUND4_STEP_BW(a, b, c, d, e, 70)
ROUND4_STEP_BW(b, c, d, e, a, 69)
ROUND4_STEP_BW(c, d, e, a, b, 68)
ROUND4_STEP_BW(d, e, a, b, c, 67)
ROUND4_STEP_BW(e, a, b, c, d, 66)
ROUND4_STEP_BW(a, b, c, d, e, 65)
*/
if (t == 65) {
ROUND4_STEP_BW(b, c, d, e, a, 64)
ROUND4_STEP_BW(c, d, e, a, b, 63)
ROUND4_STEP_BW(d, e, a, b, c, 62)
ROUND4_STEP_BW(e, a, b, c, d, 61)
ROUND4_STEP_BW(a, b, c, d, e, 60)

ROUND3_STEP_BW(b, c, d, e, a, 59)
ROUND3_STEP_BW(c, d, e, a, b, 58)
}
ROUND3_STEP_BW(d, e, a, b, c, 57)
ROUND3_STEP_BW(e, a, b, c, d, 56)
ROUND3_STEP_BW(a, b, c, d, e, 55)
ROUND3_STEP_BW(b, c, d, e, a, 54)
ROUND3_STEP_BW(c, d, e, a, b, 53)
ROUND3_STEP_BW(d, e, a, b, c, 52)
ROUND3_STEP_BW(e, a, b, c, d, 51)
ROUND3_STEP_BW(a, b, c, d, e, 50)
ROUND3_STEP_BW(b, c, d, e, a, 49)
ROUND3_STEP_BW(c, d, e, a, b, 48)
ROUND3_STEP_BW(d, e, a, b, c, 47)
ROUND3_STEP_BW(e, a, b, c, d, 46)
ROUND3_STEP_BW(a, b, c, d, e, 45)
ROUND3_STEP_BW(b, c, d, e, a, 44)
ROUND3_STEP_BW(c, d, e, a, b, 43)
ROUND3_STEP_BW(d, e, a, b, c, 42)
ROUND3_STEP_BW(e, a, b, c, d, 41)
ROUND3_STEP_BW(a, b, c, d, e, 40)

ROUND2_STEP_BW(b, c, d, e, a, 39)
ROUND2_STEP_BW(c, d, e, a, b, 38)
ROUND2_STEP_BW(d, e, a, b, c, 37)
ROUND2_STEP_BW(e, a, b, c, d, 36)
ROUND2_STEP_BW(a, b, c, d, e, 35)
ROUND2_STEP_BW(b, c, d, e, a, 34)
ROUND2_STEP_BW(c, d, e, a, b, 33)
ROUND2_STEP_BW(d, e, a, b, c, 32)
ROUND2_STEP_BW(e, a, b, c, d, 31)
ROUND2_STEP_BW(a, b, c, d, e, 30)
ROUND2_STEP_BW(b, c, d, e, a, 29)
ROUND2_STEP_BW(c, d, e, a, b, 28)
ROUND2_STEP_BW(d, e, a, b, c, 27)
ROUND2_STEP_BW(e, a, b, c, d, 26)
ROUND2_STEP_BW(a, b, c, d, e, 25)
ROUND2_STEP_BW(b, c, d, e, a, 24)
ROUND2_STEP_BW(c, d, e, a, b, 23)
ROUND2_STEP_BW(d, e, a, b, c, 22)
ROUND2_STEP_BW(e, a, b, c, d, 21)
ROUND2_STEP_BW(a, b, c, d, e, 20)

ROUND1_STEP_BW(b, c, d, e, a, 19)
ROUND1_STEP_BW(c, d, e, a, b, 18)
ROUND1_STEP_BW(d, e, a, b, c, 17)
ROUND1_STEP_BW(e, a, b, c, d, 16)
ROUND1_STEP_BW(a, b, c, d, e, 15)
ROUND1_STEP_BW(b, c, d, e, a, 14)
ROUND1_STEP_BW(c, d, e, a, b, 13)
ROUND1_STEP_BW(d, e, a, b, c, 12)
ROUND1_STEP_BW(e, a, b, c, d, 11)
ROUND1_STEP_BW(a, b, c, d, e, 10)
ROUND1_STEP_BW(b, c, d, e, a, 9)
ROUND1_STEP_BW(c, d, e, a, b, 8)
ROUND1_STEP_BW(d, e, a, b, c, 7)
ROUND1_STEP_BW(e, a, b, c, d, 6)
ROUND1_STEP_BW(a, b, c, d, e, 5)
ROUND1_STEP_BW(b, c, d, e, a, 4)
ROUND1_STEP_BW(c, d, e, a, b, 3)
ROUND1_STEP_BW(d, e, a, b, c, 2)
ROUND1_STEP_BW(e, a, b, c, d, 1)
ROUND1_STEP_BW(a, b, c, d, e, 0)

hIn.save(a, b, c, d, e);
a = s.a; b = s.b; c = s.c; d = s.d; e = s.e;

/* Condition to go fowards: if (t <= step) */
/* Earliest restart is T=58; skip.
ROUND1_STEP(a, b, c, d, e, 0)
ROUND1_STEP(e, a, b, c, d, 1)
ROUND1_STEP(d, e, a, b, c, 2)
ROUND1_STEP(c, d, e, a, b, 3)
ROUND1_STEP(b, c, d, e, a, 4)
ROUND1_STEP(a, b, c, d, e, 5)
ROUND1_STEP(e, a, b, c, d, 6)
ROUND1_STEP(d, e, a, b, c, 7)
ROUND1_STEP(c, d, e, a, b, 8)
ROUND1_STEP(b, c, d, e, a, 9)
ROUND1_STEP(a, b, c, d, e, 10)
ROUND1_STEP(e, a, b, c, d, 11)
ROUND1_STEP(d, e, a, b, c, 12)
ROUND1_STEP(c, d, e, a, b, 13)
ROUND1_STEP(b, c, d, e, a, 14)
ROUND1_STEP(a, b, c, d, e, 15)
ROUND1_STEP(e, a, b, c, d, 16)
ROUND1_STEP(d, e, a, b, c, 17)
ROUND1_STEP(c, d, e, a, b, 18)
ROUND1_STEP(b, c, d, e, a, 19)

ROUND2_STEP(a, b, c, d, e, 20)
ROUND2_STEP(e, a, b, c, d, 21)
ROUND2_STEP(d, e, a, b, c, 22)
ROUND2_STEP(c, d, e, a, b, 23)
ROUND2_STEP(b, c, d, e, a, 24)
ROUND2_STEP(a, b, c, d, e, 25)
ROUND2_STEP(e, a, b, c, d, 26)
ROUND2_STEP(d, e, a, b, c, 27)
ROUND2_STEP(c, d, e, a, b, 28)
ROUND2_STEP(b, c, d, e, a, 29)
ROUND2_STEP(a, b, c, d, e, 30)
ROUND2_STEP(e, a, b, c, d, 31)
ROUND2_STEP(d, e, a, b, c, 32)
ROUND2_STEP(c, d, e, a, b, 33)
ROUND2_STEP(b, c, d, e, a, 34)
ROUND2_STEP(a, b, c, d, e, 35)
ROUND2_STEP(e, a, b, c, d, 36)
ROUND2_STEP(d, e, a, b, c, 37)
ROUND2_STEP(c, d, e, a, b, 38)
ROUND2_STEP(b, c, d, e, a, 39)

ROUND3_STEP(a, b, c, d, e, 40)
ROUND3_STEP(e, a, b, c, d, 41)
ROUND3_STEP(d, e, a, b, c, 42)
ROUND3_STEP(c, d, e, a, b, 43)
ROUND3_STEP(b, c, d, e, a, 44)
ROUND3_STEP(a, b, c, d, e, 45)
ROUND3_STEP(e, a, b, c, d, 46)
ROUND3_STEP(d, e, a, b, c, 47)
ROUND3_STEP(c, d, e, a, b, 48)
ROUND3_STEP(b, c, d, e, a, 49)
ROUND3_STEP(a, b, c, d, e, 50)
ROUND3_STEP(e, a, b, c, d, 51)
ROUND3_STEP(d, e, a, b, c, 52)
ROUND3_STEP(c, d, e, a, b, 53)
ROUND3_STEP(b, c, d, e, a, 54)
ROUND3_STEP(a, b, c, d, e, 55)
ROUND3_STEP(e, a, b, c, d, 56)
ROUND3_STEP(d, e, a, b, c, 57)
*/
if (t == 58) {
ROUND3_STEP(c, d, e, a, b, 58)
ROUND3_STEP(b, c, d, e, a, 59)

ROUND4_STEP(a, b, c, d, e, 60)
ROUND4_STEP(e, a, b, c, d, 61)
ROUND4_STEP(d, e, a, b, c, 62)
ROUND4_STEP(c, d, e, a, b, 63)
ROUND4_STEP(b, c, d, e, a, 64)
}
ROUND4_STEP(a, b, c, d, e, 65)
ROUND4_STEP(e, a, b, c, d, 66)
ROUND4_STEP(d, e, a, b, c, 67)
ROUND4_STEP(c, d, e, a, b, 68)
ROUND4_STEP(b, c, d, e, a, 69)
ROUND4_STEP(a, b, c, d, e, 70)
ROUND4_STEP(e, a, b, c, d, 71)
ROUND4_STEP(d, e, a, b, c, 72)
ROUND4_STEP(c, d, e, a, b, 73)
ROUND4_STEP(b, c, d, e, a, 74)
ROUND4_STEP(a, b, c, d, e, 75)
ROUND4_STEP(e, a, b, c, d, 76)
ROUND4_STEP(d, e, a, b, c, 77)
ROUND4_STEP(c, d, e, a, b, 78)
ROUND4_STEP(b, c, d, e, a, 79)

+ 70
- 0
org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/Sha1CollisionException.java View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2017, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* 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 Eclipse Foundation, Inc. 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 THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
*/

package org.eclipse.jgit.util.sha1;

import java.text.MessageFormat;

import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ObjectId;

/**
* Thrown by {@link SHA1} if it detects a likely hash collision.
*
* @since 4.7
*/
public class Sha1CollisionException extends RuntimeException {
private static final long serialVersionUID = 1L;

/**
* Initialize with default message.
*
* @param id
* object whose contents are a hash collision.
*/
public Sha1CollisionException(ObjectId id) {
super(MessageFormat.format(
JGitText.get().sha1CollisionDetected1,
id.name()));
}
}

+ 1040
- 0
org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/UbcCheck.java
File diff suppressed because it is too large
View File


Loading…
Cancel
Save