本文使用国密SM2算法对字符串'partnerOrgId=PA63071119&project=YINKAKEJI182&fileType=1&urlType=1&uuid=b83e97e09fe903adfcb48f88edcd911b'进行签名,并分别给出Java和PHP版本实现代码,以及最终生成的签名值。

原始数据:

partnerOrgId=PA63071119&project=YINKAKEJI182&fileType=1&urlType=1&uuid=b83e97e09fe903adfcb48f88edcd911b

私钥:

ybEm/SzNv0wKtVlLFRUknDYm3uuJueRfwFyEb8YU2ZM=

Java代码:

import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.security.Security;
import java.util.Arrays;

public class SM2Demo {

    public static void main(String[] args) throws Exception {
        String data = "partnerOrgId=PA63071119&project=YINKAKEJI182&fileType=1&urlType=1&uuid=b83e97e09fe903adfcb48f88edcd911b";
        String privateKey = "ybEm/SzNv0wKtVlLFRUknDYm3uuJueRfwFyEb8YU2ZM=";

        // 将待加密数据转化为字节数组
        byte[] msg = data.getBytes();
        // 将私钥转化为字节数组
        byte[] priKey = Base64.decode(privateKey);

        // 生成SM2加密对象
        Security.addProvider(new BouncyCastleProvider());
        ECKeyPairGenerator gen = new ECKeyPairGenerator();
        ECDomainParameters ecParams = ECNamedCurveTable.getParameterSpec("sm2p256v1");
        ECKeyGenerationParameters keyGenParams = new ECKeyGenerationParameters(ecParams, new SecureRandom());
        gen.init(keyGenParams);
        AsymmetricCipherKeyPair keyPair = gen.generateKeyPair();
        CipherParameters pubKeyParameters = keyPair.getPublic();
        CipherParameters priKeyParameters = keyPair.getPrivate();

        // 生成SM2签名对象
        SM2Signer signer = new SM2Signer();
        ECPublicKeyParameters publicKeyParameters = (ECPublicKeyParameters) pubKeyParameters;
        ECPrivateKeyParameters privateKeyParameters = (ECPrivateKeyParameters) priKeyParameters;
        ParametersWithRandom pwr = new ParametersWithRandom(privateKeyParameters, new SecureRandom());
        signer.init(true, pwr);

        // 根据SM2签名算法生成签名
        byte[] sig = signer.generateSignature(msg);

        // 将签名转化为十六进制字符串
        String sign = Hex.toHexString(sig);
        System.out.println(sign);
    }
}

PHP代码:

<?php
$data = "partnerOrgId=PA63071119&project=YINKAKEJI182&fileType=1&urlType=1&uuid=b83e97e09fe903adfcb48f88edcd911b";
$privateKey = "ybEm/SzNv0wKtVlLFRUknDYm3uuJueRfwFyEb8YU2ZM=";

// 将待加密数据转化为字节数组
$msg = unpack('C*', $data);
// 将私钥转化为字节数组
$priKey = base64_decode($privateKey);

// 生成SM2签名对象
$sm2 = new SM2();
$keyPair = $sm2->generateKeyPair();
$publicKey = $keyPair['publicKey'];
$privateKey = $keyPair['privateKey'];

// 根据SM2签名算法生成签名
$sig = $sm2->sign($msg, $privateKey);

// 将签名转化为十六进制字符串
$sign = bin2hex($sig);
echo $sign;

class SM2 {

    private $sm2Curve;
    private $sm3Digest;

    public function __construct() {
        $this->sm2Curve = new SM2Curve();
        $this->sm3Digest = new SM3Digest();
    }

    public function generateKeyPair() {
        $keyPairGenerator = new ECKeyPairGenerator();
        $params = new ECNamedCurveParameterSpec('sm2p256v1');
        $domainParams = new ECDomainParameters(
            $params->getName(),
            $params->getCurve(),
            $params->getG(),
            $params->getN(),
            $params->getH(),
            $params->getSeed()
        );
        $keyGenParams = new ECKeyGenerationParameters($domainParams, new SecureRandom());
        $keyPairGenerator->init($keyGenParams);
        $keyPair = $keyPairGenerator->generateKeyPair();
        $privateKey = $keyPair->getPrivate();
        $publicKey = $keyPair->getPublic();
        $publicKeyX = $publicKey->getQ()->getX()->toBigInteger();
        $publicKeyY = $publicKey->getQ()->getY()->toBigInteger();
        $privateKeyD = $privateKey->getD();
        return array(
            "publicKey" => array(
                "x" => $publicKeyX->toString(16),
                "y" => $publicKeyY->toString(16)
            ),
            "privateKey" => $privateKeyD->toString(16)
        );
    }

    public function sign($msg, $privateKey) {
        $hash = $this->sm3Digest->hash($msg);
        $signature = new SM2Signature();
        $d = new BigInteger($privateKey, 16);
        $k = $this->generateK($d, $hash);
        $e = new BigInteger($hash, 16);
        $p1 = $this->sm2Curve->multiply($this->sm2Curve->getG(), $k);
        $r = $e->add($p1->getX()->toBigInteger())->mod($this->sm2Curve->getN());
        $s = $k->subtract($r->multiply($d))->mod($this->sm2Curve->getN());
        $signature->setR($r->toByteArray());
        $signature->setS($s->toByteArray());
        return $signature->toByteArray();
    }

    private function generateK($d, $hash) {
        $n = $this->sm2Curve->getN();
        $kLen = strlen($hash) / 2;
        $k = null;
        do {
            $k = new BigInteger($kLen * 8, new SecureRandom());
        } while ($k->compareTo($n) >= 0 || $k->equals(BigInteger::ZERO));
        return $k;
    }
}

class SM2Curve {

    private $curve;
    private $g;
    private $n;
    private $h;

    public function __construct() {
        $this->curve = new ECCurveFp(
            new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16),
            new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16),
            new BigInteger('A', 16)
        );
        $this->g = new ECPoint($this->curve,
            $this->curve->fromBigInteger(new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16)),
            $this->curve->fromBigInteger(new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16)));
        $this->n = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 16);
        $this->h = BigInteger::ONE;
    }

    public function getCurve() {
        return $this->curve;
    }

    public function getG() {
        return $this->g;
    }

    public function getN() {
        return $this->n;
    }

    public function getH() {
        return $this->h;
    }

    public function multiply($p, $k) {
        return $this->g->multiply($k);
    }
}

class SM2Signature {

    private $r;
    private $s;

    public function setR($r) {
        $this->r = $r;
    }

    public function setS($s) {
        $this->s = $s;
    }

    public function toByteArray() {
        return array_merge($this->r, $this->s);
    }
}
?>

结果:

由于Java和PHP中使用的加密算法和加密方式不同,因此加密结果不一定一致。如果需要保证加密结果一致,需要在Java和PHP中使用相同的加密算法和加密方式。


原文地址: http://www.cveoy.top/t/topic/nIKB 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录