java - 不同平台中相同的哈希+加密生成不同的值

标签 java android encryption hash

我正在为社交网站编写一些网络服务。 Android 将利用这些网络服务来制作 Android 应用程序。由于设计该网站的人已经不再联系了,所以我查看了整个网站代码,该代码是用java和spring框架编写的。我正在用 php 编写 Web 服务。

现在,当我尝试向 php 页面发送 post 请求时,该页面将确认给定的用户名和密码组合是否正确,然后返回 session 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==

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

最佳答案

我不希望 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 等具有大量轮数和随机盐的东西,但这本身就是一个主题。

关于java - 不同平台中相同的哈希+加密生成不同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16609949/

相关文章:

android - 在没有硬编码值的情况下以精确的矩形android线性布局设计编辑文本

java - 瓦片不会随 map View 加载,但会随 fragment 加载

java - 如何从 Android 上 Firestore 的子集合中获取数据?

java - 黑莓中使用 NoPadding 进行 AES 加密

java - 如何安全地存储加密密码

java - Firebase Valueeventlistener 花费了很多时间

java - swt 或 swing 中的边框布局

java - 使用RSA在java中加密和解密大字符串

java - Exiftool 从一个目录创建多个 JSon 文件

Java 如何将字符串化点流转换为 ArrayList<Point2D.Double>