我使用openssl API来替换命令,但解密的数据头是错误的。为什么?

时间:2013-12-29 08:24:31

标签: api openssl command

我使用openssl API替换下面的命令行。但是解密的文件头是错误的。有人可以帮帮我吗?

#openssl  enc -d  -aes192 -pass "pass:3eDc#9ujN"  -p -in  hfb1062.enc -out a.cpio
salt=28C7761EE45FFB06
key=00297EE7F640FB3545C9466583B9D008A4EB3CF24A4EFF65
iv =F4F137201648930D6BA620806691EF71

salf,key和iv与openssl命令行输出相同。 以下是实现about openssl命令行的代码:

#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
#include <stdio.h>
#include <openssl/bio.h>


unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
const EVP_CIPHER *cipher=NULL;
int pass2keyiv(char *infile)
{
    const char magic[]="Salted__";
    char mbuf[sizeof magic-1];

    const EVP_MD *dgst = NULL;
    unsigned char salt[PKCS5_SALT_LEN];
    const char *password = "3eDc#9ujN";
    int i;

    BIO *in=NULL;
    in=BIO_new(BIO_s_file());

    printf("Please specify openssl enc -in arg [file]\n");
    {
    //argv[1] openssl enc -in 
        if (BIO_read_filename(in,infile) <= 0)
        {
            perror(infile);
            return;
        }
        printf("her BIO_read_filename argv[1]=%s \n",infile);
    }
     printf("her in %p \n",in);

     if((BIO_read(in,mbuf,sizeof mbuf) != sizeof mbuf
                      || BIO_read(in,
                              (unsigned char *)salt,
                    sizeof salt) != sizeof salt)){
      perror("read salt error");
      return;
    }
    OpenSSL_add_all_algorithms();

    cipher = EVP_get_cipherbyname("aes192");//"aes-192-cbc");
    if(!cipher) { fprintf(stderr, "no such cipher\n"); return 1; }

    dgst=EVP_get_digestbyname("md5");
    if(!dgst) { fprintf(stderr, "no such digest\n"); return 1; }

    if(!EVP_BytesToKey(cipher, dgst, salt,
        (unsigned char *) password,
        strlen(password), 1, key, iv))
    {
        fprintf(stderr, "EVP_BytesToKey failed\n");
        return 1;
    }
    printf("salt: "); for(i=0; i<PKCS5_SALT_LEN; ++i) { printf("%02x", salt[i]); } printf("\n");
    printf("Key: "); for(i=0; i<cipher->key_len; ++i) { printf("%02x", key[i]); } printf("\n");
    printf("IV: "); for(i=0; i<cipher->iv_len; ++i) { printf("%02x", iv[i]); } printf("\n");

    return 0;
}

int do_crypt(FILE *in, FILE *out)
{
    #define BSIZE   (8*1024)
    char inbuf[BSIZE]={0}, outbuf[BSIZE + EVP_MAX_BLOCK_LENGTH]={0};
    const char magic[]="Salted__";
    char mbuf[sizeof magic-1];

    int inlen, outlen;

    char * needle =NULL;


    EVP_CIPHER_CTX ctx;
    EVP_CIPHER_CTX_init(&ctx);

    if(fread(mbuf,1,sizeof mbuf,in) != sizeof mbuf)//If I skip the magic size or remove this code line, the decryped data is also wrong.
        printf("bad magic number\n");
    printf("Magic number %s\n",mbuf); 

    //do_encrypt:1 for encryption,0 for decryption
    EVP_CipherInit_ex(&ctx,cipher, NULL, key, iv, 0);

    for(;;)
    {
        bzero(inbuf,sizeof inbuf);
        inlen = fread(inbuf, 1, BSIZE, in);
        if(inlen <= 0) break;
        bzero(outbuf,sizeof outbuf);
        if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen))
        {
            /* Error */
            EVP_CIPHER_CTX_cleanup(&ctx);
            return 0;
        }


        fwrite(outbuf, 1, outlen, out);
    }
    if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen))
    {
        /* Error */
        EVP_CIPHER_CTX_cleanup(&ctx);
        return 0;
    }
    fwrite(outbuf, 1, outlen, out);
    EVP_CIPHER_CTX_cleanup(&ctx);
    return 1;
}

int main(int argc,char**argv)
{
    FILE *in=fopen(argv[1],"rb");
    FILE *out=fopen(argv[2],"wb");
    if ( argc != 3){
        printf("Usage: in_file_to_be_decryped out_file%d\n",argc);
        return;
    }
    if (NULL ==in){
        printf("error fopen\n");
        return 0;
    }
    pass2keyiv(argv[1]);
    do_crypt(in,out);
    fclose(in);
    fclose(out);
    return 0;
}

2 个答案:

答案 0 :(得分:0)

我有类似的问题,对我来说,我必须在perl脚本中解决它,你可以很容易地将它变成Java。

注意我正在使用DES,因此盐的大小和位置与您的不同。我还使用DES_EDE,您需要使用AES

my $salt = substr($data, 8, 8);
my $ct = substr($data, 16);

my $rounds = 3;
my $data00 = $Key.$salt;
my @md5_hash;
$md5_hash[0] = md5($data00);
my $result = $md5_hash[0];
for (my $i = 1; $i < $rounds; $i++) {
 $md5_hash[$i] = md5($md5_hash[$i - 1].$data00);
 $result .= $md5_hash[$i];
}

my $key = substr($result, 0, 24);
my $iv  = substr($result, 24, 8);

my $m = Crypt::Mode::CFB->new('DES_EDE');
my $plaintext = $m->decrypt($ct, $key, $iv);

return $plaintext;

对于AES,我认为盐的长度为16,因此ct(密文)将从位置24开始。我还认为AES使用的是SHA而不是MD5,但我对此并不是100%肯定。

答案 1 :(得分:0)

这是我的解决方案:我认为我们应该跳过一个块大小,这是加密时的默认填充。

#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
#include <stdio.h>
#include <openssl/bio.h>

/*
#openssl  enc -d  -aes192 -pass "pass:3eDc#9ujN"  -p -in  hfb1062.enc -out a.cpio
salt=28C7761EE45FFB06
key=00297EE7F640FB3545C9466583B9D008A4EB3CF24A4EFF65
iv =F4F137201648930D6BA620806691EF71
*/

unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
const EVP_CIPHER *cipher=NULL;
int pass2keyiv(char *infile)
{
    const char magic[]="Salted__";
    char mbuf[sizeof magic-1];

    const EVP_MD *dgst = NULL;
    unsigned char salt[PKCS5_SALT_LEN];
    const char *password = "3eDc#9ujN";
    int i;

    BIO *in=NULL;
    in=BIO_new(BIO_s_file());

    printf("Please specify openssl enc -in arg [file]\n");
    {
    //argv[1] openssl enc -in 
        if (BIO_read_filename(in,infile) <= 0)
        {
            perror(infile);
            return;
        }
        printf("her BIO_read_filename argv[1]=%s \n",infile);
    }
     printf("her in %p \n",in);

     if((BIO_read(in,mbuf,sizeof mbuf) != sizeof mbuf
                      || BIO_read(in,
                              (unsigned char *)salt,
                    sizeof salt) != sizeof salt)){
      perror("read salt error");
      return;
    }
    OpenSSL_add_all_algorithms();

    cipher = EVP_get_cipherbyname("aes192");//"aes-192-cbc");
    if(!cipher) { fprintf(stderr, "no such cipher\n"); return 1; }

    dgst=EVP_get_digestbyname("md5");
    if(!dgst) { fprintf(stderr, "no such digest\n"); return 1; }

    if(!EVP_BytesToKey(cipher, dgst, salt,
        (unsigned char *) password,
        strlen(password), 1, key, iv))
    {
        fprintf(stderr, "EVP_BytesToKey failed\n");
        return 1;
    }
    printf("salt: "); for(i=0; i<PKCS5_SALT_LEN; ++i) { printf("%02x", salt[i]); } printf("\n");
    printf("Key: "); for(i=0; i<cipher->key_len; ++i) { printf("%02x", key[i]); } printf("\n");
    printf("IV: "); for(i=0; i<cipher->iv_len; ++i) { printf("%02x", iv[i]); } printf("\n");

    if (in != NULL) BIO_free(in);

    return 0;
}

int do_crypt(FILE *in, FILE *out)
{
    #define BSIZE   (8*1024)
    char inbuf[BSIZE]={0}, outbuf[BSIZE + EVP_MAX_BLOCK_LENGTH]={0};

    int inlen, outlen;
    char * needle =NULL;
    char mblock[1024];
    int blocksize=0;

    EVP_CIPHER_CTX ctx;
    EVP_CIPHER_CTX_init(&ctx);

    blocksize = EVP_CIPHER_block_size(cipher);
    printf("block size %d\n",blocksize);

    fread(mblock,1,blocksize,in);//skip the magic size

    //EVP_CIPHER_CTX_set_padding(&ctx, 1);
    //do_encrypt:1 for encryption,0 for decryption
    EVP_CipherInit_ex(&ctx,cipher, NULL, key, iv, 0);


    for(;;)
    {
        bzero(inbuf,sizeof inbuf);
        inlen = fread(inbuf, 1, BSIZE, in);
        if(inlen <= 0) break;
        bzero(outbuf,sizeof outbuf);
        if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen))
        {
            /* Error */
            EVP_CIPHER_CTX_cleanup(&ctx);
            return 0;
        }

        fwrite(outbuf, 1, outlen, out);
    }
    if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen))
    {
        /* Error */
        EVP_CIPHER_CTX_cleanup(&ctx);
        return 0;
    }
    fwrite(outbuf, 1, outlen, out);
    EVP_CIPHER_CTX_cleanup(&ctx);
    return 1;
}

int main(int argc,char**argv)
{
    FILE *in=fopen(argv[1],"rb");
    FILE *out=fopen(argv[2],"wb");
    if ( argc != 3){
        printf("Usage: in_file_to_be_decryped out_file%d\n",argc);
        return;
    }
    if (NULL ==in){
        printf("error fopen\n");
        return 0;
    }
    pass2keyiv(argv[1]);
    do_crypt(in,out);
    fclose(in);
    fclose(out);
    return 0;
}