A descodificação do CCCrypt no AES CBC funciona mesmo sem IV

Eu tenho um problema confuso, onde a descodificação de um ficheiro que foi encriptado usando o modo AES-CBC do CCCrypt com um aleatório, 16byte IV produz exactamente o mesmo resultado, quer eu passe no mesmo IV correcto usado para encriptação ou nenhum.

o que eu espero: usar um IV nulo para descodificar não deve resultar numa descodificação correcta. O que eu observo: usar um IV nulo resulta no mesmo resultado que o IV usado para criptografia.

Abaixo, por uma questão de Completude, aqui está o excertos de código importantes, iv é passado como NSData de 16 bytes aleatorizados de forma segura.

O que não estou a entender? O CCCrypt está a descobrir a IV a partir dos dados encriptados? Não encontrei nada perto disso nos médicos.

- (NSData *)encryptedDataForData:(NSData *)rawData
                         withKey:(NSData *)key
                              iv:(NSData *)iv
                           error:(NSError __autoreleasing**)error
{
    size_t outLength;
    NSMutableData *cipherData = [NSMutableData dataWithLength:rawData.length + kAlgorithmBlockSize];

    CCCryptorStatus result = CCCrypt(kCCEncrypt,
                                     kCCAlgorithmAES128,
                                     kCCOptionPKCS7Padding | kCCModeCBC,
                                     key.bytes,
                                     key.length,
                                     iv.bytes,
                                     rawData.bytes,
                                     rawData.length,
                                     cipherData.mutableBytes,
                                     cipherData.length,
                                     &outLength);
    if (result == kCCSuccess) {
        cipherData.length = outLength;
        return cipherData;
    } else {
        return nil;
    }
}

- (NSData *)decryptedDataForData:(NSData *)encryptedData withKey:(NSData *)key error:(NSError __autoreleasing**)error
{
    size_t outLength;
    NSMutableData *decryptedData = [NSMutableData dataWithLength:encryptedData.length];

    // this line is just to illustrate how setting the exact same iv here - if this one
    // was used for encryption - results in same output as when passing iv = NULL
    NSData *iv = [Cryptor dataForHex:@"724a7fc0 0d8ac9d5 f09ff4c1 64d2d1bb"];

    CCCryptorStatus result = CCCrypt(kCCDecrypt,
                                     kCCAlgorithmAES128,
                                     kCCOptionPKCS7Padding | kCCModeCBC,
                                     key.bytes,
                                     key.length,
                                     iv.bytes, // iv OR NULL --> same result o_O
                                     encryptedData.bytes,
                                     encryptedData.length,
                                     decryptedData.mutableBytes,
                                     decryptedData.length,
                                     &outLength);
    if (result == kCCSuccess) {
        decryptedData.length = outLength;
        return decryptedData;
    } else {
        return nil;
    }
}

editar:

para elaborar sobre isso, não importa qual IV eu uso para decriptação (experimentei um par de IV diferentes randomizados) eu sempre recebo byte para byte os resultados idênticos. Mesmo quando descriptografo apenas alguns parte do ficheiro encriptado algures no meio do ficheiro encriptado.

isto está relacionado com os dados reais que estou a decifrar (ficheiros mp3)?

Quando passo um pedaço arbitrário do ficheiro encriptado para o descodificador, não deveria ser necessário o bloco antes desse conjunto de dados (que não forneço explicitamente como o IV) para fazer a descodificação adequada? A única explicação que eu poderia pensar aqui pessoalmente é que CCCrypt sempre usa o os primeiros 16-bytes como o IV e não descriptografa esses, mas deixa-os cair na saída.

Editar 2:

Saída De en/ decryption, mostrando os dois primeiros blocos de dados de entrada e saída, a chave e o iv:

# encryption
data <4cd9b050 30c04bf9 2a0cb024 19010a31 400c2261 0069196a d77bcae6 9799ae26>
iv <724a7fc0 0d8ac9d5 f09ff4c1 64d2d1bb>
key <78656a1a 337fddd6 fa52e34d 9156d187>
encrypted <cf85cdbe 10a87309 a6fb4c4e ce640619 8f445b70 3738018a e78291a7 b4ea26ce>

# decryption with correct IV
data <cf85cdbe 10a87309 a6fb4c4e ce640619 8f445b70 3738018a e78291a7 b4ea26ce>
iv <724a7fc0 0d8ac9d5 f09ff4c1 64d2d1bb>
key <78656a1a 337fddd6 fa52e34d 9156d187>
decrypted <4cd9b050 30c04bf9 2a0cb024 19010a31 400c2261 0069196a d77bcae6 9799ae26>

# decryption with zero IV
data <cf85cdbe 10a87309 a6fb4c4e ce640619 8f445b70 3738018a e78291a7 b4ea26ce>
iv <00000000 00000000 00000000 00000000>
key <78656a1a 337fddd6 fa52e34d 9156d187>
decrypted <4cd9b050 30c04bf9 2a0cb024 19010a31 400c2261 0069196a d77bcae6 9799ae26>

# decryption with different IV
data <cf85cdbe 10a87309 a6fb4c4e ce640619 8f445b70 3738018a e78291a7 b4ea26ce>
iv <12345678 9abcdef1 23456789 abcdef12>
key <78656a1a 337fddd6 fa52e34d 9156d187>
decrypted <4cd9b050 30c04bf9 2a0cb024 19010a31 400c2261 0069196a d77bcae6 9799ae26>

editar 3:

o código para -dataForHex: é:

+ (NSData *)dataForHex:(NSString *)hex
{
    NSString *hexNoSpaces = [[[hex stringByReplacingOccurrencesOfString:@" " withString:@""]
            stringByReplacingOccurrencesOfString:@"<" withString:@""]
            stringByReplacingOccurrencesOfString:@">" withString:@""];

    NSMutableData *data = [[NSMutableData alloc] init];
    unsigned char whole_byte = 0;
    char byte_chars[3] = {'\0','\0','\0'};
    for (NSUInteger i = 0; i < [hexNoSpaces length] / 2; i++) {
        byte_chars[0] = (unsigned char) [hexNoSpaces characterAtIndex:(NSUInteger) (i * 2)];
        byte_chars[1] = (unsigned char) [hexNoSpaces characterAtIndex:(NSUInteger) (i * 2 + 1)];
        whole_byte = (unsigned char)strtol(byte_chars, NULL, 16);
        [data appendBytes:&whole_byte length:1];
    }
    return data;
}
Author: Dennis, 2014-11-19

4 answers

Usado para Comentário de formatação.

Com iv:

clear data:   <4cd9b050 30c04bf9 2a0cb024 19010a31>
iv data:      <724a7fc0 0d8ac9d5 f09ff4c1 64d2d1bb>
key data:     <78656a1a 337fddd6 fa52e34d 9156d187>
crypt data:   <d2c2efee 54e43781 549eec03 9db688e1 7c4248e7 e2ac1d80 7105ffae 4043ffb3>
decrypt data: <4cd9b050 30c04bf9 2a0cb024 19010a31>

Com iv de 0:

clear data:   <4cd9b050 30c04bf9 2a0cb024 19010a31>
iv data:      <00000000 00000000 00000000 00000000>
key data:     <78656a1a 337fddd6 fa52e34d 9156d187>
crypt data:   <cf85cdbe 10a87309 a6fb4c4e ce640619 6be7b155 9db3f066 97e461e7 ced7960f>
decrypt data: <4cd9b050 30c04bf9 2a0cb024 19010a31>

É evidente que o iv não está a ser utilizado no código de operação.

Código acima:

CCCryptorStatus ccStatus   = kCCSuccess;
size_t          cryptBytes = 0;
NSMutableData  *dataOut    = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];

ccStatus = CCCrypt( encryptOrDecrypt, // kCCEncrypt or kCCDecrypt
                   kCCAlgorithmAES128,
                   kCCOptionPKCS7Padding,
                   key.bytes, 
                   kCCKeySizeAES128,
                   iv.bytes,
                   dataIn.bytes,
                   dataIn.length,
                   dataOut.mutableBytes,
                   dataOut.length,
                   &cryptBytes);

dataOut.length = cryptBytes;
 5
Author: zaph, 2014-11-20 12:28:05
Também vale a pena salientar que nunca se deve incluir o modo com as opções de enchimento. Eu vi isso por aí um pouco, e eu realmente caí na mesma armadilha tentando ser um "explícito quanto possível".
kCCOptionPKCS7Padding | kCCModeCBC

Deve ser:

kCCOptionPKCS7Padding

Fun fact 1: ambos kCCModeEBC e kCCOptionPKCS7Padding partilham o mesmo valor: 1, e na verdade avaliariam ao usar kCCOptionPKCS7Padding, o que por omissão seria kCCModeCBC.

Facto Engraçado 2: usar kCCOptionPKCS7Padding | kCCModeCBC avalia a ambos kCCOptionPKCS7Padding marca e kCCOptionECBMode, o que resulta na utilização de kCCModeEBC.

 5
Author: ocgully, 2015-03-05 22:30:01

O iv só é usado para o primeiro bloco na descodificação, outros blocos usam o texto cifrado do bloco anterior, por isso é um pouco auto-sincronizado.

Imagem da Wikipédia: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation

Do Wikipedia Modo de cifra em bloco da operação .

Então, apanhar a descodificação no meio de uma transmissão cifrada num bloco de fronteira funciona, excepto no primeiro bloco.
 3
Author: zaph, 2014-11-19 14:34:12
Pode ler a resposta correcta aqui.: http://www.remote-exploit.org/archives/2012/01/09/the_apple_idioten_vektor_iv/

A Apple cometeu um erro na sua biblioteca de cifra que assume que se o vetor IV não for fornecido, eles automaticamente configuram o IV como um vetor zero em vez de retornar um erro. Um IV deve ser sempre fornecido para garantir a melhor segurança e a Apple não deve estar a fazer a sua suposição zero, uma vez que enfraquece muito a segurança e torna-a vulnerável a ataque.

 0
Author: USTD, 2016-03-22 14:22:19