代码之家  ›  专栏  ›  技术社区  ›  Muppet

React和Python之间的跨环境ECDSA签名验证失败

  •  0
  • Muppet  · 技术社区  · 1 年前

    我正在进行一个项目,需要在React应用程序中生成ECDSA签名,然后在Python后端进行验证。签名生成和验证在各自的环境中工作,但React中生成的签名无法通过Python中的验证。我使用的是React中的椭圆库和Python中的密码学库。

    React代码(签名生成):

    import { useEffect } from 'react';
    import { ec as EC } from 'elliptic';
    
    const App = () => {
      useEffect(() => {
        const ec = new EC('secp256k1');
        const private_key_hex = "cf63f7ffe346cd800e431b34bdbd45f6aac3c2ac6055ac18195753aff9b9cce8";
        const message_hash_hex = "2f8fc7172db7dcbd71ec70c83263db33a54ff761b02a54480a8d07b9c633d651";
    
        const privateKey = ec.keyFromPrivate(private_key_hex, 'hex');
        const signature = privateKey.sign(message_hash_hex, 'hex', { canonical: true });
        const signature_der_hex = signature.toDER('hex');
    
        console.log("Signature (DER hex):", signature_der_hex);
      }, []);
    
      return <div><h1>ECDSA Signature in React</h1></div>;
    };
    
    export default App;
    

    顺从的:

    Signature (DER hex): 3045022100e5c678f346cdd180815912e580c27d9d70a4a2e71ab6cfb2bdaedfbf4cdf24cc02200bba6ae9b3bb25c886b5cc8549ac6796438f295e91320a1d705f17e25cb7199b
    

    这里是我试图在python中验证签名的部分:

    from cryptography.hazmat.primitives.asymmetric import ec
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.backends import default_backend
    
    def verify_signature(public_key_hex, signature_der_hex, message_hash_hex):
        public_key_bytes = bytes.fromhex(public_key_hex)
        try:
            public_key = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256K1(), public_key_bytes)
        except Exception as e:
            print(f"Error loading public key: {e}")
            return False
    
        hashed_message = bytes.fromhex(message_hash_hex)
        try:
            signature_bytes = bytes.fromhex(signature_der_hex)
            public_key.verify(signature_bytes, hashed_message, ec.ECDSA(hashes.SHA256()))
            return True
        except Exception as e:
            print(f"Verification failed: {e}")
            return False
    
    public_key_hex = "03aa4fcbf0792ce77a3be9415bf96bff99a832466f56ecba3bb8ce630877de2701"
    
    # Replace with signature from React
    signature_der_hex = "3045022100e5c678f346cdd180815912e580c27d9d70a4a2e71ab6cfb2bdaedfbf4cdf24cc02200bba6ae9b3bb25c886b5cc8549ac6796438f295e91320a1d705f17e25cb7199b"  
    
    message_hash_hex = "2f8fc7172db7dcbd71ec70c83263db33a54ff761b02a54480a8d07b9c633d651"
    verification_result = verify_signature(public_key_hex, signature_der_hex, message_hash_hex)
    print("Verification:", verification_result)
    

    问题: 当我在Python验证代码中使用React应用程序生成的签名时,验证失败。但是,当我在每个环境中分别运行签名和验证过程时,它会成功。

    我尝试过的:

    • 确保消息哈希在两种环境中都相同。
    • 在发送到Python之前,在React中将签名转换为DER格式(按照上面的代码)
    • 在React和Python之间调整公钥格式。

    我怀疑问题可能与签名的编码方式有关,或者与库处理ECDSA操作的一些细微差别有关。对于如何使这两种环境兼容的任何见解或建议,我们将不胜感激。

    1 回复  |  直到 1 年前
        1
  •  1
  •   Topaco    1 年前

    椭圆形 NodeJS库 pyca/密码学 默认情况下,Python库隐式哈希。由于在这两种情况下都传递了散列,所以一次散列的消息在NodeJS代码中签名,但两次散列的信息在Python代码中验证,这就是验证失败的原因。
    为了成功使用Python进行验证,必须禁用隐式哈希,具体操作如下:

    from cryptography.hazmat.primitives.asymmetric import utils
    ...
    public_key.verify(signature_bytes, hashed_message, ec.ECDSA(utils.Prehashed(hashes.SHA256())))
    

    通过此更改,使用Python代码进行验证是成功的。