Diferencia entre PKCS1-padding / encryption RSA ios objc y java

Estoy desarrollando una aplicación para ios y Android. Soy relativamente nuevo en tareas criptográficas y durante los últimos 3 días sigo golpeando la panetworking porque no puedo hacer que se ejecute el encryption RSA.

Ambos clientes reciben una key pública de un server java. En Android tengo (obviamente, porque es casi el mismo código que en el lado del server) no hay problemas, pero la parte ios parece no ser compatible en absoluto. Quiero encriptar un pedacito de datos (key AES) con la key pública y así es como hago esto en Java:

try { String publickey = "MCwwDQYJKoZIhvcNAQEBBQADGwAwGAIRAK+dBpbOKw+1VKMWoFxjU6UCAwEAAQ=="; byte[] bArr = Crypto.base64Decode(publicKey, false); KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC"); EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKey); PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC"); cipher.init(1,publicKey); int cipherBlockSize = cipher.getBlockSize(); ByteArrayOutputStream bArrOut = new ByteArrayOutputStream(); bArrOut.flush(); int pos = 0; Log.i("ContentBufferLength", contentBuffer.length+""); while (true) { if (cipherBlockSize > contentBuffer.length - pos) { cipherBlockSize = contentBuffer.length - pos; } Log.i("CipherBlockSize", cipherBlockSize+""); byte[] tmp = cipher.doFinal(contentBuffer, pos, cipherBlockSize); bArrOut.write(tmp); pos += cipherBlockSize; if (contentBuffer.length <= pos) { break; } } bArrOut.flush(); encryptedBuffer = bArrOut.toByteArray(); bArrOut.close(); } catch (Exception ex) { throw ex; } // Log.i("Encrypted Buffer Length", encryptedBuffer.length+""); return encryptedBuffer; 

Y este es mi código ios (no funciona correctamente), tomado de aquí:

http://blog.wingsofhermes.org/?p=75 y los ejercicios de apple crypto.

 -(NSString* )encryptWithPublicKey:(NSString*)key input:(NSString*) input { const size_t BUFFER_SIZE = 16; const size_t CIPHER_BUFFER_SIZE = 16; //const uint32_t PADDING = kSecPaddingNone; const uint32_t PADDING = kSecPaddingPKCS1; static const UInt8 publicKeyIdentifier[] = "de.irgendwas.app"; NSData *publicTag; publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)]; NSMutableDictionary *publicKey2 = [[NSMutableDictionary alloc] init]; [publicKey2 setObject:kSecClassKey forKey:kSecClass]; [publicKey2 setObject:kSecAttrKeyTypeRSA forKey:kSecAttrKeyType]; [publicKey2 setObject:publicTag forKey:kSecAttrApplicationTag]; SecItemDelete((CFDictionaryRef)publicKey2); NSData *strippedPublicKeyData = [NSData dataFromBase64String:key]; unsigned char * bytes = (unsigned char *)[strippedPublicKeyData bytes]; size_t bytesLen = [strippedPublicKeyData length]; size_t i = 0; if (bytes[i++] != 0x30) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; /* Skip size bytes */ if (bytes[i] > 0x80) i += bytes[i] - 0x80 + 1; else i++; if (i >= bytesLen) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; if (bytes[i] != 0x30) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; /* Skip OID */ i += 15; if (i >= bytesLen - 2) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; if (bytes[i++] != 0x03) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; /* Skip length and null */ if (bytes[i] > 0x80) i += bytes[i] - 0x80 + 1; else i++; if (i >= bytesLen) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; if (bytes[i++] != 0x00) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; if (i >= bytesLen) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; strippedPublicKeyData = [NSData dataWithBytes:&bytes[i] length:bytesLen - i]; DLog(@"X.509 Formatted Public Key bytes:\n%@",[strippedPublicKeyData description]); if (strippedPublicKeyData == nil) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; CFTypeRef persistKey = nil; [publicKey2 setObject:strippedPublicKeyData forKey:kSecValueData]; [publicKey2 setObject: (kSecAttrKeyClassPublic) forKey:kSecAttrKeyClass]; [publicKey2 setObject:[NSNumber numberWithBool:YES] forKey:kSecReturnPersistentRef]; OSStatus secStatus = SecItemAdd((CFDictionaryRef)publicKey2, &persistKey); if (persistKey != nil) CFRelease(persistKey); if ((secStatus != noErr) && (secStatus != errSecDuplicateItem)) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; SecKeyRef keyRef = nil; [publicKey2 removeObjectForKey:kSecValueData]; [publicKey2 removeObjectForKey:kSecReturnPersistentRef]; [publicKey2 setObject:[NSNumber numberWithBool:YES] forKey:kSecReturnRef]; [publicKey2 setObject: kSecAttrKeyTypeRSA forKey:kSecAttrKeyType]; SecItemCopyMatching((CFDictionaryRef)publicKey2,(CFTypeRef *)&keyRef); if (!keyRef) [Exception raise:FAILURE function:__PRETTY_FUNCTION__ line:__LINE__ description:@"Could not set public key."]; uint8_t *plainBuffer; uint8_t *cipherBuffer; uint8_t *decryptedBuffer; const char inputString[] = "1234"; int len = strlen(inputString); // TODO: this is a hack since i know inputString length will be less than BUFFER_SIZE if (len > BUFFER_SIZE) len = BUFFER_SIZE-1; plainBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t)); cipherBuffer = (uint8_t *)calloc(CIPHER_BUFFER_SIZE, sizeof(uint8_t)); decryptedBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t)); strncpy( (char *)plainBuffer, inputString, len); size_t plainBufferSize = strlen((char *)plainBuffer); size_t cipherBufferSize = CIPHER_BUFFER_SIZE; NSLog(@"SecKeyGetBlockSize() public = %lu", SecKeyGetBlockSize(keyRef)); // Error handling // Encrypt using the public. OSStatus status = noErr; status = SecKeyEncrypt(keyRef, PADDING, plainBuffer, plainBufferSize, &cipherBuffer[0], &cipherBufferSize ); NSLog(@"encryption result code: %ld (size: %lu)", status, cipherBufferSize); return [[[NSString stringWithFormat:@"%s",cipherBuffer] dataUsingEncoding:NSUTF8StringEncoding] base64EncodedString]; } 

Para propósitos de testing y simplicidad por el momento estoy tratando de cifrar solo una input con una longitud de 4 bytes. Esto debería ser lo suficientemente pequeño como para caber en un bloque. La import de key pública y el process de encryption parece funcionar, pero siempre recibo un resultado mucho más largo en comparación con el método Android.

La única diferencia que encontré hasta ahora es el hecho de que SecKeyGetBlockSize returns 16 y en java cipher.blocksize devuelve 5. Creo que los otros 11 bytes están reservados para el relleno de pkcs1, pero ¿cómo forzar el mismo comportamiento en ios/objc ?

Prueba con dividir el text encryption en varias partes para que cada una tenga 16 char y decodifique por separado. Yo también enfrenté el mismo problema, pero eso fue en PHP por mucho time y el truco anterior funcionó para mí.

Esto puede ayudarlo a salir del problema.