使用evp_sealinit / evp_openinit api时,我没有得到正确的数据(通常是前16个字节)。我在这做错了什么?

时间:2011-12-20 22:23:31

标签: openssl rsa public-key

我在这里做错了什么?我一定错过了什么..

我正在使用EVP_Seal / EVP_Open API。我已经生成了公钥/私钥和证书。我看到了一些奇怪的东西 - 我解码后的第一个16字节是垃圾。如果我的数据很小(小于16字节),那么我没有从EVP_Open函数获得任何输出。

继承我的测试计划:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #include <openssl/ssl.h>
    #include <openssl/err.h>
    #include <openssl/rsa.h>
    #include <openssl/pem.h>
    #include <openssl/err.h>
    #include <openssl/rand.h>

    #define PORT 6999
    #define HOST "localhost"

    #define PUBLIC_KEYFILE "pubkey.pem"
    #define CERT_FILE "server.crt"

    #define PRIVATE_KEYFILE "server.key"

    void run_client(void);

    EVP_CIPHER_CTX en_ctx;
    EVP_CIPHER_CTX de_ctx;

    typedef struct {
    int keylen;
    unsigned char key[512];
    unsigned char iv[EVP_MAX_IV_LENGTH];
     } keys_t;

     unsigned char msg[1024];
     unsigned char enc_buf[1024];
     unsigned char de_buf[1024];


     int main(int argc, char **argv)
     {

     // Init malloc, free etc for OpenSSL's CRYPTO_malloc_init();
     ERR_load_BIO_strings();    
     OpenSSL_add_all_algorithms();
     run_client();

     return 0;  

     }

     int encrypt_with_cert(unsigned char **secret_key, int *keylen, 
                           unsigned char **out_iv, 
                   unsigned char *data, int *datalen)
    {
    FILE *fp;
    X509 *x509;
    EVP_PKEY *pkey;

        unsigned char *ek;
        int eklen;
    int retval = 0;
    unsigned char iv[EVP_MAX_IV_LENGTH];
    int i=0;

        RAND_pseudo_bytes(iv, EVP_MAX_IV_LENGTH);

        fp = fopen(CERT_FILE, "r");
    if (!fp) {
      fprintf(stderr, "Cannot open certificate file\n");
      goto out;
    }

    x509 = PEM_read_X509(fp, NULL, 0, NULL);
    if (x509 == NULL) {
      ERR_print_errors_fp(stderr);
      goto out;
    }
    fclose(fp);

    pkey = X509_extract_key(x509);

    X509_free(x509);

    if (pkey == NULL) {
      ERR_print_errors_fp(stderr);
    }

    EVP_CIPHER_CTX_init(&en_ctx);
    ek = malloc(EVP_PKEY_size(pkey));

    if (!EVP_SealInit(&en_ctx, EVP_aes_256_cbc(), &ek, 
                          &eklen, iv, &pkey, 1)) {
      fprintf(stderr, "EVP_SealInit failed\n");
      retval = 3;
      goto out_free;
    }

     int buf_len = 0;
     int tot_len = 0;

     printf("Encoding string: {%s}, len: %d\n", data, *datalen);
     memset(enc_buf, 0 , 1024);

     EVP_SealInit(&en_ctx, NULL, NULL, NULL, NULL, NULL, 1);
     EVP_SealUpdate(&en_ctx, enc_buf, &buf_len, data, *datalen);
     tot_len += buf_len;

     EVP_SealFinal(&en_ctx, enc_buf+buf_len, &buf_len);
     tot_len += buf_len;

     *(enc_buf + tot_len) = '\0';
     *datalen = tot_len;

     printf("Encoded length: %d\n", tot_len);
     printf("Encoded message: {");
     for (i=0; i< tot_len; i++) {
    printf("%02x", enc_buf[i]);
     }
     printf("}\n");

     goto out;

      out_free:
     EVP_PKEY_free(pkey);
     free(ek);

      out:
    *secret_key = ek;
    *keylen = eklen;
    *out_iv = iv;
    return retval;
    }

    void decrypt_message(unsigned char *secret_key, int keylen, 
                         unsigned char *iv, int buflen)
    {
    FILE *privkey;

    int retval = 0;
    int klen=0;

    int tot_len = 0;
    EVP_PKEY *pkey;
    int i = 0;

    privkey = fopen(PRIVATE_KEYFILE, "r");
    if (!privkey) {
      fprintf(stderr, "Error opening private key\n");
        }   

    pkey = PEM_read_PrivateKey(privkey, NULL, 0 , NULL);
    if (!pkey) {
      fprintf(stderr, "Error loading Server's RSA private key\n");
      retval = 2;
      goto out; 
    }


    if(keylen != EVP_PKEY_size(pkey)) {
       EVP_PKEY_free(pkey);
       fprintf(stderr, "keylength mismatch!\n");
       retval = 2;
       goto out;
    }       

    klen = EVP_OpenInit(&de_ctx, EVP_aes_256_cbc(), secret_key, keylen, iv, pkey);
    if (klen == 0) {
      fprintf(stderr, "EVP_OpenInit failed\n");
    }

    int de_len = 0;
    tot_len = 0;

    printf("\n\nNow decoding..\n");
    printf("Encoded length: %d\n", buflen);
    printf("Encoded message: {");
    for (i=0; i< buflen; i++) {
      printf("%02x", enc_buf[i]);
    }
    printf("}\n");


    EVP_OpenInit(&de_ctx, NULL, NULL, keylen, NULL, NULL);
    EVP_OpenUpdate(&de_ctx, de_buf, &de_len, enc_buf, buflen);
    tot_len += de_len;


    EVP_OpenFinal(&de_ctx, de_buf+tot_len, &de_len);
    tot_len += de_len;
    *(de_buf+tot_len) = '\0';


    printf("Decoded length: %d,  String: %s\n", tot_len, de_buf);

     out:
    fclose(privkey);
return;
    } 

   void run_client()
   {

    unsigned char *secret_key = NULL;
    int keylen;
    unsigned char *iv = NULL;
    int data_len = 0;
    int retval = 0;

    //strcpy((char *)msg, "abcdefghijklmnopqrstuvwxyz0123456789");
    //strcpy((char *)msg, "this is a secret message\n");


        strcpy((char *)msg, "1234567890");

        data_len = strlen((char *)msg) + 1; 

    retval = encrypt_with_cert(&secret_key, &keylen, &iv, msg, &data_len);
    if (retval != 0) {
    printf("encrypt with certificate failed! retval = %d\n", retval);
    }

    decrypt_message(secret_key, keylen, iv, data_len);

    }

当我在这里运行时,我得到的是:         [示例] $ gcc -Wall -g -o openssl_seal -lcrypto openssl_seal.c

    [sample]$ ./openssl_seal
    Encoding string: {1234567890}, len: 11
    Encoded length: 16
    Encoded message: {9753c483d6816b64693f604b2376f0a0}


    Now decoding..
    Encoded length: 16
    Encoded message: {9753c483d6816b64693f604b2376f0a0}
    Decoded length: 0,  String:


   [sample]$ gcc -Wall -g -o openssl_seal -lcrypto openssl_seal.c
   [sample]$ ./openssl_seal
   Encoding string: {abcdefghijklmnopqrstuvwxyz0123456789}, len: 37
   Encoded length: 48
   Encoded message:          {ad264f30fe70cc6f9c8d712073bc72049e7f7515a28c1cf0aeef648d6c4c4bfd717ae2fd21396bb95eb7ec0ce88f7f9d}


   Now decoding..
   Encoded length: 48
   Encoded message: {ad264f30fe70cc6f9c8d712073bc72049e7f7515a28c1cf0aeef648d6c4c4bfd717ae2fd21396bb95eb7ec0ce88f7f9d}
   Decoded length: 37,  String: abcd.VO[vтOqrstuvwxyz0123456789

1 个答案:

答案 0 :(得分:0)

看起来您正在调用EVP_SealInit两次,并且第二次忽略iv参数。您应该只调用此方法一次,保存IV参数并将其传输到解密端。同样,您只应拨打EVP_OpenInit一次。