0

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?

Andiana
  • 1,912
  • 5
  • 37
  • 73

1 Answers1

1

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.

Lery
  • 402
  • 3
  • 16
  • You saved my life! – Andiana Dec 02 '16 at 01:32
  • You're welcome. Please note that I don't know how you generate your IV, but be very careful to never use twice the same IV, otherwise as soon as you'll encrypt twice with the same key (but different data) you're exposing your data to classical attacks against CTR mode. So make sure you are not having twice the same IV (even after increment). So when you use e.g. 17 as an IV to encrypt 5 blocks, you cannot use anymore the whole range of IV from 17 to 22! – Lery Dec 02 '16 at 06:20
  • 2
    Crypto++ supplies [IncrementCounterByOne](http://www.cryptopp.com/docs/ref/misc_8h.html) for purposes of incrementing a counter represented as a byte array. – jww Dec 02 '16 at 21:23
  • 1
    Nice one, I didn't know that. Effectively it can be a good idea then to use it instead to avoid having to deal with the big integer directly. Thanks for the update, jww. Don't forget to increment at the end of the loop and not at the beginning as you do now, @Andiana. – Lery Dec 02 '16 at 21:34