2013-05-10 46 views
11

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.

+1

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 ")' –

+0

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

+0

Đ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'. –

Trả lời

8

Mã Python của bạn sai. Tôi có thể tái tạo, bằng Python, câu trả lời bạn có trong Java.

Nếu tôi sử dụng đầu vào của bạn:

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

tôi nhận được giá trị mà bạn có trong Java:

>>> base64.b64encode(hmac.new(preshared_key_hex, concat_hex, hashlib.sha256).digest()) 
b'FpDE2JLmCBr+/rW+n/jBHH13F8AV80sUM2fQAY2IpRs=' 

Tuy nhiên, giá trị đó có lẽ cũng sai. Bạn hầu như chắc chắn sẽ giải mã hex các giá trị đầu vào.

Tôi không thể tạo lại những gì bạn có trong Python; một trong các giá trị bạn đang chuyển đến hmac.new không phải là những gì bạn nghĩ. print chúng ngay lập tức trước khi gọi hmac.new và bạn sẽ thấy những gì không khớp.

+0

Xin lỗi tôi không nhìn thấy nơi trong Python của tôi tôi giải mã 'preshared_key' hoặc' concat'? Tôi chỉ giải mã cho giải mã. Đối với hồ sơ tôi đang sử dụng Python 2,7, tôi đoán bạn đang sử dụng 3 + cho ký hiệu 'b'''? Điều đó có quan trọng không? Xin lỗi nếu tôi là một noob, tôi chỉ không thể nhìn thấy nó :) – DanH

+3

@DanH Tôi không thể sao chép những gì bạn có trong Python cả. Tôi chỉ đề cập đến những giá trị đó có lẽ nên được giải mã hex. Không có bất kỳ sự khác biệt Python 2/3 ở đây. Bất kể mã hóa, bạn đang mắc lỗi trong Python ở đâu đó. Nếu bạn in ra các giá trị trước khi gọi 'hmac.new' bạn sẽ thấy rằng chúng không khớp với những gì bạn đang truyền nó trong Java - vì nếu bạn chuyển các giá trị đó, như tôi đã làm, bạn sẽ nhận được câu trả lời giống như trong Java. Vì vậy, vấn đề trước mắt của bạn là bằng Python. – agf

+0

OK Tôi sẽ có một giao diện khác, mã này thậm chí còn không hợp lý với tôi nữa! Nó chỉ là điểm ảnh D: – DanH