通过openssl非对称加密解密

最近有项目需要实现加密和解密,实际使用通过openssl的对称加密去实现。在看了对称加密后,顺便也看了一下非对称加密(以RSA为例),在此做一下记录,便于今后要用的时候可以回头来看看。

一、命令行的方式

1. 生成秘钥

openssl genrsa -out private.pem 秘钥长度默认为1024

2. 根据私钥导出公钥

openssl rsa -in private.pem -pubout -out public.pem

3. 通过公钥对文件进行加密

openssl rsautl -encrypt -pubin -inkey public.pem -in plainFile -out encryptedFile

注意,这里使用公钥的话,需要写成 -pubin -inkey,单独-inkey表示私钥。因此通过私钥加密的话,命令行如下所示:

openssl rsautl -encrypt -inkey private.pem -in plainFile -out encryptedFile

4. 通过私钥进行解密

openssl rsautl -decrypt -inkey private.pem -in encryptedFile -out plainFile

解密我试了一下,只能通过私钥来进行。

但是如果直接使用秘钥来加密、解密的话,对内容长度有限制。比如秘钥长度为1024时,加密的时候,最多只能加密124个字节,所以文件长度超过124个字节时,就会报错。如果要加密、解密大文件,可以通过证书和smime应用来进行。

5. 大文件的加密和解密

生成私钥和证书:

sudo openssl req -x509 -nodes -days 100000 -newkey rsa:2048 -keyout private.pem -out cacert.pem

生成私钥和证书的时候,会要求输入信息,国家、省份等信息。

注:证书是用来确保被访问的对象是可信的。但是证书本身如何证明是可靠的呢?证书由机构发布(CA),证书上带有机构的签名。通讯过程中,客户端与服务器建立连接后,服务器将证书发给客户端。客户端利用CA的公钥对证书签名进行验证。因此从证书可以到处公钥,通过openssl x509 -in cacert.pem -pubkey -noout -out demo.pem。这里demo.pem就是公钥。同样的,也可以使用rsa指令根据私钥去到处公钥,经过对比,两种方式导出的公钥是一模一样的。

通过证书对文件进行加密:

openssl smime -encrypt -in plainFile -out encryptedFile cacert.pem

通过私钥对文件进行解密:

openssl smime -decrypt -in encryptedFile -out plainFile -inkey private.pem

二、调用EVP函数实现

1.加密

加密主要通过EVP_Seal**函数去实现。包括EVP_SealInit,EVP_SealUpdate和EVP_SealFinal。

2.解密

解密主要通过EVP_Open**函数去实现。包括EVP_OpenInit,EVP_OpenUpdate和EVP_OpenFinal。

3. demo

int test_EVP_Enveloped(void)
{
    int ret = 0;
    EVP_CIPHER_CTX *ctx = NULL;
    EVP_PKEY *keypair = NULL;
    unsigned char *kek = NULL;
    unsigned char iv[EVP_MAX_IV_LENGTH];
    static const unsigned char msg[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    int len, kek_len, ciphertext_len, plaintext_len;
    unsigned char ciphertext[32], plaintext[16];
    const EVP_CIPHER *type = EVP_aes_256_cbc();

    if (!TEST_ptr(keypair = load_example_rsa_key())
            || !TEST_ptr(kek = OPENSSL_zalloc(EVP_PKEY_size(keypair)))
            || !TEST_ptr(ctx = EVP_CIPHER_CTX_new())
            || !TEST_true(EVP_SealInit(ctx, type, &kek, &kek_len, iv,
                                       &keypair, 1))
            || !TEST_true(EVP_SealUpdate(ctx, ciphertext, &ciphertext_len,
                                         msg, sizeof(msg)))
            || !TEST_true(EVP_SealFinal(ctx, ciphertext + ciphertext_len,
                                        &len)))
        goto err;

    ciphertext_len += len;

    if (!TEST_true(EVP_OpenInit(ctx, type, kek, kek_len, iv, keypair))
            || !TEST_true(EVP_OpenUpdate(ctx, plaintext, &plaintext_len,
                                         ciphertext, ciphertext_len))
            || !TEST_true(EVP_OpenFinal(ctx, plaintext + plaintext_len, &len)))
        goto err;

    plaintext_len += len;
    if (!TEST_mem_eq(msg, sizeof(msg), plaintext, plaintext_len))
        goto err;

    ret = 1;
err:
    OPENSSL_free(kek);
    EVP_PKEY_free(keypair);
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

你可能感兴趣的:(openssl,ssl)