首页 文章

使用EVP和OpenSSL,用C编码

提问于
浏览
1

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

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

我需要做的是:

  • 取消签名 symmetrickey.bin 并将其存储到文本文件中 .

  • 使用 symmetrickey.txt 和某些算法(如AES)加密 message.txt .

  • 使用 privatekey_A.pem 对加密的消息进行签名并写入文件 cipher.bin .

  • 之后我需要取消签名并验证 cipher.bin 上的签名 .

  • 然后使用我们的对称密钥解密消息,然后写入另一个文件 .

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

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

1 回答

  • 1

    对于sign / unsign键部分,我需要进一步的信息,这个签名是如何完成的?例如,此签名在文件末尾是否为X字节长度,然后可以轻松删除?

    对于列表中的项目2-5,以下代码肯定会有所帮助,它基于openssl文档中的示例,其中包含更多注释和调整以满足您的需求 . 如果您有任何未评论的问题,请随时询问!

    crpytor.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以进行解密 . 它使用私钥priv解密在ek参数中传递的长度为ekl字节的加密对称密钥 . IV以iv参数提供 . EVP_OpenUpdate()和EVP_OpenFinal()具有与EVP_DecryptUpdate()和EVP_DecryptFinal()例程完全相同的属性,如EVP_EncryptInit(3)手册页中所述 .

    EVP_OpenInit() 用于密钥文件

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

相关问题