/*
 * 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.

See RFC 3174.

Unlike MessageDigest, this implementation includes the algorithm used by sha1dc to detect cryptanalytic collision attacks against SHA-1, such as the one used by SHAttered. See sha1collisiondetection for more information.

When detectCollision is true (default), this implementation throws Sha1CollisionException from any digest method if a potential collision was detected.

Since:4.7
/** * 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 */
public class SHA1 { private static final 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; }
Create a new context to compute a SHA-1 hash of data.
Returns:a new context to compute a SHA-1 hash of data.
/** * Create 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() { return new SHA1(); } private final State h = new State(); private final int[] w = new int[80];
Buffer to accumulate partial blocks to 64 byte alignment.
/** Buffer to accumulate partial blocks to 64 byte alignment. */
private final byte[] buffer = new byte[64];
Total number of bytes in the message.
/** 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.

Default is true.

May also be set by system property: -Dorg.eclipse.jgit.util.sha1.detectCollision=true.

Params:
  • detect – a boolean.
Returns:this
/** * 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; }
Update the digest computation by adding a byte.
Params:
  • b – a byte.
/** * Update the digest computation by adding a byte. * * @param b a byte. */
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.
Params:
  • in – input array of bytes.
/** * Update the digest computation by adding bytes to the message. * * @param in * input array of bytes. */
public void update(byte[] in) { update(in, 0, in.length); }
Update the digest computation by adding bytes to the message.
Params:
  • in – input array of bytes.
  • p – offset to start at from in.
  • len – number of bytes to hash.
/** * 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. */
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.

Once digest() is called, this instance should be discarded.

Throws:
Returns:the bytes for the resulting hash.
/** * 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. */
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.

Once digest() is called, this instance should be discarded.

Throws:
Returns:the ObjectId for the resulting hash.
/** * 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. */
public ObjectId toObjectId() throws Sha1CollisionException { finish(); return h.toObjectId(); }
Finish the digest and return the resulting hash.

Once digest() is called, this instance should be discarded.

Params:
  • id – destination to copy the digest to.
Throws:
/** * 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. */
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.

This method only returns an accurate result after the digest was obtained through digest(), digest(MutableObjectId) or toObjectId(), as the hashing function must finish processing to know the final state.

Returns:true if a likely collision was detected.
/** * 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.
Returns:this.
/** * 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); } } }