Merge branch 'stable-6.2' into stable-6.3
* stable-6.2: [benchmarks] Remove profiler configuration Add SHA1 benchmark [benchmarks] Set version of maven-compiler-plugin to 3.8.1 Fix running JMH benchmarks Add option to allow using JDK's SHA1 implementation Ignore IllegalStateException if JVM is already shutting down Change-Id: I9c1576011c11b4ff8f453d18d9e786cee59860fa
This commit is contained in:
commit
f3e0e9d5a3
|
@ -37,13 +37,17 @@
|
||||||
<groupId>org.openjdk.jmh</groupId>
|
<groupId>org.openjdk.jmh</groupId>
|
||||||
<artifactId>jmh-generator-annprocess</artifactId>
|
<artifactId>jmh-generator-annprocess</artifactId>
|
||||||
<version>${jmh.version}</version>
|
<version>${jmh.version}</version>
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jgit</groupId>
|
<groupId>org.eclipse.jgit</groupId>
|
||||||
<artifactId>org.eclipse.jgit</artifactId>
|
<artifactId>org.eclipse.jgit</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jgit</groupId>
|
||||||
|
<artifactId>org.eclipse.jgit.junit</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -69,8 +69,6 @@ public FileSnapshot testCreateFileSnapshot() {
|
||||||
public static void main(String[] args) throws RunnerException {
|
public static void main(String[] args) throws RunnerException {
|
||||||
Options opt = new OptionsBuilder()
|
Options opt = new OptionsBuilder()
|
||||||
.include(CreateFileSnapshotBenchmark.class.getSimpleName())
|
.include(CreateFileSnapshotBenchmark.class.getSimpleName())
|
||||||
// .addProfiler(StackProfiler.class)
|
|
||||||
// .addProfiler(GCProfiler.class)
|
|
||||||
.forks(1).jvmArgs("-ea").build();
|
.forks(1).jvmArgs("-ea").build();
|
||||||
new Runner(opt).run();
|
new Runner(opt).run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,8 +128,6 @@ public static void main(String[] args) throws RunnerException {
|
||||||
Options opt = new OptionsBuilder()
|
Options opt = new OptionsBuilder()
|
||||||
.include(FileMoveBenchmark.class
|
.include(FileMoveBenchmark.class
|
||||||
.getSimpleName())
|
.getSimpleName())
|
||||||
// .addProfiler(StackProfiler.class)
|
|
||||||
// .addProfiler(GCProfiler.class)
|
|
||||||
.forks(1).jvmArgs("-ea").build();
|
.forks(1).jvmArgs("-ea").build();
|
||||||
new Runner(opt).run();
|
new Runner(opt).run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,6 @@ public FileStore testLookupFileStore() throws IOException {
|
||||||
public static void main(String[] args) throws RunnerException {
|
public static void main(String[] args) throws RunnerException {
|
||||||
Options opt = new OptionsBuilder()
|
Options opt = new OptionsBuilder()
|
||||||
.include(LookupFileStoreBenchmark.class.getSimpleName())
|
.include(LookupFileStoreBenchmark.class.getSimpleName())
|
||||||
.addProfiler(StackProfiler.class)
|
|
||||||
// .addProfiler(GCProfiler.class)
|
|
||||||
.forks(1).jvmArgs("-ea").build();
|
.forks(1).jvmArgs("-ea").build();
|
||||||
new Runner(opt).run();
|
new Runner(opt).run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022, Matthias Sohn <matthias.sohn@sap.com> and others
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
* https://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
package org.eclipse.jgit.benchmarks;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.junit.MockSystemReader;
|
||||||
|
import org.eclipse.jgit.util.SystemReader;
|
||||||
|
import org.eclipse.jgit.util.sha1.SHA1;
|
||||||
|
import org.eclipse.jgit.util.sha1.SHA1.Sha1Implementation;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Fork;
|
||||||
|
import org.openjdk.jmh.annotations.Measurement;
|
||||||
|
import org.openjdk.jmh.annotations.Mode;
|
||||||
|
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
import org.openjdk.jmh.annotations.TearDown;
|
||||||
|
import org.openjdk.jmh.annotations.Warmup;
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
import org.openjdk.jmh.runner.Runner;
|
||||||
|
import org.openjdk.jmh.runner.RunnerException;
|
||||||
|
import org.openjdk.jmh.runner.options.Options;
|
||||||
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
|
||||||
|
@State(Scope.Thread)
|
||||||
|
public class SHA1Benchmark {
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
public static class BenchmarkState {
|
||||||
|
|
||||||
|
@Param({ "1", "2", "4", "8", "16", "32", "64" })
|
||||||
|
int size;
|
||||||
|
|
||||||
|
@Param({ "false", "true" })
|
||||||
|
boolean detectCollision;
|
||||||
|
|
||||||
|
@Param({ "java", "jdkNative" })
|
||||||
|
String impl;
|
||||||
|
|
||||||
|
private SecureRandom rnd;
|
||||||
|
|
||||||
|
byte[] content;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setupBenchmark() {
|
||||||
|
SystemReader.setInstance(new MockSystemReader());
|
||||||
|
if (impl.equalsIgnoreCase(Sha1Implementation.JDKNATIVE.name())) {
|
||||||
|
System.setProperty("org.eclipse.jgit.util.sha1.implementation",
|
||||||
|
Sha1Implementation.JDKNATIVE.name());
|
||||||
|
}
|
||||||
|
content = new byte[size * 1024];
|
||||||
|
try {
|
||||||
|
rnd = SecureRandom.getInstanceStrong();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
rnd.nextBytes(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TearDown
|
||||||
|
public void teardown() {
|
||||||
|
SystemReader.setInstance(null);
|
||||||
|
rnd = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode({ Mode.AverageTime })
|
||||||
|
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
||||||
|
@Warmup(iterations = 2, time = 100, timeUnit = TimeUnit.MILLISECONDS)
|
||||||
|
@Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS)
|
||||||
|
@Fork(1)
|
||||||
|
public void testSHA1(Blackhole blackhole, BenchmarkState state) {
|
||||||
|
SHA1 hash = SHA1.newInstance();
|
||||||
|
hash.setDetectCollision(state.detectCollision);
|
||||||
|
hash.update(state.content);
|
||||||
|
blackhole.consume(hash.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws RunnerException {
|
||||||
|
Options opt = new OptionsBuilder()
|
||||||
|
.include(SHA1Benchmark.class.getSimpleName())
|
||||||
|
.forks(1).jvmArgs("-ea").build();
|
||||||
|
new Runner(opt).run();
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,8 +71,6 @@ public SimpleLruCache<String, String> testCacheRead() {
|
||||||
public static void main(String[] args) throws RunnerException {
|
public static void main(String[] args) throws RunnerException {
|
||||||
Options opt = new OptionsBuilder()
|
Options opt = new OptionsBuilder()
|
||||||
.include(SimpleLruCacheBenchmark.class.getSimpleName())
|
.include(SimpleLruCacheBenchmark.class.getSimpleName())
|
||||||
// .addProfiler(StackProfiler.class)
|
|
||||||
// .addProfiler(GCProfiler.class)
|
|
||||||
.forks(1).jvmArgs("-ea").build();
|
.forks(1).jvmArgs("-ea").build();
|
||||||
new Runner(opt).run();
|
new Runner(opt).run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.junit.Assume.assumeFalse;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -22,11 +23,20 @@
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.junit.MockSystemReader;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.util.IO;
|
import org.eclipse.jgit.util.IO;
|
||||||
import org.junit.Test;
|
import org.eclipse.jgit.util.SystemReader;
|
||||||
|
import org.eclipse.jgit.util.sha1.SHA1.Sha1Implementation;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.experimental.theories.DataPoints;
|
||||||
|
import org.junit.experimental.theories.Theories;
|
||||||
|
import org.junit.experimental.theories.Theory;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(Theories.class)
|
||||||
public class SHA1Test {
|
public class SHA1Test {
|
||||||
private static final String TEST1 = "abc";
|
private static final String TEST1 = "abc";
|
||||||
|
|
||||||
|
@ -34,7 +44,32 @@ public class SHA1Test {
|
||||||
private static final String TEST2b = "jkijkljklmklmnlmnomnopnopq";
|
private static final String TEST2b = "jkijkljklmklmnlmnomnopnopq";
|
||||||
private static final String TEST2 = TEST2a + TEST2b;
|
private static final String TEST2 = TEST2a + TEST2b;
|
||||||
|
|
||||||
@Test
|
@DataPoints
|
||||||
|
public static Sha1Implementation[] getDataPoints() {
|
||||||
|
return new Sha1Implementation[] { Sha1Implementation.JAVA,
|
||||||
|
Sha1Implementation.JDKNATIVE };
|
||||||
|
}
|
||||||
|
|
||||||
|
private Sha1Implementation sha1Implementation;
|
||||||
|
|
||||||
|
public SHA1Test(Sha1Implementation impl) {
|
||||||
|
this.sha1Implementation = impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockSystemReader mockSystemReader = new MockSystemReader();
|
||||||
|
SystemReader.setInstance(mockSystemReader);
|
||||||
|
System.setProperty("org.eclipse.jgit.util.sha1.implementation",
|
||||||
|
sha1Implementation.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
SystemReader.setInstance(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Theory
|
||||||
public void test0() throws NoSuchAlgorithmException {
|
public void test0() throws NoSuchAlgorithmException {
|
||||||
ObjectId exp = ObjectId
|
ObjectId exp = ObjectId
|
||||||
.fromString("da39a3ee5e6b4b0d3255bfef95601890afd80709");
|
.fromString("da39a3ee5e6b4b0d3255bfef95601890afd80709");
|
||||||
|
@ -56,7 +91,7 @@ public void test0() throws NoSuchAlgorithmException {
|
||||||
assertEquals(exp, s2);
|
assertEquals(exp, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Theory
|
||||||
public void test1() throws NoSuchAlgorithmException {
|
public void test1() throws NoSuchAlgorithmException {
|
||||||
ObjectId exp = ObjectId
|
ObjectId exp = ObjectId
|
||||||
.fromString("a9993e364706816aba3e25717850c26c9cd0d89d");
|
.fromString("a9993e364706816aba3e25717850c26c9cd0d89d");
|
||||||
|
@ -78,7 +113,7 @@ public void test1() throws NoSuchAlgorithmException {
|
||||||
assertEquals(exp, s2);
|
assertEquals(exp, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Theory
|
||||||
public void test2() throws NoSuchAlgorithmException {
|
public void test2() throws NoSuchAlgorithmException {
|
||||||
ObjectId exp = ObjectId
|
ObjectId exp = ObjectId
|
||||||
.fromString("84983e441c3bd26ebaae4aa1f95129e5e54670f1");
|
.fromString("84983e441c3bd26ebaae4aa1f95129e5e54670f1");
|
||||||
|
@ -100,9 +135,13 @@ public void test2() throws NoSuchAlgorithmException {
|
||||||
assertEquals(exp, s2);
|
assertEquals(exp, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Theory
|
||||||
public void shatteredCollision()
|
public void shatteredCollision()
|
||||||
throws IOException, NoSuchAlgorithmException {
|
throws IOException, NoSuchAlgorithmException {
|
||||||
|
assumeFalse(
|
||||||
|
System.getProperty("org.eclipse.jgit.util.sha1.implementation")
|
||||||
|
.equalsIgnoreCase("jdkNative"));
|
||||||
|
|
||||||
byte[] pdf1 = read("shattered-1.pdf", 422435);
|
byte[] pdf1 = read("shattered-1.pdf", 422435);
|
||||||
byte[] pdf2 = read("shattered-2.pdf", 422435);
|
byte[] pdf2 = read("shattered-2.pdf", 422435);
|
||||||
MessageDigest md;
|
MessageDigest md;
|
||||||
|
@ -149,8 +188,12 @@ public void shatteredCollision()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Theory
|
||||||
public void shatteredStoredInGitBlob() throws IOException {
|
public void shatteredStoredInGitBlob() throws IOException {
|
||||||
|
assumeFalse(
|
||||||
|
System.getProperty("org.eclipse.jgit.util.sha1.implementation")
|
||||||
|
.equalsIgnoreCase("jdkNative"));
|
||||||
|
|
||||||
byte[] pdf1 = read("shattered-1.pdf", 422435);
|
byte[] pdf1 = read("shattered-1.pdf", 422435);
|
||||||
byte[] pdf2 = read("shattered-2.pdf", 422435);
|
byte[] pdf2 = read("shattered-2.pdf", 422435);
|
||||||
|
|
||||||
|
@ -158,8 +201,10 @@ public void shatteredStoredInGitBlob() throws IOException {
|
||||||
// the Git blob header permutes the data enough for this specific
|
// the Git blob header permutes the data enough for this specific
|
||||||
// attack example to not be detected as a collision. (A different file
|
// attack example to not be detected as a collision. (A different file
|
||||||
// pair that takes the Git header into account however, would.)
|
// pair that takes the Git header into account however, would.)
|
||||||
ObjectId id1 = blob(pdf1, SHA1.newInstance().setDetectCollision(true));
|
ObjectId id1 = blob(pdf1,
|
||||||
ObjectId id2 = blob(pdf2, SHA1.newInstance().setDetectCollision(true));
|
SHA1.newInstance().setDetectCollision(true));
|
||||||
|
ObjectId id2 = blob(pdf2,
|
||||||
|
SHA1.newInstance().setDetectCollision(true));
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
ObjectId.fromString("ba9aaa145ccd24ef760cf31c74d8f7ca1a2e47b0"),
|
ObjectId.fromString("ba9aaa145ccd24ef760cf31c74d8f7ca1a2e47b0"),
|
||||||
|
@ -169,8 +214,12 @@ public void shatteredStoredInGitBlob() throws IOException {
|
||||||
id2);
|
id2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Theory
|
||||||
public void detectsShatteredByDefault() throws IOException {
|
public void detectsShatteredByDefault() throws IOException {
|
||||||
|
assumeFalse(
|
||||||
|
System.getProperty("org.eclipse.jgit.util.sha1.implementation")
|
||||||
|
.equalsIgnoreCase("jdkNative"));
|
||||||
|
|
||||||
assumeTrue(System.getProperty("org.eclipse.jgit.util.sha1.detectCollision") == null);
|
assumeTrue(System.getProperty("org.eclipse.jgit.util.sha1.detectCollision") == null);
|
||||||
assumeTrue(System.getProperty("org.eclipse.jgit.util.sha1.safeHash") == null);
|
assumeTrue(System.getProperty("org.eclipse.jgit.util.sha1.safeHash") == null);
|
||||||
|
|
||||||
|
|
|
@ -537,6 +537,13 @@ public final class ConfigConstants {
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_KEY_SUPPORTSATOMICFILECREATION = "supportsatomicfilecreation";
|
public static final String CONFIG_KEY_SUPPORTSATOMICFILECREATION = "supportsatomicfilecreation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "sha1Implementation" key in the "core" section
|
||||||
|
*
|
||||||
|
* @since 5.13.2
|
||||||
|
*/
|
||||||
|
public static final String SHA1_IMPLEMENTATION = "sha1implementation";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "noprefix" key in the "diff" section
|
* The "noprefix" key in the "diff" section
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
|
|
|
@ -299,14 +299,19 @@ public static final class FileStoreAttributes {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Shut down the SAVE_RUNNER on System.exit()
|
// Shut down the SAVE_RUNNER on System.exit()
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
try {
|
||||||
try {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
SAVE_RUNNER.shutdownNow();
|
try {
|
||||||
SAVE_RUNNER.awaitTermination(100, TimeUnit.MILLISECONDS);
|
SAVE_RUNNER.shutdownNow();
|
||||||
} catch (Exception e) {
|
SAVE_RUNNER.awaitTermination(100,
|
||||||
// Ignore; we're shutting down
|
TimeUnit.MILLISECONDS);
|
||||||
}
|
} catch (Exception e) {
|
||||||
}));
|
// Ignore; we're shutting down
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// ignore - may fail if shutdown is already in progress
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017, Google Inc. and others
|
* Copyright (C) 2022, Matthias Sohn <matthias.sohn@sap.com> and others
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available under the
|
* This program and the accompanying materials are made available under the
|
||||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
@ -7,99 +7,96 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.eclipse.jgit.util.sha1;
|
package org.eclipse.jgit.util.sha1;
|
||||||
|
|
||||||
import static java.lang.Integer.lowestOneBit;
|
import java.io.IOException;
|
||||||
import static java.lang.Integer.numberOfTrailingZeros;
|
import java.security.MessageDigest;
|
||||||
import static java.lang.Integer.rotateLeft;
|
|
||||||
import static java.lang.Integer.rotateRight;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
import java.util.Arrays;
|
import org.eclipse.jgit.lib.ConfigConstants;
|
||||||
|
|
||||||
import org.eclipse.jgit.internal.JGitText;
|
|
||||||
import org.eclipse.jgit.lib.MutableObjectId;
|
import org.eclipse.jgit.lib.MutableObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.util.NB;
|
|
||||||
import org.eclipse.jgit.util.SystemReader;
|
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.
|
* SHA-1 interface from FIPS 180-1 / RFC 3174 with optional collision detection.
|
||||||
*
|
* Some implementations may not support collision detection.
|
||||||
* <p>
|
* <p>
|
||||||
* See <a href="https://tools.ietf.org/html/rfc3174">RFC 3174</a>.
|
* 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 org.eclipse.jgit.util.sha1.Sha1CollisionException} from any digest
|
|
||||||
* method if a potential collision was detected.
|
|
||||||
*
|
|
||||||
* @since 4.7
|
|
||||||
*/
|
*/
|
||||||
public class SHA1 {
|
public abstract class SHA1 {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(SHA1.class);
|
/**
|
||||||
private static final boolean DETECT_COLLISIONS;
|
* SHA1 implementations available in JGit
|
||||||
|
*/
|
||||||
|
public enum Sha1Implementation {
|
||||||
|
/**
|
||||||
|
* {@link SHA1Java} implemented in Java, supports collision detection.
|
||||||
|
*/
|
||||||
|
JAVA(SHA1Java.class),
|
||||||
|
/**
|
||||||
|
* Native implementation based on JDK's {@link MessageDigest}.
|
||||||
|
*/
|
||||||
|
JDKNATIVE(SHA1Native.class);
|
||||||
|
|
||||||
static {
|
private final String implClassName;
|
||||||
SystemReader sr = SystemReader.getInstance();
|
|
||||||
String v = sr.getProperty("org.eclipse.jgit.util.sha1.detectCollision"); //$NON-NLS-1$
|
private Sha1Implementation(Class implClass) {
|
||||||
DETECT_COLLISIONS = v != null ? Boolean.parseBoolean(v) : true;
|
this.implClassName = implClass.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return implClassName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Sha1Implementation SHA1_IMPLEMENTATION = fromConfig();
|
||||||
|
|
||||||
|
private static Sha1Implementation fromConfig() {
|
||||||
|
try {
|
||||||
|
return SystemReader.getInstance().getUserConfig().getEnum(
|
||||||
|
ConfigConstants.CONFIG_CORE_SECTION, null,
|
||||||
|
ConfigConstants.SHA1_IMPLEMENTATION,
|
||||||
|
Sha1Implementation.JAVA);
|
||||||
|
} catch (ConfigInvalidException | IOException e) {
|
||||||
|
return Sha1Implementation.JAVA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Sha1Implementation getImplementation() {
|
||||||
|
String fromSystemProperty = System
|
||||||
|
.getProperty("org.eclipse.jgit.util.sha1.implementation"); //$NON-NLS-1$
|
||||||
|
if (fromSystemProperty == null) {
|
||||||
|
return SHA1_IMPLEMENTATION;
|
||||||
|
}
|
||||||
|
if (fromSystemProperty
|
||||||
|
.equalsIgnoreCase(Sha1Implementation.JAVA.name())) {
|
||||||
|
return Sha1Implementation.JAVA;
|
||||||
|
}
|
||||||
|
if (fromSystemProperty
|
||||||
|
.equalsIgnoreCase(Sha1Implementation.JDKNATIVE.name())) {
|
||||||
|
return Sha1Implementation.JDKNATIVE;
|
||||||
|
}
|
||||||
|
return SHA1_IMPLEMENTATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new context to compute a SHA-1 hash of data.
|
* Create a new context to compute a SHA-1 hash of data.
|
||||||
|
* <p>
|
||||||
|
* If {@code core.sha1Implementation = jdkNative} in the user level global
|
||||||
|
* git configuration or the system property
|
||||||
|
* {@code org.eclipse.jgit.util.sha1.implementation = jdkNative} it will
|
||||||
|
* create an object using the implementation in the JDK. If both are set the
|
||||||
|
* system property takes precedence. Otherwise the pure Java implementation
|
||||||
|
* will be used which supports collision detection but is slower.
|
||||||
*
|
*
|
||||||
* @return a new context to compute a SHA-1 hash of data.
|
* @return a new context to compute a SHA-1 hash of data.
|
||||||
*/
|
*/
|
||||||
public static SHA1 newInstance() {
|
public static SHA1 newInstance() {
|
||||||
return new SHA1();
|
if (getImplementation() == Sha1Implementation.JDKNATIVE) {
|
||||||
}
|
return new SHA1Native();
|
||||||
|
}
|
||||||
private final State h = new State();
|
return new SHA1Java();
|
||||||
private final int[] w = new int[80];
|
|
||||||
|
|
||||||
/** Buffer to accumulate partial blocks to 64 byte alignment. */
|
|
||||||
private final byte[] buffer = new byte[64];
|
|
||||||
|
|
||||||
/** 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() {
|
|
||||||
h.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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}.
|
|
||||||
*
|
|
||||||
* @param detect
|
|
||||||
* a boolean.
|
|
||||||
* @return {@code this}
|
|
||||||
*/
|
|
||||||
public SHA1 setDetectCollision(boolean detect) {
|
|
||||||
detectCollision = detect;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,14 +104,7 @@ public SHA1 setDetectCollision(boolean detect) {
|
||||||
*
|
*
|
||||||
* @param b a byte.
|
* @param b a byte.
|
||||||
*/
|
*/
|
||||||
public void update(byte b) {
|
public abstract void update(byte b);
|
||||||
int bufferLen = (int) (length & 63);
|
|
||||||
length++;
|
|
||||||
buffer[bufferLen] = b;
|
|
||||||
if (bufferLen == 63) {
|
|
||||||
compress(buffer, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the digest computation by adding bytes to the message.
|
* Update the digest computation by adding bytes to the message.
|
||||||
|
@ -122,9 +112,7 @@ public void update(byte b) {
|
||||||
* @param in
|
* @param in
|
||||||
* input array of bytes.
|
* input array of bytes.
|
||||||
*/
|
*/
|
||||||
public void update(byte[] in) {
|
public abstract void update(byte[] in);
|
||||||
update(in, 0, in.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the digest computation by adding bytes to the message.
|
* Update the digest computation by adding bytes to the message.
|
||||||
|
@ -136,344 +124,7 @@ public void update(byte[] in) {
|
||||||
* @param len
|
* @param len
|
||||||
* number of bytes to hash.
|
* number of bytes to hash.
|
||||||
*/
|
*/
|
||||||
public void update(byte[] in, int p, int len) {
|
public abstract void update(byte[] in, int p, int len);
|
||||||
// SHA-1 compress can only process whole 64 byte blocks.
|
|
||||||
// Hold partial updates in buffer, whose length is the low bits.
|
|
||||||
int bufferLen = (int) (length & 63);
|
|
||||||
length += len;
|
|
||||||
|
|
||||||
if (bufferLen > 0) {
|
|
||||||
int n = Math.min(64 - bufferLen, len);
|
|
||||||
System.arraycopy(in, p, buffer, bufferLen, n);
|
|
||||||
p += n;
|
|
||||||
len -= n;
|
|
||||||
if (bufferLen + n < 64) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
compress(buffer, 0);
|
|
||||||
}
|
|
||||||
while (len >= 64) {
|
|
||||||
compress(in, p);
|
|
||||||
p += 64;
|
|
||||||
len -= 64;
|
|
||||||
}
|
|
||||||
if (len > 0) {
|
|
||||||
System.arraycopy(in, p, buffer, 0, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void compress(byte[] block, int p) {
|
|
||||||
initBlock(block, p);
|
|
||||||
int ubcDvMask = detectCollision ? UbcCheck.check(w) : 0;
|
|
||||||
compress();
|
|
||||||
|
|
||||||
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++) {
|
|
||||||
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] = rotateLeft(x, 1); // S^1(...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// @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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
switch (t) {
|
|
||||||
case 58:
|
|
||||||
s = state58;
|
|
||||||
break;
|
|
||||||
case 65:
|
|
||||||
s = state65;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
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;
|
|
||||||
|
|
||||||
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() {
|
|
||||||
int bufferLen = (int) (length & 63);
|
|
||||||
if (bufferLen > 55) {
|
|
||||||
// Last block is too small; pad, compress, pad another block.
|
|
||||||
buffer[bufferLen++] = (byte) 0x80;
|
|
||||||
Arrays.fill(buffer, bufferLen, 64, (byte) 0);
|
|
||||||
compress(buffer, 0);
|
|
||||||
Arrays.fill(buffer, 0, 56, (byte) 0);
|
|
||||||
} else {
|
|
||||||
// Last block can hold padding and length.
|
|
||||||
buffer[bufferLen++] = (byte) 0x80;
|
|
||||||
Arrays.fill(buffer, bufferLen, 56, (byte) 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SHA-1 appends the length of the message in bits after the
|
|
||||||
// padding block (above). Here length is in bytes. Multiply by
|
|
||||||
// 8 by shifting by 3 as part of storing the 64 bit byte length
|
|
||||||
// into the two words expected in the trailer.
|
|
||||||
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(MessageFormat.format(JGitText.get().sha1CollisionDetected,
|
|
||||||
id.name()));
|
|
||||||
throw new Sha1CollisionException(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish the digest and return the resulting hash.
|
* Finish the digest and return the resulting hash.
|
||||||
|
@ -484,17 +135,7 @@ private void finish() {
|
||||||
* @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
|
* @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
|
||||||
* if a collision was detected and safeHash is false.
|
* if a collision was detected and safeHash is false.
|
||||||
*/
|
*/
|
||||||
public byte[] digest() throws Sha1CollisionException {
|
public abstract byte[] digest() throws Sha1CollisionException;
|
||||||
finish();
|
|
||||||
|
|
||||||
byte[] b = new byte[20];
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish the digest and return the resulting hash.
|
* Finish the digest and return the resulting hash.
|
||||||
|
@ -505,10 +146,7 @@ public byte[] digest() throws Sha1CollisionException {
|
||||||
* @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
|
* @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
|
||||||
* if a collision was detected and safeHash is false.
|
* if a collision was detected and safeHash is false.
|
||||||
*/
|
*/
|
||||||
public ObjectId toObjectId() throws Sha1CollisionException {
|
public abstract ObjectId toObjectId() throws Sha1CollisionException;
|
||||||
finish();
|
|
||||||
return h.toObjectId();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish the digest and return the resulting hash.
|
* Finish the digest and return the resulting hash.
|
||||||
|
@ -520,60 +158,42 @@ public ObjectId toObjectId() throws Sha1CollisionException {
|
||||||
* @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
|
* @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
|
||||||
* if a collision was detected and safeHash is false.
|
* if a collision was detected and safeHash is false.
|
||||||
*/
|
*/
|
||||||
public void digest(MutableObjectId id) throws Sha1CollisionException {
|
public abstract void digest(MutableObjectId id)
|
||||||
finish();
|
throws Sha1CollisionException;
|
||||||
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.
|
* Reset this instance to compute another hash.
|
||||||
*
|
*
|
||||||
* @return {@code this}.
|
* @return {@code this}.
|
||||||
*/
|
*/
|
||||||
public SHA1 reset() {
|
public abstract SHA1 reset();
|
||||||
h.init();
|
|
||||||
length = 0;
|
|
||||||
foundCollision = false;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class State {
|
/**
|
||||||
int a;
|
* Enable likely collision detection.
|
||||||
int b;
|
* <p>
|
||||||
int c;
|
* Default for implementations supporting collision detection is
|
||||||
int d;
|
* {@code true}.
|
||||||
int e;
|
* <p>
|
||||||
|
* Implementations not supporting collision detection ignore calls to this
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @param detect
|
||||||
|
* a boolean.
|
||||||
|
* @return {@code this}
|
||||||
|
*/
|
||||||
|
public abstract SHA1 setDetectCollision(boolean detect);
|
||||||
|
|
||||||
final void init() {
|
/**
|
||||||
// Magic initialization constants defined by FIPS180.
|
* Check if a collision was detected. This method only returns an accurate
|
||||||
save(0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0);
|
* 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.
|
||||||
final void save(int a1, int b1, int c1, int d1, int e1) {
|
* <p>
|
||||||
a = a1;
|
* Implementations not supporting collision detection always return
|
||||||
b = b1;
|
* {@code false}.
|
||||||
c = c1;
|
* <p>
|
||||||
d = d1;
|
*
|
||||||
e = e1;
|
* @return {@code true} if a likely collision was detected.
|
||||||
}
|
*/
|
||||||
|
public abstract boolean hasCollision();
|
||||||
ObjectId toObjectId() {
|
}
|
||||||
return new ObjectId(a, b, c, d, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,579 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017, Google Inc. and others
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
* https://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.text.MessageFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.internal.JGitText;
|
||||||
|
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 org.eclipse.jgit.util.sha1.Sha1CollisionException} from any digest
|
||||||
|
* method if a potential collision was detected.
|
||||||
|
*
|
||||||
|
* @since 4.7
|
||||||
|
*/
|
||||||
|
class SHA1Java extends SHA1 {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(SHA1Java.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final State h = new State();
|
||||||
|
private final int[] w = new int[80];
|
||||||
|
|
||||||
|
/** Buffer to accumulate partial blocks to 64 byte alignment. */
|
||||||
|
private final byte[] buffer = new byte[64];
|
||||||
|
|
||||||
|
/** 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();
|
||||||
|
|
||||||
|
SHA1Java() {
|
||||||
|
h.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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}.
|
||||||
|
*
|
||||||
|
* @param detect
|
||||||
|
* a boolean.
|
||||||
|
* @return {@code this}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public SHA1 setDetectCollision(boolean detect) {
|
||||||
|
detectCollision = detect;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the digest computation by adding a byte.
|
||||||
|
*
|
||||||
|
* @param b a byte.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void update(byte b) {
|
||||||
|
int bufferLen = (int) (length & 63);
|
||||||
|
length++;
|
||||||
|
buffer[bufferLen] = b;
|
||||||
|
if (bufferLen == 63) {
|
||||||
|
compress(buffer, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the digest computation by adding bytes to the message.
|
||||||
|
*
|
||||||
|
* @param in
|
||||||
|
* input array of bytes.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void update(byte[] in) {
|
||||||
|
update(in, 0, in.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the digest computation by adding bytes to the message.
|
||||||
|
*
|
||||||
|
* @param in
|
||||||
|
* input array of bytes.
|
||||||
|
* @param p
|
||||||
|
* offset to start at from {@code in}.
|
||||||
|
* @param len
|
||||||
|
* number of bytes to hash.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void update(byte[] in, int p, int len) {
|
||||||
|
// SHA-1 compress can only process whole 64 byte blocks.
|
||||||
|
// Hold partial updates in buffer, whose length is the low bits.
|
||||||
|
int bufferLen = (int) (length & 63);
|
||||||
|
length += len;
|
||||||
|
|
||||||
|
if (bufferLen > 0) {
|
||||||
|
int n = Math.min(64 - bufferLen, len);
|
||||||
|
System.arraycopy(in, p, buffer, bufferLen, n);
|
||||||
|
p += n;
|
||||||
|
len -= n;
|
||||||
|
if (bufferLen + n < 64) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
compress(buffer, 0);
|
||||||
|
}
|
||||||
|
while (len >= 64) {
|
||||||
|
compress(in, p);
|
||||||
|
p += 64;
|
||||||
|
len -= 64;
|
||||||
|
}
|
||||||
|
if (len > 0) {
|
||||||
|
System.arraycopy(in, p, buffer, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compress(byte[] block, int p) {
|
||||||
|
initBlock(block, p);
|
||||||
|
int ubcDvMask = detectCollision ? UbcCheck.check(w) : 0;
|
||||||
|
compress();
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
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] = rotateLeft(x, 1); // S^1(...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// @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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
switch (t) {
|
||||||
|
case 58:
|
||||||
|
s = state58;
|
||||||
|
break;
|
||||||
|
case 65:
|
||||||
|
s = state65;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
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;
|
||||||
|
|
||||||
|
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() {
|
||||||
|
int bufferLen = (int) (length & 63);
|
||||||
|
if (bufferLen > 55) {
|
||||||
|
// Last block is too small; pad, compress, pad another block.
|
||||||
|
buffer[bufferLen++] = (byte) 0x80;
|
||||||
|
Arrays.fill(buffer, bufferLen, 64, (byte) 0);
|
||||||
|
compress(buffer, 0);
|
||||||
|
Arrays.fill(buffer, 0, 56, (byte) 0);
|
||||||
|
} else {
|
||||||
|
// Last block can hold padding and length.
|
||||||
|
buffer[bufferLen++] = (byte) 0x80;
|
||||||
|
Arrays.fill(buffer, bufferLen, 56, (byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA-1 appends the length of the message in bits after the
|
||||||
|
// padding block (above). Here length is in bytes. Multiply by
|
||||||
|
// 8 by shifting by 3 as part of storing the 64 bit byte length
|
||||||
|
// into the two words expected in the trailer.
|
||||||
|
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(MessageFormat.format(JGitText.get().sha1CollisionDetected,
|
||||||
|
id.name()));
|
||||||
|
throw new Sha1CollisionException(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish the digest and return the resulting hash.
|
||||||
|
* <p>
|
||||||
|
* Once {@code digest()} is called, this instance should be discarded.
|
||||||
|
*
|
||||||
|
* @return the bytes for the resulting hash.
|
||||||
|
* @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
|
||||||
|
* if a collision was detected and safeHash is false.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public byte[] digest() throws Sha1CollisionException {
|
||||||
|
finish();
|
||||||
|
|
||||||
|
byte[] b = new byte[20];
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish the digest and return the resulting hash.
|
||||||
|
* <p>
|
||||||
|
* Once {@code digest()} is called, this instance should be discarded.
|
||||||
|
*
|
||||||
|
* @return the ObjectId for the resulting hash.
|
||||||
|
* @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
|
||||||
|
* if a collision was detected and safeHash is false.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ObjectId toObjectId() throws Sha1CollisionException {
|
||||||
|
finish();
|
||||||
|
return h.toObjectId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish the digest and return the resulting hash.
|
||||||
|
* <p>
|
||||||
|
* Once {@code digest()} is called, this instance should be discarded.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* destination to copy the digest to.
|
||||||
|
* @throws org.eclipse.jgit.util.sha1.Sha1CollisionException
|
||||||
|
* if a collision was detected and safeHash is false.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void digest(MutableObjectId id) throws Sha1CollisionException {
|
||||||
|
finish();
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean hasCollision() {
|
||||||
|
return foundCollision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset this instance to compute another hash.
|
||||||
|
*
|
||||||
|
* @return {@code this}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022, Matthias Sohn <matthias.sohn@sap.com> and others
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
* https://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
package org.eclipse.jgit.util.sha1;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.Constants;
|
||||||
|
import org.eclipse.jgit.lib.MutableObjectId;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA1 implementation using native implementation from JDK. It doesn't support
|
||||||
|
* collision detection but is faster than the pure Java implementation.
|
||||||
|
*/
|
||||||
|
class SHA1Native extends SHA1 {
|
||||||
|
|
||||||
|
private final MessageDigest md;
|
||||||
|
|
||||||
|
SHA1Native() {
|
||||||
|
md = Constants.newMessageDigest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte b) {
|
||||||
|
md.update(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte[] in) {
|
||||||
|
md.update(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte[] in, int p, int len) {
|
||||||
|
md.update(in, p, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] digest() throws Sha1CollisionException {
|
||||||
|
return md.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectId toObjectId() throws Sha1CollisionException {
|
||||||
|
return ObjectId.fromRaw(md.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void digest(MutableObjectId id) throws Sha1CollisionException {
|
||||||
|
id.fromRaw(md.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SHA1 reset() {
|
||||||
|
md.reset();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SHA1 setDetectCollision(boolean detect) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCollision() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown by {@link org.eclipse.jgit.util.sha1.SHA1} if it detects a likely hash
|
* Thrown by {@link org.eclipse.jgit.util.sha1.SHA1Java} if it detects a likely hash
|
||||||
* collision.
|
* collision.
|
||||||
*
|
*
|
||||||
* @since 4.7
|
* @since 4.7
|
||||||
|
|
Loading…
Reference in New Issue