在不同平台中使用相同的散列+加密生成不同的值

时间:2013-05-17 13:11:07

标签: java android encryption hash

我正在为社交网站编写一些网络服务。这些网络服务将被android用于制作android-app。由于设计网站的人不再接触,我查看了使用spring框架用java编写的整个网站代码。我正在用PHP编写Web服务。

现在,当我尝试向php页面发送帖子请求时,会确认给定的用户名和用户名。传递组合是否正确,然后返回会话ID。但是我无法获得正确的散列方法来获取保存在数据库中的正确散列值。 因此,每次,我都被php代码拒绝了。

我在网站代码中找到的加密如下:

public static final synchronized String encrypt(String plaintext, String algorithm, String encoding) throws Exception
{
  MessageDigest msgDigest = null;
  String hashValue = null;
  try
  {
    msgDigest = MessageDigest.getInstance(algorithm);
    msgDigest.update(plaintext.getBytes(encoding));
    byte rawByte[] = msgDigest.digest();
    hashValue = (new BASE64Encoder()).encode(rawByte);

  }
  catch (NoSuchAlgorithmException e)
  {
    System.out.println("No Such Algorithm Exists");
  }
  catch (UnsupportedEncodingException e)
  {
    System.out.println("The Encoding Is Not Supported");
  }
  return hashValue;
}

例如,如果我将密码设置为monkey123作为密码,则它将在base 64中编码的哈希值为:hge2WiM7vlaTTS1qU404 + Q ==

现在,经过几个小时的努力在php中做同样的事情,我意识到我可以在android本身做上述程序。所以,我写了下面的代码:

MessageDigest pwdDigest=MessageDigest.getInstance("MD5");
pwdDigest.update(password.getBytes("UTF-16"));
byte rawbyte[]=pwdDigest.digest();
String passwordHash=Base64.encodeToString(rawbyte,Base64.DEFAULT);


URL url = new URL(loginURL);

HttpURLConnection Connection = (HttpURLConnection) url.openConnection();

Connection.setReadTimeout(10000);
Connection.setAllowUserInteraction(false);

Connection.setDoOutput(true);

//set the request to POST and send

Connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

DataOutputStream out = new DataOutputStream(Connection.getOutputStream());
out.writeBytes("username=" + URLEncoder.encode(username, "UTF-8"));
out.writeBytes("&password="+URLEncoder.encode(passwordHash,"UTF-8"));
out.flush();
out.close();
if(Connection.getResponseCode()==200){
  String data="Connected";            
  return data;
} else 
  return Connection.getResponseCode()+": "+Connection.getResponseMessage();

我预计这会成功,因为在这两种情况下,我都在做同样的过程来加密密码,但令人惊讶的是,这并没有给出哈希值:   hge2WiM7vlaTTS1qU404+Q==但它正在给予:nZlvVe7GSS2Zso1dOwJrIA==

我真的很难找出这两者不一样的原因。任何帮助都将非常感激。

1 个答案:

答案 0 :(得分:0)

我不希望MD5在平台之间有所不同。它稳定且文档齐全,是核心库的一部分。如果在某些Android版本中出现这种情况,那么手机上的任何内容都无效。

重新编码为UTF-8是无害的,因为所有Base64字符都适合较低的ASCII范围。 base64字母表的三个字符需要URL编码,但如果出现问题,你会看到%-escapes。

Base64是不太稳定的地面(很多很多不同的实现,没有单一的规范),但它也不完全是火箭科学。同样,我不认为错误的实现会真正实现它,但Base64步骤可能会出现差异。

就个人而言,我怀疑在password.getBytes("UTF-16")电话会议期间引入了错误。验证此预感的一种快速方法是在两个平台上的调试器中检查生成的字节数组。 根据java.lang.Charset,“UTF-16”编码将使用大端字节顺序,而您的PHP代码可能默认为小端,因为它在x86上运行且不存在字节顺序标记(我不太清楚PHP是否足以判断此行为是否已明确定义)。尝试修改Java代码以使用password.getBytes("UTF-16LE"),看看是否有所作为。

附注:MD5不再被认为是安全的哈希密码;你会想要使用像scrypt或PBKDF2这样的东西,有很多轮和一个随机盐,但这本身就是一个话题。