How to seek in CTR mode and decrypt part of the stream?

匿名 (未验证) 提交于 2019-12-03 09:02:45

问题:

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)     ) ); 

回答1:

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).



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!