Dựa trên phản hồi và phát hiện gần đây về vấn đề này, tôi đã viết lại câu hỏi để loại bỏ tiếng ồn.Java vs Python HMAC-SHA256 Không khớp
Tôi có 2 đường dẫn mã riêng biệt, một trong Java (Android), một và Python thực hiện các mục đích sau đây để đàm phán ghép nối giữa thiết bị Android và Python/Django.
Java:
- Tạo một syncKey
- Hash một chuỗi nối các giá trị khác nhau bằng cách sử dụng presharedKey (bao gồm cả syncKey)
- Mã hóa các syncKey sử dụng một presharedKey
- Gửi Hash, mã hóa syncKey, DeviceId và biến tùy ý tới máy chủ web
Python
- Lấy presharedKey từ deviceId
- Decrypt các syncKey mã hóa
- Hash một chuỗi nối các giá trị khác nhau bằng cách sử dụng presharedKey (bao gồm cả syncKey giải mã)
- Hãy chắc chắn rằng các trận đấu băm, trong đó khẳng định rằng syncKey được giải mã thành công và rằng deviceId giữ đúng presharedKey.
Quá trình này hoạt động nếu tôi gửi syncKey không được mã hóa. Các kết quả băm cuối cùng, chứng minh deviceId có khóa chia sẻ chính xác, tuy nhiên ngay sau khi tôi thêm en/decryption vào quá trình, hàm băm không còn khớp, mặc dù thực tế cả chuỗi syncKey và chuỗi được ghép đều xuất hiện để khớp hoàn hảo ký tự cho ký tự từ đầu ra gỡ lỗi của cả Java/Python.
Một quirk của quá trình này là một khóa 256 bit là cần thiết cho thuật toán mã hóa AES256, vì vậy tôi đang cắt presharedKey 512 bit trong một nửa. Việc thay thế bằng cách sử dụng chỉ có một phím 256bit trên bảng đã yêu cầu tôi vượt qua khóa thông qua encode('ascii')
ở phía trăn, hoặc người nào khác nó đã ném lên các lỗi trong quá trình băm với khóa ngắn hơn.
Đây là mã có liên quan:
Java:
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:
hash = getHash(request)
# hash from Java: FpDE2JLmCBr+/rW+n/jBHH13F8AV80sUM2fQAY2IpRs=
encrypted_sync_key = getEncSyncKey(request)
# encryptedSyncKey from Java:
# Yrl0/SuTUUTC6oJ8o4TCOy65EwO0JzoXfEi9kLq0AOlf6rH+nN7+BEc0s5uE7TIo1UlJb/DvR2Ca
# ACmQVXXhgpZUTB4sQ0eSo+t32lg0EEb9xKI5CZ4l9QO5raw0xBn7r/tfIdVm8AIFkN9QCcthS0DF
# KH3oWhpwNS+tfEuibLPgGqP/zGTozmido9U9lb4n
device_id = getDeviceId(request)
# 1605788742789230
preshared_key = getPresharedKeyFromDevice(deviceId)
# f8250b0d5960444e4de6ecc3a78900bb941246a1dece7848fc72b90092ab3ecd0c1c8e36fddba501ef92e72c95b47e07f98f7fd9cb63da75c008a3201124ea5d
enc_key = preshared_key[:len(preshared_key)/2]
# f8250b0d5960444e4de6ecc3a78900bb941246a1dece7848fc72b90092ab3ecd
aes = AES.new(enc_key.decode('hex'), AES.MODE_CBC, IV="\x00"*16)
sync_key = aes.decrypt(base64.b64decode(encrypted_sync_key))
# 824C1EE9EF507B52EA28362C71BD4AD512A5F82ACFAE80DEF531F73AC124CA814BA30CE805A157D6ADB9EC04FC99AAE6FDC4238FCD76B87CE22BC2FE33B2E5C9
concat = sync_key
# 824C1EE9EF507B52EA28362C71BD4AD512A5F82ACFAE80DEF531F73AC124CA814BA30CE805A157D6ADB9EC04FC99AAE6FDC4238FCD76B87CE22BC2FE33B2E5C9
import hashlib
from hmac import new as hmac
verify_hash = hmac(preshared_key, concat, hashlib.sha256).digest().encode('base64')
# IoSc2w2sQ4/fwhJTdUQHw/Hdyjy+ranzQ1z3J5LfYbA=
Từ kết xuất debug dưới đây bạn sẽ nhìn thấy syncKey
được mã hóa và giải mã thành công, và concat
giống hệt nhau. Tuy nhiên kết quả hash
kết thúc là khác nhau.
Hãy thử thay đổi 'key.getBytes()' thành 'key.getBytes (" US-ASCII ")'; nếu điều đó không hiệu quả, hãy thử 'key.getBytes (" ISO-8859-1 ")' –
Cảm ơn, tôi đã thử nghiệm với một số mã hóa khác nhau cho khóa theo lời khuyên của bạn, tuy nhiên tất cả các tùy chọn dường như cung cấp chuỗi băm. Tôi cũng đã thử điều tương tự ở phía bên python, tuy nhiên điều này cũng cung cấp cùng một hash không khớp. – DanH
Điều này có thể không liên quan, nhưng có vẻ như bạn đang sử dụng lược đồ đệm trong mã Java và không tính toán nó ở phía Python? PyCrypto không _not_ tự xử lý phần đệm đó. Ngoài ra, mã Python như được hiển thị không hợp lệ: các tham số không chứa khóa có tên 'serial_number', nhưng thay vào đó có 'device_id'. –