RSAloginnode.js并在C ++中validation

我正在努力保护从node.js服务器发送到C ++应用程序的消息。

从node.js,我创build了一个密钥对。

我正在使用node-rsa读取node.js端的公钥( https://github.com/rzcoder/node-rsa )

var rsa = new nodeRSA(publicKeyBuffer ,{encryptionScheme :'pkcs1'}) 

由于我的信息可能会很长,所以在调用encryption之前,我会计算一条消息的盐渍sha256。

 const hash = crypto.createHash('sha256').update(message + config.signSalt).digest('hex') 

这部分工作正常,因为我能够在C ++端生成完全相同的散列。

然后,我调用node-rsa的encryption函数来生成一个缓冲区

 const signature = rsa.encrypt(hash) 

我尝试过各种编码,但由于数据是通过websocket(+ MsgPack打包)发送的,二进制格式是一个很好的select

在C ++方面,我首先阅读char []的键

 const char keyStr[] = "-----BEGIN RSA PRIVATE KEY-----\n" .......... BIO* bio = BIO_new_mem_buf(keyStr, (int)strlen(keyStr)); // -1: assume string is null terminated m_rsaPrivKey = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL); if (!m_rsaPrivKey) LogOutSys("ERROR: Could not load PRIVATE KEY! PEM_write_bio_RSAPrivateKey FAILED: %s\n", ERR_error_string(ERR_get_error(), NULL)); 

关键是读取没有错误,之后,我正在计算从消息散列,从unsigned char缓冲区中std ::string

 std::string hash = sha256(msg.c_str()); std::string signatureStr(signature.begin(), signature.end()); char *decrypt; int decryptLen; decrypt = new char[RSA_size(m_rsaPrivKey)]; decryptLen = RSA_private_decrypt((int)msg.size() + 1, (unsigned char*)msg.c_str(), (unsigned char*)decrypt, m_rsaPrivKey, RSA_NO_PADDING /* RSA_PKCS1_OAEP_PADDING */ ); if (decryptLen == -1) { char errStr[130]; ERR_error_string(ERR_get_error(), errStr); LogOutSys("Rsa::decrypt - Error decrypting string ssl error %s", errStr); } for (int i = 0; i < decryptLen; i++) { decryptData.push_back(decrypt[i]); } delete decrypt; 

解密失败,出现以下错误

Rsa :: decrypt – 错误解密stringssl错误错误:0406506C:lib(4):func(101):reason(108)

我试过各种编码和填充模式,但总是得到一个错误。

(假设你想在nodejs端使用私钥进行签名,并在openssl端使用公钥进行validation)

签名string使用示例私钥进行Test ,使用例如:

 NodeRSA=require('node-rsa'); key = new NodeRSA(null, {signingScheme: 'pkcs1-sha256'}); key.importKey('-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAI2GkqoVj1l59MQh\nI/ZswgdnNG3o5XSmyeGgNdmTgQQ6cWCJcscCS6d3+nWFl3Xe7SxzKxo7pHMHTeJU\nGTZpLzW7fk5Y/ISWIr2Qsswpm8JUVOAUQVU/qwZYPr0ACCDQLGLaVByKFgvKnf5p\npkdroM63AFakn5YlCP+WM4ASuZyvAgMBAAECgYAUsBNIYZZu0fEBqoaDQyqpwmBb\noKvJ/YeNP8ofX/yADbr9DZqFlMRSWqt1+m1FgazRzpQCZa2IUw0DhJ+a4I1R6E30\nw7ZVWdVvWtkA70YGMaqB618fMR6SpTmzVGUjzQqk7Zim+uQVugTXEimC6/7sa7em\nLtVdjXuvOFOCVEeXwQJBAO/bN2q2u8YTBy9q4A34KoeeM8NX8zV3bRVhrB4eVcT0\ngpNNCrvjo2g5qKQs1fmLmjylSBihus0RjjJZTwxsffkCQQCXDRhh83OCtLfDEztO\nObu5BvVFcli76VEdw4EqzJtrddG77B43ggYYyJFxOuJHz+33oM4GtnHEiHkV9sRS\n47nnAkBcu8qPLZsnl4+9m3qIrBv1Vwr4SXa0gznffGXJNz096rLZNH4j6nzw/Ong\nn50S4BB/xf871rucMV9iw/i1+vQxAkEAjDBDKOVhlzVSN2Jp8Df02cxzZnixkfUA\nq7b+8lHjDODUPqztfmbWcbn0Ajq8OBnqqaA8lk5NWDGw74mOu79OkQJARDwRop7c\nfkd39rY/+an50uj2L4UJv1Jb+Yal5c0u37ACRnp+0n6qlcL0pj98UfW9H+oYFqwT\nKXzq4lptzgfQIg==\n-----END PRIVATE KEY-----\n', 'pkcs8'); signature=key.sign('Test', 'hex'); 

给出一个hex编码签名:

 '45f0c0672c8c07ecfe318b8ffa425c169ed2458ac6f0e4f1ffe0bcebec38cc3e59311858ed443d45f0dc81935ee0c490fa452b2f427d59a2c43fdd69f71f2b46d9e39072cb517b4afba5d5c66b26e14ca8a2900650b923fd77271deba84103d42c1f81619825d4987eeabc05401b0bc35bee08c59843aa94a535d2fb032b681b' 

要用opensslvalidation这个签名,使用例如:

 #include <stdlib.h> #include <stdio.h> #include <openssl/pem.h> #include <openssl/evp.h> int main(void) { // Read public key from memory EVP_PKEY *pubKey=NULL; { BIO * pubKeyPemBio = BIO_new_mem_buf("-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCNhpKqFY9ZefTEISP2bMIHZzRt\n6OV0psnhoDXZk4EEOnFgiXLHAkund/p1hZd13u0scysaO6RzB03iVBk2aS81u35O\nWPyEliK9kLLMKZvCVFTgFEFVP6sGWD69AAgg0Cxi2lQcihYLyp3+aaZHa6DOtwBW\npJ+WJQj/ljOAErmcrwIDAQAB\n-----END PUBLIC KEY-----", -1); if(pubKeyPemBio==NULL) { printf("Error at line %i\n", __LINE__); return 0; } pubKey=PEM_read_bio_PUBKEY(pubKeyPemBio, &pubKey, NULL, NULL); BIO_free(pubKeyPemBio); if(pubKey==NULL) { printf("Error at line %i\n", __LINE__); return 0; } } // Verify signature { EVP_MD_CTX *ctx = EVP_MD_CTX_create(); if(ctx==NULL) { printf("Error at line %i\n", __LINE__); return 0; } int ret=EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, pubKey); if(ret!=1) { printf("Error at line %i\n", __LINE__); return 0; } ret=EVP_DigestVerifyUpdate(ctx, "Test", 4); if(ret!=1) { printf("Error at line %i\n", __LINE__); return 0; } ret=EVP_DigestVerifyFinal(ctx, "\x45\xf0\xc0\x67\x2c\x8c\x07\xec\xfe\x31\x8b\x8f\xfa\x42\x5c\x16\x9e\xd2\x45\x8a\xc6\xf0\xe4\xf1\xff\xe0\xbc\xeb\xec\x38\xcc\x3e\x59\x31\x18\x58\xed\x44\x3d\x45\xf0\xdc\x81\x93\x5e\xe0\xc4\x90\xfa\x45\x2b\x2f\x42\x7d\x59\xa2\xc4\x3f\xdd\x69\xf7\x1f\x2b\x46\xd9\xe3\x90\x72\xcb\x51\x7b\x4a\xfb\xa5\xd5\xc6\x6b\x26\xe1\x4c\xa8\xa2\x90\x06\x50\xb9\x23\xfd\x77\x27\x1d\xeb\xa8\x41\x03\xd4\x2c\x1f\x81\x61\x98\x25\xd4\x98\x7e\xea\xbc\x05\x40\x1b\x0b\xc3\x5b\xee\x08\xc5\x98\x43\xaa\x94\xa5\x35\xd2\xfb\x03\x2b\x68\x1b", 128); if(ret!=1) { printf("Error at line %i\n", __LINE__); return 0; } EVP_MD_CTX_destroy(ctx); } EVP_PKEY_free(pubKey); printf("All OK!\n"); return EXIT_SUCCESS; } 

一些(随机)笔记:

  • 上面的代码只是在nodejs和openssl之间进行RSA签名/validation的工作概念certificate。 请不要期望它是一个安全的实现,具有正确的error handling,安全的密钥长度,安全的时间/旁道攻击等。

  • 带符号的string/缓冲区可以是任意长的,散列由node-rsa执行

  • 编码的公钥/私钥可以使用例如key.exportKey('pkcs8-public') / key.exportKey('pkcs8')在nodejs中获得

  • select适合你的编码(我使用了string和hexstring,因为它们清晰可读)。 你可能想要使用缓冲区

祝你好运!

免责声明:我不是密码专家,所以请确认我的想法。


使用私钥:

 -----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAI2GkqoVj1l59MQh I/ZswgdnNG3o5XSmyeGgNdmTgQQ6cWCJcscCS6d3+nWFl3Xe7SxzKxo7pHMHTeJU GTZpLzW7fk5Y/ISWIr2Qsswpm8JUVOAUQVU/qwZYPr0ACCDQLGLaVByKFgvKnf5p pkdroM63AFakn5YlCP+WM4ASuZyvAgMBAAECgYAUsBNIYZZu0fEBqoaDQyqpwmBb oKvJ/YeNP8ofX/yADbr9DZqFlMRSWqt1+m1FgazRzpQCZa2IUw0DhJ+a4I1R6E30 w7ZVWdVvWtkA70YGMaqB618fMR6SpTmzVGUjzQqk7Zim+uQVugTXEimC6/7sa7em LtVdjXuvOFOCVEeXwQJBAO/bN2q2u8YTBy9q4A34KoeeM8NX8zV3bRVhrB4eVcT0 gpNNCrvjo2g5qKQs1fmLmjylSBihus0RjjJZTwxsffkCQQCXDRhh83OCtLfDEztO Obu5BvVFcli76VEdw4EqzJtrddG77B43ggYYyJFxOuJHz+33oM4GtnHEiHkV9sRS 47nnAkBcu8qPLZsnl4+9m3qIrBv1Vwr4SXa0gznffGXJNz096rLZNH4j6nzw/Ong n50S4BB/xf871rucMV9iw/i1+vQxAkEAjDBDKOVhlzVSN2Jp8Df02cxzZnixkfUA q7b+8lHjDODUPqztfmbWcbn0Ajq8OBnqqaA8lk5NWDGw74mOu79OkQJARDwRop7c fkd39rY/+an50uj2L4UJv1Jb+Yal5c0u37ACRnp+0n6qlcL0pj98UfW9H+oYFqwT KXzq4lptzgfQIg== -----END PRIVATE KEY----- 

使用相应的公钥:

 -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCNhpKqFY9ZefTEISP2bMIHZzRt 6OV0psnhoDXZk4EEOnFgiXLHAkund/p1hZd13u0scysaO6RzB03iVBk2aS81u35O WPyEliK9kLLMKZvCVFTgFEFVP6sGWD69AAgg0Cxi2lQcihYLyp3+aaZHa6DOtwBW pJ+WJQj/ljOAErmcrwIDAQAB -----END PUBLIC KEY-----