AES interoperabilità tra .Net e iPhone?
-
22-08-2019 - |
Domanda
Ho bisogno di cifrare una stringa su iPhone e inviarlo a un servizio Web Net per la decrittazione. Sono in grado di cifrare / decifrare su iPhone e con .Net, ma le stringhe criptate da iPhone non possono essere decifrati da .Net. L'errore che ottengo è "imbottitura non è valido e non può essere rimosso."
Il codice .Net è da: http: //blog.realcoderscoding. com / index.php / 2008/07 / dot-net-crittografia-semplici-AES-wrapper /
Il codice di iPhone utilizza il codice di esempio da: http://nootech.wordpress.com/2009/01/17/symmetric-encryption-with-the-iphone-sdk/
Per quanto ne sappia 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 "ENC -AES-128-CBC openssl -nosalt -a -in ciao.txt -pass passare: ciao" genera: QA + Ul + r6Zmr7yHipMcHSbQ ==
Aggiornamento: ho postato il codice di lavoro per questo qui .
Soluzione
Per lo meno, si sta utilizzando differenti vettori di inizializzazione (IV).
-
Il codice .NET utilizza la chiave per la 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]);
. In caso contrario, una chiave la cui lunghezza% 8 == 0 utilizzerà la stessa lettera più volte, doh!Così il IV (e la chiave) utilizzato da NET è:
hleolhleolhleolh
. Questo non fa parte delle API, ma piuttosto a causa del codice wrapper che si indicò (che ha un grave bug in esso ...). -
Il codice di 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 byte del base64 decodificati stringa è "Salted__". Si può anche chiedere OpenSSL non utilizzare un sale (-nosalt) e / o 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.
Altri suggerimenti
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(“0123456789123456”);
//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, aggiungi 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 = [@"0123456789123456" 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"
}
Sei sicuro che si sta utilizzando la stessa chiave AES nei test? L'esempio OpenSSL nel tuo post utilizza una password che OpenSSL deriva una chiave e un IV da (e probabilmente utilizza un sale pure.
Generare una chiave a 128 bit casuali 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.