使用OpenSSL API读取公用密钥的密码回调 [英] Password callback for reading public key with OpenSSL API

查看:163
本文介绍了使用OpenSSL API读取公用密钥的密码回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用公钥加密时,通常习惯以加密格式存储私钥,因为它们当然被认为是秘密.这在OpenSSL C API中得到了反映,该API提供了PEM_write_PrivateKey之类的功能,该函数将用于加密密钥(例如AES)的可选密码作为函数参数.然后,当从磁盘读回加密密钥时,OpenSSL API提供诸如PEM_read_PrivateKey之类的功能,该功能允许用户提供用作回调的函数指针,以便应用程序可以向OpenSSL提供加密密钥的密码. /p>

但是令我困惑的是,OpenSSL API似乎还允许用户在读取 Public 密钥时提供密码回调.例如,用于读取公共密钥的一个API函数签名是:

 EVP_PKEY *PEM_read_PUBKEY(FILE *fp, EVP_PKEY **x,
                                        pem_password_cb *cb, void *u);

那么在读取公共密钥时提供密码回调的目的是什么? AFAIK加密公共密钥是没有意义的,因为根据定义,公共密钥应该对公众可用.那么,为什么OpenSSL API的函数参数在此处需要进行密码回调?

解决方案

RFC 1421 中定义了隐私增强邮件(PEM)的消息加密您的问题,有趣的是查看示例消息 第4.6节封装的标题字段摘要"

-----BEGIN PRIVACY-ENHANCED MESSAGE-----
Proc-Type: 4,ENCRYPTED
Content-Domain: RFC822
DEK-Info: DES-CBC,F8143EDE5960C597
Originator-ID-Symmetric: linn@zendia.enet.dec.com,,
Recipient-ID-Symmetric: linn@zendia.enet.dec.com,ptf-kmc,3
Key-Info: DES-ECB,RSA-MD2,9FD3AAD2F2691B9A,
          B70665BB9BF7CBCDA60195DB94F727D3
Recipient-ID-Symmetric: pem-dev@tis.com,ptf-kmc,4
Key-Info: DES-ECB,RSA-MD2,161A3F75DC82EF26,
          E2EF532C65CBCFF79F83A2658132DB47

LLrHB0eJzyhP+/fSStdW8okeEnv47jxe7SJ/iN72ohNcUk2jHEUSoH1nvNSIWL9M
8tEjmF/zxB+bATMtPjCUWbz8Lr9wloXIkjHUlBLpvXR0UrUzYbkNpk0agV2IzUpk
J6UiRRGcDSvzrsoK+oNvqu6z7Xs5Xfz5rDqUcMlK1Z6720dcBWGGsDLpTpSCnpot
dXd/H5LMDWnonNvPCwQUHt==
-----END PRIVACY-ENHANCED MESSAGE-----

查看OpenSSL的1.1分支,它具有功能 支持读取此类消息并将其拆分为其名称(如第一行所示),标头(其下的名称/值对)和数据(以base64编码的内容):

 int PEM_read_bio(BIO *in, char **name, char **header,
                  unsigned char **data, long *len);

所有OpenSSL PEM_read_XYZ()函数有时会从

When using public key cryptography, it is often customary to store private keys in an encrypted format, since they are of course supposed to be a secret. This is reflected in the OpenSSL C API, which provides functions like PEM_write_PrivateKey, which takes as function arguments an optional cipher to use to encrypt the key (like AES). Then, when reading the encrypted key back in from disk, the OpenSSL API provides functions like PEM_read_PrivateKey, which allows the user to provide a function pointer used as a callback so the application can provide OpenSSL with the password for the encrypted key.

But what confuses me is that the OpenSSL API also seems to let the user provide a password callback when reading in a Public key. For example, one API function signature for reading in a public key is:

 EVP_PKEY *PEM_read_PUBKEY(FILE *fp, EVP_PKEY **x,
                                        pem_password_cb *cb, void *u);

So what is the purpose of providing a password callback when reading in a public key? AFAIK it makes no sense to encrypt a public key, since a public key is by definition supposed to be available to the general public. So why does the OpenSSL API have a function parameter here that takes a password callback?

解决方案

As mentioned in this comment, any PEM-encoded data can be encrypted. Message encryption for privacy-enhanced mail (PEM) is defined in RFC 1421 and in the context of your question, it is interesting to look at the example message in section 4.6 Summary of Encapsulated Header Fields

-----BEGIN PRIVACY-ENHANCED MESSAGE-----
Proc-Type: 4,ENCRYPTED
Content-Domain: RFC822
DEK-Info: DES-CBC,F8143EDE5960C597
Originator-ID-Symmetric: linn@zendia.enet.dec.com,,
Recipient-ID-Symmetric: linn@zendia.enet.dec.com,ptf-kmc,3
Key-Info: DES-ECB,RSA-MD2,9FD3AAD2F2691B9A,
          B70665BB9BF7CBCDA60195DB94F727D3
Recipient-ID-Symmetric: pem-dev@tis.com,ptf-kmc,4
Key-Info: DES-ECB,RSA-MD2,161A3F75DC82EF26,
          E2EF532C65CBCFF79F83A2658132DB47

LLrHB0eJzyhP+/fSStdW8okeEnv47jxe7SJ/iN72ohNcUk2jHEUSoH1nvNSIWL9M
8tEjmF/zxB+bATMtPjCUWbz8Lr9wloXIkjHUlBLpvXR0UrUzYbkNpk0agV2IzUpk
J6UiRRGcDSvzrsoK+oNvqu6z7Xs5Xfz5rDqUcMlK1Z6720dcBWGGsDLpTpSCnpot
dXd/H5LMDWnonNvPCwQUHt==
-----END PRIVACY-ENHANCED MESSAGE-----

Looking at the 1.1 branch of OpenSSL it has a function PEM_read_bio() that supports reading such a message and splitting it into its name (as given in the top line), header (the name-value pairs below that) and data (the base64-encoded stuff):

 int PEM_read_bio(BIO *in, char **name, char **header,
                  unsigned char **data, long *len);

All OpenSSL PEM_read_XYZ() functions at some point invoke it, from PEM_bytes_read_bio(), because they are all implemented in the same way by means of macro expansions. That function contains the following calls:

PEM_read_bio(bp, &nm, &header, &data, &len)

to split the message, then

PEM_get_EVP_CIPHER_INFO(header, &cipher);

to figure out which type of encryption information is found in the header of that message and fill an EVP_CIPHER_INFO object with it, and then

PEM_do_header(&cipher, data, &len, cb, u);

to do the decryption of the data based on the cipher information found -- again if needed. Note the cb parameter which stands for callback, a mechanism to get input for any passphrase if needed.

Now what might be confusing, is that certain private key formats, like for example PKCS#8, also have their own mechanism of storing encryption information independent of the PEM encoding. Technically speaking, it should be possible to apply encryption to such keys twice: once at the PEM level and once at the PKCS#8 level. The OpenSSL tools for generating or converting to PKCS#8 formatted keys do not seem to offer that option though. Also, none of the tools seem to expose the option of encrypting any generated public key PEM files, unless a private key is included as well.

You can check some of the outputs to see if they match my story. First, generating an RSA key pair to a PKCS#1 format, nothing encrypted:

$ openssl genrsa
Generating RSA private key, 2048 bit long modulus (2 primes)
.................+++++
............+++++
e is 65537 (0x010001)
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAlcnR/w7zPoLrhuqFvcfz5fn8DFb0fEcCKOKSj+x+JJxGth9P
rJbxkt4pRXxbMIL0fX59HN5bRvQh2g59l/kfr30kCOnclap9nRrohWyg2i7720Cw
<truncated>

Then the same command, but using encryption, which happens at the PEM level, as you can see in the headers:

$ openssl genrsa -des3
Generating RSA private key, 2048 bit long modulus (2 primes)
.....................+++++
....................+++++
e is 65537 (0x010001)
Enter pass phrase:
Verifying - Enter pass phrase:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,D90861647707F687

DIupLghCjcvpLenqAAULaJj1EDvUUfc2Xc58YVh7rMTSVgLwZ+9CtnUQJcup4aUQ
a1EdGXTadwBQB2jTtiFJbH67/5D26PHXPnM+YN2rnoReOExVS7hKu3DTq7c4j6a3
<truncated>

Finally generating a similar key but now to PKCS#8, which has its own encryption and therefore does not get encrypted at the PEM level. You can see that the PEM headers are not there.

$ openssl genpkey -algorithm RSA -des3
.........................................+++++
...........................................................................+++++
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIV0Ih4bsI6egCAggA
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECNOim8HAN8j5BIIEyEe05hHtc8HL
<truncated>

If all my reasoning is correct, then the prompt "Enter PEM pass phrase" is inaccurate since this is not a PEM-level encryption but a PKCS#8-level encryption.

这篇关于使用OpenSSL API读取公用密钥的密码回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆