2009-02-11 10 views
21

Ho bisogno di crittografare una stringa sull'iPhone e inviarla a un servizio web .Net per la decrittografia. Sono in grado di crittografare/decifrare su iPhone e con. Net, ma le stringhe crittografate da iPhone non possono essere decodificate da .Net. L'errore che ricevo è "Il riempimento non è valido e non può essere rimosso."interoperabilità AES tra .Net e iPhone?

Il codice .Net è da: http://blog.realcoderscoding.com/index.php/2008/07/dot-net-encryption-simple-aes-wrapper/

Il codice iPhone utilizza il codice di esempio da: http://nootech.wordpress.com/2009/01/17/symmetric-encryption-with-the-iphone-sdk/

per quanto ne so le mie impostazioni sono identici:

result.BlockSize = 128; // iPhone: kCCBlockSizeAES128 
result.KeySize = 128; // kCCBlockSizeAES128 
result.Mode = CipherMode.CBC; 
result.Padding = PaddingMode.PKCS7; // kCCOptionPKCS7Padding 

ho provato diversi modi di generare testo cifrato. ciao/ciao è:

e0PnmbTg/3cT3W + 92CDw1Q == in Net

yrKe5Z7p7MNqx9 + CbBvNqQ == su iPhone

e "openssl enc -AES-128-CBC -nosalt -a -in hello.txt -passpass: ciao "genera: QA + Ul + r6Zmr7yHipMcHSbQ ==

Aggiornamento: I've posted the working code for this here.

+0

Ho anche provato openSSL e non ha funzionato neanche: openssl enc -d -AES -128-cbc -a -in crypt.txt -pass pass: ciao –

+0

Se si passa l'argomento -nosalt a openssl, si ottiene una codifica base64 di dimensioni simili. Sembrerebbe che. Net e iPhone non stiano usando un esplicito Vettore di inizializzazione (sale). Ma anche allora, openssl non può decodificare neanche. Immagino che ogni biblioteca abbia il suo sale predeterminato? – johnny

+0

ehi capo, so che questa è una vecchia domanda, ma ho problemi nel tentativo di implementare il codice che hai caricato perché penso di avere un modo diverso di implementare la crittografia aes, io uso un IV con una lunghezza di 16. Dato che sono nuovo con obiettivi, non sono sicuro di dove si stia stabilendo questa lunghezza. – gdubs

risposta

16

Per lo meno, si sta utilizzando differenti vettori di inizializzazione (IV).

  • Il codice .Net utilizza la chiave per IV.

    private static AesCryptoServiceProvider GetProvider(byte[] key) 
    { 
        //Set up the encryption objects 
        AesCryptoServiceProvider result = new AesCryptoServiceProvider(); 
        byte[] RealKey = Encryptor.GetKey(key, result); 
        result.Key = RealKey; 
        result.IV = RealKey; 
        return result; 
    }

    e

    private static byte[] GetKey(byte[] suggestedKey, AesCryptoServiceProvider p) 
    { 
        byte[] kRaw = suggestedKey; 
        List kList = new List(); 
        for (int i = 0; i < p.LegalKeySizes[0].MinSize; i += 8) 
        { 
         kList.Add(kRaw[i % kRaw.Length]); 
        } 
        byte[] k = kList.ToArray(); 
        return k; 
    }

    che dovrebbe probabilmente essere: kList.Add(kRaw[(i/8) % kRaw.Length]);. Altrimenti una chiave la cui lunghezza% 8 == 0 utilizzerà ripetutamente la stessa lettera, doh!

    Così IV (e chiave) utilizzato da Net è: hleolhleolhleolh. Questo non fa parte dell'API, ma piuttosto a causa del codice wrapper che hai indicato (che ha un bug grave in esso ...).

  • Il codice iPhone utilizza 0 per il IV.

    // Initialization vector; dummy in this case 0's. 
    uint8_t iv[kChosenCipherBlockSize]; 
    memset((void *) iv, 0x0, (size_t) sizeof(iv));
  • openssl predefinita antepone un sale generato casualmente (che è il motivo per cui l'uscita è più lungo!).

L'uscita openssl è più sicuro poiché è anteporre un vettore di inizializzazione casuale. Sembra che i primi pochi byte della stringa decodificata in base64 siano "Salted__". Puoi anche chiedere a openssl di non usare un sale (-nosalt) e/o di fornire un IV (-iv).

In sostanza, OpenSSL, .Net, e l'iPhone stanno utilizzando la stessa codifica, basta fare attenzione a come si inizializza le API con la chiave di crittografia e il vettore di inizializzazione.

+0

Grazie! Una volta modificato il .Net per usare la chiave corretta e gli 0 per la IV, l'uscita è la stessa. Che cosa dovrebbe essere il IV? Lo 0 è OK? Sarebbe più sicuro se usassi qualcos'altro? –

+0

IV = 0 è OK solo se si utilizza ciascun tasto una sola volta. Altrimenti dovresti usare un IV mutante (un contatore, un nonce o un IV completamente casuale). Uno dei rischi con l'utilizzo di un IV statico è che lo stesso testo in chiaro genererà lo stesso testo crittografato ogni volta, il che si apre per molti attacchi. –

+0

Normalmente si utilizzerà un algoritmo di hash sicuro per derivare la chiave e l'IV dalla password e un sale casuale. Ad esempio, vedi RFC 2898, che credo utilizzi HMACSHA1. – Cheeso

2

Sei sicuro di utilizzare lo stesso tasto AES nei test? L'esempio OpenSSL nel tuo post usa una password che OpenSSL ricava una chiave e una IV da (e probabilmente usa anche un salt.

generare un caso chiave a 128 bit e specificare questa chiave in formato esadecimale per OpenSSL con:

openssl enc -aes-128-cbc -a -in hello.txt -K KEY_IN_HEX -iv 0 

Non si deve usare IV = 0 in ogni sistema sicuro, ma per i test di interoperabilità è ok.

+0

funziona per decodificare l'esempio di iPhone usando openssl. chiave = 68656c6c6f (ciao). – johnny

+0

L'utilizzo di "ciao" come chiave fornisce solo 40 bit, quindi le diverse implementazioni AES utilizzeranno un metodo per aumentare questo a 128 bit. Probabilmente non usano lo stesso metodo per questo ... Prova a specificare una chiave raw a 128 bit (16 caratteri). –

+0

Infine. Ha funzionato come un fascino. Grazie mille. – reinaldoluckman

2

in C#

void test(){ 
    string ctB64 = encrypt("hola"); 
    Console.WriteLine(ctB64); // the same as in objective-c 
} 

string encrypt(string input) 
     { 
      try 
      { 
       // Create a new instance of the AesManaged class. This generates a new key and initialization vector (IV). 
       AesManaged myAes = new AesManaged(); 

       // Override the cipher mode, key and IV 
       myAes.Mode = CipherMode.CBC; 
       myAes.IV = new byte[16] { 0x10, 0x16, 0x1F, 0xAD, 0x10, 0x10, 0xAA, 0x22, 0x12, 0x51, 0xF1, 0x1E, 0x15, 0x11, 0x1B, 0x10 }; // must be the same as in objective-c 
       myAes.Key = Encoding.UTF8.GetBytes(“”); 
       //CipherKey; // Byte array representing the key 
       myAes.Padding = PaddingMode.PKCS7; 

       // Create a encryption object to perform the stream transform. 
       ICryptoTransform encryptor = myAes.CreateEncryptor(); 

       // perform the encryption as required... 
       MemoryStream ms = new MemoryStream(); 
       CryptoStream ct = new CryptoStream(ms, encryptor, CryptoStreamMode.Write); 
       byte[] binput = Encoding.UTF8.GetBytes(input); 
       ct.Write(binput, 0, binput.Length); 
       ct.Close(); 
       byte [] result = ms.ToArray(); 
       return Convert.ToBase64String(result); 
      } 
      catch (Exception ex) 
      { 
       // TODO: Log the error 
       Console.WriteLine(ex); 
       throw ex; 
      } 

     } 

· In Objective-C, aggiungere biblioteca CocoaSecurity da https://github.com/kelp404/CocoaSecurity

#import "CocoaSecurity.h" 
#import "Base64.h" 

… 

- (void) test{ 
unsigned char bytes[] = { 0x10, 0x16, 0x1F, 0xAD, 0x10, 0x10, 0xAA, 0x22, 0x12, 0x51, 0xF1, 0x1E, 0x15, 0x11, 0x1B, 0x10 }; // must be the same as in c# 

    NSData *iv = [NSData dataWithBytesNoCopy:bytes length:16 freeWhenDone:YES]; 
    NSData* key = [@"" dataUsingEncoding:NSUTF8StringEncoding]; 

    CocoaSecurityResult *result = [CocoaSecurity aesEncrypt:@"hola" key:key iv:iv]; 
    NSLog(@"%@", result.base64); // the same as in c# 


    NSData *data = [NSData dataWithBase64EncodedString:result.base64]; 
    CocoaSecurityResult *result2 = [CocoaSecurity aesDecryptWithData:data key:key iv:iv]; 

    NSLog(@"%@", result2.utf8String); // show "hola" 

}