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_Seal**函数去实现。包括EVP_SealInit,EVP_SealUpdate和EVP_SealFinal。
解密主要通过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;
}