【问题标题】:Load rsa private key from integers and convert to PEM format or RSA structure in openssl to sign message从整数加载 rsa 私钥并在 openssl 中转换为 PEM 格式或 RSA 结构以对消息进行签名
【发布时间】:2015-06-01 12:34:35
【问题描述】:

我有 RSA 密钥的 public exponent(e)、modulus(n) 和 private exponent(d),如何将它们转换为 PEM 格式的 RSA 密钥或定义的 RSA 结构在 openssl 中?

我想使用带有 openssl 的 RSA 私钥对文本进行签名,可以使用 C 代码或 openssl 实用程序。

我搜索了互联网,有相当多的帖子可以从PEM 键中提取参数,但未能找到有关如何使用C 将它们转换回 PEM 的有用信息。好像这不是常见的场景……

编辑:对不起,标题有点误导,我的最终目的是用它来签署消息(如描述中所述)

【问题讨论】:

  • "... 或 openssl 实用程序是可以接受的" - 如果您需要有关使用 OpenSSL 命令的帮助,那么您应该询问 Super UserUnix & Linux Stack Exchange。 Stack Overflow 是一个编程和开发问答网站。 Super UserUnix & Linux Stack Exchange 是帮助您使用命令的网站。
  • @jww ,其实我想用c程序来实现,但是如果有openssl命令可以解决这个问题,我可以通过引用openssl的源代码来制作我的程序...

标签: openssl rsa pem


【解决方案1】:

RSA 数学只需要nd 来实现签名。此外,OpenSSL 的实现也只需要nd 进行签名。您可以直接在 RSA 结构中设置这些值。此示例仅显示“...在 C 代码中使用带有 openssl ... 的 RSA 私钥签名文本”的示例,并忽略您的 PEM 查询。

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/evp.h>

static void printerrors() {
    char errbuf[1024];
    while (1) {
        unsigned long error = ERR_get_error();
        if (error == 0) {
            break;
        }
        ERR_error_string(error, errbuf);
        fputs(errbuf, stderr);
    }
    fflush(stderr);
}

static void sign(RSA *rsa, const char *message) {
    EVP_PKEY *pkey = EVP_PKEY_new();
    if (!EVP_PKEY_set1_RSA(pkey, rsa)) goto err;
    EVP_MD_CTX *ctx = EVP_MD_CTX_create();
    if (!EVP_DigestSignInit(ctx, NULL, EVP_sha256(), NULL, pkey)) goto err;
    if (!EVP_DigestSignUpdate(ctx, (const void * ) message, strlen(message))) goto err;
    size_t siglen;
    if (!EVP_DigestSignFinal(ctx, NULL, &siglen)) goto err;
    unsigned char *signature = malloc(siglen);
    if (signature == NULL) goto err;

    if (!EVP_DigestSignFinal(ctx, signature, &siglen)) goto err;

    for (int i = 0; i < siglen; i++) {
        printf("%02x", signature[i]);
    }
    printf("\n");
    free(signature);
    EVP_MD_CTX_destroy(ctx);
    EVP_PKEY_free(pkey);

    return;
err:
    printerrors();
    exit(1);
}

int main(int argc, char *argv[]) {
    const int BITS = 1024;
    const int PUBLIC_EXPONENT = 65537;
    OpenSSL_add_all_algorithms();
    RSA *rsa = RSA_generate_key(BITS, PUBLIC_EXPONENT, NULL, NULL);

    RSA *rsa2 = RSA_new();
    rsa2->n = BN_dup(rsa -> n);
    rsa2->e = BN_dup(rsa -> e);
    rsa2->d = BN_dup(rsa -> d);

    RSA_print_fp(stdout, rsa2, 0);
    sign(rsa2, "Sign me, please");
    RSA_free(rsa2);
    RSA_free(rsa);
}

通常与私钥相关联的其他值,pq 等并非绝对必要。如果存在,它们可用于加速私钥操作,包括利用中国剩余定理进行签名。此外,如果需要,它们可以很容易地从 nde 派生出来:例如参见 section 8.2.2 (i) of the Handbook Of Applied Cryptography

【讨论】:

  • 它有效,非常感谢!我曾经认为openssl可能需要更多参数来执行rsa签名操作(如@ice13berg所列,除了ndd之外还有很多其他字段)
【解决方案2】:

我认为您并不具备 RSA 密钥所需的一切。具体来说,您没有生成 RSA 密钥所需的素数 pq

RSA 密钥需要用于计算 ned 的原始素整数,因此仅拥有它们不足以生成完整的 RSA 密钥。

有关更多信息,请参阅有关 ASN1 编码的文档 here

编辑:@GregS:nd 对于公私密钥对来说是不够的,因为 e 实际上是密钥 (n,e)(d,e) 的一部分。

here可以看出,RSA私钥需要prime1, pprime2, q,而公钥只需要(n,e)

RSA 私钥文件 (PKCS#1) RSA 私钥 PEM 文件专用于 RSA 密钥。

RSAPrivateKey ::= SEQUENCE {
      version           Version,
      modulus           INTEGER,  -- n
      publicExponent    INTEGER,  -- e
      privateExponent   INTEGER,  -- d
      prime1            INTEGER,  -- p
      prime2            INTEGER,  -- q
      exponent1         INTEGER,  -- d mod (p-1)
      exponent2         INTEGER,  -- d mod (q-1)
      coefficient       INTEGER,  -- (inverse of q) mod p
      otherPrimeInfos   OtherPrimeInfos OPTIONAL
    }

【讨论】:

  • 只需要nd
  • @GregS - 我在野外看到过使用非标准 e 的证书(即不是 3、17 或 65535)。在这些情况下,您无法猜测 e 是一个众所周知的值。
  • @jww:要签名,这是 OP 要求的,只需要 n 和 d。
  • 感谢这一点,其实我发现RSA结构中参数太多了,所以我不确定我是否可以只用nd@987654343来签名消息@ -- 幸运的是它起作用了。
猜你喜欢
  • 2016-04-07
  • 1970-01-01
  • 2023-02-07
  • 2012-06-15
  • 1970-01-01
  • 1970-01-01
  • 2010-11-03
  • 2021-07-14
  • 2014-01-13
相关资源
最近更新 更多