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

若如初见. 提交于 2019-12-08 01:36:49

问题


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



来源:https://stackoverflow.com/questions/40362351/how-to-seek-in-ctr-mode-and-decrypt-part-of-the-stream

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