zl程序教程

您现在的位置是:首页 >  APP

当前栏目

使用公钥完成签名验证

2023-03-15 23:26:33 时间

在对接微信支付接口时,需要对微信支付返回的信息进行签名验证,防止中间人攻击,替换微信支付返回的结果

整体过程

  • 微信支付生成签名:私钥 + 内容 -> signature
  • 调用方验证签名:公钥 + 内容 验证 signature

示例

  • 生成签名
   /**
     * 生成签名.
     *
     * @param originalData 原始数据
     * @param privateKey   私钥
     * @return 签名串
     */
    public static String sign(String originalData, PrivateKey privateKey) {
        String base64Sign = "";
        try {
            //返回指定签名的Signature对象
            Signature sign = Signature.getInstance("SHA1withRSA");

            //初始化这个用于签名的对象
            sign.initSign(privateKey);

            byte[] bysData = originalData.getBytes(StandardCharsets.UTF_8);

            //使用指定的byte数组更新要签名的数据
            sign.update(bysData);
            //返回所有已经更新数据的签名字节
            byte[] signByte = sign.sign();
            //对其进行Base64编码
            BASE64Encoder encoder = new BASE64Encoder();
            base64Sign = encoder.encode(signByte);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return base64Sign;
    }
  • 验证签名
   /**
     * 验证签名.
     *
     * @param signStr      签名串
     * @param originalData 原始数据
     * @param publicKey    公钥
     * @return 是否验证通过
     */
    public static boolean verify(String signStr, String originalData, PublicKey publicKey) {
        System.out.println("开始进行验签,原始数据为:" + originalData);
        try {
            //将签名数据
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] signed = decoder.decodeBuffer(signStr);

            //通过Signature的getInstance方法,获取指定签名算法的Signature对象
            Signature signature = Signature.getInstance("SHA1withRSA");
            //初始化用于验证的对象
            signature.initVerify(publicKey);
            //使用指定的byte[]更新要验证的数据
            signature.update(originalData.getBytes(StandardCharsets.UTF_8));
            //验证传入的签名
            return signature.verify(signed);
        } catch (Exception e) {
            return false;
        }
    }
  • 测试
    public static void main(String[] args) throws Exception {
        String p12 = "KLFJDLJFL";
        byte[] decode = Base64.getDecoder().decode(p12);
        String keypasswd = "passwd";
        String keyalias = "tenpay certificate";
        KeyStore ks = KeyStore.getInstance("PKCS12");

        ks.load(new ByteArrayInputStream(decode), keypasswd.toCharArray());

        Enumeration<String> aliases = ks.aliases();
        while (aliases.hasMoreElements()) {
            System.out.println(aliases.nextElement());
        }
        PrivateKey prikey = (PrivateKey) ks.getKey(keyalias, keypasswd.toCharArray());
        Certificate cert = ks.getCertificate(keyalias);
        PublicKey pubkey = cert.getPublicKey();

        String originData = "hello world";
        String sign = sign(originData, prikey);

        boolean verify = verify(sign, originData, pubkey);
        System.out.println(verify);
    }

疑问

使用了HTTPS,为什么微信支付还要用公私钥签名呢?