| 
6 | 6 | 
 
  | 
7 | 7 | import java.io.UnsupportedEncodingException;  | 
8 | 8 | import java.math.BigInteger;  | 
9 |  | -import java.security.MessageDigest;  | 
10 |  | -import java.security.NoSuchAlgorithmException;  | 
11 | 9 | import java.util.Arrays;  | 
12 | 10 | import java.util.List;  | 
13 | 11 | 
 
  | 
14 |  | -import org.hibernate.HibernateException;  | 
15 |  | - | 
16 | 12 | import static java.util.Comparator.comparing;  | 
17 | 13 | 
 
  | 
18 | 14 | /**  | 
@@ -125,27 +121,121 @@ public String generateHashedConstraintName(  | 
125 | 121 | 
 
  | 
126 | 122 | 	/**  | 
127 | 123 | 	 * 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.  | 
131 | 127 | 	 *  | 
132 | 128 | 	 * @param name The name to be hashed.  | 
133 | 129 | 	 *  | 
134 | 130 | 	 * @return String The hashed name.  | 
135 | 131 | 	 */  | 
136 | 132 | 	public String hashedName(String name) {  | 
 | 133 | +		final byte[] bytes;  | 
137 | 134 | 		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;  | 
146 | 208 | 		}  | 
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 );  | 
149 | 237 | 		}  | 
 | 238 | + | 
 | 239 | +		return padded;  | 
150 | 240 | 	}  | 
151 | 241 | }  | 
0 commit comments