In a effort to encrypt large file using Crypto++, I am following ecrypting using Java-like Init-Update-Final in Crypto++,
The demo code seem to work, everytime the Put is invoked, the output byte is printed to screen:
encoder.Put(buffer, ready);
But I can't find anyway to get the output of all cipher text. For example
'H' -> print 01 to screen
'E' -> print A9 to screen
'L' -> print 5J to screen
'L' -> print 13 to screen
'O' -> print 3d to screen ...
But I can't retrieve the full result to a byte array 01A95J133d...
A question in here related to using Init-Update-Final to encrypt large files but seem like not provided a working solution yet.
This is the full demo code:
enum { ENCRYPT_MODE = 1, DECRYPT_MODE = 2 };
struct JavaAlgorithmParameter
{
JavaAlgorithmParameter()
: key(NULL), ksize(0), iv(NULL), vsize(0) {}
const byte* key;
size_t ksize;
const byte* iv;
size_t vsize;
};
/////////////////////////
/////////////////////////
class JavaCipher
{
public:
static JavaCipher* getInstance(const std::string& transformation);
void init(int opmode, const JavaAlgorithmParameter& params);
size_t update(const byte* in, size_t isize, byte* out, size_t osize);
size_t final(byte* out, size_t osize);
std::string getAlgorithm() const;
protected:
JavaCipher(const std::string& transformation);
private:
std::string m_transformation;
member_ptr<SymmetricCipher> m_cipher;
member_ptr<StreamTransformationFilter> m_filter;
};
/////////////////////////
/////////////////////////
JavaCipher* JavaCipher::getInstance(const std::string& transformation)
{
return new JavaCipher(transformation);
}
JavaCipher::JavaCipher(const std::string& transformation)
: m_transformation(transformation) { }
std::string JavaCipher::getAlgorithm() const
{
return m_transformation;
}
/////////////////////////
/////////////////////////
size_t JavaCipher::final(byte* out, size_t osize)
{
m_filter.get()->MessageEnd();
if (!out || !osize || !m_filter.get()->AnyRetrievable())
return 0;
size_t t = CryptoPP::STDMIN(m_filter.get()->MaxRetrievable(), (word64)osize);
t = m_filter.get()->Get(out, t);
return t;
}
/////////////////////////
/////////////////////////
size_t JavaCipher::update(const byte* in, size_t isize, byte* out, size_t osize)
{
if (in && isize)
m_filter.get()->Put(in, isize);
if (!out || !osize || !m_filter.get()->AnyRetrievable())
return 0;
size_t t = STDMIN(m_filter.get()->MaxRetrievable(), (word64)osize);
t = m_filter.get()->Get(out, t);
return t;
}
/////////////////////////
/////////////////////////
void JavaCipher::init(int opmode, const JavaAlgorithmParameter& params)
{
if (m_transformation == "AES/ECB/PKCSPadding" && opmode == ENCRYPT_MODE)
{
m_cipher.reset(new ECB_Mode<AES>::Encryption);
m_cipher.get()->SetKey(params.key, params.ksize);
m_filter.reset(new StreamTransformationFilter(*m_cipher.get(), NULL, BlockPaddingSchemeDef::PKCS_PADDING));
}
else if (m_transformation == "AES/ECB/PKCSPadding" && opmode == DECRYPT_MODE)
{
m_cipher.reset(new ECB_Mode<AES>::Decryption);
m_cipher.get()->SetKey(params.key, params.ksize);
m_filter.reset(new StreamTransformationFilter(*m_cipher.get(), NULL, BlockPaddingSchemeDef::PKCS_PADDING));
}
else if (m_transformation == "AES/CBC/PKCSPadding" && opmode == ENCRYPT_MODE)
{
m_cipher.reset(new CBC_Mode<AES>::Encryption);
m_cipher.get()->SetKeyWithIV(params.key, params.ksize, params.iv);
m_filter.reset(new StreamTransformationFilter(*m_cipher.get(), NULL, BlockPaddingSchemeDef::PKCS_PADDING));
}
else if (m_transformation == "AES/CBC/PKCSPadding" && opmode == DECRYPT_MODE)
{
m_cipher.reset(new CBC_Mode<AES>::Decryption);
m_cipher.get()->SetKeyWithIV(params.key, params.ksize, params.iv);
m_filter.reset(new StreamTransformationFilter(*m_cipher.get(), NULL, BlockPaddingSchemeDef::PKCS_PADDING));
}
else if (m_transformation == "AES/CTR/NoPadding" && opmode == ENCRYPT_MODE)
{
m_cipher.reset(new CTR_Mode<AES>::Encryption);
m_cipher.get()->SetKeyWithIV(params.key, params.ksize, params.iv);
m_filter.reset(new StreamTransformationFilter(*m_cipher.get(), NULL, BlockPaddingSchemeDef::NO_PADDING));
}
else if (m_transformation == "AES/CTR/NoPadding" && opmode == DECRYPT_MODE)
{
m_cipher.reset(new CTR_Mode<AES>::Decryption);
m_cipher.get()->SetKeyWithIV(params.key, params.ksize, params.iv);
m_filter.reset(new StreamTransformationFilter(*m_cipher.get(), NULL, BlockPaddingSchemeDef::NO_PADDING));
}
else
throw NotImplemented(m_transformation + " is not implemented");
}
/////////////////////////
/////////////////////////
int main(int argc, char* argv[])
{
try
{
byte key[32], iv[16];
OS_GenerateRandomBlock(false, key, COUNTOF(key));
OS_GenerateRandomBlock(false, iv, COUNTOF(iv));
HexEncoder encoder(new FileSink(cout));
JavaAlgorithmParameter params;
params.key = key;
params.ksize = COUNTOF(key);
params.iv = iv;
params.vsize = COUNTOF(iv);
//JavaCipher* cipher = JavaCipher::getInstance("AES/CTR/NoPadding");
JavaCipher* cipher = JavaCipher::getInstance("AES/CBC/PKCSPadding");
cipher->init(ENCRYPT_MODE, params);
cout << "Algorithm: " << cipher->getAlgorithm() << endl;
cout << "Key: ";
encoder.Put(key, COUNTOF(key));
cout << endl;
cout << "IV: ";
encoder.Put(iv, COUNTOF(iv));
cout << endl;
char * allText = FileUtil::readAllByte("1MB.txt");
long len = strlen(allText);
byte buffer[64];
size_t ready = 0;
for (unsigned int i = 0; i <= len; i++)
{
byte b = allText[i];
//cout << "Put 0x";
encoder.Put(b);
cout << endl;
ready = cipher->update(&b, 1, buffer, COUNTOF(buffer));
if (ready)
{
//cout << "Get: ";
encoder.Put(buffer, ready);
cout << endl;
}
}
ready = cipher->final(NULL, 0);
if (ready)
{
//cout << "Final: ";
encoder.Put(buffer, ready);
cout << endl;
}
ready = cipher->final(buffer, COUNTOF(buffer));
if (ready)
{
//cout << "Final: ";
encoder.Put(buffer, ready);
cout << endl;
}
delete cipher;
getchar();
}
catch (const Exception& ex)
{
cerr << ex.what() << endl;
}
return 0;
}
But I can't find anyway to get the output of all cipher text. For example
'H' -> print 01 to screen 'E' -> print A9 to screen 'L' -> print 5J to screen 'L' -> print 13 to screen 'O' -> print 3d to screen ...
But I can't retrieve the full result to a byte array 01A95J133d...
Call cipher::update
with no output buffer:
cipher->update(&b, 1, NULL, 0);
Then, retrieve the buffer after you call cipher::final
:
size_t size = <some appropriately size for the cipher text>;
byte result[size];
cipher->final(result, size);
If you are having trouble with <some appropriately size for the cipher text>
, then add a new method to the class:
size_t ready() const
{
return m_filter.get()->MaxRetrievable();
}