/******************************************************************************* * Copyright (c) 2005, 2007 Remy Suen * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Remy Suen <remy.suen@gmail.com> - initial API and implementation ******************************************************************************/ package org.eclipse.ecf.protocol.msn.internal.encode; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public final class Challenge { public static final String PRODUCT_ID = "PROD0090YUAUV{2B"; //$NON-NLS-1$ private static final String PRODUCT_KEY = "YMM8C_H7KCQ2S_KL"; //$NON-NLS-1$ private static MessageDigest instance; static { try { instance = MessageDigest.getInstance("MD5"); //$NON-NLS-1$ } catch (NoSuchAlgorithmException e) { throw new RuntimeException("No MD5 digest found"); //$NON-NLS-1$ } } public static String createQuery(String challenge) { String[] s = computeMD5DigestAsStringArray((challenge + PRODUCT_KEY) .getBytes()); String md5Hash = computeMD5Digest((challenge + PRODUCT_KEY).getBytes()); int[] md5 = new int[4]; for (int i = 0; i < 4; i++) { md5[i] = Integer.parseInt(s[i], 16); } String chl = challenge + PRODUCT_ID; while (chl.length() % 8 != 0) { chl += '0'; } char[] array = chl.toCharArray(); String[] values = new String[chl.length() / 4]; for (int i = 0; i < array.length; i += 4) { int j = array[i + 3]; String value = Integer.toHexString(j); j = array[i + 2]; value += Integer.toHexString(j); j = array[i + 1]; value += Integer.toHexString(j); j = array[i]; value += Integer.toHexString(j); values[i / 4] = value; } int[] ints = new int[values.length]; for (int i = 0; i < values.length; i++) { ints[i] = Integer.parseInt(values[i], 16); } long high = 0; long low = 0; for (int i = 0; i < ints.length; i += 2) { long temp = ints[i]; temp = (temp * 0xe79a9c1L) % 0x7fffffff; temp += high; temp = md5[0] * temp + md5[1]; temp = temp % 0x7fffffff; high = ints[i + 1]; high = (high + temp) % 0x7fffffff; high = md5[2] * high + md5[3]; high = high % 0x7fffffff; low = low + high + temp; } high = (high + md5[1]) % 0x7fffffff; low = (low + md5[3]) % 0x7fffffff; String highString = Long.toHexString(high); String lowString = Long.toHexString(low); while (highString.length() < 8) { highString = '0' + highString; } while (lowString.length() < 8) { lowString = '0' + lowString; } highString = highString.substring(6, 8) + highString.substring(4, 6) + highString.substring(2, 4) + highString.substring(0, 2); lowString = lowString.substring(6, 8) + lowString.substring(4, 6) + lowString.substring(2, 4) + lowString.substring(0, 2); high = Long.parseLong(highString, 16); low = Long.parseLong(lowString, 16); String first = Long.toHexString((Long.parseLong( md5Hash.substring(0, 8), 16) ^ high)); String second = Long.toHexString((Long.parseLong(md5Hash.substring(8, 16), 16) ^ low)); String third = Long.toHexString((Long.parseLong(md5Hash.substring(16, 24), 16) ^ high)); String fourth = Long.toHexString((Long.parseLong(md5Hash.substring(24, 32), 16) ^ low)); while (first.length() < 8) { first = '0' + first; } while (second.length() < 8) { second = '0' + second; } while (third.length() < 8) { third = '0' + third; } while (fourth.length() < 8) { fourth = '0' + fourth; } return first + second + third + fourth; } /** * Computes the MD5 digest of a string given its bytes. * * @param bytes * the bytes of the string to be digested * @return the MD5 digest of the original string */ private static final String computeMD5Digest(byte[] bytes) { byte[] hash = instance.digest(bytes); StringBuffer buffer = new StringBuffer(); synchronized (buffer) { for (int i = 0; i < hash.length; i++) { int value = 0xff & hash[i]; if (value < 16) { buffer.append('0').append(Integer.toHexString(value)); } else { buffer.append(Integer.toHexString(value)); } } return buffer.toString(); } } private static final String[] computeMD5DigestAsStringArray(byte[] bytes) { byte[] hash = instance.digest(bytes); StringBuffer buffer = new StringBuffer(); synchronized (buffer) { for (int i = 0; i < hash.length; i++) { int value = 0xff & hash[i]; if (value < 16) { buffer.append('0').append(Integer.toHexString(value)); } else { buffer.append(Integer.toHexString(value)); } } } String result = buffer.toString(); String[] results = new String[4]; results[0] = result.substring(0, 8); results[1] = result.substring(8, 16); results[2] = result.substring(16, 24); results[3] = result.substring(24, 32); for (int i = 0; i < 4; i++) { char[] array = results[i].toCharArray(); char[] swapped = new char[8]; for (int j = 0; j < 8; j += 2) { swapped[7 - j] = array[j + 1]; swapped[6 - j] = array[j]; } results[i] = new String(swapped); } for (int i = 0; i < 4; i++) { long l = Long.parseLong(results[i], 16); l = l & 0x7fffffff; if (l < 0x10000000) { results[i] = '0' + Long.toHexString(l); } else { results[i] = Long.toHexString(l); } } return results; } }