需要验证从后端收到的 Json 响应的 Hash 值。哈希值在Python中正确计算并与后端服务器哈希值匹配,这是正确的。我在 Kotlin Android 中总是得到不同的哈希值。分享下面的代码片段。
Python:
import json
import hashlib
import base64
msg = {
"name": "Alice",
"age": 25,
"address": {
"city": "Wonderland",
"street": "Rabbit Hole"
}
}
# Sort keys and ensure ASCII encoding
json_str = json.dumps(msg, ensure_ascii=False, sort_keys=True)
print(f"Serialized JSON (Python): {json_str}")
json_bin = json_str.encode('utf-8')
# Create SHA-224 hash and take first 16 bytes
hash_calculator = hashlib.sha224(json_bin)
hash_digest = hash_calculator.digest()[:16]
# Print hex digest
print(f"Hex digest (Python): {hash_digest.hex()}")
# Base64 encode
hash_encoded64 = base64.urlsafe_b64encode(hash_digest).decode('utf8')
print(f"Base64 encoded hash (Python): {hash_encoded64}")
但是当我将相同的 python 代码转换为 Kotlin 并运行时,我得到了不同的值。谁能检查一下并让我知道出了什么问题吗?
科特林:
fun calculateHas(){
// Original JSON message as a string
val msg = """
{
"name": "Alice",
"age": 25,
"address": {
"city": "Wonderland",
"street": "Rabbit Hole"
}
}
""".trim().trimIndent().replace("\n","")
// Parse the JSON string into a JSONObject
val jsonObj = JSONObject(msg)
// Serialize the JSONObject into a string with sorted keys
val sortedJsonObj = JSONObject()
val keys = jsonObj.keys().asSequence().toList().sorted()
for (key in keys) {
sortedJsonObj.put(key, jsonObj.get(key))
}
val sortedJsonStr = sortedJsonObj.toString().replace("\n","").toByteArray(StandardCharsets.UTF_8)
// Create a SHA-224 hash of the JSON byte array
val sha224Digest = MessageDigest.getInstance("SHA-224")
val hashBytes = sha224Digest.digest(sortedJsonStr)
// Get the first 16 bytes of the hash
val truncatedHash = hashBytes.sliceArray(0 until 16)
// Encode the truncated hash in Base64 (URL-safe, without padding)
val hashBase64 = Base64.encodeToString(truncatedHash, Base64.URL_SAFE or Base64.NO_WRAP)
// Print the Base64-encoded hash
println(hashBase64)
Log.e("Code:" , hashBase64)
}
您正在获取 JSON 字符串的哈希值。 JSON 对象作为字符串的表示形式并未标准化,这样做会让您面临很大的风险。碰巧,Python 和 Kotlin 生成的 JSON 字符串是不同的:
由Python使用
json.dumps
生成:
{"address": {"city": "Wonderland", "street": "Rabbit Hole"}, "age": 25, "name": "Alice"}
由 Kotlin 使用
JSONObject.toString
制作:
{"address":{"city":"Wonderland","street":"Rabbit Hole"},"name":"Alice","age":25}
我假设您正在使用 JSON-Java 库中的
org.json.JSONObject
(如果您指定它将会有所帮助)。该库创建一个没有空格的字符串。可能还有其他 JSON 库会在冒号后创建一个空格,就像 Python 一样,但我不知道有哪一个。
手动在冒号后添加空格是错误的,因为这也会对属于数据一部分的冒号执行此操作,而您不想更改冒号。
更改 Python 的输出以匹配 Kotlin 的输出会更简单。您可以使用分隔符参数来执行此操作:
json.dumps(msg, ensure_ascii=False, sort_keys=True, separators=(',',':'))
当然,这意味着您必须重新散列服务器上的任何现有哈希值,以便它们不使用空格。