1

我正在为一个社交网站编写一些网络服务。这些网络服务将被 android 用于制作 android-app。由于设计网站的人已经没有联系了,我看了一下整个网站的代码,都是用java用spring框架写的。我正在用 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==

我真的很难找出这两个不一样的原因。任何帮助将不胜感激。

4

1 回答 1

0

我不希望 MD5 在平台之间有所不同。它是稳定且有据可查的,并且是核心库的一部分。如果这在某些 Android 版本中被破坏,那么该手机将无法正常工作。

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

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

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

旁注:MD5 不再被认为对散列密码是安全的;你会想要使用 scrypt 或 PBKDF2 之类的东西,有很多轮次和随机盐,但这本身就是一个话题。

于 2013-05-18T07:53:06.387 回答