繁体   English   中英

使用 DER 二进制私钥对 SHA256 哈希进行签名

[英]Sign a SHA256 hash using a DER binary private key

假设你得到一个二进制私有文件,如下所示: Notepad++ 中二进制文件的屏幕截图 你知道它是 DER 编码的。

此外,二进制文件受密码保护,假设密码是“密码”

并且您想对一个已经散列的字符串进行签名 (RSA),换句话说,您要签名的数据实际上是一个 SHA256 散列,可能如下所示:

78/YCOiMFRP66tXunCviIi/GaDvgBWFudaWnfcSkU4M=

你想在 C++ 中使用 OpenSSL 来做到这一点。

我们如何做到这一点?

因为我没有网页,所以我会在这里发布这个,我想大多数人来这里是为了寻求答案。

首先,我们希望能够打开受密码保护的二进制私钥并能够读取其内容。 使用 OpenSSL 命令行,我们可以使用以下行执行此操作:

openssl pkcs8 -in binPrivateKey.key -inform DER -passin pass:password -out private.key 

这会将私钥输出到文件 private.key 中,如下所示:

-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCN0peKpgfOL75i
YRv1fqq+oVYsLPVUR/GibYmGKc9InHFy5lYF6OTYjnIIvmkOdRobbGlCUxORX/tL
qY9/8F5mUvVgkcczsIgGdvf9vMQPSf3jjCiKj7j6ucxl1+FwJWmbvgNmiaUR/0q4
....
h0lBer2hP8NFqBPBBTNDwQ==
-----END PRIVATE KEY-----

在 OpenSSL 中有一个名为d2i_PKCS8PrivateKey_fp的函数, 实际上采用 DER 二进制文件指针并输出内部密钥类型(OpenSSL 内部),它可以是 EVP_PKEY,这是 OpenSSL 中的签名过程所必需的。 这个函数实际上可以带密码来处理二进制文件。 但是,密码必须通过回调函数输入,如果我们不处理 GUI 或命令行程序,只需稍作调整即可。

以下函数采用包含二进制私钥路径的字符串和包含密码的字符指针。

EVP_PKEY * PKCS8_DERtoEVP(std::string der_key_file, char * pwd){
    FILE * fp = NULL;
    EVP_PKEY * evp_pvt = NULL;
    OpenSSL_add_all_algorithms(); //This is necessary for some reason I do not fully understand.
    fp = fopen(der_key_file.c_str(),"rb"); //Usual file pointer of C++.
    if( fp ){
        evp_pvt = d2i_PKCS8PrivateKey_fp(fp, &evp_pvt, pwd_cb, pwd); //pwd_cb is a function callback I'll describe later.
        if (evp_pvt == NULL) {
            //ERROR HANDLING...
            fclose(fp);
            return NULL ;
            }
    }
    fclose(fp);
    return evp_pvt;
}

为了以防万一我们不期望任何用户输入,我提到的调整如下,我正在使用 OpenSSL 的标准密码回调:

int pwd_cb(char *buf, int size, int rwflag, void *u){
    char * pwd;
    if (u == NULL){
       pwd = "1234";
    } else {
       pwd = (char*)u;
    }
    size_t len = strlen(pwd);
    if (len > size) len = size;
    memcpy(buf,pwd,len);

    return len;
}

这样,我们可以“欺骗”系统认为用户输入是存储在char数组中的密码。

现在,我们已经准备好签署我们的哈希了。 签名的核心功能如下:

unsigned char* signHash_DER(std::string hash_str, std::string privateKey_file, char * passphrase = NULL){
    EVP_PKEY * pkey = PKCS8_DERtoEVP(privateKey_file,passphrase);
    EVP_PKEY_CTX *ctx; //Context used in signature.
    unsigned char *sig; //The container of the signature.
    size_t siglen;
    size_t mdlen;
    if (pkey == NULL) {
        //Error handling...
        return NULL;
        }
    //Here our 'clear message' is actually our hash str and we copy it from the parameters.
    unsigned char clear_message[hash_str.length()];
    strcpy((char*) clear_message,hash_str.c_str());
    //In my implementation we require this decoding, it might not be the case for everyone.
    unsigned char * md = base64_decode(clear_message, strlen((char*) clear_message), &mdlen);
    //Initiate the context and stablish we're using default RSA.
    ctx = EVP_PKEY_CTX_new(pkey, ENGINE_get_default_RSA() /* no engine */);
    if(!ctx) {
    LOGF_ERROR("Error CTX_new");
    return NULL;
  }
  if (EVP_PKEY_sign_init(ctx) <= 0){
    //Error handling
    return NULL;
  }
 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0){
    //Error handling
    return NULL;
 }
 if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0){
    //Error handling
    return NULL;
 }
 /* Determine buffer length */
 if (EVP_PKEY_sign(ctx, NULL, &siglen, md, mdlen) <= 0){
    //Error handling
    return NULL;
 }
 sig = (unsigned char*)OPENSSL_malloc(siglen);

 if (!sig){
    //Error handling
    return NULL;
 }

 if (EVP_PKEY_sign(ctx, sig, &siglen, md, mdlen) <= 0){
    std::cout << "Error sign";
    return NULL;
 }
 /* Signature is siglen bytes written to buffer sig */
 // encode to base64 again .
 size_t signed_string_len;
 unsigned char * signed_string = base64_encode(sig, siglen, &signed_string_len);

 return signed_string;
}

差不多就是这样,最后一个函数代码的大部分是从 OpenSSL 文档中获得的,这很糟糕,但是有点耐心完成了这项工作。

调用示例:

unsigned char* signature_decoded = signHash_DER(hashed_string, "privateBinary.key","dont4get");

如果您有任何疑问,请告诉我,希望这对某人有所帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM