2012-06-05 15 views
5

Tengo una aplicación que necesita codificar algunos datos usando AES/CBC/sin relleno. La aplicación también está portada en Android. Allí, la codificación se realiza de esta manera:cifrado iOS AES128/CBC/nopadding ¿por qué no funciona?

byte[] encodedKey = getKey(); 
    SecretKeySpec skeySpec = new SecretKeySpec(encodedKey, "AES"); 
    AlgorithmParameterSpec paramSpec = new IvParameterSpec(initializationVector); 

    Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); 
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, paramSpec); 

    int blockSize = cipher.getBlockSize(); 
    int diffSize = decrypted.length % blockSize; 
    System.out.println("Cipher size: " + blockSize); 
    System.out.println("Current size: " + decrypted.length); 
    if (diffSize != 0) { 
     diffSize = blockSize - diffSize; 
     byte[] oldDecrypted = decrypted; 
     decrypted = new byte[decrypted.length + diffSize]; 
     System.arraycopy(oldDecrypted, 0, decrypted, 0, oldDecrypted.length); 
     for (int i = 0; i < diffSize; i++) { 
     decrypted[i + oldDecrypted.length] = " ".getBytes()[0]; 
     } 
     System.out.println("New size: " + decrypted.length); 

    } 
    return cipher.doFinal(decrypted); 

la initializationVector se ve así:

private byte[] initializationVector = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 

en IOS tengo algo como esto para el cifrado:

- (NSData *)AES128EncryptWithKey:(NSString *)key 
{ 
    // 'key' should be 16 bytes for AES128, will be null-padded otherwise 
    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused) 
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) 


    // fetch key data 
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; 

    NSUInteger dataLength = [self length]; 

    //See the doc: For block ciphers, the output size will always be less than or 
    //equal to the input size plus the size of one block. 
    //That's why we need to add the size of one block here 
    size_t bufferSize = dataLength + kCCBlockSizeAES128; 
    void *buffer = malloc(bufferSize); 

    size_t numBytesEncrypted = 0; 
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, 
              kCCAlgorithmAES128, 
              0x0000, 
              keyPtr, 
              kCCKeySizeAES128, 
              NULL /* initialization vector (optional) */, 
              [self bytes], dataLength, /* input */ 
              buffer, bufferSize, /* output */ 
              &numBytesEncrypted); 
    if (cryptStatus == kCCSuccess) { 
     //the returned NSData takes ownership of the buffer and will free it on deallocation 
     return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; 
    } 

    free(buffer); //free the buffer; 
    return nil; 
} 

el método descrito anteriormente es parte de una categoría sobre NSData. el método se llama así:

NSData *data = [@"4915200456727" dataUsingEncoding:NSUTF8StringEncoding]; 
    NSData *cipher = [data AES128EncryptWithKey:@"@x#zddXekZerBBw6"]; 
    NSString *ecriptedString = [NSString stringWithFormat:@"%.*s", [cipher length], [cipher bytes]]; 

el problema que tengo es que no recibo los mismos datos cifrados en iOS y Android. En iOS, los datos cifrados tienen 0 bytes de longitud.

¿Podría dar algún consejo sobre cómo cifrar una cadena utilizando AES128 con CBC y sin relleno y tal vez un ejemplo?

Gracias

Respuesta

7

He encontrado la solución a mi problema. Para hacer que el cifrado funcione sin relleno, tuve que agregar 0x0000 en lugar de kCCOptionPKCS7Padding o kCCOptionECBMode, que son tratados.

Además, si los datos que deben codificarse no tienen una longitud múltiple de kCCKeySizeAES128 (16), entonces el vector que contiene los datos debe redimensionarse para que tenga la longitud múltiple con kCCKeySizeAES128 y los valores vacíos llenos con algo. Agregué espacios.

- (NSData *)AES128EncryptWithKey:(NSString *)key 
{ 
    char keyPtr[kCCKeySizeAES128+1]; 
    bzero(keyPtr, sizeof(keyPtr)); 

    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; 

    int dataLength = [self length]; 
    int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128); 
    int newSize = 0; 

    if(diff > 0) 
    { 
     newSize = dataLength + diff; 
    } 

    char dataPtr[newSize]; 
    memcpy(dataPtr, [self bytes], [self length]); 
    for(int i = 0; i < diff; i++) 
    { 
     dataPtr[i + dataLength] = 0x20; 
    } 

    size_t bufferSize = newSize + kCCBlockSizeAES128; 
    void *buffer = malloc(bufferSize); 

    size_t numBytesEncrypted = 0; 
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, 
              kCCAlgorithmAES128, 
              0x0000, //No padding 
              keyPtr, 
              kCCKeySizeAES128, 
              NULL, 
              dataPtr, 
              sizeof(dataPtr), 
              buffer, 
              bufferSize, 
              &numBytesEncrypted); 

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

    return nil; 
} 
+0

Los esquemas de relleno no existen para nada. Si sus datos simples finalizan con el mismo valor que el byte de relleno, su propio esquema fallará. En su lugar, debe usar el relleno PKCS # 5/PKCS # 7. Dependiendo de su necesidad, también debería tener la protección de integridad agregada (encriptación del modo AESCMAC, HMAC o GCM). –

+0

el problema es que el lado del servidor ya está implementado usando AES128/CBC/sin relleno y no se modificará para aceptar el relleno. Sé que el relleno no existe para nada, pero en este caso la posibilidad de que los datos necesarios para ser encriptados terminará con el byte de relleno es realmente pequeña a 0. –

+2

OK, está bien entonces, pero tenga en cuenta: un millón una oportunidad tiene éxito nueve veces de cada diez (Terry Pratchett). Asegúrese de documentar esta "característica". –

Cuestiones relacionadas