Ho passato due giorni su questo fino ad ora e ho passato in rassegna ogni fonte a mia disposizione, quindi questa è l'ultima risorsa.Problemi di decrittografia in C# qualcosa criptato su iPhone usando RSA
Ho un certificato X509 con chiave pubblica che ho memorizzato nel portachiavi dell'iPhone (solo simulatore a questo punto). Sul lato ASP.NET, ho ottenuto il certificato nel cert store con una chiave privata. Quando crittografo una stringa sull'iPhone e la decrypt sul server, ottengo un "Dati non validi" CryptographicException
. Ho provato il Array.Reverse
suggerito nella pagina RSACryptoServiceProvider
su un longshot, ma non è stato d'aiuto.
Ho confrontato le stringhe 64 base su entrambi i lati e sono uguali. Ho confrontato gli array di byte grezzi dopo la decodifica e anch'essi sono uguali. Se crittografo sul server utilizzando la chiave pubblica, l'array di byte è diverso dalla versione di iPhone e decifra prontamente utilizzando la chiave privata. La stringa in chiaro in chiaro è di 115 caratteri, quindi è compresa nella limitazione a 256 byte della mia chiave a 2048 bit.
Ecco il metodo di crittografia iPhone (più o meno testualmente metodo s' il CryptoExercise sample appwrapSymmetricKey
):
+ (NSData *)encrypt:(NSString *)plainText usingKey:(SecKeyRef)key error:(NSError **)err
{
size_t cipherBufferSize = SecKeyGetBlockSize(key);
uint8_t *cipherBuffer = NULL;
cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
memset((void *)cipherBuffer, 0x0, cipherBufferSize);
NSData *plainTextBytes = [plainText dataUsingEncoding:NSUTF8StringEncoding];
OSStatus status = SecKeyEncrypt(key, kSecPaddingNone,
(const uint8_t *)[plainTextBytes bytes],
[plainTextBytes length], cipherBuffer,
&cipherBufferSize);
if (status == noErr)
{
NSData *encryptedBytes = [[[NSData alloc]
initWithBytes:(const void *)cipherBuffer
length:cipherBufferSize] autorelease];
if (cipherBuffer)
{
free(cipherBuffer);
}
NSLog(@"Encrypted text (%d bytes): %@",
[encryptedBytes length], [encryptedBytes description]);
return encryptedBytes;
}
else
{
*err = [NSError errorWithDomain:@"errorDomain" code:status userInfo:nil];
NSLog(@"encrypt:usingKey: Error: %d", status);
return nil;
}
}
Ed ecco il metodo C# decrittazione lato server:
private string Decrypt(string cipherText)
{
if (clientCert == null)
{
// Get certificate
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach (var certificate in store.Certificates)
{
if (certificate.GetNameInfo(X509NameType.SimpleName, false) == CERT)
{
clientCert = certificate;
break;
}
}
}
using (var rsa = (RSACryptoServiceProvider)clientCert.PrivateKey)
{
try
{
var encryptedBytes = Convert.FromBase64String(cipherText);
var decryptedBytes = rsa.Decrypt(encryptedBytes, false);
var plaintext = Encoding.UTF8.GetString(decryptedBytes);
return plaintext;
}
catch (CryptographicException e)
{
throw(new ApplicationException("Unable to decrypt payload.", e));
}
}
}
Il mio sospetto è che c'erano alcuni problemi di codifica tra le piattaforme.
So che uno è big-endian e l'altro è little-endian ma non so abbastanza da dire quale sia o come superare la differenza.
Mac OS X, Windows e iPhone sono tutti little-endian quindi non è questo il problema.
Nuova teoria: se si imposta il riempimento OAEP booleano su falso, il valore predefinito è PKCS # 1 1.5.
Apparentemente, SecKey
ha solo definizioni
SecPadding
di
PKCS1
,
PKCS1MD2
,
PKCS1MD5
e
PKCS1SHA1
. Forse Microsoft PKCS # 1 1.5! = PKCS1 di Apple e quindi il padding sta influenzando l'output binario della crittografia. Ho provato a utilizzare
kSecPaddingPKCS1
con il
fOAEP
impostato su
false
e ancora non ha funzionato.
kSecPaddingPKCS1
è equivalent a PKCS # 1 1.5. Torna al tavolo da disegno su teorie e hellip;
Altre teorie neo-provato:
- Certificate su iPhone (file CER) non è esattamente la stessa di PKCS # 12 fascio sul server (file .pfx) e quindi potrebbe mai funzionare. File .cer installato in diversi store certificati e stringhe crittografate dal server racchiuse in modo corretto;
- La conversione in base-64 e l'operazione di POSTing sul server ha provocato stranezze non presenti nel roundtrip della stessa classe, quindi prima ho provato alcuni URLEncoding/Decoding e poi ho postato il binario raw da iPhone, verificato che era uguale e ha gli stessi cattivi dati;
- La mia stringa originale era di 125 byte, quindi ho pensato che potesse essere troncata in UTF-8 (long shot), quindi l'ho ritagliata su una stringa di 44 byte senza risultato;
- Si guardava indietro nella libreria System.Cryptography per assicurarsi che stavo usando una classe appropriata e ho scoperto `RSAPKCS1KeyExchangeDeformatter`, si è esaltato nei confronti dei nuovi potenziali clienti e si è abbattuto quando si è comportato esattamente allo stesso modo.
Successo!
Si è scoperto che avevo un cruft nel mio portachiavi sul simulatore di iPhone che stava confondendo le acque, per così dire. Ho cancellato il Keychain DB allo ~/Library/Application Support/iPhone Simulator/User/Library/Keychains/keychain-2-debug.db
per farlo ricreare e ha funzionato bene. Grazie per tutto il vostro aiuto. Immagina che sarebbe stato qualcosa di semplice ma non ovvio. (Due cose che ho imparato: 1) disinstallare l'app dal simulatore non cancella le voci del portachiavi e 2) iniziare assolutamente fresco periodicamente.)
NOTA: il percorso generico per il file portachiavi dipende dalla versione iOS: ~/Libreria/Supporto applicazioni/iPhone Simulator/[versione] /Libreria/Keychains/keychain-2-debug.db ad es., ~/Libreria/Supporto applicazioni/Simulatore iPhone/4.3/Libreria/Portachiavi/portachiavi-2-debug .db
Tempo per una taglia! – bbrown