首页 文章

从整数加载rsa私钥并在openssl中转换为PEM格式或RSA结构以签名消息

提问于
浏览
2

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

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

我有很多帖子可以从 PEM 键中提取参数,但未能找到有关如何使用 C 将它们转换回PEM的有用信息 . 似乎这不是常见的情况......

编辑:对不起, Headers 有点误导,我的最终目的是用它来签名留言(如说明中所述)

2 回答

  • 2

    RSA数学只需要 nd 来实现签名 . 此外,OpenSSL的实现也只需要 nd 来进行签名 . 您可以直接在RSA结构中设置这些值 . 此示例仅显示"...sign text with RSA private key with openssl ... in C code"的示例,并忽略您的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 .

  • 0

    我没有生成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
        }
    

相关问题