实习的第一天,项目经理给了个小问题,我这个C#的MD5加密算法出来的结果只有31位,有时也有32位,你用java实现一下,也必须要有31位或者32位的情况。好吧,仔细分析了下31位结果产生的原因,当8位的字节进行16进制转换时,如果前面四位产生的结果为0,那么后面最后的结果可能就把0省略掉了,也就是0X0A会变成0XA。其实内心是崩溃的,输出成标准的32位不是最好的吗?好吧,还是来整理一下。
先看一下项目经理给的C#代码:
public static string MD5Encryption(string source, string key)
{
string temp = source + key;
MD5 md5 = new MD5CryptoServiceProvider();
byte[] fromData = System.Text.Encoding.Unicode.GetBytes(temp);
byte[] targetData = md5.ComputeHash(fromData);
string byte2String = null;
for (int i = 0; i < targetData.Length; i++)
{
byte2String += targetData[i].ToString("x");
}
return byte2String;
}
{
string temp = source + key;
MD5 md5 = new MD5CryptoServiceProvider();
byte[] fromData = System.Text.Encoding.Unicode.GetBytes(temp);
byte[] targetData = md5.ComputeHash(fromData);
string byte2String = null;
for (int i = 0; i < targetData.Length; i++)
{
byte2String += targetData[i].ToString("x");
}
return byte2String;
}
现在的目标情况是,需要把它翻译成java代码,代码如下:
/**
* MD5加密
* @param str
* @return
*/
public static String encrypt(String source ,String key){
//输入字符串
String str = source + key;
//返回字符串
String str_return = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
//依据数组的编码方式得到待加密的数组,注意编码方式,你的可能会有不同
byte[]byte_temp=str.getBytes("UTF-16LE");
md.update(byte_temp);
byte b[] = md.digest();
//进行转换
str_return = byte2hex(b);
} catch (Exception e){
}
return str_return;
}
* MD5加密
* @param str
* @return
*/
public static String encrypt(String source ,String key){
//输入字符串
String str = source + key;
//返回字符串
String str_return = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
//依据数组的编码方式得到待加密的数组,注意编码方式,你的可能会有不同
byte[]byte_temp=str.getBytes("UTF-16LE");
md.update(byte_temp);
byte b[] = md.digest();
//进行转换
str_return = byte2hex(b);
} catch (Exception e){
}
return str_return;
}
/**
*
* @param b
* @return
*/
public static String byte2hex(byte[] b) {
//进行二进制转16进制后返回的字符串
String hs = "";
//进行单个字节进行转换的局部字符串
String stmp = "";
//迭代进行转换
for (int n = 0; n < b.length; n++) {
//对于数组中每个元素进行转换得到16进制编码
stmp = (Integer.toHexString(b[n] & 0XFF));
//转换后添加到返回字符串末尾
hs += stmp;
}
return hs.toLowerCase();
}
*
* @param b
* @return
*/
public static String byte2hex(byte[] b) {
//进行二进制转16进制后返回的字符串
String hs = "";
//进行单个字节进行转换的局部字符串
String stmp = "";
//迭代进行转换
for (int n = 0; n < b.length; n++) {
//对于数组中每个元素进行转换得到16进制编码
stmp = (Integer.toHexString(b[n] & 0XFF));
//转换后添加到返回字符串末尾
hs += stmp;
}
return hs.toLowerCase();
}
这样产生的结果就跟C#代码一样的了。
但是这样其实是不好的,我们更想要一些标准的结果:32位的。
采用如下的方法就好了:
public static String getMD5(String str) {
byte[] source = str.getBytes();
String s = null;
char hexDigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try
{
java.security.MessageDigest md = java.security.MessageDigest.getInstance( "MD5" );
md.update( source );
byte tmp[] = md.digest();
char str[] = new char[16 * 2];
int k = 0;
for (int i = 0; i < 16; i++) {
byte byte0 = tmp[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
s = new String(str);
}catch( Exception e ){
e.printStackTrace();
}
byte[] source = str.getBytes();
String s = null;
char hexDigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try
{
java.security.MessageDigest md = java.security.MessageDigest.getInstance( "MD5" );
md.update( source );
byte tmp[] = md.digest();
char str[] = new char[16 * 2];
int k = 0;
for (int i = 0; i < 16; i++) {
byte byte0 = tmp[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
s = new String(str);
}catch( Exception e ){
e.printStackTrace();
}
但是在这里,一定要注意理解
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
的含义是什么。第一句的意思是取字节的左四位然后转换成16进制,第二句话的意思是后四位再转换成16进制。
这样就好理解了。