如何使用Crypto++验证Python-RSA生成的RSA签名



我有一个用Python编写的服务器和一个c++客户端。Python服务器有一个RSA私钥,可重新分发的c++客户端有配对的公钥。c++客户端向Python服务器发送一个字符串,服务器通过用它的私钥编码这个字符串来生成一个签名,并以ASCII格式发送给客户端。最后,c++客户端验证此签名,以确保a)签名来自配对密钥而不是其他,b)签名是基于此特定字符串而不是其他。

Python端是这样的:

import rsa
from base64 import b64encode
str = "message"
pub, priv = rsa.newkeys(2048)
keyB64 = rsa.sign(str.encode('utf-8'), privkey, 'SHA-1')    
signature = b64encode(keyB64).decode('ascii')
with open("public_key.txt", "w") as file:
file.write(pub.save_pkcs1().decode('utf8'))
file.close()
生成的公钥文件如下所示(只是一个示例):

-----BEGIN RSA公钥-----MIGJAoGBALqrXqb17/TiXmGGbvbFwRMV + mbCqPtvnD0zlvIKxpJ4NSBVZ2Lz87SUWw69uFILy19G6prThJAzHha9pa3fWRKRv5epMXcP6TFZ3er0h0uaxOKxle + OtpnCxyW + QMzkhuDL1gR1OrgVW6jCV6lmVdca63 + m2PfTjQj1Vc64OyWBAgMBAAE =-----结束RSA公钥-----

在客户端,我读取这个文件并将两个标记之间的字符存储在一个字符串中。然后看起来像这样:

#include <./Cryptopp/rsa.h>
#include <./Cryptopp/hex.h>
#include <./Cryptopp/pssr.h>
inline bool RsaVerifyString(const std::string &aPublicKeyStrASCII,
const std::string &str,
const std::string &aSignatureStrASCII)
{
// decode and load public key (using pipeline)
CryptoPP::RSA::PublicKey publicKey;
publicKey.Load(CryptoPP::StringSource(aPublicKeyStrASCII, true).Ref());
// decode signature
std::string decodedSignature;
CryptoPP::StringSource ss(aSignatureStrASCII, true);
// verify message
bool result = false;
CryptoPP::RSASS<CryptoPP::PSSR, CryptoPP::SHA1>::Verifier verifier(publicKey);
CryptoPP::StringSource ss2(decodedSignature + str, true,
new CryptoPP::SignatureVerificationFilter(verifier,
new CryptoPP::ArraySink((unsigned char*)&result,
sizeof(result))));
return result;
}
//...
std::string message("message");
if(RsaVerifyString(publicKeyASCII, message, signatureASCII))
{
std::cout << "OK" << std::endl;
}

但是它不起作用:它总是返回false,并且CryptoPP的体系结构对我来说太复杂了,无法调试-而我确信它实际上非常简单,只是一个调整参数的问题。

有经验的人可以告诉我我做错了什么吗?

更新尝试将其移植到PyCryptoDome以增加兼容性,根据注释的建议:

from Crypto import Random
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
PRIV_PATH = '../priv.pem'
PUB_PATH= '../pub.pem'

def gen_key_pair():
random_generator = Random.new().read
key = RSA.generate(2048, random_generator)
print(key.exportKey(), key.publickey().exportKey())
with open(PRIV_PATH, 'wb') as file:
file.write(key.exportKey())
with open(PUB_PATH, 'wb') as file:
file.write(key.publickey().exportKey())
return key.exportKey(), key.publickey().exportKey()

def sign_message(message):
key = RSA.importKey(open(PRIV_PATH, 'rb').read())
h = SHA.new(message)
signer = PKCS1_v1_5.new(key)
signature = signer.sign(h)
return signature

def verify_sign(message, signature):
key = RSA.importKey(open(PUB_PATH, 'rb').read())
h = SHA.new(message)
verifier = PKCS1_v1_5.new(key)
if verifier.verify(h, signature):
print("The signature is authentic.")
else:
print("The signature is not authentic.")

# TEST CRYPTO
gen_key_pair()
message = 'Hello pycrypto!'.encode('utf-8')
signature = sign_message(message).hex()
print('signature='+signature)
verify_sign(message, bytes.fromhex(signature))

在客户端,我希望做以下更改(在清理代码之前):

inline bool RsaVerifyString(const std::string &aPublicKeyStrASCII,
const std::string &str,
const std::string &aSignatureStrASCII)
{
// decode and load public key (using pipeline)
CryptoPP::RSA::PublicKey publicKey;
publicKey.Load(CryptoPP::StringSource(aPublicKeyStrASCII, true).Ref());
// decode signature
std::string decodedSignature;
CryptoPP::StringSource ss(aSignatureStrASCII, true);
// verify message
bool result = false;
CryptoPP::RSASS<CryptoPP::PKCS1v15, CryptoPP::SHA256>::Verifier verifier(publicKey);
CryptoPP::StringSource ss2(decodedSignature + str, true,
new CryptoPP::SignatureVerificationFilter(verifier,
new CryptoPP::ArraySink((unsigned char*)&result,
sizeof(result))));
return result;
}

我还不能编译Crypto++(它抛出失败使函数内联),但我怀疑它会工作。

我放弃了Crypto++,因为我不能让它在QtCreator + Windows上工作,而是使用OpenSSL。这是可怕的违反直觉的代码,但有很多的支持,我得到了它的工作与成员的帮助在这个线程:验证在OpenSSL c++中PyCryptoDome生成的签名

如果你对验证过程的c++实现很灵活,并且你不能让Crypto++工作,那么使用这个,所有的代码都在那里。

最新更新