简体   繁体   English

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

[英]How to verify RSA signature generated by Python-RSA using Crypto++

I have a server written in Python, and a C++ client.我有一个用 Python 编写的服务器和一个 C++ 客户端。 The Python server has a private RSA key, and the redistributable C++ client has the paired public key. Python 服务器有一个 RSA 私钥,可再分发的 C++ 客户端有配对的公钥。 The C++ client sends a string to the Python server, the server generates a signature by encoding this string with its private key, and sends it to the client in ASCII format. C++客户端发送一个字符串给Python服务器,服务器用自己的私钥对该字符串进行编码生成签名,并以ASCII格式发送给客户端。 Finally, the C++ client verifies this signature to ensure a) the signature comes from the paired key and no other, and b) the signature was made based on this specific string, and no other.最后,C++ 客户端验证此签名以确保 a) 签名来自配对密钥而不是其他,以及 b) 签名是基于此特定字符串而不是其他。

The Python side looks like this: 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()

With the generated public key file looking like this (just an example):生成的公钥文件看起来像这样(只是一个例子):

-----BEGIN RSA PUBLIC KEY----- MIGJAoGBALqrXqb17/TiXmGGbvbFwRMV+mbCqPtvnD0zlvIKxpJ4NSBVZ2Lz87SU Ww69uFILy19G6prThJAzHha9pa3fWRKRv5epMXcP6TFZ3er0h0uaxOKxle+OtpnC xyW+QMzkhuDL1gR1OrgVW6jCV6lmVdca63+m2PfTjQj1Vc64OyWBAgMBAAE= -----END RSA PUBLIC KEY----- -----BEGIN RSA PUBLIC KEY----- MIGJAoGBALqrXqb17/TiXmGGbvbFwRMV+mbCqPtvnD0zlvIKxpJ4NSBVZ2Lz87SU Ww69uFILy19G6prThJAzHha9pa3fWRKRv5epMXcP6TFZ3er0h0uaxOKxle+OtpnC xyW+QMzkhuDL1gR1OrgVW6jCV6lmVdca63+m2PfTjQj1Vc64OyWBAgMBAAE= -----END RSA PUBLIC KEY-----

On the client side, I read this file and store the characters between the two tags in a string.在客户端,我读取这个文件并将两个标签之间的字符存储在一个字符串中。 Then it looks like this:然后它看起来像这样:

#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;
}

But it doesn't work: it always returns false, and CryptoPP's architecture is too complicated for me to debug - whereas I'm sure it's actually very simple and just a matter of adapting parameters.但它不起作用:它总是返回 false,而且 CryptoPP 的架构对我来说太复杂了,无法调试——而我确信它实际上非常简单,只是调整参数的问题。

Anyone with experience in these could tell me what I'm doing wrong?任何有这方面经验的人都可以告诉我我做错了什么?

Update更新

Trying to port it to PyCryptoDome to increase compatibility upon recommendation of a comment:根据评论的建议,尝试将其移植到 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))

On the client side I expect to have the following changes to make (before cleaning the code):在客户端,我希望进行以下更改(在清理代码之前):

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;
}

I can't yet compile Crypto++ (it's throwing failures to make functions inline) but I doubt it would work as-is.我还不能编译 Crypto++(它会引发内联函数失败),但我怀疑它是否会按原样工作。

I abandoned Crypto++ because I couldn't get it to work on QtCreator + Windows, and used OpenSSL instead.我放弃了 Crypto++,因为我无法让它在 QtCreator + Windows 上工作,而是使用了 OpenSSL。 It's horribly counterintuitive to code, but there is a lot of support and I got it to work with a member's help in this thread: Verify in OpenSSL C++ a signature generated in PyCryptoDome这对代码来说非常违反直觉,但有很多支持,我在这个线程中得到了成员的帮助: 在 OpenSSL C++ 中验证在 PyCryptoDome 中生成的签名

Use this if you are flexible on the C++ implementation of the verifying process and you can't get Crypto++ to work, all the code is there.如果您对验证过程的 C++ 实现很灵活并且无法使 Crypto++ 工作,请使用它,所有代码都在那里。

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

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