Java与Python HMACSHA256不匹配

2024-10-01 17:27:22 发布

您现在位置:Python中文网/ 问答频道 /正文

根据最近关于这个问题的反馈和调查结果,我重写了这个问题以消除噪音。在

我有两个独立的代码路径,一个是Java(Android),一个是Python,它们完成了以下任务,目的是协商Android设备和Python/Django之间的配对。在

爪哇语:

  • 生成同步密钥
  • 使用presharedKey(包括syncKey)散列各种值的串联字符串
  • 使用预共享密钥加密syncKey
  • 将哈希、加密的syncKey、DeviceId和任意变量发送到web服务器

Python

  • 从deviceId获取预共享密钥
  • 解密加密的同步密钥
  • 使用预共享密钥(包括解密的syncKey)散列各种值的串联字符串
  • 确保哈希匹配,这将确认syncKey已成功解密,并且deviceId持有正确的预共享密钥。在

现在,如果我不加密地发送同步密钥,这个过程就可以工作了。最后的哈希匹配,这证明deviceId具有正确的预共享密钥,但是一旦我将en/decryption添加到进程中,哈希就不再匹配了,尽管事实上syncKey和连接的字符串从Java/Python的调试输出中看起来都完全匹配。在

这个过程的一个奇怪之处是,AES256加密算法需要256位密钥,所以我将512位预共享密钥一分为二。在python端,只使用256bit键的另一种选择是要求我通过encode('ascii')传递该键,否则在使用较短的键进行散列时会抛出错误。在

以下是相关代码:

爪哇语:

String presharedKey = getKey();
// f8250b0d5960444e4de6ecc3a78900bb941246a1dece7848fc72b90092ab3ecd0c1c8e36fddba501ef92e72c95b47e07f98f7fd9cb63da75c008a3201124ea5d

String deviceId = getDeviceId();
// 1605788742789230

SyncKey syncKey = generateSyncKey();
// 824C1EE9EF507B52EA28362C71BD4AD512A5F82ACFAE80DEF531F73AC124CA814BA30CE805A157D6ADB9EC04FC99AAE6FDC4238FCD76B87CE22BC2FE33B2E5C9

String concat = syncKey.hexString();
// 824C1EE9EF507B52EA28362C71BD4AD512A5F82ACFAE80DEF531F73AC124CA814BA30CE805A157D6ADB9EC04FC99AAE6FDC4238FCD76B87CE22BC2FE33B2E5C9

String ALGORITHM = "HmacSHA256";
String hash = null;
try {
    SecretKeySpec keySpec = new SecretKeySpec(
        presharedKey.getBytes(),
        ALGORITHM);
    Mac mac = Mac.getInstance(ALGORITHM);
    mac.init(keySpec);
    byte[] result = mac.doFinal(concat.getBytes());
    hash = Base64.encodeToString(result, Base64.DEFAULT);
    // FpDE2JLmCBr+/rW+n/jBHH13F8AV80sUM2fQAY2IpRs=
} catch (NoSuchAlgorithmException x) {
} catch (InvalidKeyException x) {
}

String encKey = presharedKey.substring(0, presharedKey.length() / 2);
// f8250b0d5960444e4de6ecc3a78900bb941246a1dece7848fc72b90092ab3ecd

int len = encKey.length();
byte[] encKeyBytes = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
    encKeyBytes[i / 2] = (byte) ((Character.digit(encKey.charAt(i), 16) << 4)
            + Character.digit(encKey.charAt(i+1), 16));
}

String encryptedSyncKey = null;
try {
    byte[] iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
    SecretKeySpec encKeySpec = new SecretKeySpec(encKeyBytes, "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, encKeySpec, ivSpec);
    byte[] encryptedSyncKeyBytes = cipher.doFinal(syncKey.hexString().getBytes());
    encryptedSyncKey = Base64.encodeToString(encryptedSyncKeyBytes, Base64.DEFAULT);
    /*
        Yrl0/SuTUUTC6oJ8o4TCOy65EwO0JzoXfEi9kLq0AOlf6rH+nN7+BEc0s5uE7TIo1UlJb/DvR2Ca
        ACmQVXXhgpZUTB4sQ0eSo+t32lg0EEb9xKI5CZ4l9QO5raw0xBn7r/tfIdVm8AIFkN9QCcthS0DF
        KH3oWhpwNS+tfEuibLPgGqP/zGTozmido9U9lb4n
    */
} catch (InvalidAlgorithmParameterException e) {
} catch (NoSuchAlgorithmException e) {
} catch (NoSuchPaddingException e) {
} catch (InvalidKeyException e) {
} catch (IllegalBlockSizeException e) {
} catch (BadPaddingException e) {
}

sendStuffToWeb(encryptedSyncKey, deviceId, hash);

Python:

^{pr2}$

从下面的调试输出可以看到syncKey被成功地加密和解密,concat是相同的。然而,得到的hash结果却不同。在


Tags: 字符串newstring密钥hashbytealgorithmbase64
1条回答
网友
1楼 · 发布于 2024-10-01 17:27:22

你的Python代码是错误的。我可以用Python复制Java中的答案。在

如果我使用你的输入:

>>> preshared_key_hex
b'f8250b0d5960444e4de6ecc3a78900bb941246a1dece7848fc72b90092ab3ecd0c1c8e36fddba501ef92e72c95b47e07f98f7fd9cb63da75c008a3201124ea5d'
>>> concat_hex
b'824C1EE9EF507B52EA28362C71BD4AD512A5F82ACFAE80DEF531F73AC124CA814BA30CE805A157D6ADB9EC04FC99AAE6FDC4238FCD76B87CE22BC2FE33B2E5C9'

我得到的值与Java中的值相同:

^{pr2}$

然而,这个值也可能是错误的。几乎可以肯定的是对输入值进行十六进制解码。在

我无法重现Python中的结果;传递给hmac.new的值之一不是您所认为的值。print在调用hmac.new之前立即调用它们,您应该看到哪些不匹配。在

相关问题 更多 >

    热门问题