TL; DR: OpenSSLは廃止予定のいくつかのレガシーフォーマットをサポートしています。入力がRSA秘密鍵のペアの場合、openssl rsa -pubout
の特別なケースがあるようです。最後に、OPの暗号化(およびそれに対応する復号化)を成功させる2つのコマンドシーケンスを与えます。 1つはPEMではなくDERを使用し、もう1つはDERを最初に放出し、次にそれをPEMに変換します...奇妙なことに、openssl rsa
を使用して、入力がDERでエンコードされた公開鍵...とにかく、OPの最初の試みが失敗した理由の長い説明が以下にあります。 「なぜそんなに不十分な文書化がなされたのか」... OpenSSLへようこそ。グリフを高速化するので、ソースディレクトリ構造をよく学んでください。 format = FORMAT_PEM
へ:)
長い説明(詳細には、OpenSSL 1.0.2mから採取)
のOpenSSL rsautlアプリデフォルト-inform
引数(着信キー表現)。
それから、次のようなフォーマットを使用して、着信キーのリーダーを選択:
else if (format == FORMAT_PEMRSA) {
RSA *rsa;
rsa = PEM_read_bio_RSAPublicKey(key, NULL,
(pem_password_cb *)password_callback,
&cb_data);
/* ... */
}
else if (format == FORMAT_PEM) {
pkey = PEM_read_bio_PUBKEY(key, NULL,
(pem_password_cb *)password_callback,
&cb_data);
をので、私たちはPEM_read_bio_PUBKEY
を使用することがあります。上記のFORMAT_PEMRSA
のエントリに注意してください... PEM_read_bio_RSAPublicKey
につながるパスを同時に開発します。
# define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \
type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\
{ \
return PEM_ASN1_read_bio((d2i_of_void *)d2i_##asn1, str,bp,(void **)x,cb,u); \
}
:これらの読者の両方がいくつかのマクロ順番にと実際の定義を構築する
# define IMPLEMENT_PEM_read(name, type, str, asn1) \
IMPLEMENT_PEM_read_bio(name, type, str, asn1) \
IMPLEMENT_PEM_read_fp(name, type, str, asn1)
を使用することを
# define IMPLEMENT_PEM_rw(name, type, str, asn1) \
IMPLEMENT_PEM_read(name, type, str, asn1) \
IMPLEMENT_PEM_write(name, type, str, asn1)
# define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \
IMPLEMENT_PEM_read(name, type, str, asn1) \
IMPLEMENT_PEM_write_const(name, type, str, asn1)
に拡大
crypto/pem/pem_all.c:427:IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY)
crypto/pem/pem_all.c:241:IMPLEMENT_PEM_rw_const(RSAPublicKey, RSA, PEM_STRING_RSA_PUBLIC, RSAPublicKey)
経由で定義されています
r noteはバージョンの場合はPEM_STRING_PUBLIC
、PEM_read_bio_RsaPublicKey
バージョンの場合はPEM_STRING_RSA_PUBLIC
として渡される第3引数、str
です。これらの文字列は、それぞれ、
./crypto/pem/pem.h:122:# define PEM_STRING_PUBLIC "PUBLIC KEY"
./crypto/pem/pem.h:124:# define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY"
がPEM_ASN1_read_bio
の実装を見ると、我々はそれを部分に分割することも、重要なファイルを読み込みPEM_bytes_read_bio
void *PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x,
pem_password_cb *cb, void *u)
{
const unsigned char *p = NULL;
unsigned char *data = NULL;
long len;
char *ret = NULL;
if (!PEM_bytes_read_bio(&data, &len, NULL, name, bp, cb, u))
return NULL;
/* ... */
PEM_bytes_read_bio
呼び出して参照してください。 nm
は-----
秒の間にマーカーを取得します(-----BEGIN RSA PUBLIC KEY-----
など)。check_pem
でチェックされます。nm
ファイルで見つかった文字列、およびname
で次のように
int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
const char *name, BIO *bp, pem_password_cb *cb,
void *u)
{
EVP_CIPHER_INFO cipher;
char *nm = NULL, *header = NULL;
unsigned char *data = NULL;
long len;
int ret = 0;
for (;;) {
if (!PEM_read_bio(bp, &nm, &header, &data, &len)) {
if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE)
ERR_add_error_data(2, "Expecting: ", name);
return 0;
}
if (check_pem(nm, name))
そしてcheck_pem
チェックは、ハードコーディングされPEM_read_bio_XXX
関数であるから渡されました。
static int check_pem(const char *nm, const char *name)
{
/* Normal matching nm and name */
if (!strcmp(nm, name))
return 1;
/* special cases for
PKCS8 format (BEGIN PRIVATE KEY or BEGIN ENCRYPTED PRIVATE KEY)
Various things ending in PARAMETERS
Various X509 related files
PKCS7 format (BEGIN PKCS7 or BEGIN PKCS7 SIGNED DATA)
CMS things (BEGIN CMS) */
/* ... */
それはちょうどname
とnm
間strcmp
を行います。だから、PEM_read_bio_PUBKEY
でRSA公開鍵を正常に読むには、それは-----BEGIN PUBLIC KEY-----
で始まる必要がありますが、OPの指示で生成された鍵を見ると、-----BEGIN RSA PUBLIC KEY-----
が見つかります。しかし、これはPEM_read_bio_RsaPublicKey
に対応する文字列です... -inform
を代わりに使用してformat = FORMAT_PEMRSA
を選択し、rsautl
に公開鍵を読み取ることができます。 rsautl
は、str2fmt
というファンクションを使用して、-inform
引数を解析します。見てみましょう:
int str2fmt(char *s)
{
if (s == NULL)
return FORMAT_UNDEF;
if ((*s == 'D') || (*s == 'd'))
return (FORMAT_ASN1);
else if ((*s == 'T') || (*s == 't'))
return (FORMAT_TEXT);
else if ((*s == 'N') || (*s == 'n'))
return (FORMAT_NETSCAPE);
else if ((*s == 'S') || (*s == 's'))
return (FORMAT_SMIME);
else if ((*s == 'M') || (*s == 'm'))
return (FORMAT_MSBLOB);
else if ((*s == '1')
|| (strcmp(s, "PKCS12") == 0) || (strcmp(s, "pkcs12") == 0)
|| (strcmp(s, "P12") == 0) || (strcmp(s, "p12") == 0))
return (FORMAT_PKCS12);
else if ((*s == 'E') || (*s == 'e'))
return (FORMAT_ENGINE);
else if ((*s == 'H') || (*s == 'h'))
return FORMAT_HTTP;
else if ((*s == 'P') || (*s == 'p')) {
if (s[1] == 'V' || s[1] == 'v')
return FORMAT_PVK;
else
return (FORMAT_PEM);
} else
return (FORMAT_UNDEF);
}
いいえ。 FORMAT_PEMRSAを返す方法はありません。
マーカを-----BEGIN PUBLIC KEY-----
と言うように公開鍵ファイルを編集するとどうなりますか?
$ sed -e "s/RSA PUBLIC/PUBLIC/" public_key.pem > public_key_mod.pem
$ echo "this is the cleartext" | openssl rsautl -encrypt -out encrypted_with_pub_key -pubin -inkey public_key_mod.pem
unable to load Public Key
いいえ。
公開鍵をPEMではなくDERに抽出するとどうなりますか?
$ openssl rsa -in private_key.pem -out public_key.der -outform DER -pubout
writing RSA key
$ echo "this is the cleartext" | openssl rsautl -encrypt -out encrypted_with_pub_key -pubin -inkey public_key.der -keyform DER
$ openssl rsautl -decrypt -in encrypted_with_pub_key -inkey private_key.pem
this is the cleartext
成功!多分私達は、OpenSSLがrsautl
$ openssl rsa -in public_key.der -inform DER -pubin -out test.pem
writing RSA key
$ cat test.pem
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM3uGdU6YtwI5S8K+GgddW8KhrzmSFVI
6cvBT+XqOuSVo+n8VyUfADHw4rPxjy/dWDpyOxzWdTg8VZ77Vs06af8CAwEAAQ==
-----END PUBLIC KEY-----
$ echo "this is the cleartext" | openssl rsautl -encrypt -out encrypted_with_pub_key -pubin -inkey test.pem
$ openssl rsautl -decrypt -in encrypted_with_pub_key -inkey private_key.pem
this is the cleartext
と互換性のある形式にDERキーを変換するために取得することができ、それは、入力としてBEGIN RSA PRIVATE KEY
を取るときそうです...それはopenssl rsa
のように見えるだけ時代遅れBEGIN RSA PUBLIC KEY
フォームを書き込みます。