2010-02-17 16 views
25

Sto crittografando una stringa in ogg-c e anche crittografando la stessa stringa in Java usando AES e sto vedendo alcuni strani problemi. La prima parte del risultato corrisponde a un certo punto ma poi è diversa, quindi quando vado a decodificare il risultato da Java sull'iPhone non è in grado di decrittografarlo.Come posso rendere la mia crittografia AES identica tra Java e Objective-C (iPhone)?

Sto usando una stringa sorgente di "Ora, allora, e cos'è questa assurdità?" Lo sai? " Utilizzando una chiave di "123456789"

Il codice Objective-C per crittografare è la seguente: NOTA: si tratta di una categoria NSData così scontato che il metodo viene chiamato su un oggetto NSData cosi 'sé' contiene i dati byte crittografare.

- (NSData *)AESEncryptWithKey:(NSString *)key { 
char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused) 
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) 

// fetch key data 
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; 

NSUInteger dataLength = [self length]; 

//See the doc: For block ciphers, the output size will always be less than or 
//equal to the input size plus the size of one block. 
//That's why we need to add the size of one block here 
size_t bufferSize = dataLength + kCCBlockSizeAES128; 
void *buffer = malloc(bufferSize); 

size_t numBytesEncrypted = 0; 
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
      keyPtr, kCCKeySizeAES128, 
      NULL /* initialization vector (optional) */, 
      [self bytes], dataLength, /* input */ 
      buffer, bufferSize, /* output */ 
      &numBytesEncrypted); 
if (cryptStatus == kCCSuccess) { 
    //the returned NSData takes ownership of the buffer and will free it on deallocation 
    return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; 
} 

free(buffer); //free the buffer; 
return nil; 
} 

E il codice di crittografia Java è ...

public byte[] encryptData(byte[] data, String key) { 
    byte[] encrypted = null; 

    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 
    byte[] keyBytes = key.getBytes(); 

    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); 

    try { 
     Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 
     cipher.init(Cipher.ENCRYPT_MODE, keySpec); 

     encrypted = new byte[cipher.getOutputSize(data.length)]; 
     int ctLength = cipher.update(data, 0, data.length, encrypted, 0); 
     ctLength += cipher.doFinal(encrypted, ctLength); 
    } catch (Exception e) { 
     logger.log(Level.SEVERE, e.getMessage()); 
    } finally { 
     return encrypted; 
    } 
} 

L'uscita esadecimale del codice Objective-C è -

7a68ea36 8288c73d f7c45d8d 22432577 9693920a 4fae38b2 2e4bdcef 9aeb8afe 69394f3e 1eb62fa7 74da2b5c 8d7b3c89 a295d306 f1f90349 6899ac34 63a6efa0 

e l'uscita è java -

7a68ea36 8288c73d f7c45d8d 22432577 e66b32f9 772b6679 d7c0cb69 037b8740 883f8211 748229f4 723984beb 50b5aea1 f17594c9 fad2d05e e0926805 572156d 

Come potete vedere, tutto va bene fino a -

7a68ea36 8288c73d f7c45d8d 22432577 

Sono indovinando ho alcune delle impostazioni diverse, ma non si può capire che cosa, ho provato a cambiare tra la BCE e CBC sul lato Java e non ha avuto alcun effetto.

Qualcuno può aiutare !? per favore ....

+0

Ragazzi mi avete salvato da un incubo autosufficiente ... Grazie! – Shade

risposta

18

Dato che CCCrypt accetta un IV, non utilizza un metodo di cifratura a blocchi di concatenamento (come CBC)? Ciò sarebbe coerente con ciò che si vede: il primo blocco è identico, ma nel secondo blocco la versione Java applica la chiave originale per crittografare, ma la versione OSX sembra utilizzare qualcos'altro.

EDIT:

Da here ho visto un esempio. Sembra che è necessario passare la kCCOptionECBMode a CCCrypt:

ccStatus = CCCrypt(encryptOrDecrypt, 
     kCCAlgorithm3DES, 
     kCCOptionECBMode, <-- this could help 
     vkey, //"123456789", //key 
     kCCKeySize3DES, 
     nil, //"init Vec", //iv, 
     vplainText, //"Your Name", //plainText, 
     plainTextBufferSize, 
     (void *)bufferPtr, 
     bufferPtrSize, 
     &movedBytes); 

EDIT 2:

Ho suonato in giro con qualche riga di comando per vedere quale era giusto. Pensavo di poter contribuire esso:

$ echo "Now then and what is this nonsense all about. Do you know?" | openssl enc -aes-128-ecb -K $(echo 123456789| xxd -p) -iv 0 | xxd 
0000000: 7a68 ea36 8288 c73d f7c4 5d8d 2243 2577 zh.6...=..]."C%w 
0000010: e66b 32f9 772b 6679 d7c0 cb69 037b 8740 .k2.w+fy...i.{[email protected] 
0000020: 883f 8211 7482 29f4 7239 84be b50b 5aea .?..t.).r9....Z. 
0000030: eaa7 519b 65e8 fa26 a1bb de52 083b 478f ..Q.e..&...R.;G. 
+0

Stavo pensando questo, ma ho cambiato il codice Java al seguente ... Cipher.getInstance ("AES/CBC/PKCS7Padding", "BC"); ... ma non ha fatto differenza. A meno che non debba cambiare qualcos'altro per far sì che il codice Java usi CBC? –

+1

Assolutamente perfetto! Grazie mille. Posso smettere di sbattere la testa contro il muro ora :) Ancora un saluto. –

+0

Nessun problema, felice di essere di aiuto. Ho giocato con openssl cercando di capire se Java o Mac fossero rithg. Ho aggiunto la riga di comando di openssl che ho usato per generare il codice. Spero possa essere utile. –

9

Per chiunque altro che ha bisogno di questo, disown è stato assolutamente perfetto ... la chiamata rivisto per creare la cripta in Objective-C è il seguente (si noti il ​​necessario la modalità BCE e l'imbottitura) ...

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode + kCCOptionPKCS7Padding, 
              keyPtr, kCCKeySizeAES128, 
              NULL /* initialization vector (optional) */, 
              [self bytes], dataLength, /* input */ 
              buffer, bufferSize, /* output */ 
              &numBytesEncrypted); 
+0

Per sicurezza, la modalità CBC è considerata di gran lunga superiore alla BCE. L'ECB perde informazioni su quali blocchi di input sono identici tra loro e tali blocchi identici si verificano abbastanza spesso in "dati normali". La CBC può essere vista come una sorta di randomizzazione dei dati, il che rende molto meno probabile l'occorrenza di tali blocchi. –

+0

Grazie! Avrei passato un'intera giornata a cercare di capirlo. – ebi

+0

Questo ha aiutato !! La risposta accettata genererà un errore come "più parametri nella chiamata al metodo". Questa dovrebbe essere la risposta. – abhi1992

11

ho trascorso un paio di settimane decifrare un base64 codificata, AES256 stringa crittografata. La crittografia è stata eseguita da CCCrypt (Objective-C) su un iPad. La decodifica doveva essere fatta in Java (usando il castello gonfiabile).

Alla fine sono riuscito e ho imparato molto nel processo. Il codice di crittografia era esattamente lo stesso di sopra (immagino sia preso dall'esempio Objective-C nella documentazione per gli sviluppatori di iPhone).

Che documentazione CCCrypt() NON menziona è che utilizza la modalità CBC per impostazione predefinita (se non si specifica un'opzione come kCCOptionECBMode). Fa notare che l'IV, se non specificato, imposta tutti gli zeri su default (quindi IV sarà una matrice di byte di 0x00, 16 membri di lunghezza).

Utilizzando queste due informazioni, è possibile creare un modulo di crittografia funzionalmente identico tramite CBC (ed evitare l'uso di ECB meno sicuro) su Java e OSx/iphone/ipad (CCCrypt).

La Cipher funzione init prenderà la matrice IV di byte come terzo argomento:

cipher.init(Cipher.ENCRYPT_MODE, keySpec, IV). 
+0

Grazie per questo, mi hai salvato la giornata. – Esko

+0

La documentazione CCCrypt parla di utilizzare CBC per impostazione predefinita, almeno sono sicuro di averlo visto da qualche parte. Quello che ho fatto * non * vedere ovunque era una menzione di default della IV. Quello era l'ingrediente mancante - grazie! – David

+0

Per chiunque altro stia leggendo questo ... non puoi più passare la IV a 'Cipher.init()'. Quello che devi fare è (1) ottenere un oggetto 'AlgorithmParameters' (usando il metodo factory di classe' getInstance() ', (2) memorizzare l'IV nell'oggetto parameter:' params.init (new IvParameterSpec (iv)) ; 'e (3) passano l'oggetto' params' come terzo argomento a 'cipher.init()'. – David

2

solo per aggiungere al primo post: nel codice C obiettivo/cacao è stato utilizzato in modalità CBC e nel codice Java hai usato EBC e un vettore di inizializzazione IV non è stato utilizzato in entrambi. Il codice EBC è blocco per blocco e le catene CBC sul blocco precedente, quindi se il testo è inferiore a 1 blocco (= 16 byte nell'esempio), il testo cifrato prodotto da entrambi è decifrabile dall'altro (lo stesso).

Se stai cercando un modo per standardizzare l'utilizzo dei cifrari, NIST Special Publication 800-38A, 2001 Edition dispone di vettori di test. Posso inserire il codice per i vettori ABC CBC ed EBC se è utile a chiunque.

Problemi correlati