Search code examples
cencryptionpadding3des

Decoding char to UTF8 in C after 3DES decryption


I need some help decoding a char in C to its UTF8 interpretation.

My code so far works this way:

  • A char is initialised with hexadecimal representation of 'password' 70617373776F7264
  • It is then encrypted using 3DES DD201F609E49C0609FABA4C8AAFBB1E5
  • Then it is decrypted successfully using 3DES 70617373776F72640808080808080808

In theprintf("decrypted: %s",dec) statement, all looks fine and it is displayed as decrypted: password

However when doing a string compare, it does not match. Looking closely at the char, I can see that it comes out as \001password\010\010\010\010\010\010\010\010 (this is due to the padding)

Is there any way to either un-pad or to decode to UTF8? something similar to this

Edit with code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/des.h>
#include <openssl/rand.h>
#include <ldap.h>
#include "k.h"
#include "hex.h"


#define ULONG unsigned long
#define INT unsigned int


char *encrypt(char *data)
{

  int i = 0;
  int len = 0;
  int nlen = 0;


  char *key1 = "1313232323231313";
  char *key2 = "6789678967896789";
  char *key3 = "1313232323231313";

  /* Padding */
  char ch = '\0';
  unsigned char out[64] = {0};
  unsigned char src[64] = {0};


  unsigned char *ptr  = NULL;
  unsigned char block[8] = {0};
  DES_key_schedule ks1, ks2, ks3;

  /* set password table */
  ptr = hex2bin(key1, strlen(key1), &nlen);
  memcpy(block, ptr, sizeof(block));
  free(ptr);
  DES_set_key_unchecked((C_Block *)block, &ks1);

  ptr = hex2bin(key2, strlen(key2), &nlen);
  memcpy(block, ptr, sizeof(block));
  free(ptr);
  DES_set_key_unchecked((C_Block *)block, &ks2);

  ptr = hex2bin(key3, strlen(key3), &nlen);
  memcpy(block, ptr, sizeof(block));
  free(ptr);
  DES_set_key_unchecked((C_Block *)block, &ks3);

  ptr = hex2bin(data, strlen(data), &nlen);
  memcpy(src, ptr, nlen);
  free(ptr);

  len = (nlen / 8 + (nlen % 8 ? 1: 0)) * 8;

  ch = 8 - nlen % 8;
  memset(src + nlen, ch, (8 - nlen % 8) % 8);

  printf("Raw data: ");
  for (i = 0; i < len; i++) {
      printf("%02X", *(src + i));
  }
  printf("\n");

  for (i = 0; i < len; i += 8) {
      DES_ecb3_encrypt((C_Block *)(src + i), (C_Block *)(out + i), &ks1, &ks2, &ks3, DES_ENCRYPT);
  }

  printf("Encrypted: ");
  for (i = 0; i < len; i++) {
      printf("%02X" , *(out + i));
  }
  printf("\n");


  return out;

}


char *decrypt(char *data)
{

  int i = 0;
  int len = 0;
  int nlen = 0;


  char *key1 = "1313232323231313";
  char *key2 = "6789678967896789";
  char *key3 = "1313232323231313";

  /* Padding */
  int ch = 0;
  unsigned char out[64] = {0};
  unsigned char src[64] = {0};


  unsigned char *ptr  = NULL;
  unsigned char block[8] = {0};
  DES_key_schedule ks1, ks2, ks3;

  /* set password table */
  ptr = hex2bin(key1, strlen(key1), &nlen);
  memcpy(block, ptr, sizeof(block));
  free(ptr);
  DES_set_key_unchecked((C_Block *)block, &ks1);

  ptr = hex2bin(key2, strlen(key2), &nlen);
  memcpy(block, ptr, sizeof(block));
  free(ptr);
  DES_set_key_unchecked((C_Block *)block, &ks2);

  ptr = hex2bin(key3, strlen(key3), &nlen);
  memcpy(block, ptr, sizeof(block));
  free(ptr);
  DES_set_key_unchecked((C_Block *)block, &ks3);

  ptr = hex2bin(data, strlen(data), &nlen);
  memcpy(src, ptr, nlen);
  free(ptr);

  len = (nlen / 8 + (nlen % 8 ? 1: 0)) * 8;

  ch = 8 - nlen % 8;
  memset(src + nlen, ch, (8 - nlen % 8) % 8);

  printf("Raw data: ");
  for (i = 0; i < len; i++) {
      printf("%02X", *(src + i));
  }
  printf("\n");

  for (i = 0; i < len; i += 8) {
      DES_ecb3_encrypt((C_Block *)(src + i), (C_Block *)(out + i), &ks1, &ks2, &ks3, DES_DECRYPT);
  }

  printf("Decrypted: ");
  for (i = 0; i < len; i++) {
      printf("%02X", *(out + i));
  }

  printf("\n");
  return out;

}


K DES_ecb3_do(K user, K pass,K fl )
{
  int res = 0;
  int flag = fl->i;
  char *usn = user->s;

  char *enc = pass->s;
  char *decr = "";
  char dec[32];

  if(flag==1)
  {
    decr = encrypt(enc);
    strcat(dec,decr);
  }
  else if(flag==0)
  {
    decr = decrypt(enc);
    strcat(dec,decr);
  }
  int ret;
  ret = strcmp(dec, "password");
  if(ret==0)
  {
    printf("they match");
  }
  else
  {
    printf("they don't match\n");
    return (K) 0;
  }  
 printf("decrypted pass is:%s\n",dec);

   return ks(dec);
}

Solution

  • In decrypt function you return the result of decryption from a local variable, that is out of scope in the caller.

    Change out[64] to static or as global, or malloc it.

    Finally your code invoke UB because of you are returning an address of stack area.

    EDIT after OP comment request

    Your code is

    char *decrypt(char *data)
    {
    
      int i = 0;
      int len = 0;
      int nlen = 0;
    
    
      char *key1 = "1313232323231313";
      char *key2 = "6789678967896789";
      char *key3 = "1313232323231313";
    
      /* Padding */
      int ch = 0;
      unsigned char out[64] = {0};
      unsigned char src[64] = {0};
    
      // stuff....
     return out;
    }
    

    This code is declaring out array as local, otherwise stack allocated. That the variable is available only in local scope: inside decrypt function.

    This means that when the function return to the caller function DES_ecb3_do a memory address that could be corrupted. You should not access that address.

    To solve the problem you must make out variable available out of decrypt function scope using, for example, one of the following:

    1) you define the out as global:

    unsigned char out[64] = {0};
    
    char *decrypt(char *data)
    {
       // STUFF
    }
    

    2) You define out as static inside your function:

    char *decrypt(char *data)
    {
       static unsigned char out[64] = {0};
       // STUFF
    }
    

    3) You define out as a poiter and malloc it:

    char *decrypt(char *data)
    {
       unsigned char *out] = malloc(64);
       // STUFF
    }
    

    Hope it is clear enough.