Jak Mogę sprawić, by moje szyfrowanie AES było identyczne pomiędzy Javą a Objective - C (iPhone)?

Szyfruję ciąg znaków w objective-c, a także ten sam ciąg w Javie za pomocą AES i widzę dziwne problemy. Pierwsza część wyniku pasuje do pewnego punktu, ale potem jest inaczej, stąd kiedy idę rozszyfrować wynik z Javy na iPhone ' a nie można go odszyfrować.

Używam źródłowego ciągu " teraz wtedy i o co w tym wszystkim chodzi. Wiesz?" Korzystanie z klucza "1234567890123456"

Kod objective-c do zaszyfrowania to following: notatka: jest to kategoria NSData, więc załóżmy, że metoda jest wywołana na obiekcie nsdata, więc 'self' zawiera dane bajtowe do zaszyfrowania.

   - (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;
}

A kod szyfrujący java jest...

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;
    }
}

Wyjście szesnastkowe kodu objective-c to -

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

A wyjście Javy to -

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

Jak widać wszystko jest w porządku do-

7a68ea36 8288c73d f7c45d8d 22432577

Domyślam się, że niektóre ustawienia są inne, ale nie mogę ustalić, co, próbowałem zmienić między EBC i CBC na strony Javy i nie miało to żadnego wpływu.

Czy ktoś może pomóc?? proszę....
Author: Paŭlo Ebermann, 2010-02-17

4 answers

Ponieważ CCCrypt pobiera kroplówkę, czy nie używa metody szyfrowania blokowego (takiej jak CBC)? Byłoby to zgodne z tym, co widzisz: pierwszy blok jest identyczny, ale w drugim bloku wersja Java stosuje oryginalny klucz do szyfrowania, ale wersja OSX wydaje się używać czegoś innego.

EDIT:

Z tutaj zobaczyłem przykład. Wydaje się, że trzeba przekazać kCCOptionECBMode do 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);

EDIT 2:

I played around with some command linia, aby zobaczyć, który z nich miał rację. Myślałem, że mogę się do tego przyczynić:

$ 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.{.@
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.
 18
Author: Alexander Torstling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-17 12:44:36

Spędziłem kilka tygodni odszyfrowując zaszyfrowany ciąg base64, AES256. Szyfrowanie zostało wykonane przez CCCrypt (Objective-C)na iPadzie. Deszyfrowanie miało być wykonane w Javie (za pomocą Bouncy Castle).

W końcu się udało i wiele się w tym procesie nauczyłem. Kod szyfrowania był dokładnie taki sam jak powyżej (myślę, że pochodzi z próbki Objective-C w dokumentacji dewelopera iPhone ' a).

Dokumentacja CCCrypt() nie wspomina o tym, że domyślnie używa trybu CBC (jeśli nie określić opcję jak kccoptionecbmode). Wspomina on, że IV, jeśli nie jest określony, domyślnie ustawia wszystkie zera(więc IV będzie tablicą bajtów o długości 0x00, 16 członów).

Używając tych dwóch informacji, możesz utworzyć funkcjonalnie identyczny moduł szyfrowania za pomocą CBC (i uniknąć używania mniej bezpiecznego ECB) zarówno w Javie,jak i OSx / iphone/ipad (CCCrypt).

Funkcja INIT zaszyfrowana przyjmuje tablicę IV bajtów jako trzeci argument:

cipher.init(Cipher.ENCRYPT_MODE, keySpec, IV).
 11
Author: user357614,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-22 23:01:54

Dla każdego, kto tego potrzebuje, wyrzekanie się było absolutnie na miejscu... zmienione wywołanie do utworzenia krypty w objective-c wygląda następująco (Uwaga, potrzebujesz trybu EBC i padding)...

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode + kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES128,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
 9
Author: Simon Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-17 12:26:45

Żeby dodać do pierwszego posta: w kodzie objective C / cocoa użyłeś trybu CBC, a w kodzie java użyłeś EBC i Wektor inicjalizacji IV też nie był używany. Szyfr EBC jest blok po bloku, a łańcuch CBC po poprzednim bloku, więc jeśli twój tekst jest mniejszy niż 1 blok (=16 bajtów w twoim przykładzie), zaszyfrowany tekst wyprodukowany przez oba są odszyfrowane przez drugi (ten sam).

Jeśli szukasz sposobu na standaryzację użycia szyfrów, specjalna Publikacja NIST 800-38A, wydanie z 2001 roku ma wektory testowe. Mogę wysłać kod do wektorów AES CBC i EBC, jeśli to komuś pomoże.

 2
Author: Nichole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-06 06:40:14