2017-03-20 13 views
5

Implementacja AES256 na iOS przy użyciu funkcji CCCrypt. Ale długość bufora wyjściowego i wyjściowego różni się od Androida.Szyfrowanie AES w systemie iOS i Android, rozmiar wyjściowy i bufor są różne

Klasa Cipher w systemie Android generuje 48 bajtów danych, gdzie w systemie iOS otrzymujemy 80 bajtów danych.

W systemie IOS za pomocą kCCAlgorithmAES, kCCOptionPKCS7Padding oraz w systemie Android przy użyciu AES/CBC/PKCS5Padding.

w IOS IV jest NULL i na Androidzie tworząc iv jako nową 16-bajtową tablicę.

Proszę o pomoc.

proszę znaleźć dane wejściowe i kod w celach informacyjnych.

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    NSString *message = [NSString stringWithFormat:@"com.myapp.com|355004059196637|911111111111|11341e5e-9643-4559-bbb7-34d40555e96c"]; 
    NSString *key = [NSString stringWithFormat:@"4f28d5901b4b7b80d33fda76ca372c2a20bd1a6c2aad7fa215dc79d507330678"]; 
    NSString *shaEncryptMessage = [self sha256:message length:0]; 
    NSData *aesEncryptData = [self aesEncrypt:[shaEncryptMessage dataUsingEncoding:NSUTF8StringEncoding] key:key iv:nil]; 
    NSString *hMac = [aesEncryptData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; 
    NSLog(@"hMac = %@",hMac); 

    // IOS output : Can+oQR79D3/lsQGctzY/d2VBNZbWWtJxGI8iRIu80R2yTskn9gf2oKHaRESX73u 
    //     LpJHLx1Xr6iH11jFPlmqwW7mQz0xAW4uACNAMEoZ0kY= 
    // Android output : MiMDkdo5cGsPMj2qCnNobgp7dr5KMvBhGuKTonrqr1lCYte/kKegGMtI/4TPhUNI 
} 


- (NSString*) sha256:(NSString *)key length:(NSInteger) length{ 
    const char *s=[key cStringUsingEncoding:NSASCIIStringEncoding]; 
    NSData *keyData=[NSData dataWithBytes:s length:strlen(s)]; 

    uint8_t digest[CC_SHA256_DIGEST_LENGTH]={0}; 
    CC_SHA256(keyData.bytes, (unsigned int)keyData.length, digest); 
    NSData *out=[NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH]; 
    NSString *hash=[out description]; 
    hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""]; 
    hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""]; 
    hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""]; 
    return hash; 
} 
- (NSData *)aesEncrypt:(NSData *)plainText key:(NSString *)key iv:(NSString *)iv { 
    char keyPointer[kCCKeySizeAES256+2],// room for terminator (unused) ref: https://devforums.apple.com/message/876053#876053 
    ivPointer[kCCBlockSizeAES128]; 
    BOOL patchNeeded; 
    bzero(keyPointer, sizeof(keyPointer)); // fill with zeroes for padding 
    //key = [[StringEncryption alloc] md5:key]; 
    key = [self stringFromHex:key]; 
    patchNeeded= ([key length] > kCCKeySizeAES256+1); 
    if(patchNeeded) 
    { 
     key = [key substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256) 
    } 

    [key getCString:keyPointer maxLength:sizeof(keyPointer) encoding:NSUTF8StringEncoding]; 
    [iv getCString:ivPointer maxLength:sizeof(ivPointer) encoding:NSUTF8StringEncoding]; 

    // if (patchNeeded) { 
    //  keyPointer[0] = '\0'; // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256 
    // } 

    NSUInteger dataLength = [plainText length]; 

    // For block ciphers, the output size will always be less than or equal to the input size plus the size of one block. 
    size_t buffSize = dataLength + kCCBlockSizeAES128; 
    void *buff = malloc(buffSize); 

    size_t numBytesEncrypted = 0; 



    CCCryptorStatus status = CCCrypt(kCCEncrypt, /* kCCEncrypt, etc. */ 
            kCCAlgorithmAES128, /* kCCAlgorithmAES128, etc. */ 
            kCCOptionPKCS7Padding, /* kCCOptionPKCS7Padding, etc. */ 
            keyPointer, kCCKeySizeAES256, /* key and its length */ 
            NULL, /* initialization vector - use random IV everytime */ 
            [plainText bytes], [plainText length], /* input */ 
            buff, buffSize,/* data RETURNED here */ 
            &numBytesEncrypted); 


    if (status == kCCSuccess) { 
     return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted]; 
    } 

    free(buff); 
    return nil; 
} 

- (NSString *) stringFromHex:(NSString *)str 
{ 
    NSMutableData *stringData = [[NSMutableData alloc] init]; 
    unsigned char whole_byte; 
    char byte_chars[3] = {'\0','\0','\0'}; 
    int i; 
    for (i=0; i < [str length]/2; i++) { 
     byte_chars[0] = [str characterAtIndex:i*2]; 
     byte_chars[1] = [str characterAtIndex:i*2+1]; 
     whole_byte = strtol(byte_chars, NULL, 16); 
     [stringData appendBytes:&whole_byte length:1]; 
    } 
    return [[NSString alloc] initWithData:stringData encoding:NSASCIIStringEncoding]; 
} 

Proszę znaleźć kod android Również

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    generateHMAC(); 
} 

String K0 = "4f28d5901b4b7b80d33fda76ca372c2a20bd1a6c2aad7fa215dc79d507330678"; 
String generatedString = "com.myapp.com|355004059196637|911111111111|11341e5e-9643-4559-bbb7-34d40555e96c"; 

private void generateHMAC() { 
    Log.d("Message of Hash", generatedString); 
    byte[] var14 = new byte[0]; 
    try { 
     var14 = SHA256(generatedString); 
     byte[] var15 = new byte[0]; 
     var15 = encrypt(var14, hexStringToByteArray(K0)); 
     String var4 = Base64.encodeToString(var15, 2); 
     Log.d("Existing K0", K0); 
     Log.d("HMAC", var4); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 


public byte[] SHA256(String paramString) throws Exception { 
    MessageDigest md = MessageDigest.getInstance("SHA-256"); 
    md.update(paramString.getBytes("UTF-8")); 
    byte[] digest = md.digest(); 
    return digest; 
} 

public byte[] encrypt(byte[] var1, byte[] var2) throws Exception { 
    SecretKeySpec var3 = new SecretKeySpec(var2, "AES"); 
    byte[] var4 = new byte[16]; 
    IvParameterSpec var5 = new IvParameterSpec(var4); 
    Cipher var6 = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    var6.init(1, var3, var5); 
    byte[] var7 = var6.doFinal(var1); 
    return var7; 
} 

public byte[] hexStringToByteArray(String var1) { 
    byte[] var2 = new byte[var1.length()/2]; 

    for (int var3 = 0; var3 < var2.length; ++var3) { 
     int var4 = var3 * 2; 
     int var5 = Integer.parseInt(var1.substring(var4, var4 + 2), 16); 
     var2[var3] = (byte) var5; 
    } 

    return var2; 
} 
+0

pls spróbuj https://github.com/alexeypro/EncryptDecrypt its AES256EncryptWithKey – Rivendell

+0

Czy możesz wpisać kod, proszę? – TheGreatContini

+0

Mimo że to nie odpowiada na twoje pytanie, powinieneś wiedzieć, że chociaż Apple mówi ci, że wektor inicjujący (IV) jest opcjonalny, szyfrowanie nie jest bezpieczne, jeśli nie określisz go i nie wybierzesz IV w nieprzewidywalny sposób. Wstyd na Apple za to słabe API do kryptografii. – TheGreatContini

Odpowiedz

3

Aktualizacje po podałeś kodu iOS:

  • aesEncryptData powinien być wyjście. Pozbądź się hmac, który nie ma nic wspólnego z szyfrowaniem AES (zamiast tego jest integralnością wiadomości).
  • Jedynym sposobem na dopasowanie kodu Androida jest użycie tego samego kodu IV, którego używa kod Androida.

Wcześniej odpowiedź:

Jak długo jest wejście? Dostarczenie kodu źródłowego i przykładowych danych może pomóc nam szybciej rozwiązać problem.

Bez wymaganych informacji, nie mam odpowiedzi, ale mam kilka wskazówek, które mogą pomóc Ci dotrzeć do sedna nim:

  • Twój wyściółka jest w porządku. PKCS5Padding w Javie to wrongly named implementacja PKCS # 7, więc powinna być zgodna z kCCOptionPKCS7Padding firmy Apple.
  • pod maską, jeśli nie określono trybu, więc zgadza się z kodem Androida. Więc to nie może być problemem.
  • Podczas szyfrowania tekst zaszyfrowany będzie wielokrotnością 16 bajtów (ponieważ AES ma rozmiar bloku N = 16 bajtów i według definicji z PKCS #7). W szczególności:
    • Jeśli dane wejściowe są wielokrotnością 16 bajtów, wynik powinien być dokładnie 16 bajtów większy niż dane wejściowe.
    • Jeśli wejście nie jest wielokrotnością 16 bajtów, wyjście powinno mieć wartość 16 * Pułap (długość wejścia/16). Przykład: 47 bajtów powinno mieć 16 * Pułap (17/16) = 16 * 3 = 48 bajtów wyjściowych.
  • Jest możliwe, że jedna z implementacji wyprowadza IV jako część zaszyfrowanego tekstu. Jeśli tak się dzieje, powinien znajdować się na początku szyfrogramu. Powinieneś być w stanie sprawdzić, czy tak się dzieje.(Daj mi znać, jeśli tak się stanie, proszę).

Powiedziawszy to, coś jest dziwne i prawdopodobnie zostało zaimplementowane nieprawidłowo, a my potrzebujemy kodu, aby dotrzeć do sedna. Nie ma sensu, że kod Androida daje 3 bloki 16, podczas gdy kod Apple daje 5 bloków po 16.

Ponadto, tak jak to zauważyłem powyżej, nawet jeśli Apple mówi, że IV jest opcjonalne, to znaczy, że jest opcjonalne, jeśli chodzi o uruchomienie kodu. Jest to not optional for security. IV są wymagane i muszą być nieprzewidywalne w trybie pracy CBC i nigdy nie powinny być powtarzane. Jeśli to zignorujesz, wyciekniesz informacji o swoich danych, aw niektórych sytuacjach osoba atakująca może odszyfrować dane (wyskakujące ataki oracle).

+0

Dzięki @TheGreatContini, dodając kod iOS i przykładowe dane wejściowe w celach informacyjnych. Pomóż to rozwiązać. – Pradip

+0

@Pradip masz HMAC-sha256 po AES, który jest zupełnie innym algorytmem. Wyjmij HMAC, chcesz tylko zaszyfrować i nic więcej. Aby dopasować Androida, musisz użyć tego samego IV, który jest używany w systemie Android. Nie można po prostu zastąpić nil i oczekiwać dopasowania danych, ponieważ nie będzie. – TheGreatContini

+0

Znajdź zaktualizowany kod Androida, SHA256, a następnie AES i ouput, a następnie kodowanie base64 (zgodnie z wymaganiami naszej logiki). Chcę podobnej logiki dla iOS, jak w Androidzie. – Pradip

Powiązane problemy