c - 使用 OpenSSL C API 读取 PEM 格式的 RSA key 文件

标签 c cryptography openssl

我正在尝试读入使用 Ruby 和 OpenSSL API 生成的 AES-128-CBC 加密 PEM key 文件。生成 PEM key 的代码如下:

OpenSSL::PKey::RSA.new(2048).to_pem(OpenSSL::Cipher::AES.new('128-CBC'), "password")

这是读取 PEM 文件的代码:

RSA *rsa;

BIO *pem = BIO_new(BIO_s_mem());
BIO_puts(pem, "-----BEGIN RSA PRIVATE KEY-----\n"
  "Proc-Type: 4,ENCRYPTED\n"
  "DEK-Info: AES-128-CBC,BB13D39833DD6ED1FF9843644E7981EE\n\n
  "Eugt8JZNKQKErsabWkwfm3wQhU/Tmp9T0QaP5HM8VIWpZwKlDmRlSUDptADU6RPD\n"
  "5VtG3DPieXcf+6deyARImid9sBBmQ9mK2omkNRcTMemqTOhAuaKBu78TMt9G4YSf\n"
  "RjoXWSqu3jMwrlcGkpn7bIum8wImITRZ3p28oSzk9aDUNBrIU/2Si8DM4RYIZ/fK\n"
  "Uvvgdok9dgcd0SjvucivX2HaGeg/IUz23q1jg9inDpimZvFJD1FJfGEUWDgyfJfa\n"
  "M8JIxTKbWOPEopONDkT7u4dC5VcSjK29MVbfd7iCKFPMh5UN+c96rPxTng/OWyW5\n"
  "0tvzHyyyvAG9p0Hx5Lr4pDbv21GHyu43sA6wbs9jWyqO3AB7CaoEEQhumwfLsdjj\n"
  "YGrX6bWThpYv/XNBDmmvltHlKFfe01NCybivOb4KwBnvi45x21PBqaZCKDTFdEkL\n"
  "iwDMTiG2iTxSUvPFLy30VFozE+pGyMcGDUyZDVqjsaqI/MRj8khnn5nyubXc27G3\n"
  "8Kbsnlix2SW2M0VDxqiy9dyjcxXrkFRSnOFYVs1PFlgjFVTG4Mwh6CZxKw8mFVbi\n"
  "EmLvUYwzoDZ1ve4VXSPp/vrKEh33JuHhM0vJOpqI6wqw0QR0I2o6etM1ZRJClPcw\n"
  "VIcgcvwenEgLOkoHDqOr0IZQAtYWvAuqq822wKt258hc6z8+ALQf5iMroqk7ADd4\n"
  "FlRLz4XTwqlg7pPtTde/emI1DT8dQWzq++QI0lr0CS/N1GXJKqTQDvauXLIiI3Qy\n"
  "KfFYFpV9jyYfRfTjNtisI/edPtp98auK0mb9o/wS/hruFI9behgv63iW1IwAOXCW\n"
  "ZlkWgobUH13gS864rL+AcrAXreo2j4dDQouTeRaJUEG0HoYTP65Zun/VsCi2aSOH\n"
  "JwSnnmHz9OxvcGY80WJDN3kqOCBRIJoDKBv6jcOxGVCsVK+WSdGZ7cfb8lwp7aA8\n"
  "8ND1bwL9FYkwkeIsoakj91iinqv4o3+3PUPgCU5oe68WYvAFjuU+criyf+EhmXJV\n"
  "JQ1vFFZPrGzgntJz19uXXh1h2iwQPggRouJm2RozYwvv1nz4eQ40Y3eT1F9UOYJU\n"
  "CKEhOtI2NpLeVOayqo8g9wO2oC+CQVhZhdYBE5o7pM7akFnYLvRg9s1UsWdcvT0G\n"
  "IpFmejLSRJ/F954aQMHTUc6vBOJZH/VNC5Qt+ulFXl634Sr9wQQK2qlqSJyA04TR\n"
  "1ixbCNOX71esvpFImsrlsO5oTA22T3h2GyJPUM10XhqGtDXtsTnal6smLna9U9B3\n"
  "gTVxFWWukQOF5Lm8ZFQipo2loHWjkozTBc4REPYP44SoXJXstv7k4pt1cK7x6/2H\n"
  "ElspXzjveqMhcrveWv1KaA2OGd+hGfUiNsCoIdapJjLz1Bd/+oIQ/ZWQeo0nRowE\n"
  "R/HlbbED3V+fRIdJpgydFEAw6gK5E9sYJcgF7uf/n2NabFxxEZL3g6MJQ64Dtusg\n"
  "DEH/MpvIYDSX4Navh1gTwCtOeG1CzW3diYaqbZK+UZCBLFU7j27YvVPSd6F2+Wud\n"
  "WnAqU3S5BCPqk5OD3wqZv+sEcqJgGPGy1Gv0tl8ARJomdKAru03KsRn2eIWqR5/C\n"
  "-----END RSA PRIVATE KEY-----\n");

// Retrieve RSA key from PEM file.
rsa = PEM_read_bio_RSAPrivateKey(pem, NULL, pem_password_callback, "password");

这是一个虚拟的密码回调(不确定这个函数的用途,但我认为它可能会返回密码的长度):

int pem_password_callback(char *buf, int max_len, int flag, void *pwd)
{
  return 8;
}

目前,rsa = ... 部分不会抛出错误,但也不会返回格式正确的结果。

最佳答案

And here's a dummy password callback (not sure about this function's purpose, but I think it may return the length of the password):

 int pem_password_callback(char *buf, int max_len, int flag, void *pwd)
 {
     return 8;
 }

不,它不是假人。在您的示例中,您刚刚返回了一个包含 8 个垃圾字符的缓冲区(buf 中的任何内容)。

密码回调是您以编程方式插入密码的地方。系统为您提供了一个 max_lenbuff,您需要将密码复制到缓冲区中并返回复制的字节数。

int pem_password_callback(char *buf, int max_len, int flag, void *ctx)
{
    const char* PASSWD = "password";
    int len = strlen(PASSWD);

    if(len > max_len)
        return 0;

    memcpy(buf, PASSWD, len);
    return len;
}

标志 是一个读/写标志,表示您是在读取 key 还是写入 key 。实际上,我从未使用过它。

您将使用它类似于:

FILE* file = ...;
EVP_PKEY* pkey = PEM_read_PrivateKey(file, NULL, pem_password_callback, NULL);

与写入例程(需要 EVP_* 密码)不同,读取例程知道您使用什么来加密 key ,因为它已编码在私钥中。

在我的系统中,我实际上使用标签的上下文来确保相同的密码到达不同的派生 key :

EVP_PKEY* pkey = PEM_read_PrivateKey(file, NULL, pem_password_callback, "Some Context");

然后,在我的密码回调中:

int pem_password_callback(char *buf, int max_len, int flag, void *ctx)
{
    // "Some Context" in the example above
    char* label = (char*)ctx;

    // Hash password and label
    // ...

    // Copy hash to buffer, return length
    ...
}

关于c - 使用 OpenSSL C API 读取 PEM 格式的 RSA key 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16675147/

相关文章:

c - 跨端口拆分时 PIC18 读/写数据

c - 十六进制 uint32_t 的 printf() 格式,不丢失零。 (在 c89 中)

java - 谁能告诉我在使用 RSA 的图像加密和解密过程中犯了什么错误

ssl - 链接具有相同主题的两个证书

c - epoll:当我在同一事件中获得 EPOLLOUT 和 EPOLLHUP 时,什么是适当的行为?

将 char *arr[] 作为 const char **arr 传递给函数时出现 c 编译器警告

math - 计算有限域中的乘法逆元

python - pyconfig.h 在 "pip install cryptography"期间丢失

ruby-on-rails - sendmail:OpenSSL::SSL::SSLError:主机名不匹配

c - 使用 RSA_PKCS1_OAEP_PADDING 进行 RSA 签名