Skip to main content

AES-CBC-CTS Decryption using OpenSSL

Recently I was testing few test streams encrypted with AES-CBC-CTS mode, which is another block cipher mode that allows encrypting of data that is not evenly divisible into blocks (unlike AES-CBC mode).

I also found that decryption of such streams is not possible using OpenSSL, as it does not support this block cipher mode. Since OpenSSL does support encryption/decryption for AES-CBC mode, I decided to extend this logic to support AES-CBC-CTS mode.

I found following article on wikipedia which explains CBC-CTS encryption/decryption in detail.

Following C Routine can be used to decrypt data encrypted with AES-CBC-CTS block cipher mode.

_DecryptData(DRM_KeyCtx_T  KEY_CTX, // KeyCtx_T is a structure containing the Key and IV.
                     UINT8 *data, // encrypted data
                     UINT32 inputLength, // encrypted data length
                     UINT8 *outData, // decrypted data
                     UINT32 *outputLength ) // decrypted data length
{
UINT8 Iv[WV_IV_SIZE];
void* lastIvData = NULL;
UINT8 Tn1[16], Tn[16], resBlk[16];
int extraBytes = 0;
int olen=0;
UINT32 tlen=0;
int actualLength = inputLength;

 if (inputLength<16)
 {
    if (data!=outData)
    memcpy(outData, data, inputLength);
    *outputLength = inputLength;
     return SUCCESS;
 }
 // Get Last IV
 if (inputLength&0xf) // not aligned by 16 : CTS
 {
    if (inputLength>=32) // Use Cn-2 Block
    {
       lastIvData = (void*)(data+(inputLength&0xfffffff0)-(IV_SIZE*2)); // IV_SIZE is maximum size of IV.
       memcpy(Iv, lastIvData, 16);
     }
  }

  *outputLength = 0;

   if(!EVP_DecryptInit (&opensslCtx.ctx, opensslCtx.cipher, KEY_CTX.key, KEY_CTX.iv))
        {
            return FAILURE;
        }

   EVP_CIPHER_CTX_set_padding(&opensslCtx.ctx, 0);

   extraBytes = inputLength%16;
   if(extraBytes)
   {
      inputLength -= extraBytes+IV_SIZE;
      if(!inputLength)
         {
              return SUCCESS;
          }
    }

    if (EVP_DecryptUpdate (&opensslCtx.ctx, outData, &olen, data, inputLength) != 1)
    {
       return FAILURE;
    }

    if (EVP_DecryptFinal (&opensslCtx.ctx, outData + olen, (int *)&tlen) != 1)
    {
       return FAILURE;
    }

    olen +=tlen;
    *outputLength += olen;

    // For CBC CTS and handling extrabytes at the end of the inputbuffer
    if(extraBytes)
    {
        memset(resBlk, 0, IV_SIZE);
        memcpy(resBlk, data+inputLength+IV_SIZE, extraBytes);

        olen = 0;
        tlen = 0;

        if(!EVP_DecryptInit (&opensslCtx.ctx, opensslCtx.cipher, KEY_CTX.key, resBlk))
        {
            return FAILURE;
        }

          
        EVP_CIPHER_CTX_set_padding(&opensslCtx.ctx, 0);

        if (EVP_DecryptUpdate (&opensslCtx.ctx, Tn1, &olen, data+inputLength, IV_SIZE) != 1)
        {
           return FAILURE;
         }

         if (EVP_DecryptFinal (&opensslCtx.ctx, Tn1 + olen, (int *)&tlen) != 1)
         {
            return FAILURE;
         }

         olen = 0;
         tlen = 0;

         memcpy(resBlk+extraBytes, Tn1+extraBytes, IV_SIZE-extraBytes);

         if(!EVP_DecryptInit (&opensslCtx.ctx, opensslCtx.cipher, KEY_CTX.key, Iv))
         {
             return FAILURE;
         }

         EVP_CIPHER_CTX_set_padding(&opensslCtx.ctx, 0);

         if (EVP_DecryptUpdate (&opensslCtx.ctx, Tn, &olen, resBlk, IV_SIZE) != 1)
         {
             return FAILURE;
         }

         if (EVP_DecryptFinal (&opensslCtx.ctx, Tn + olen, (int *)&tlen) != 1)
         {
             return FAILURE;
         }

         memcpy(outData+*outputLength, Tn, IV_SIZE);
         memcpy(outData+*outputLength+IV_SIZE, Tn1, extraBytes);
         *outputLength = actualLength;
    }
    return SUCCESS;
}

Comments

  1. Hello Guys, Use this online converter for file converting to other formats like these;

    Best File Converter

    ReplyDelete
  2. And this converter will transfer one file to other formats like these;

    Pptm to Pdf

    Psd to Ai

    Caf to Aiff

    Tga to Jpg

    Swf to Mp4

    ReplyDelete

Post a Comment