Come posso rendere la mia crittografia AES identica tra Java e Objective-C (iPhone)?

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.

Sto usando una stringa sorgente di “Ora, allora, e cos’è questa assurdità?” Lo sai? ” Utilizzando una chiave di “1234567890123456”

Il codice objective-c per crittografare è il seguente: NOTA: è una categoria NSData, quindi supponiamo che il metodo sia chiamato su un object NSData in modo che ‘self’ contenga i dati del byte da 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’output esadecimale del codice objective-c è –

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

e l’output java è –

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

Come puoi vedere tutto va bene fino a –

 7a68ea36 8288c73d f7c45d8d 22432577 

Sto indovinando che ho alcune delle impostazioni diverse ma non riesco a capire cosa, ho provato a cambiare tra ECB e CBC sul lato Java e non ha avuto alcun effetto.

Qualcuno può aiutare !? per favore….

Dato che CCCrypt accetta un IV, non usa un metodo di cifratura a blocchi concatenati (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.

MODIFICARE:

Da qui ho visto un esempio. Sembra che tu debba passare il kCCOptionECBMode a CCCrypt:

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

MODIFICA 2:

Ho giocato con alcune linee di comando per vedere quale era giusto. Ho pensato di poterlo contribuire:

 $ echo "Now then and what is this nonsense all about. Do you know?" | openssl enc -aes-128-ecb -K $(echo 1234567890123456 | 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 ..Qe.&...R.;G. 

Ho trascorso alcune settimane a decifrare una stringa codificata in base 64, codificata AES256. 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).

La documentazione di CCCrypt () NON menziona che usa 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, è ansible creare un modulo di crittografia funzionalmente identico utilizzando CBC (ed evitare l’uso di ECB meno sicuro) sia su Java che su OSx / iphone / ipad (CCCrypt).

La funzione di inizializzazione del cifratore prenderà l’array di byte IV come terzo argomento:

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

Per chiunque altro abbia bisogno di questo, disown era assolutamente azzeccato … la chiamata rivista per creare la cripta in ogg-c è la seguente (nota che hai bisogno della modalità ECB e del padding) …

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

Solo per aggiungere al primo post: nel tuo codice C / cocoa objective hai usato la modalità CBC e nel tuo codice java hai usato EBC e un vettore di inizializzazione IV non è stato utilizzato in nessuno dei due. 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 il tuo uso dei cifrari, NIST Special Publication 800-38A, 2001 Edition ha vettori di prova. Posso inserire il codice per i vettori ABC CBC ed EBC se è utile a chiunque.