Skip to content

Commit f97aa74

Browse files
committed
HHH-19471 use custom implementation of MD5
because the JDK version is not available in FIPS mode
1 parent 7bae44e commit f97aa74

File tree

1 file changed

+107
-17
lines changed

1 file changed

+107
-17
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/naming/NamingHelper.java

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,9 @@
66

77
import java.io.UnsupportedEncodingException;
88
import java.math.BigInteger;
9-
import java.security.MessageDigest;
10-
import java.security.NoSuchAlgorithmException;
119
import java.util.Arrays;
1210
import java.util.List;
1311

14-
import org.hibernate.HibernateException;
15-
1612
import static java.util.Comparator.comparing;
1713

1814
/**
@@ -125,27 +121,121 @@ public String generateHashedConstraintName(
125121

126122
/**
127123
* Hash a constraint name using MD5. Convert the MD5 digest to base 35
128-
* (full alphanumeric), guaranteeing
129-
* that the length of the name will always be smaller than the 30
130-
* character identifier restriction enforced by a few dialects.
124+
* (full alphanumeric), guaranteeing that the length of the name will
125+
* always be smaller than the 30 character identifier restriction
126+
* enforced by some dialects.
131127
*
132128
* @param name The name to be hashed.
133129
*
134130
* @return String The hashed name.
135131
*/
136132
public String hashedName(String name) {
133+
final byte[] bytes;
137134
try {
138-
final MessageDigest md5 = MessageDigest.getInstance( "MD5" );
139-
md5.reset();
140-
md5.update( charset != null ? name.getBytes( charset ) : name.getBytes() );
141-
final BigInteger bigInt = new BigInteger( 1, md5.digest() );
142-
// By converting to base 35 (full alphanumeric), we guarantee
143-
// that the length of the name will always be smaller than the 30
144-
// character identifier restriction enforced by a few dialects.
145-
return bigInt.toString( 35 );
135+
bytes = charset == null
136+
? name.getBytes()
137+
: name.getBytes( charset );
138+
}
139+
catch (UnsupportedEncodingException uee) {
140+
throw new IllegalArgumentException(uee);
141+
}
142+
final byte[] digest = hash( pad( bytes ) );
143+
return new BigInteger( 1, digest ).toString( 35 );
144+
}
145+
146+
// Constants for MD5
147+
private static final int[] S = {
148+
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
149+
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
150+
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
151+
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
152+
};
153+
154+
private static final int[] K = new int[64];
155+
static {
156+
for ( int i = 0; i < 64; i++ ) {
157+
K[i] = (int)(long) ( (1L << 32) * Math.abs( Math.sin( i + 1 ) ) );
158+
}
159+
}
160+
161+
public static byte[] hash(byte[] message) {
162+
int a0 = 0x67452301;
163+
int b0 = 0xefcdab89;
164+
int c0 = 0x98badcfe;
165+
int d0 = 0x10325476;
166+
167+
for ( int i = 0; i < message.length / 64; i++ ) {
168+
final int[] M = new int[16];
169+
for (int j = 0; j < 16; j++) {
170+
M[j] = ((message[i * 64 + j * 4] & 0xFF))
171+
| ((message[i * 64 + j * 4 + 1] & 0xFF) << 8)
172+
| ((message[i * 64 + j * 4 + 2] & 0xFF) << 16)
173+
| ((message[i * 64 + j * 4 + 3] & 0xFF) << 24);
174+
}
175+
176+
int A = a0, B = b0, C = c0, D = d0;
177+
178+
for (int j = 0; j < 64; j++) {
179+
final int F, g;
180+
if (j < 16) {
181+
F = (B & C) | (~B & D);
182+
g = j;
183+
}
184+
else if (j < 32) {
185+
F = (D & B) | (~D & C);
186+
g = (5 * j + 1) % 16;
187+
}
188+
else if (j < 48) {
189+
F = B ^ C ^ D;
190+
g = (3 * j + 5) % 16;
191+
}
192+
else {
193+
F = C ^ (B | ~D);
194+
g = (7 * j) % 16;
195+
}
196+
197+
final int temp = D;
198+
D = C;
199+
C = B;
200+
B = B + Integer.rotateLeft( A + F + K[j] + M[g], S[j] );
201+
A = temp;
202+
}
203+
204+
a0 += A;
205+
b0 += B;
206+
c0 += C;
207+
d0 += D;
146208
}
147-
catch ( NoSuchAlgorithmException | UnsupportedEncodingException e ) {
148-
throw new HibernateException( "Unable to generate a hashed name", e );
209+
210+
// Convert final state to byte array (little-endian)
211+
final byte[] digest = new byte[16];
212+
encodeInt( digest, 0, a0 );
213+
encodeInt( digest, 4, b0 );
214+
encodeInt( digest, 8, c0 );
215+
encodeInt( digest, 12, d0 );
216+
return digest;
217+
}
218+
219+
private static void encodeInt(byte[] output, int offset, int value) {
220+
output[offset] = (byte) (value & 0xFF);
221+
output[offset + 1] = (byte) ((value >>> 8) & 0xFF);
222+
output[offset + 2] = (byte) ((value >>> 16) & 0xFF);
223+
output[offset + 3] = (byte) ((value >>> 24) & 0xFF);
224+
}
225+
226+
private static byte[] pad(byte[] input) {
227+
final int originalLength = input.length;
228+
final int numPaddingBytes = ( 56 - (originalLength + 1) % 64 + 64 ) % 64;
229+
230+
final byte[] padded = new byte[originalLength + 1 + numPaddingBytes + 8];
231+
System.arraycopy( input, 0, padded, 0, originalLength );
232+
padded[originalLength] = (byte) 0x80;
233+
234+
long bitLength = (long) originalLength * 8;
235+
for ( int i = 0; i < 8; i++ ) {
236+
padded[padded.length - 8 + i] = (byte) ( ( bitLength >>> (8 * i) ) & 0xFF );
149237
}
238+
239+
return padded;
150240
}
151241
}

0 commit comments

Comments
 (0)