Crypto++, что делать с IV

Поэтому я пытаюсь использовать шифрование из Crypto++ в проекте Objective-C. Проблема в том, что делать с IV? Я пытаюсь предварительно добавить его в зашифрованный текст. Но тогда у меня проблема с восстановлением для расшифровки.

Вот код:

- (NSString *)encryptUsingSerpentWithPlaintext:(NSString *)plaintext andKey:(NSData *)keyData
{
    std::string ptext = [plaintext UTF8String];
    std::string ciphertext;

    byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];

    CryptoPP::AutoSeededX917RNG<CryptoPP::Serpent> rng;
    rng.GenerateBlock(iv, CryptoPP::Serpent::BLOCKSIZE);

    std::string ivs(reinterpret_cast<char const *>(iv));
    lcl_log(lcl_cCrypto, lcl_vDebug, @"Random IV:%s",ivs.c_str());


    ::memcpy(key, keyData.bytes, keyData.length);


    CryptoPP::Serpent::Encryption serpentEncryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcSerpentEncryptor (serpentEncryptor, iv);

    CryptoPP::StreamTransformationFilter stfSerpentEncryptor(cbcSerpentEncryptor, new CryptoPP::StringSink (ciphertext));
    stfSerpentEncryptor.Put( reinterpret_cast<const unsigned char*>( ptext.c_str() ), ptext.length() + 1);
    stfSerpentEncryptor.MessageEnd();

    lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded ciphertext [size:%lu]:%s",sizeof(ciphertext),ciphertext.c_str());

    std::string finalCT;

    ciphertext = ivs + ciphertext; // add the IV before the ciphertext

    lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded iv+ciphertext [size:%lu]:%s",sizeof(ciphertext),ciphertext.c_str());

    CryptoPP::StringSource base64Encoder (ciphertext, true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(finalCT)));

    // apply HMAC
    // TO DO

    NSString *cryptogram = [NSString stringWithUTF8String:finalCT.c_str()];

    return cryptogram;
}

- (NSString *)decryptUsingSerpentWithCiphertext:(NSString *)ciphertext andKey:(NSData *)keyData
{
    std::string ctext;
    std::string plaintext;

    byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];

    ::memcpy(key, keyData.bytes, keyData.length);

    // decode from base64
    std::string encoded = [ciphertext UTF8String];
    CryptoPP::StringSource base64Decoder (encoded, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(ctext)));

    lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded iv+ciphertext [size:%lu]:%s",sizeof(ctext),ctext.c_str());

    // get the IV from the beggining of the cryptogram
    std::string ivs = ctext.substr(0,CryptoPP::Serpent::BLOCKSIZE+5);

    lcl_log(lcl_cCrypto, lcl_vDebug, @"Recovered IV:%s",ivs.c_str());

    ::memcpy(iv, &ivs, ivs.size());

    // remove the IV from the cryptogram

    ctext.erase(0,CryptoPP::Serpent::BLOCKSIZE+5);

    lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded ciphertext [size:%lu]:%s",sizeof(ctext),ctext.c_str());


    CryptoPP::Serpent::Decryption serpentDecryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcSerpentDecryptor (serpentDecryptor, iv);

    CryptoPP::StreamTransformationFilter stfSerpentDecryptor(cbcSerpentDecryptor, new CryptoPP::StringSink (plaintext));
    stfSerpentDecryptor.Put( reinterpret_cast<const unsigned char*>( ctext.c_str() ), ctext.length());
    stfSerpentDecryptor.MessageEnd();

    NSString *plainText = [NSString stringWithUTF8String:plaintext.c_str()];

    return plainText;
}

Обратите внимание, что мне нужно добавить 5 к ожидаемому размеру iv, чтобы получить полный IV. И тогда я получаю сообщение об ошибке "найден неверный отступ PCKS#7. Неверный зашифрованный текст"

Как лучше всего управлять IV? (Я также хотел бы добавить HMAC к зашифрованному тексту iv+ (Encrypt-then-MAC)...

Если я сделаю это:

// get the IV from the beggining of the cryptogram
std::string ivs = ctext.substr(0,CryptoPP::Serpent::BLOCKSIZE);

lcl_log(lcl_cCrypto, lcl_vDebug, @"Recovered IV:%s",ivs.c_str());

::memcpy(iv, &ivs, ivs.size());

// remove the IV from the cryptogram

ctext.erase(0,CryptoPP::Serpent::BLOCKSIZE);

Журналы покажут количество байтов IV, все еще находящихся в зашифрованном тексте, и сгенерируют исключение "недействительный зашифрованный текст, размер не кратный размеру блока".

Журналы:

2013-12-01 17:59:37.747 App[413:70b] D Crypto:PSCryptoCore.mm:51:-[PSCryptoCore testSerpentEncryptonMechanism] Initial plaintext:Serpentine and black...
2013-12-01 17:59:37.748 App[413:70b] D Crypto:PSCryptoCore.mm:74:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Random IV:ç©ìùËß,¬<ÎΩ9ZÑ0 Û
2013-12-01 17:59:37.749 App[413:70b] D Crypto:PSCryptoCore.mm:87:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Non-Encoded ciphertext [size:4]:PÉò»ÓÔҥ 1æIõ¶”Áˆ™8äºBmº†c
õ
2013-12-01 17:59:37.749 App[413:70b] D Crypto:PSCryptoCore.mm:93:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Non-Encoded iv+ciphertext [size:4]:ç©ìùËß,¬<ÎΩ9ZÑ0 ÛPÉò»ÓÔҥ 1æIõ¶”Áˆ™8äºBmº†c
õ
2013-12-01 17:59:37.750 App[413:70b] D Crypto:PSCryptoCore.mm:54:-[PSCryptoCore testSerpentEncryptonMechanism] ciphertext:C42pk53opyzCPOu9FDlahDAg8wgBUIOYyO7M0/G0IDG+SZum0+f2qjiKvA4RQm28HaBjCps=
2013-12-01 17:59:37.750 App[413:70b] D Crypto:PSCryptoCore.mm:118:-[PSCryptoCore decryptUsingSerpentWithCiphertext:andKey:] Non-Encoded iv+ciphertext [size:4]:ç©ìùËß,¬<ÎΩ9ZÑ0 ÛPÉò»ÓÔҥ 1æIõ¶”Áˆ™8äºBmº†c
õ
2013-12-01 17:59:37.752 App[413:70b] D Crypto:PSCryptoCore.mm:123:-[PSCryptoCore decryptUsingSerpentWithCiphertext:andKey:] Recovered IV:ç©ìùËß,¬<ÎΩ9ZÑ
2013-12-01 17:59:37.753 App[413:70b] D Crypto:PSCryptoCore.mm:131:-[PSCryptoCore decryptUsingSerpentWithCiphertext:andKey:] Non-Encoded ciphertext [size:4]:0 ÛPÉò»ÓÔҥ 1æIõ¶”Áˆ™8äºBmº†c
õ
libc++abi.dylib: terminating with uncaught exception of type CryptoPP::InvalidCiphertext: StreamTransformationFilter: ciphertext length is not a multiple of block size

Обратите внимание, что часть IV все еще находится перед зашифрованным текстом после того, как я пытаюсь удалить его. Почему это так?

2 ответа

Предвосхищение IV совершенно верно. Почему вы добавляете 5 к размеру блока? Декодировать из Base-64 в данные. Вытащите первые байты BLOCKSIZE как IV. Расшифруйте остаток.

Мне удалось это исправить. Это код

- (NSString *)encryptUsingSerpentWithPlaintext:(NSString *)plaintext andKey:(NSData *)keyData
{
    std::string ptext = [plaintext UTF8String];
    std::string ciphertext;

    byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];

    CryptoPP::AutoSeededX917RNG<CryptoPP::Serpent> rng;
    rng.GenerateBlock(iv, CryptoPP::Serpent::BLOCKSIZE);

    std::string ivs(reinterpret_cast<char const *>(iv));
    lcl_log(lcl_cCrypto, lcl_vDebug, @"Random IV:%s",ivs.c_str());


    ::memcpy(key, keyData.bytes, keyData.length);


    CryptoPP::Serpent::Encryption serpentEncryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcSerpentEncryptor (serpentEncryptor, iv);

    CryptoPP::StreamTransformationFilter stfSerpentEncryptor(cbcSerpentEncryptor, new CryptoPP::StringSink (ciphertext),CryptoPP::StreamTransformationFilter::BlockPaddingScheme::ONE_AND_ZEROS_PADDING);
    stfSerpentEncryptor.Put( reinterpret_cast<const unsigned char*>( ptext.c_str() ), ptext.length() + 1);
    stfSerpentEncryptor.MessageEnd();

    lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded ciphertext [size:%lu]:%s",sizeof(ciphertext),ciphertext.c_str());

    std::string finalCT;

    CryptoPP::StringSource base64Encoder (ciphertext, true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(finalCT)));

    std::string ivB64;

    CryptoPP::StringSource base64IVEncoder (ivs , true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(ivB64)));

    lcl_log(lcl_cCrypto, lcl_vDebug, @"IV base64[size:%lu]:%s",ivB64.length(),ivB64.c_str());

    finalCT = ivB64 + finalCT;

    lcl_log(lcl_cCrypto, lcl_vDebug, @"Cryptogram:%s",finalCT.c_str());

    // apply HMAC
    // TO DO

    NSString *cryptogram = [NSString stringWithUTF8String:finalCT.c_str()];

    return cryptogram;
}

- (NSString *)decryptUsingSerpentWithCiphertext:(NSString *)ciphertext andKey:(NSData *)keyData
{
    std::string ctext;
    std::string plaintext;

    byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];

    ::memcpy(key, keyData.bytes, keyData.length);

    // decode from base64
    std::string encoded = [ciphertext UTF8String];

    // pull IV from ciphertext
    std::string ivs = encoded.substr(0,29);
    encoded.erase(0,29);

    CryptoPP::StringSource base64Decoder (encoded, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(ctext)));

    std::string iv_tmp;
    CryptoPP::StringSource base64IVDecoder (ivs, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(iv_tmp)));



    lcl_log(lcl_cCrypto, lcl_vDebug, @"Recovered IV[encoded]:%s",ivs.c_str());

    ::memcpy(iv, iv_tmp.data(), CryptoPP::Serpent::BLOCKSIZE);



    CryptoPP::Serpent::Decryption serpentDecryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcSerpentDecryptor (serpentDecryptor, iv);

    CryptoPP::StreamTransformationFilter stfSerpentDecryptor(cbcSerpentDecryptor, new CryptoPP::StringSink (plaintext), CryptoPP::StreamTransformationFilter::BlockPaddingScheme::ONE_AND_ZEROS_PADDING);
    stfSerpentDecryptor.Put( reinterpret_cast<const unsigned char*>( ctext.c_str() ), ctext.length());
    stfSerpentDecryptor.MessageEnd();

    NSString *plainText = [NSString stringWithUTF8String:plaintext.c_str()];

    return plainText;
}

Я заметил, что IV в Base64 имеет длину 29 ... Я не уверен, что это всегда так... может ли быть так, что для некоторых других 16-байтовых IV длина строки base64 отличается?

Другие вопросы по тегам