Crypto++ CTR mode manual implement

328 Views Asked by At

I am trying to make CTR manually on top of ECB mode (but still) using Crypto++. The idea is:

For single block: Just use ECB For multiple block, use CTR algorithm (AFAIK):

//We have n block of plain data -> M
PlainData M[n];
key;
iv;
char *CTR;
cipher ="";
for(i = 0; i<n; i++ ){
  if(i ==0){
      CTR = iv;
  }
  ei = encryptECB(CTR + i)
  cipherI = xor(ei, M[i])
  cipher += cipherI;
}

//My xor() to XOR two char array

void xor(char  *s1, char* s2, char *& result, int len){

    try{
        int i;
        for (i = 0; i < len; i++){
            int u = s1[i] ^ s2[i];
            result[i] = u;
        }
        result[i] = '\0';
    }
    catch (...){
        cout << "Errp";
    }
}

Test 1: 100% Crypto++ CTR

string auto_ctr(char * s1, long size){
    CTR_Mode< AES >::Encryption e;
    e.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    string cipherZ;
    StringSource s(s1, true,
        new StreamTransformationFilter(e,
        new StringSink(cipherZ), BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING
        )
        );
    return cipherZ;
}

Test 2: Manual CTR based on ECB

string encrypt(char* s1, int size){
    ECB_Mode< AES >::Encryption e;
    e.SetKey(key, size);
    string cipher;
    string s(s1, size);
    StringSource ss1(s, true,
        new StreamTransformationFilter(e,
        new StringSink(cipher), BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING
        ) // StreamTransformationFilter
        ); // StringSource
    return cipher;
}

static string manual_ctr(char *plain, long &size){
    int nBlocks = size / BLOCK_SIZE;
    char* encryptBefore = new char[BLOCK_SIZE];
    char *ci = new char[BLOCK_SIZE] ;
    string cipher;
    for (int i = 0; i < nBlocks; i++){
        //If the first loop, CTR = IV
        if (i == 0){
            memcpy(encryptBefore, iv, BLOCK_SIZE);
        }
        encryptBefore[BLOCK_SIZE] = '\0';
        memcpy(encryptBefore, encryptBefore + i, BLOCK_SIZE);


        char *buffer = new char[BLOCK_SIZE];
        memcpy(buffer, &plain[i], BLOCK_SIZE);
        buffer[BLOCK_SIZE] = '\0';
        //Encrypt the CTR
        string e1 = encrypt(encryptBefore, BLOCK_SIZE);
        //Xor it with m[i] => c[i]
        xor((char*)e1.c_str(), buffer, ci, BLOCK_SIZE);
        //Append to the summary cipher
        /*for (int j = 0; j < BLOCK_SIZE/2; j++){
            SetChar(cipher, ci[j], i*BLOCK_SIZE + j);
        }*/
        cipher += ci;
        //Set the cipher back to iv
        //memcpy(encryptBefore, ci, BLOCK_SIZE);
    }
    return cipher;
}

And this is Main for testing:

void main(){

    long size = 0;
    char * plain = FileUtil::readAllByte("some1.txt", size);
    string auto_result = auto_ctr(plain, size);
    string manual_result = manual_ctr(plain, size);
    getchar();
}

The auto_result is:

"Yž+eÞsÂÙ\bü´\x1a¨Ü_ÙR•L¸Ð€¦å«ÎÍÊ[w®Ÿg\fT½\ý7!p\r^ÍdžúP\bîT\x3\x1cZï.s%\x1ei{ÚMˆØ…Pä¾õ\x46\r5\tâýï‚ú\x16ç’Qiæ²\x15š€á^ªê]W ÊNqdŒ¥ ˆ†¾j%8.Ìù\x6Þ›ÔÏ’[c\x19"

The manual_result is:

"Yž+eÞsÂÙ\bü´\x1a¨Ü_Ù·\x18ýuù\n\nl\x11Á\x19À†Žaðƒºñ®GäþŽá•\x11ÇYœf+^Q\x1a\x13B³‘QQµºëÑÌåM\"\x12\x115â\x10¿Ô„›s°‰=\x18*\x1c:²IF'n@ŠŠ¾mGÂzõžÀ\x1eÏ\SëYU¼í‘" >

What is the problem with my implement?

1

There are 1 best solutions below

4
Lery On BEST ANSWER

Since your first block seems to be working fine, I've only searched for problems in the management of the counter itself and here is what seems me wrong :

memcpy(encryptBefore, encryptBefore + i, BLOCK_SIZE);

Here you are trying to increment your IV i times, I presume, but this is not what happens, what you do is trying to copy into your encryptBefore pointer the content of the encryptBefore+i pointer spanning over BLOCK_SIZE bytes. This is not at all incrementing the IV, but it works for the first block because then i=0.

What you want to do is actually creating a big integer using CryptoPP::Integer to use as an IV and increment that integer and then convert it into a byte array using the Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const function from the CryptoPP Integer class when you need to use bytes instead of integers.

Ps: when performing i/o operations, I recommend you to use hexadecimal strings, take a look at the CryptoPP::HexEncoder and HexDecoder classes, they both are well documented on CryptoPP wiki.