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

Popular posts from this blog

Getting and Setting Microphone Gain or Microphone Boost on Windows 7 / 8 Programmatically

After hours of searching the net I have finally figured out a way to programmatically get and set the microphone gain (boost) value. The code mentioned below can be built on VS and does the job of setting gain value. #include "stdafx.h" #include <mmdeviceapi.h> #include <endpointvolume.h> #include <Functiondiscoverykeys_devpkey.h> #include "Audioclient.h" #include "comutil.h" #define EXIT_ON_ERROR(hres)   if (FAILED(hres)) { goto Exit; } #define SAFE_RELEASE(punk)   if ((punk) != NULL)  { (punk)->Release(); (punk) = NULL; } HRESULT getMicrophoneBoostVolumeLevel(IMMDevice *pEndptDev, IAudioVolumeLevel** ppVolumeLevel) { HRESULT hr = S_OK; DataFlow flow; IDeviceTopology *pDeviceTopology = NULL; IConnector *pConnFrom = NULL; IConnector *pConnTo = NULL; IPart *pPartPrev = NULL; IPart *pPartNext = NULL; *ppVolumeLevel = NULL; wchar_t microphoneBoostName[] = L"Microphone Boost";//if your system ...

Simple example of strong and weak pointers on Android using RefBase class

Here is a simple example explaining the usage of strong and weak pointers using android's RefBase class and the Android.mk to compile the same. Its a modified version of code written by Daniel in the following link. http://himmele.blogspot.com/2012/03/androids-c-reference-counting.html strong_pointer.cpp file:  #include <stdio.h> #include "utils/RefBase.h" namespace android {  class RefTest : public RefBase { public:     RefTest(int32_t id) : mID(id) {         printf("RefTest ctor: %d\n", mID);     }     virtual ~RefTest() {         printf("RefTest dtor: %d\n", mID);     }     int32_t id() const {         return mID;     } private:     int32_t mID; }; int strong_pointer() {     sp<RefTest> ref1 = new RefTest(1);     sp<RefTest> ref5;   ...