|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.provider; |
|
|
|
import java.security.MessageDigestSpi; |
|
import java.security.DigestException; |
|
import java.security.ProviderException; |
|
import java.util.Arrays; |
|
import java.util.Objects; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
abstract class DigestBase extends MessageDigestSpi implements Cloneable { |
|
|
|
|
|
private byte[] oneByte; |
|
|
|
|
|
private final String algorithm; |
|
|
|
private final int digestLength; |
|
|
|
|
|
private final int blockSize; |
|
// buffer to store partial blocks, blockSize bytes large |
|
// Subclasses should not access this array directly except possibly in their |
|
|
|
byte[] buffer; |
|
|
|
private int bufOfs; |
|
|
|
// number of bytes processed so far. subclasses should not modify |
|
// this value. |
|
// also used as a flag to indicate reset status |
|
// -1: need to call engineReset() before next call to update() |
|
|
|
long bytesProcessed; |
|
|
|
|
|
|
|
*/ |
|
DigestBase(String algorithm, int digestLength, int blockSize) { |
|
super(); |
|
this.algorithm = algorithm; |
|
this.digestLength = digestLength; |
|
this.blockSize = blockSize; |
|
buffer = new byte[blockSize]; |
|
} |
|
|
|
|
|
protected final int engineGetDigestLength() { |
|
return digestLength; |
|
} |
|
|
|
|
|
protected final void engineUpdate(byte b) { |
|
if (oneByte == null) { |
|
oneByte = new byte[1]; |
|
} |
|
oneByte[0] = b; |
|
engineUpdate(oneByte, 0, 1); |
|
} |
|
|
|
|
|
protected final void engineUpdate(byte[] b, int ofs, int len) { |
|
if (len == 0) { |
|
return; |
|
} |
|
if ((ofs < 0) || (len < 0) || (ofs > b.length - len)) { |
|
throw new ArrayIndexOutOfBoundsException(); |
|
} |
|
if (bytesProcessed < 0) { |
|
engineReset(); |
|
} |
|
bytesProcessed += len; |
|
|
|
if (bufOfs != 0) { |
|
int n = Math.min(len, blockSize - bufOfs); |
|
System.arraycopy(b, ofs, buffer, bufOfs, n); |
|
bufOfs += n; |
|
ofs += n; |
|
len -= n; |
|
if (bufOfs >= blockSize) { |
|
|
|
implCompress(buffer, 0); |
|
bufOfs = 0; |
|
} |
|
} |
|
|
|
if (len >= blockSize) { |
|
int limit = ofs + len; |
|
ofs = implCompressMultiBlock(b, ofs, limit - blockSize); |
|
len = limit - ofs; |
|
} |
|
|
|
if (len > 0) { |
|
System.arraycopy(b, ofs, buffer, 0, len); |
|
bufOfs = len; |
|
} |
|
} |
|
|
|
|
|
private int implCompressMultiBlock(byte[] b, int ofs, int limit) { |
|
implCompressMultiBlockCheck(b, ofs, limit); |
|
return implCompressMultiBlock0(b, ofs, limit); |
|
} |
|
|
|
private int implCompressMultiBlock0(byte[] b, int ofs, int limit) { |
|
for (; ofs <= limit; ofs += blockSize) { |
|
implCompress(b, ofs); |
|
} |
|
return ofs; |
|
} |
|
|
|
private void implCompressMultiBlockCheck(byte[] b, int ofs, int limit) { |
|
if (limit < 0) { |
|
return; |
|
// and an exception is thrown if ofs < 0. |
|
} |
|
|
|
Objects.requireNonNull(b); |
|
|
|
if (ofs < 0 || ofs >= b.length) { |
|
throw new ArrayIndexOutOfBoundsException(ofs); |
|
} |
|
|
|
int endIndex = (limit / blockSize) * blockSize + blockSize - 1; |
|
if (endIndex >= b.length) { |
|
throw new ArrayIndexOutOfBoundsException(endIndex); |
|
} |
|
} |
|
|
|
|
|
protected final void engineReset() { |
|
if (bytesProcessed == 0) { |
|
|
|
return; |
|
} |
|
implReset(); |
|
bufOfs = 0; |
|
bytesProcessed = 0; |
|
Arrays.fill(buffer, (byte) 0x00); |
|
} |
|
|
|
|
|
protected final byte[] engineDigest() { |
|
byte[] b = new byte[digestLength]; |
|
try { |
|
engineDigest(b, 0, b.length); |
|
} catch (DigestException e) { |
|
throw (ProviderException) |
|
new ProviderException("Internal error").initCause(e); |
|
} |
|
return b; |
|
} |
|
|
|
|
|
protected final int engineDigest(byte[] out, int ofs, int len) |
|
throws DigestException { |
|
if (len < digestLength) { |
|
throw new DigestException("Length must be at least " |
|
+ digestLength + " for " + algorithm + "digests"); |
|
} |
|
if ((ofs < 0) || (len < 0) || (ofs > out.length - len)) { |
|
throw new DigestException("Buffer too short to store digest"); |
|
} |
|
if (bytesProcessed < 0) { |
|
engineReset(); |
|
} |
|
implDigest(out, ofs); |
|
bytesProcessed = -1; |
|
return digestLength; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
abstract void implCompress(byte[] b, int ofs); |
|
|
|
|
|
|
|
|
|
*/ |
|
abstract void implDigest(byte[] out, int ofs); |
|
|
|
|
|
|
|
|
|
*/ |
|
abstract void implReset(); |
|
|
|
public Object clone() throws CloneNotSupportedException { |
|
DigestBase copy = (DigestBase) super.clone(); |
|
copy.buffer = copy.buffer.clone(); |
|
return copy; |
|
} |
|
|
|
|
|
static final byte[] padding; |
|
|
|
static { |
|
// we need 128 byte padding for SHA-384/512 |
|
// and an additional 8 bytes for the high 8 bytes of the 16 |
|
|
|
padding = new byte[136]; |
|
padding[0] = (byte)0x80; |
|
} |
|
} |