mssql.security.provider.MD4 Maven / Gradle / Ivy
Show all versions of mssql-jdbc Show documentation
package mssql.security.provider;
/**
* This code originates from sun.security.provider.MD4.java. It is modified to remove dependencies to DigestBase,
* Provider, ByteArrayAccess.
*/
/*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. ORACLE PROPRIETARY/CONFIDENTIAL. Use is
* subject to license terms.
*/
/**
* The MD4 class is used to compute an MD4 message digest over a given buffer of bytes. It is an implementation of the
* RSA Data Security Inc MD4 algorithm as described in Internet RFC 1320.
*
*
* The MD4 algorithm is very weak and should not be used unless it is unavoidable. Therefore, it is not registered in
* our standard providers. To obtain an implementation, call the static getInstance() method in this class.
*
* @author Andreas Sterbenz
*/
public final class MD4 {
// state of this object
private final int[] state;
// temporary buffer, used by implCompress()
private final int[] x;
// rotation constants
private static final int S11 = 3;
private static final int S12 = 7;
private static final int S13 = 11;
private static final int S14 = 19;
private static final int S21 = 3;
private static final int S22 = 5;
private static final int S23 = 9;
private static final int S24 = 13;
private static final int S31 = 3;
private static final int S32 = 9;
private static final int S33 = 11;
private static final int S34 = 15;
// size of the input to the compression function in bytes
private static final int blockSize = 64;
// buffer to store partial blocks, blockSize bytes large
private final byte[] buffer = new byte[blockSize];
// offset into buffer
private int bufOfs;
// number of bytes processed so far.
// also used as a flag to indicate reset status
// -1: need to call engineReset() before next call to update()
// 0: is already reset
private long bytesProcessed;
private static final byte[] padding;
static {
padding = new byte[136];
padding[0] = (byte) 0x80;
}
// Standard constructor, creates a new MD4 instance.
public MD4() {
state = new int[4];
x = new int[16];
implReset();
}
/**
* Resets the digest for further use
*/
public void reset() {
implReset();
}
/**
* Updates the digest using the specified array of bytes
*/
public void update(byte[] input) {
engineUpdate(input, 0, input.length);
}
/**
* Completes the hash computation by performing final operations such as padding.
*/
public byte[] digest() {
byte[] out = new byte[16];
implDigest(out, 0);
return out;
}
/**
* Reset the state of this object.
*/
private void implReset() {
// Load magic initialization constants.
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
bufOfs = 0;
bytesProcessed = 0;
}
/**
* Perform the final computations, any buffered bytes are added to the digest, the count is added to the digest, and
* the resulting digest is stored.
*/
private void implDigest(byte[] out, int ofs) {
long bitsProcessed = bytesProcessed << 3;
int index = (int) bytesProcessed & 0x3f;
int padLen = (index < 56) ? (56 - index) : (120 - index);
engineUpdate(padding, 0, padLen);
/**
* the following replaces:
*
*
* i2bLittle4((int) bitsProcessed, buffer, 56);
* i2bLittle4((int) (bitsProcessed >>> 32), buffer, 60);
* i2bLittle(state, 0, out, ofs, 16);
*
*/
buffer[56] = (byte) bitsProcessed;
buffer[57] = (byte) (bitsProcessed >> 8);
buffer[58] = (byte) (bitsProcessed >> 16);
buffer[59] = (byte) (bitsProcessed >> 24);
buffer[60] = (byte) (bitsProcessed >> 32);
buffer[61] = (byte) (bitsProcessed >> 40);
buffer[62] = (byte) (bitsProcessed >> 48);
buffer[63] = (byte) (bitsProcessed >> 56);
implCompress(buffer, 0);
for (int i = 0; i < state.length; i++) {
int x = state[i];
out[ofs++] = (byte) x;
out[ofs++] = (byte) (x >> 8);
out[ofs++] = (byte) (x >> 16);
out[ofs++] = (byte) (x >> 24);
}
}
private 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) {
implReset();
}
bytesProcessed += len;
// if buffer is not empty, we need to fill it before proceeding
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) {
// compress completed block now
implCompress(buffer, 0);
bufOfs = 0;
}
}
// compress complete blocks
while (len >= blockSize) {
implCompress(b, ofs);
len -= blockSize;
ofs += blockSize;
}
// copy remainder to buffer
if (len > 0) {
System.arraycopy(b, ofs, buffer, 0, len);
bufOfs = len;
}
}
private static int FF(int a, int b, int c, int d, int x, int s) {
a += ((b & c) | ((~b) & d)) + x;
return ((a << s) | (a >>> (32 - s)));
}
private static int GG(int a, int b, int c, int d, int x, int s) {
a += ((b & c) | (b & d) | (c & d)) + x + 0x5a827999;
return ((a << s) | (a >>> (32 - s)));
}
private static int HH(int a, int b, int c, int d, int x, int s) {
a += ((b ^ c) ^ d) + x + 0x6ed9eba1;
return ((a << s) | (a >>> (32 - s)));
}
/**
* This is where the functions come together as the generic MD4 transformation operation. It consumes 64 bytes from
* the buffer, beginning at the specified offset.
*/
private void implCompress(byte[] buf, int ofs) {
/**
* the following replaces:
*
*
* b2iLittle64(buf, ofs, x);
*
*/
for (int xfs = 0; xfs < x.length; xfs++) {
x[xfs] = (buf[ofs] & 0xff) | ((buf[ofs + 1] & 0xff) << 8) | ((buf[ofs + 2] & 0xff) << 16)
| ((buf[ofs + 3] & 0xff) << 24);
ofs += 4;
}
int a = state[0];
int b = state[1];
int c = state[2];
int d = state[3];
/* Round 1 */
a = FF(a, b, c, d, x[0], S11); /* 1 */
d = FF(d, a, b, c, x[1], S12); /* 2 */
c = FF(c, d, a, b, x[2], S13); /* 3 */
b = FF(b, c, d, a, x[3], S14); /* 4 */
a = FF(a, b, c, d, x[4], S11); /* 5 */
d = FF(d, a, b, c, x[5], S12); /* 6 */
c = FF(c, d, a, b, x[6], S13); /* 7 */
b = FF(b, c, d, a, x[7], S14); /* 8 */
a = FF(a, b, c, d, x[8], S11); /* 9 */
d = FF(d, a, b, c, x[9], S12); /* 10 */
c = FF(c, d, a, b, x[10], S13); /* 11 */
b = FF(b, c, d, a, x[11], S14); /* 12 */
a = FF(a, b, c, d, x[12], S11); /* 13 */
d = FF(d, a, b, c, x[13], S12); /* 14 */
c = FF(c, d, a, b, x[14], S13); /* 15 */
b = FF(b, c, d, a, x[15], S14); /* 16 */
/* Round 2 */
a = GG(a, b, c, d, x[0], S21); /* 17 */
d = GG(d, a, b, c, x[4], S22); /* 18 */
c = GG(c, d, a, b, x[8], S23); /* 19 */
b = GG(b, c, d, a, x[12], S24); /* 20 */
a = GG(a, b, c, d, x[1], S21); /* 21 */
d = GG(d, a, b, c, x[5], S22); /* 22 */
c = GG(c, d, a, b, x[9], S23); /* 23 */
b = GG(b, c, d, a, x[13], S24); /* 24 */
a = GG(a, b, c, d, x[2], S21); /* 25 */
d = GG(d, a, b, c, x[6], S22); /* 26 */
c = GG(c, d, a, b, x[10], S23); /* 27 */
b = GG(b, c, d, a, x[14], S24); /* 28 */
a = GG(a, b, c, d, x[3], S21); /* 29 */
d = GG(d, a, b, c, x[7], S22); /* 30 */
c = GG(c, d, a, b, x[11], S23); /* 31 */
b = GG(b, c, d, a, x[15], S24); /* 32 */
/* Round 3 */
a = HH(a, b, c, d, x[0], S31); /* 33 */
d = HH(d, a, b, c, x[8], S32); /* 34 */
c = HH(c, d, a, b, x[4], S33); /* 35 */
b = HH(b, c, d, a, x[12], S34); /* 36 */
a = HH(a, b, c, d, x[2], S31); /* 37 */
d = HH(d, a, b, c, x[10], S32); /* 38 */
c = HH(c, d, a, b, x[6], S33); /* 39 */
b = HH(b, c, d, a, x[14], S34); /* 40 */
a = HH(a, b, c, d, x[1], S31); /* 41 */
d = HH(d, a, b, c, x[9], S32); /* 42 */
c = HH(c, d, a, b, x[5], S33); /* 43 */
b = HH(b, c, d, a, x[13], S34); /* 44 */
a = HH(a, b, c, d, x[3], S31); /* 45 */
d = HH(d, a, b, c, x[11], S32); /* 46 */
c = HH(c, d, a, b, x[7], S33); /* 47 */
b = HH(b, c, d, a, x[15], S34); /* 48 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
}