2013-05-10 15 views
11

Sulla base di recenti riscontri e risultati su questo problema, ho riscritto la domanda per eliminare il rumore.Java vs Python HMAC-SHA256 Mancata corrispondenza

Ho due percorsi di codice separati, uno in Java (Android), uno e Python che eseguono quanto segue ai fini della negoziazione di un accoppiamento tra un dispositivo Android e un Python/Django.

Java:

  • Generare uno syncKey
  • Hash una stringa concatenata di diversi valori utilizzando il PreSharedKey (tra cui lo syncKey)
  • crittografare lo syncKey utilizzando un PreSharedKey
  • Invia Hash, criptato syncKey, DeviceId e variabili arbitrarie sul web server

Python

  • Prendi il PreSharedKey dal deviceId
  • decifrare lo syncKey criptato
  • Hash una stringa concatenata di diversi valori utilizzando il PreSharedKey (compreso lo syncKey decriptato)
  • Assicurarsi che le partite di hash, che conferma che il syncKey è stato decodificato correttamente e il deviceId contiene la presharedKey corretta.

Ora questo processo funziona se invio syncKey non criptato. Le ultime hash match, che dimostrano che deviceId ha la chiave preshared corretta, tuttavia non appena aggiungo l'en/decryption nel processo, l'hash non corrisponde più, nonostante il fatto che sia la syncKey sia la stringa concatenata sembrano corrispondere perfettamente carattere per carattere dall'output di debug di Java/Python.

Una stranezza del processo è che una chiave a 256 bit è necessaria per l'algoritmo di crittografia AES256, quindi sto tagliando a metà la presharedKey a 512 bit. L'alternativa di utilizzare solo una chiave a 256 bit su tutta la linea richiedeva che io passassi la chiave attraverso encode('ascii') sul lato python, oppure che stava generando errori durante l'hashing con la chiave più breve.

Ecco il codice rilevante:

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= 

Dal output di debug qui sotto potete vedere la syncKey è codificati e decodificati con successo, e il concat è identico. Tuttavia il risultato hash finisce per essere diverso.

+1

Provare a cambiare 'key.getBytes()' in 'key.getBytes (" US-ASCII ")'; se questo non funziona, prova 'key.getBytes (" ISO-8859-1 ")' –

+0

Grazie, ho sperimentato un certo numero di codifiche differenti per la chiave come da tuo consiglio, tuttavia tutte le opzioni sembrano fornire lo stesso stringa di hash. Ho anche provato la stessa cosa sul lato python, tuttavia questo fornisce anche lo stesso hash di mismatching. – DanH

+0

Probabilmente questo non è rilevante, ma sembra che tu stia usando uno schema di riempimento nel codice Java, e non rendendolo conto sul lato Python? PyCrypto non _non_ gestisce quel riempimento da solo. Inoltre, il codice Python come mostrato non è valido: params non contiene una chiave chiamata 'serial_number', ma ha 'device_id'. –

risposta

8

Il codice Python è errato. Posso riprodurre, in Python, la risposta che hai ottenuto in Java.

Se io uso gli ingressi:

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

ottengo lo stesso valore che si ottiene in Java:

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

Tuttavia, tale valore è probabilmente anche sbagliato. Dovresti quasi sicuramente decodificare esadecimale i valori di input.

Non riesco a riprodurre ciò che hai ottenuto in Python; uno dei valori che stai passando a hmac.new non è quello che pensi che sia. print immediatamente prima di chiamare hmac.new e dovresti vedere ciò che non corrisponde.

+0

Scusa se non vedo dove nel mio Python sto decodificando 'preshared_key' o' concat'? Sto solo decodificando per la decrittazione. Per la cronaca sto usando Python 2.7, suppongo tu stia usando 3+ data la notazione 'b'''? È importante? Scusa se sono un noob, non riesco a vederlo :) – DanH

+3

@DanH Non riesco a riprodurre quello che hai ottenuto in Python. Stavo solo citando quei valori che probabilmente dovrebbero essere decodificati esadecimali. Non ci sono differenze Python 2/3 qui. Indipendentemente dalla codifica, stai facendo un errore in Python da qualche parte. Se si stampano i valori prima di chiamare 'hmac.new', si vedrà che non corrispondono a quello che si sta passando in Java - poiché se si passano questi valori, come ho fatto io, si ottiene la stessa risposta di Giava. Quindi il tuo problema immediato è in Python. – agf

+0

OK Avrò un'altra occhiata, il codice non ha più senso per me! Sono solo i pixel D: – DanH

Problemi correlati