赞
踩
上一篇博客介绍了SM2算法生成密钥的过程,详见-SM2生成密钥。这篇博客接着介绍SM2算法如何用上篇博客生成的密钥进行加解密操作。
因为密钥都是byte数组,在进行加解密前,我们需要将密钥转换成BC库的CipherParameters。代码如下:
- /**
- * 私钥转换为 {@link ECPrivateKeyParameters}
- * @param key key
- * @return
- * @throws InvalidKeyException
- */
- public static ECPrivateKeyParameters privateKeyToParams(String algorithm, byte[] key) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException {
- Preconditions.checkNotNull(key, "key must be not null !");
- PrivateKey privateKey = generatePrivateKey(algorithm, key);
- return (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey);
- }
-
- /**
- * 生成私钥
- * @param algorithm 算法
- * @param key key
- * @return
- */
- public static PrivateKey generatePrivateKey(String algorithm, byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
- Preconditions.checkNotNull(algorithm, "algorithm must be not null !");
- Preconditions.checkNotNull(key, "key must be not null !");
- KeySpec keySpec = new PKCS8EncodedKeySpec(key);
- algorithm = getAlgorithmAfterWith(algorithm);
- return getKeyFactory(algorithm).generatePrivate(keySpec);
- }
-
- /**
- * 公钥转换为 {@link ECPublicKeyParameters}
- * @param key key
- * @return
- * @throws InvalidKeyException
- */
- public static ECPublicKeyParameters publicKeyToParams(String algorithm, byte[] key) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException {
- Preconditions.checkNotNull(key, "key must be not null !");
- PublicKey publicKey = generatePublicKey(algorithm, key);
- return (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
- }
-
- /**
- * 生成公钥
- * @param algorithm 算法
- * @param key key
- * @return
- */
- public static PublicKey generatePublicKey(String algorithm, byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
- Preconditions.checkNotNull(algorithm, "algorithm must be not null !");
- Preconditions.checkNotNull(key, "key must be not null !");
- KeySpec keySpec = new X509EncodedKeySpec(key);
- algorithm = getAlgorithmAfterWith(algorithm);
- return getKeyFactory(algorithm).generatePublic(keySpec);
- }
-
- /**
- * 获取用于密钥生成的算法<br>
- * 获取XXXwithXXX算法的后半部分算法,如果为ECDSA或SM2,返回算法为EC
- * @param algorithm XXXwithXXX算法
- * @return 算法
- */
- private static String getAlgorithmAfterWith(String algorithm) {
- Preconditions.checkNotNull(algorithm, "algorithm must be not null !");
- int indexOfWith = StringUtils.lastIndexOfIgnoreCase(algorithm, "with");
- if (indexOfWith > 0) {
- algorithm = StringUtils.substring(algorithm, indexOfWith + "with".length());
- }
- if ("ECDSA".equalsIgnoreCase(algorithm) || "SM2".equalsIgnoreCase(algorithm)) {
- algorithm = "EC";
- }
- return algorithm;
- }
-
- /**
- * 获取{@link KeyFactory}
- * @param algorithm 非对称加密算法
- * @return {@link KeyFactory}
- */
- private static KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException {
- final Provider provider = new BouncyCastleProvider();
- return KeyFactory.getInstance(algorithm, provider);
- }
SM2操作主要有四类:加密、解密、签名和验签。代码如下:
- /**
- * 加密
- * @param data 数据
- * @param publicKey 公钥
- * @return 加密之后的数据
- */
- public static byte[] encrypt(byte[] data, byte[] publicKey) throws Exception {
- CipherParameters pubKeyParameters = new ParametersWithRandom(publicKeyToParams("SM2", publicKey));
- SM2Engine engine = new SM2Engine(DIGEST);
- engine.init(true, pubKeyParameters);
- return engine.processBlock(data, 0, data.length);
- }
-
- /**
- * 解密
- * @param data 数据
- * @param privateKey 私钥
- * @return 解密之后的数据
- */
- public static byte[] decrypt(byte[] data, byte[] privateKey) throws Exception {
- CipherParameters privateKeyParameters = privateKeyToParams("SM2", privateKey);
- SM2Engine engine = new SM2Engine(DIGEST);
- engine.init(false, privateKeyParameters);
- byte[] byteDate = engine.processBlock(data, 0, data.length);
- return byteDate;
- }
-
- /**
- * 签名
- * @param data 数据
- * @return 签名
- */
- public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {
- SM2Signer signer = new SM2Signer();
- CipherParameters param = new ParametersWithRandom(privateKeyToParams("SM2", privateKey));
- signer.init(true, param);
- signer.update(data, 0, data.length);
- return signer.generateSignature();
- }
-
- /**
- * 用公钥检验数字签名的合法性
- * @param data 数据
- * @param sign 签名
- * @param publicKey 公钥
- * @return 是否验证通过
- */
- public static boolean verify(byte[] data, byte[] sign, byte[] publicKey) throws Exception {
- SM2Signer signer = new SM2Signer();
- CipherParameters param = publicKeyToParams("SM2", publicKey);
- signer.init(false, param);
- signer.update(data, 0, data.length);
- return signer.verifySignature(sign);
- }
跑个测试用例试下:
- public static void main(String[] args) throws Exception {
- KeyPair keyPair = generateSm2KeyPair();
- //明文
- String plaintext = "test";
- //加密
- String ciphertext = Base64Utils.encode(encrypt(plaintext.getBytes("utf-8"), keyPair.getPublic().getEncoded()));
- //生成签名
- String signature = Base64Utils.encode(sign(plaintext.getBytes("utf-8"),keyPair.getPrivate().getEncoded()));
- System.out.println("ciphertext: " + ciphertext);
- System.out.println("signature: " + signature);
- //解密
- plaintext = new String(decrypt(Base64Utils.decode(ciphertext),keyPair.getPrivate().getEncoded()),"utf-8");
- //验签
- boolean result = verify(plaintext.getBytes("utf-8"),Base64Utils.decode(signature),keyPair.getPublic().getEncoded());
- System.out.println("plaintext: " + plaintext);
- System.out.println("verify result: " + result);
- }
输出结果如下:
- ciphertext: BFH0SXC1bX7OL1i5I4GO/Ck8Lak6gfzrsEzhrk4GY2cKZOug73ThLBYSjbtnpC5z30CJuKmaAf/W+jlviRr9PT1dcBWyrO599UUC4XWW8as4XHej8nE/Rlr9TP5+wP+4AWaub6o=
- signature: MEYCIQC7OldJ7B8JvP51zw8P2DfieG5iAj5rWEybqZ3bPG8D5wIhAIVXlOmMxk0t4cNm0oQ0HYIzJZ5JShGIWuVwZLZ/t9mQ
- plaintext: test
- verify result: true
从结果可以看出,可以进行正常的加解密、生成签名以及验签操作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。