【问题标题】:Using PHP/Python to verify ECDSA signature使用 PHP/Python 验证 ECDSA 签名
【发布时间】:2018-01-17 14:10:14
【问题描述】:

我编写代码以使用 spongycastle lib 在 Android 上生成 ECDSA 签名。然后我将标志字符串和公钥发送到服务器(Ubuntu 16.04)并尝试使用 php 和 python 来验证这个标志。

我在我的 android 应用上测试验证。效果很好。

我使用 php-openssl 扩展,在 Python 中我使用 ecdsa 0.13。但是,这两个都失败了。我再试一次,使用 openssl 命令,也验证不了。

我不知道,我错在哪里。

为什么 ECDSA 验证失败?


这是我的代码:

  1. 生成签名(安卓):

    ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("prime256v1");
    try {
        KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA","SC");
        g.initialize(spec, new SecureRandom());
        KeyPair keyPair = g.generateKeyPair();
        privateKey = keyPair.getPrivate();
        publicKey = keyPair.getPublic();
        ///write public key to pem file
        ......
        FileOutputStream fileOutputStream1 = new FileOutputStream(file1);
        StringWriter writer1 = new StringWriter();
        PemWriter pemWriter1 = new PemWriter(writer1);
        pemWriter1.writeObject(new PemObject("PUBLIC KEY",publicKey.getEncoded()));
        pemWriter1.flush();
        pemWriter1.close();
        String publickeyPem = writer1.toString();
        fileOutputStream1.write(publickeyPem.getBytes());
        fileOutputStream1.close();
        } catch (Exception e) {
            e.printStackTrace();}
        ......
        //Sign and veryfied
         String chuoi = txtChuoi.getText().toString();
         byte[] chuoiInput = chuoi.getBytes("UTF-8");
         Signature sig = Signature.getInstance("NONEwithECDSA","SC");
         sig.initSign(privateKey);
         sig.update(chuoiInput);
         ///SIGN
         byte[] signatureBytes = sig.sign()
         txtMaHoa.setText(Base64.encodeToString(signatureBytes,Base64.DEFAULT));
         sig.initVerify(publicKey);
         sig.update(chuoiInput);
         ///VERIFIED
         txtGiaiMa.setText(sig.verify(signatureBytes)+"");
         ///Write string sign in txtMahoa to file
         .......
    
  2. 输出我有签名和公钥是:

    (Signature string) MEYCIQC7Hz631IFGsUOogcRLeN99uM9hWgLr+LGzuJvR/6nBrgIhAMXgZcvXyMRCAELXlNNS1a9j iAT1x0q2C5Mdu+2aZKtN
    

    (公钥)

    -----BEGIN PUBLIC KEY-----
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj07XEM+ulPyrdsfAf9prN2L2dNUd /Yy0rABcFdueAwYUf86f8Cc93Ws6sxzIvf2iKOapFby7EjHewjhLM/z7Qg==
     -----END PUBLIC KEY-----
    
  3. 使用 PHP 验证:

    $pubkeyid = openssl_pkey_get_public("/var/www/html/ca.pem");
    
    $data = "nguyen tran thanh Lam";
    
     $signature =
      "MEYCIQC7Hz631IFGsUOogcRLeN99uM9hWgLr+LGzuJvR/6nBrgIhAMXgZcvXyMRCAELXlNNS1a9jiAT1x0q2C5Mdu+2aZKtN";
    $ok = openssl_verify($data, $signature, $pubkeyid);
    if ($ok == 1) {
    echo "good";
    } elseif ($ok == 0) {
       echo "bad";
    } else {
    echo "ugly, error checking signature";
    }
    ?>
    

【问题讨论】:

  • 您的输出签名中有一个空白 9j iA
  • 不,这是我的打字错误。
  • 可能获得一个链接到 "/var/www/html/ca.pem",我想通过pyopenssl 进行验证?
  • ???它可以访问文件 ca.pem 但我有一个问题:在 Android 中生成字符串签名 ---> 我将其编码为 Base64 并发送到服务器。但是当我用 PHP 解码它时,它可能不像登录 android。所以我可以在android上验证这个标志但是使用php,它失败了。 PyOpenSSL?我没用过,能不能指导一下。谢谢。

标签: php android python php-openssl boringssl


【解决方案1】:

评论:...但验证函数不返回任何内容。所以我不确定

如果crypto.verify(... 没有抛出错误,这意味着验证正常。请参阅下面的更新代码。
使用错误的证书、签名或数据进行验证


评论:您对添加 base64.b64decode 有何看法。 ...因为在android代码中我有这个linetxtMaHoa.setText(Base64.encodeToString(signatureBytes,Ba‌​se64.DEFAULT));

PEM已经是base64,检查上面的.setText(Base64...是否可以省略。现在我已经用base64.b64decode更新了下面的代码。


问题:示例---- b“sha256”? "b" 是二进制(内置函数还是我必须将字符串 sha256 转换为二进制?)

仅适用于我作为字符串 (digest-names),例如:

import pem, base64
from OpenSSL import crypto

signature  = b"MEYCIQC7Hz631IFGsUOogcRLeN99uM9hWgLr+LGzuJvR/6nBrgIhAMXgZcvXyMRCAELXlNNS1a9jiAT1x0q2C5Mdu+2aZKtN"

# As Creator of the Signatur do additional base64 encoding!
signature = base64.b64decode(signature)

data = "nguyen tran thanh Lam"

certificate = pem.parse_file('Android.pem')[0]
cert = crypto.load_certificate(crypto.FILETYPE_PEM, certificate.as_bytes())

try:
    crypto.verify(cert=cert, signature=signature, data=data, digest='sha256')
except crypto.Error as exp:
    print('crypto.Error:{}'.format(exp.args))

>>>crypto.Error:([('', 'ECDSA_do_verify', 'bad signature')],)

注意:抛出crypto.Error,因为没有使用创建signaturecertificate


OpenSSL.crypto.verify(certificate, signature, data, digest)

验证数据字符串的签名。
证书是一个 X509 实例,对应于生成签名的私钥。
signature 是一个给出签名本身的 str 实例。
data 是一个 str 实例,它给出了签名适用的数据。
digest is a str instance naming the message digest type of the signature, for example b"sha256"

0.11 版中的新功能。

【讨论】:

  • 我有错误:( certificate = pem.parse_file('ecc_publickey1.pem')[0] IndexError: list index out of range)
  • 如果我删除 [0] 它也有错误: (cert = crypto.load_certificate(crypto.FILETYPE_PEM, certificate.as_bytes()) AttributeError: 'list' object has no attribute 'as_bytes')
  • 并且,我在这里更新了签名和公钥:(sig=MEUCIEa5FlEm3mBp79ZG5f+rZdZ8o0eDWrAEE+TI8yZ+1501AiEA0dDMvdDuFLkr9HPWE1RgHcxixAE9A11GNnQ/Iuut/Ts=),(原始字符串-=这是原始字符串)和(公钥----开始公钥----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDDu15deKy7eyVl9eLFmb/iNik1vq GyeC5sD9xB8mhVwROUinznICvu76bvCmDuSopp4PMRd3GRBPOLyg1uSrEQ== -----结束公钥-----)。我用ECDSA,为什么你输出的是RSA?
  • 您的PEM 无效! IndexError 表示文件中没有 no 证书。阅读what-is-a-pem-file
  • 好的,让我再检查一次。当我有结果时,我会告诉你。感谢您的帮助:D
猜你喜欢
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-30
  • 1970-01-01
相关资源
最近更新 更多