Na podstawie ostatnich opinii i ustaleń dotyczących tego problemu, przepisałem to pytanie, aby pozbyć się szumu.Java vs Python HMAC-SHA256 Niezgodność
Mam 2 oddzielne ścieżki kodu, jedną w Javie (Android), jedną i Python, które spełniają następujące warunki w celu negocjowania parowania między urządzeniem z systemem Android i Python/Django.
Java:
- wygenerować syncKey
- Hash konkatenacyjnego ciąg różnych wartościach wykorzystaniem presharedKey (w tym syncKey)
- zaszyfrować syncKey użyciu presharedKey
- Wyślij Hash, szyfrowane syncKey, DeviceId i dowolne zmienne do serwera WWW
Python
- Pobierz presharedKey z Deviceid
- odszyfrować zaszyfrowane syncKey
- Hash konkatenacyjnego ciąg różnych wartości z wykorzystaniem presharedKey (w tym rozszyfrowanej syncKey)
- Upewnij mecze hash, który potwierdza, że syncKey został odszyfrowany pomyślnie, a identyfikator urządzenia trzyma poprawny klucz wstępny.
Teraz ten proces działa, jeśli wyślę syncKey niezaszyfrowany. Końcowe wyniki mieszające, które dowodzą, że identyfikator urządzenia ma poprawny klucz wstępny, ale zaraz po dodaniu en/deszyfracji do procesu, hasz już nie pasuje, pomimo tego, że oba klucze syncKey i łączone wydają się idealnie pasować znak dla postaci z wyjścia debugowania obu programów Java/Python.
Jednym z dziwactw tego procesu jest to, że klucz 256-bitowy jest niezbędny dla algorytmu szyfrowania AES256, więc przecinam 5-bitowy klucz wstępny o wartości 512 bitów na pół. Alternatywa użycia tylko klucza 256-bitowego na całej płycie wymagała, aby przekazać klucz przez encode('ascii')
po stronie Pythona, albo też powodował on błędy podczas mieszania za pomocą krótszego klawisza.
Oto odpowiedni kod:
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=
Z wyjścia debugowania poniżej widać syncKey
są szyfrowane i odszyfrowywane powodzeniem, a concat
jest identyczny. Jednak wynik hash
kończy się inaczej.
Spróbuj zmienić 'key.getBytes()' na 'key.getBytes (" US-ASCII ")'; jeśli to nie działa, spróbuj 'key.getBytes (" ISO-8859-1 ")' –
Dzięki, eksperymentowałem z wieloma różnymi kodowaniami dla klucza, jak na twoją radę, jednak wszystkie opcje wydają się zapewniać takie same ciąg skrótów. Próbowałem również to samo po stronie Pythona, jednak zapewnia to również ten sam niedopasowany hash. – DanH
To prawdopodobnie nie ma znaczenia, ale wygląda na to, że używasz schematu dopełnienia w kodzie Java i nie rozliczasz go po stronie Pythona? PyCrypto nie _nie zajmuje się tym dopełnieniem sam. Ponadto przedstawiony kod Pythona jest nieprawidłowy: params nie zawiera klucza o nazwie "serial_number", ale ma "device_id". –