Search code examples
cencryptionopensslglibc

How do I decrypt with openssl something encrypted with cbc_crypt (xencrypt)?


In a database there is string encrypted with glibc's xencrypt which is using internally cbc_crypt and the decryption was happening with xdecrypt function which also uses cbc_crypt.

Since glibc 2.32 there is no way to enable again xencrypt and xdecrypt functions. So I am trying to decrypt the encrypted string with openssl with command:

openssl enc -des-cbc -d -in encrypted.enc -out decrypted.txt -iv 0000000000000000 -K <my key in hex>

But I get:

bad decrypt 140401522647424:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:../openssl-1.1.1k/crypto/evp/evp_enc.c:599 

What am I doing wrong and is there an openssl command or function call that can provide the same result as xdecrypt (cbc_encrypt)?

***** UPDATE *****

I tried to solve the above question also programmatically. So I used the following code in order to be also in topic as @dave_thompson_085 mentioned in comment.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/des_crypt.h>

#include <openssl/des.h>
#include <openssl/pkcs7.h>

#define BUFFSIZE 420

int glibc_encrypt(const char *, const char *, const char *, char **, unsigned int *);
int glibc_decrypt(const char *, const char *, const char *, char **);
int openssl_encrypt(const char *, const char *, const char *, unsigned int, char *, unsigned int *);
int openssl_decrypt(const char *, const char *, char *, unsigned int, char **);

int main(void) {
    const char *key = "abcdefgh";
    const char *ivec = "87654321";
    const char *data = "mypass1234test";
    char *dst_buf;
    unsigned int dst_size;
    char *final_buf;

    glibc_encrypt(key, ivec, data, &dst_buf, &dst_size);
    glibc_decrypt(key, ivec, (const char *) dst_buf, &final_buf);

    openssl_encrypt(key, ivec, data, strlen(data), dst_buf, &dst_size);
    openssl_decrypt(key, ivec, dst_buf, dst_size, &final_buf);

    return 0;
}

int glibc_encrypt(const char *key, const char *ivec, const char *data, char **dst, unsigned int *dst_size) {

    char tmpkey[BUFFSIZE], tmpivec[BUFFSIZE];
    unsigned int rawsize, i, result, pading;

    printf("*** glibc encrytion ***\n");

    strncpy(tmpkey, key, strlen(key));
    strncpy(tmpivec, ivec, strlen(ivec));

    des_setparity(tmpkey);

    rawsize = strlen(data);
    printf("data to be ecrypted is          : %s\n", data);
    printf("size of data to be encrypted is : %d\n", rawsize);

    /* Add to data to ensure size is divisable by 8. */
    pading = 8 - (rawsize % 8);
    *dst_size = rawsize + pading;
    printf("data size were rounded to       : %d\n", *dst_size);

    /* Allocate the containing ecryption buffer */
    *dst = malloc(*dst_size);
    memcpy(*dst, data, *dst_size);

    for (i = rawsize ; i < *dst_size; i++)
        dst[i] = '\0';

    result = cbc_crypt(tmpkey, *dst, *dst_size, DES_ENCRYPT | DES_SW, tmpivec);

    if (DES_FAILED(result) || strcmp(*dst, "") == 0) {
        if(strcmp(*dst, "") == 0)
            printf("*** Null Output ***\n");
        else
            printf("*** Encryption Error ***\n");
    } else {
        snprintf(tmpkey, *dst_size, "%s", *dst);
        printf("glibc encrypted data            : %s\n", tmpkey);
    }

    return 0;
}

int glibc_decrypt(const char *key, const char *ivec, const char *data, char **dst) {

    char tmpkey[BUFFSIZE], tmpivec[BUFFSIZE];
    unsigned int dstsize;
    int result;

    printf("\n*** glibc decryption ***\n");

    strncpy(tmpkey, key, strlen(key));
    strncpy(tmpivec, ivec, strlen(ivec));

    des_setparity(tmpkey);

    dstsize = strlen(data);
    printf("data to be decrypted is         : %s\n", data);
    printf("size of data to be decrypted is : %d\n", dstsize);

    /* Allocate the containing ecryption buffer */
    *dst = malloc(dstsize);
    memcpy(*dst, data, dstsize);

    result = cbc_crypt(tmpkey, *dst, dstsize, DES_DECRYPT | DES_SW, tmpivec);

    if(DES_FAILED(result) || strcmp(*dst, "") == 0) {
        if(strcmp(*dst, "") == 0)
            printf("*** Null Output ***\n");
        else
            printf("*** Decryption Error ***\n");
    } else {
        snprintf(tmpkey, dstsize, "%s", *dst);
        printf("glibc decrypted data            : %s\n", tmpkey);
    }

    return 0;
}

int openssl_encrypt(const char *key, const char *ivec, const char *_raw_ptr, unsigned int _raw_size, char *_dst_buf, unsigned int *_dst_size) {

    DES_key_schedule schedule;
    char tmpkey[BUFFSIZE];
    DES_cblock *iv3;
    int pading;
    size_t i, vt_size;
    char *mid_buf;

    printf("\n*** openssl ecryption ***\n");

    strncpy(tmpkey, key, strlen(key));

    printf("data to be ecrypted is          : %s\n", _raw_ptr);
    printf("size of data to be encrypted is : %d\n", _raw_size);

    DES_set_key_unchecked((const_DES_cblock*) &tmpkey, &schedule);

    vt_size = strlen(ivec);
    iv3 = (DES_cblock *) malloc(vt_size * sizeof(unsigned char));
    memcpy(iv3, ivec, vt_size);

    pading = 8 - (_raw_size % 8);
    *_dst_size = _raw_size + pading;

    printf("data size were rounded to       : %d\n", *_dst_size);

    mid_buf = malloc(*_dst_size);
    memcpy(mid_buf, _raw_ptr, _raw_size );

    /* Add to data to ensure size is divisable by 8. */
    for (i = _raw_size ; i < *_dst_size; i++ )
      mid_buf[i] = '\0';

    DES_ncbc_encrypt((const unsigned char*) mid_buf, (unsigned char *) _dst_buf, *_dst_size, &schedule, iv3, DES_ENCRYPT);
    printf("openssl ecrypted data           : %s\n", _dst_buf);
    printf("openssl ecrypted data size      : %d\n", *_dst_size);
    free(iv3);
    free(mid_buf);

    return 0;
}

int openssl_decrypt(const char *key, const char *ivec, char *_raw_ptr, unsigned int _raw_size, char **_dst_buf) {

    DES_key_schedule schedule;
    char tmpkey[BUFFSIZE];
    DES_cblock *iv3;
    size_t vt_size;

    printf("\n*** openssl decryption ***\n");

    strncpy(tmpkey, key, strlen(key));

    printf("data to be decrypted is         : %s\n", _raw_ptr);
    printf("size of data to be dencrypted is: %d\n", _raw_size);

    DES_set_key_unchecked((const_DES_cblock*) &tmpkey, &schedule);

    vt_size = strlen(ivec);
    iv3 = (DES_cblock *) malloc(vt_size * sizeof(unsigned char));
    memcpy(iv3, ivec, vt_size);

    *_dst_buf = (char*) malloc(_raw_size);
    DES_ncbc_encrypt((const unsigned char*) _raw_ptr, (unsigned char *) *_dst_buf, _raw_size, &schedule, iv3, DES_DECRYPT);
    printf("openssl decrypted data          : %s\n", *_dst_buf);
    free(iv3);

  return 0;
}

And here is the output:

*** glibc encrytion ***
data to be ecrypted is          : mypass1234test
size of data to be encrypted is : 14
data size were rounded to       : 16
glibc encrypted data            :▒!▒e͛▒4▒        k
▒▒

*** glibc decryption ***
data to be decrypted is         :▒!▒e͛▒4▒        k
▒▒d
size of data to be decrypted is : 16
glibc decrypted data            : mypass1234test

*** openssl ecryption ***
data to be ecrypted is          : mypass1234test
size of data to be encrypted is : 14
data size were rounded to       : 16
openssl ecrypted data           : ▒▒▒▒˛▒▒▒uc▒
openssl ecrypted data size      : 16

*** openssl decryption ***
data to be decrypted is         : ▒▒▒▒˛▒▒▒uc▒
size of data to be dencrypted is: 16
openssl decrypted data          : mypass1234test

Both openssl and glibc implementations encrypt and decrypt the data. But if used interchangeably the outcome if not correct.

I would expect the encrypted data from both of them to be exactly the same if the DES implementation is the same, as it should be I guess since the algorithm should produce the same output.

So why openssl and glibc produce seemingly different encrypted data when the same algorithm is used?


Solution

  • DISCLAIMER

    This is not the correct answer but rather a work around I found and used in case some else wants to use the same solution.

    The main problem is that recent glibc version do not provide any more the function cbc_crypt and hence xencrypt and xdecrypt.

    But libtirpc (http://sourceforge.net/projects/libtirpc) includes the missing cbc_crypt function.

    So instead of using openssl to decrypt the cbc_crypted staff I used the libtirp library.