V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
object123
V2EX  ›  程序员

请教一个 DSA 签名 在 Java 和 PHP 平台互通的问题

  •  
  •   object123 · 2020-04-03 10:57:28 +08:00 · 1201 次点击
    这是一个创建于 1455 天前的主题,其中的信息可能已经有所发展或是发生改变。

    PHP 生成签名方法为:openssl_sign($paramStr, $sign, $_privateKey,OPENSSL_ALGO_DSS1);

    JAVA 验签的部分代码是:

    Signature signet = Signature.getInstance("SHA1withDSA"); byte[] publicKeyCode = pubkey.getBytes(); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyCode); KeyFactory keyFactory = KeyFactory.getInstance("DSA"); PublicKey publicKey = keyFactory.generatePublic(keySpec); signet.initVerify(publicKey); signet.update(content.getBytes("utf-8")); // 公匙验证结果 boolean result = signet.verify(sign);

    但是 JAVA 那边验签不通过。 PHP 的生成签名方法 openssl_sign 最后一个$signature_alg 变量试过 OPENSSL_ALGO_DSS1 和 DSA,都不行。

    请问有人我遇到这种情况吗

    4 条回复    2020-04-08 10:06:59 +08:00
    object123
        1
    object123  
    OP
       2020-04-03 11:00:20 +08:00
    JAVA 那边提供的秘钥是 base64 的。

    PHP 签名代码:
    $param = array($data,$randomStr,$timestamp);
    sort($param);

    $paramStr = implode('',$param);

    $privateKey = chunk_split($this->_privateKey, 64, "\n");

    $privateKey = "-----BEGIN PRIVATE KEY-----\n" . $privateKey . "-----END PRIVATE KEY-----\n";

    $_privateKey = openssl_get_privatekey($privateKey);

    if (!openssl_sign($paramStr, $sign, $_privateKey,OPENSSL_ALGO_DSS1)){
    return false;
    } else {
    return base64_encode($sign);
    }
    Jrue0011
        2
    Jrue0011  
       2020-04-03 14:56:55 +08:00
    Java 那里 pubkey 不会还是 base64 编码吧?
    object123
        3
    object123  
    OP
       2020-04-08 09:37:10 +08:00
    @Jrue0011 是的
    Jrue0011
        4
    Jrue0011  
       2020-04-08 10:06:59 +08:00
    @object123

    真是吗? pubkey 既然是对公钥 byte 数组进行 base64 编码后的字符串,没做解码直接 pubkey.getBytes()拿到的肯定不是原来的 byte 数组,验证自然不通过。解码的话,JDK1.8 应该可以用 java.util.Base64.getDecoder().decode(pubkey),JDK1.8 以前貌似网上不建议用 sun 的实现,可以用 apache commons-codec 的 Base64.decodeBase64(pubkey)。

    另外看 PHP 代码,签名后传给 Java 的值也是一个 base64 编码的字符串?是的话,在 Java 验证这里,boolean result = signet.verify(sign),这个 sign 如果也只是用传过来的字符串直接 getBytes()的话那也是不行的,也要 base64 解码获得原本的 byte 数组。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1155 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 23:03 · PVG 07:03 · LAX 16:03 · JFK 19:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.