1

我已经看到很多关于 OpenSSL 和 EVP 的问题,但没有太多明确的答案,但我想我仍然会在这里发布我的问题并希望得到更好的反馈。

给我的材料是一个签名文件“symmetrickey.bin”,一个RSA密钥集“privatekey_A.pem”,“publickey_A.pem”,以及另一个用户的公钥“publickey_B.pem”。

我需要做的是:

  1. 取消签名symmetrickey.bin并将其存储到文本文件中。
  2. message.txt例如,使用symmetrickey.txtAES 等算法对a 进行加密。
  3. 对加密消息进行签名privatekey_A.pem并写入文件cipher.bin
  4. 之后,我需要取消签名并验证cipher.bin.
  5. 然后用我们的对称密钥解密消息,然后写入另一个文件。

我遇到的问题是了解如何实现 OpenSSL EVP 库。API 页面不是很清楚每个函数的值来自哪里。例如,EVP_OpenInit()我从哪里得到ekek“ekl”的长度?“prvi”是私钥吗?我怎么知道类型?这些是我没有得到的东西。

我看过很多实现,但大多数都没有回答我的问题,或者他们给出了疯狂的代码,几乎没有解释发生了什么或值来自哪里。我在这里发帖作为最后的手段......

4

1 回答 1

1

对于签名/取消签名密钥部分,我需要更多信息,这个签名是如何完成的?例如,这个签名是否是文件末尾的 X 字节长度,然后可以轻松删除?

对于列表中的第 2-5 项,以下代码肯定会有所帮助,它基于 openssl 文档中的示例,并根据您的需要进行了更多注释和修改。如果您有任何未评论的问题,请随时询问!

密码器.c

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <openssl/evp.h>

#define APPNAME "C"

#define CHUNK_SIZE 512
int do_crypt(FILE *in, FILE *out, int do_encrypt)
{
    /* Allow enough space in output buffer for additional block */
    unsigned char inbuf[CHUNK_SIZE];
    unsigned char outbuf[CHUNK_SIZE + EVP_MAX_BLOCK_LENGTH];
    int inlen;
    int outlen;
    EVP_CIPHER_CTX ctx;
    /* Bogus key and IV: we'd normally set these from
     * another source.
     */
    unsigned char key[] = { 0x13, 0xa3, 0xb4, 0xc1, 0x24, 0x19, 0xf5, 0x23, 0x18, 0xef, 0xca, 0x12, 0x4c, 0x9f, 0x14, 0xfe };
    unsigned char iv[] = { 0x92, 0x1c, 0x23, 0x3f, 0x5e, 0x10, 0x3d, 0x9a };
    /* Don't set key or IV because we will modify the parameters */
    EVP_CIPHER_CTX_init(&ctx);
    /* Using Blowfish encryption with cbc algorithm, you can use whichever is supported in openssl if you wish */
    EVP_CipherInit_ex(&ctx, EVP_bf_cbc(), NULL, NULL, NULL, do_encrypt);
    EVP_CIPHER_CTX_set_key_length(&ctx, 16);
    /* We finished modifying parameters so now we can set key and IV */
    EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, do_encrypt);
    for(;;)
    {
        inlen = fread(inbuf, 1, CHUNK_SIZE, in);
        if(inlen <= 0) break;
        if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen))
        {
            /* Error */
            EVP_CIPHER_CTX_cleanup(&ctx);
            return -1;
        }
        fwrite(outbuf, 1, outlen, out);
    }
    if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen))
    {
        /* Error */
        EVP_CIPHER_CTX_cleanup(&ctx);
        return -1;
    }
    fwrite(outbuf, 1, outlen, out);
    EVP_CIPHER_CTX_cleanup(&ctx);
    rewind(in);
    rewind(out);
    return 0;
}

/* This is the standalone encryptor entry point */
int main(int argc, char** argv)
{
    FILE *encode_file;
    FILE *decode_file;
    int enc_or_dec;
    if (argc < 4)
    {
        printf("Usage: %s [plain file] [encrypted file] [0/1 deccrypt/encrypt]\n", argv[0]);
        return -1;
    }
    encode_file = fopen(argv[1], "r");
    decode_file = fopen(argv[2], "w+");
    /* Stupid decimal translation */
    enc_or_dec = *argv[3]-48;

    do_crypt(encode_file, decode_file, enc_or_dec);
    return 0;
}

和Makefile:

all:
    gcc cryptor.c -o cryptor -g -lcrypto -I ../openssl-1.0.1f-host/include
clean:
    rm cryptor

此代码不使用EVP_OpenInit(),因为它仅用于解密,而我的方法(和您的需要)需要加密或解密。虽然您可以使用EVP_OpenInit()初始化解密上下文,但我将仅适用于解密的单个调用替换为同时适用于加密和解密的两个调用。

从手册页:

EVP_OpenInit()使用密码类型初始化ctx用于解密的密码上下文。它使用私钥对参数中ekl 传递的长度字节的加密对称密钥进行解密。IV 在参数中提供。并具有与和 例程 完全相同的属性,如 手册页中所述。ekprivivEVP_OpenUpdate()EVP_OpenFinal()EVP_DecryptUpdate()EVP_DecryptFinal()EVP_EncryptInit(3)

EVP_OpenInit()对于关键文件

如果您所指的签名文件是 RSA/DSA 或类似格式的公钥文件,您可以使用这个 StackOverflow 问题获得比我更好的方法,因为它会自动从文件中提取密钥(并按照EVP_OpenInit()您的要求使用)

于 2015-04-26T06:30:41.247 回答