I have a question in partial decoding in cryptopp. USE AES 256 CTR;
Encode source:
CTR_Mode< AES >::Encryption e; e.SetKeyWithIV(key, 32, iv); string encrypt; string a = "Example text to encoding"; encrypt.clear(); StringSource s(a, true, new StreamTransformationFilter(e, new StringSink(encrypt) ) );
Decode source:
CTR_Mode<AES>::Decryption d; d.SetKeyWithIV(key, 32, iv); string x; StringSource s1(encrypt, true, new StreamTransformationFilter(d, new StringSink(x) ) );
It works fine. But I don't know how decrypt only part. For example, example encrypt.begin()+10
Part Decode:
CTR_Mode<AES>::Decryption d; d.SetKeyWithIV(key, 32, iv); d.DiscardBytes(5); //bit to skip string todecrypt = encrypt.substr(5,10); // part of encrypted message string x; StringSource s1(todecrypt, true, new StreamTransformationFilter(d, new StringSink(x) ) );
How to seek in CTR mode and decrypt part of the stream?
Using a Crypto++ Pipeline is a tad bit awkward because Discard
or Skip
on a Source
does not work as expected. You have to Pump
data into "nothing" under the current implementation. Also see Skip'ing on a Source does not work as expected on Stack Overflow.
Below is an example of using AES/CTR and seeking in the stream. It needs to perform a "two part" seek. First, it discards bytes on the Source
called cipher
. Second, it seeks in the keystream on the encryption object called enc
to synchronize the counter. Once the seek is performed, the remainder of the cipher text is decrypted by calling PumpAll()
, which pumps the remainder of the data through the pipeline.
#include "modes.h" #include "aes.h" using namespace CryptoPP; int main(int argc, char* argv[]) { string plain = "Now is the time for all good men to come to the aide of their country"; byte key[AES::DEFAULT_KEYLENGTH] = {0}; byte nonce[AES::BLOCKSIZE] = {0}; CTR_Mode<AES>::Encryption enc; enc.SetKeyWithIV(key, sizeof(key), nonce, sizeof(nonce)); string cipher; StringSource ss1(plain, true, new StreamTransformationFilter(enc, new StringSink(cipher))); for(size_t i=0; i<cipher.size(); i++) { CTR_Mode<AES>::Decryption dec; dec.SetKeyWithIV(key, sizeof(key), nonce, sizeof(nonce)); StringSource ss2(cipher, false); ss2.Pump(i); dec.Seek(i); string recover; StreamTransformationFilter stf(dec, new StringSink(recover)); // Attach the decryption filter after seeking ss2.Attach(new Redirector(stf)); ss2.PumpAll(); cout << i << ": " << recover << endl; } return 0; }
Here is the result:
$ ./test.exe 0: Now is the time for all good men to come to the aide of their country 1: ow is the time for all good men to come to the aide of their country 2: w is the time for all good men to come to the aide of their country 3: is the time for all good men to come to the aide of their country 4: is the time for all good men to come to the aide of their country 5: s the time for all good men to come to the aide of their country 6: the time for all good men to come to the aide of their country 7: the time for all good men to come to the aide of their country 8: he time for all good men to come to the aide of their country 9: e time for all good men to come to the aide of their country 10: time for all good men to come to the aide of their country 11: time for all good men to come to the aide of their country 12: ime for all good men to come to the aide of their country 13: me for all good men to come to the aide of their country 14: e for all good men to come to the aide of their country 15: for all good men to come to the aide of their country 16: for all good men to come to the aide of their country 17: or all good men to come to the aide of their country 18: r all good men to come to the aide of their country 19: all good men to come to the aide of their country 20: all good men to come to the aide of their country 21: ll good men to come to the aide of their country 22: l good men to come to the aide of their country 23: good men to come to the aide of their country 24: good men to come to the aide of their country 25: ood men to come to the aide of their country 26: od men to come to the aide of their country 27: d men to come to the aide of their country 28: men to come to the aide of their country 29: men to come to the aide of their country 30: en to come to the aide of their country 31: n to come to the aide of their country 32: to come to the aide of their country 33: to come to the aide of their country 34: o come to the aide of their country 35: come to the aide of their country 36: come to the aide of their country 37: ome to the aide of their country 38: me to the aide of their country 39: e to the aide of their country 40: to the aide of their country 41: to the aide of their country 42: o the aide of their country 43: the aide of their country 44: the aide of their country 45: he aide of their country 46: e aide of their country 47: aide of their country 48: aide of their country 49: ide of their country 50: de of their country 51: e of their country 52: of their country 53: of their country 54: f their country 55: their country 56: their country 57: heir country 58: eir country 59: ir country 60: r country 61: country 62: country 63: ountry 64: untry 65: ntry 66: try 67: ry 68: y
Now that you've seen the general pattern, here are the modifications for your dataset using the range [5,10]
.
You do not have to call stf.MessageEnd()
because recovered text is ready as soon as the XOR is preformed. Others modes may need the call to MessageEnd()
. Also see Init-Update-Final on the Crypto++ wiki.
StringSource ss2(cipher, false); ss2.Pump(5); dec.Seek(5); string recover; StreamTransformationFilter stf(dec, new StringSink(recover)); // Attach the decryption filter after seeking ss2.Attach(new Redirector(stf)); ss2.Pump(10 - 5 + 1); cout << "'" << recover << "'" << endl;
It produces:
$ ./test.exe 's the '
And here's a little more:
StringSource ss2(cipher, false); ss2.Pump(5); dec.Seek(5); string recover; StreamTransformationFilter stf(dec, new StringSink(recover)); // Attach the decryption filter after seeking ss2.Attach(new Redirector(stf)); ss2.Pump(10 - 5 + 1); cout << "'" << recover << "'" << endl; ss2.Pump(1); cout << "'" << recover << "'" << endl; ss2.Pump(1); cout << "'" << recover << "'" << endl;
It produces:
$ ./test.exe 's the ' 's the t' 's the ti'
Earlier I said "Using a Crypto++ Pipeline is a tad bit awkward". Here's all we want to do, but we can't at the moment:
StringSource ss(cipher, false, new StreamTransformationFilter(dec, new StringSink(x))); ss.Skip(5); // Discard bytes and synchronize stream ss.Pump(5); // Process bytes [5,10] cout << x << endl;
Regarding Rob's comment "You must decrypt an entire 16-byte block..." - If you were working with another mode, like CBC mode, then you would have to process preceding plain text or cipher text; and you would have to operate on blocks. CBC mode and its chaining properties demand it.
However, CTR is designed a little differently. Its designed to be seekable, and it allows you to jump around in the stream. In this respect, its a lot like OFB mode. (CTR mode and OFB mode differ in the way they generate the keystream. But both XOR the keystream with the plain text or cipher text).