com.github.shepherdviolet.glacimon.java.crypto.SM2Cipher Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2022-2022 S.Violet
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Project GitHub: https://github.com/shepherdviolet/glacimon
* Email: [email protected]
*/
package com.github.shepherdviolet.glacimon.java.crypto;
import com.github.shepherdviolet.glacimon.java.crypto.base.BaseBCCipher;
import com.github.shepherdviolet.glacimon.java.crypto.base.CommonCryptoException;
import com.github.shepherdviolet.glacimon.java.crypto.base.NonStandardDataFixer;
import com.github.shepherdviolet.glacimon.java.crypto.base.SM2DefaultCurve;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import java.io.IOException;
import java.io.InputStream;
/**
* SM2签名加密工具
*
* Cipher/Signature/MessageDigest线程不安全!!!
*
* @author shepherdviolet
*/
public class SM2Cipher {
/**
* 签名算法:SM3withSM2
*/
public static final String SIGN_ALGORITHM_SM2_SM3 = "SM3withSM2";
/**
* 加密算法:SM2
*/
public static final String CRYPTO_ALGORITHM_SM2 = "SM2";
/**
* 使用SM2私钥签名数据
* @param data 待签名数据
* @param id 签名ID, 可为空, 默认"1234567812345678".getBytes()
* @param privateKeyParams 私钥
* @param signAlgorithm 签名算法(SM2Cipher.SIGN_ALGORITHM_SM2_SM3)
* @return DER编码签名数据
*/
public static byte[] sign(byte[] data, byte[] id, ECPrivateKeyParameters privateKeyParams, String signAlgorithm) throws CryptoException {
return BaseBCCipher.signBySM2PrivateKeyParams(data, id, privateKeyParams);
}
/**
* 使用SM2私钥签名输入流
* @param inputStream 待签名数据的输入流, 执行完毕后会被关闭
* @param id 签名ID, 可为空, 默认"1234567812345678".getBytes()
* @param privateKeyParams 私钥
* @param signAlgorithm 签名算法(SM2Cipher.SIGN_ALGORITHM_SM2_SM3)
* @return DER编码签名数据
*/
public static byte[] sign(InputStream inputStream, byte[] id, ECPrivateKeyParameters privateKeyParams, String signAlgorithm) throws CryptoException, IOException {
return BaseBCCipher.signBySM2PrivateKeyParams(inputStream, id, privateKeyParams);
}
/**
* 使用SM2私钥签名数据, 结果为R+S(64bytes)签名数据
* @param data 待签名数据
* @param id 签名ID, 可为空, 默认"1234567812345678".getBytes()
* @param privateKeyParams 私钥
* @param signAlgorithm 签名算法(SM2Cipher.SIGN_ALGORITHM_SM2_SM3)
* @return R+S(64bytes)签名数据
*/
public static byte[] signToRS(byte[] data, byte[] id, ECPrivateKeyParameters privateKeyParams, String signAlgorithm) throws CryptoException, CommonCryptoException {
return BaseBCCipher.derEncodedToSM2RsSignData(
BaseBCCipher.signBySM2PrivateKeyParams(data, id, privateKeyParams)
);
}
/**
* 使用SM2私钥签名输入流, 结果为R+S(64bytes)签名数据
* @param inputStream 待签名数据的输入流, 执行完毕后会被关闭
* @param id 签名ID, 可为空, 默认"1234567812345678".getBytes()
* @param privateKeyParams 私钥
* @param signAlgorithm 签名算法(SM2Cipher.SIGN_ALGORITHM_SM2_SM3)
* @return R+S(64bytes)签名数据
*/
public static byte[] signToRS(InputStream inputStream, byte[] id, ECPrivateKeyParameters privateKeyParams, String signAlgorithm) throws CryptoException, IOException, CommonCryptoException {
return BaseBCCipher.derEncodedToSM2RsSignData(
BaseBCCipher.signBySM2PrivateKeyParams(inputStream, id, privateKeyParams)
);
}
/**
* 使用SM2公钥验签
* @param data 数据
* @param sign 签名, DER编码签名数据
* @param id 签名ID, 可为空, 默认"1234567812345678".getBytes()
* @param publicKeyParams 公钥
* @param signAlgorithm 签名算法(SM2Cipher.SIGN_ALGORITHM_SM2_SM3)
* @return true:验签通过
*/
public static boolean verify(byte[] data, byte[] sign, byte[] id, ECPublicKeyParameters publicKeyParams, String signAlgorithm) {
return BaseBCCipher.verifyBySM2PublicKeyParams(data, sign, id, publicKeyParams);
}
/**
* 使用SM2公钥验签
* @param inputStream 待签名数据的输入流, 执行完毕后会被关闭
* @param sign 签名, DER编码签名数据
* @param id 签名ID, 可为空, 默认"1234567812345678".getBytes()
* @param publicKeyParams 公钥
* @param signAlgorithm 签名算法(SM2Cipher.SIGN_ALGORITHM_SM2_SM3)
* @return true:验签通过
*/
public static boolean verify(InputStream inputStream, byte[] sign, byte[] id, ECPublicKeyParameters publicKeyParams, String signAlgorithm) throws IOException {
return BaseBCCipher.verifyBySM2PublicKeyParams(inputStream, sign, id, publicKeyParams);
}
/**
* 使用SM2公钥验签, 用于R+S(64bytes)签名数据
* @param data 数据
* @param sign 签名, R+S(64bytes)签名数据
* @param id 签名ID, 可为空, 默认"1234567812345678".getBytes()
* @param publicKeyParams 公钥
* @param signAlgorithm 签名算法(SM2Cipher.SIGN_ALGORITHM_SM2_SM3)
* @return true:验签通过
*/
public static boolean verifyFromRS(byte[] data, byte[] sign, byte[] id, ECPublicKeyParameters publicKeyParams, String signAlgorithm) {
byte[] derSign;
try {
derSign = BaseBCCipher.sm2RsSignDataToDerEncoded(sign);
} catch (IOException e) {
return false;
}
return BaseBCCipher.verifyBySM2PublicKeyParams(
data,
derSign,
id,
publicKeyParams);
}
/**
* 使用SM2公钥验签, 用于R+S(64bytes)签名数据
* @param inputStream 待签名数据的输入流, 执行完毕后会被关闭
* @param sign 签名, R+S(64bytes)签名数据
* @param id 签名ID, 可为空, 默认"1234567812345678".getBytes()
* @param publicKeyParams 公钥
* @param signAlgorithm 签名算法(SM2Cipher.SIGN_ALGORITHM_SM2_SM3)
* @return true:验签通过
*/
public static boolean verifyFromRS(InputStream inputStream, byte[] sign, byte[] id, ECPublicKeyParameters publicKeyParams, String signAlgorithm) throws IOException {
byte[] derSign;
try {
derSign = BaseBCCipher.sm2RsSignDataToDerEncoded(sign);
} catch (IOException e) {
return false;
}
return BaseBCCipher.verifyBySM2PublicKeyParams(
inputStream,
derSign,
id,
publicKeyParams);
}
/**
* 使用SM2公钥加密(密文为C1C2C3格式).
* 密文开头有0x04, 表示未压缩, 有些工具加密的密文前面没有0x04, 可以尝试手工增加或者去掉实现兼容.
*
* @param publicKeyParams SM2公钥
* @param data 原文数据
* @param cryptoAlgorithm 加密算法(SM2Cipher.CRYPTO_ALGORITHM_SM2)
* @return 密文, 密文为C1C2C3格式, C1区域为随机公钥点数据(ASN.1格式), C2为密文数据, C3为摘要数据(SM3).
*/
public static byte[] encrypt(byte[] data, ECPublicKeyParameters publicKeyParams, String cryptoAlgorithm) throws InvalidCipherTextException {
return BaseBCCipher.encryptBySM2PublicKeyParams(data, publicKeyParams);
}
/**
* 使用SM2私钥解密(密文为C1C2C3格式).
* 密文开头有0x04, 表示未压缩, 有些工具加密的密文前面没有0x04, 可以尝试手工增加或者去掉实现兼容.
*
* @param privateKeyParams SM2私钥
* @param data 密文数据, 密文为C1C2C3格式, C1区域为随机公钥点数据(ASN.1格式), C2为密文数据, C3为摘要数据(SM3).
* @param cryptoAlgorithm 加密算法(SM2Cipher.CRYPTO_ALGORITHM_SM2)
* @return 原文
*/
public static byte[] decrypt(byte[] data, ECPrivateKeyParameters privateKeyParams, String cryptoAlgorithm) throws InvalidCipherTextException {
return BaseBCCipher.decryptBySM2PrivateKeyParams(data, privateKeyParams);
}
/**
* 使用SM2公钥加密(密文为C1C3C2格式).
* 密文开头有0x04, 表示未压缩, 有些工具加密的密文前面没有0x04, 可以尝试手工增加或者去掉实现兼容.
*
* @param publicKeyParams SM2公钥
* @param data 原文数据
* @param cryptoAlgorithm 加密算法(SM2Cipher.CRYPTO_ALGORITHM_SM2)
* @return 密文, 密文为C1C3C2格式, C1区域为随机公钥点数据(ASN.1格式), C2为密文数据, C3为摘要数据(SM3).
*/
public static byte[] encryptToC1C3C2(byte[] data, ECPublicKeyParameters publicKeyParams, String cryptoAlgorithm) throws InvalidCipherTextException {
return BaseBCCipher.sm2CiphertextC1C2C3ToC1C3C2(
BaseBCCipher.encryptBySM2PublicKeyParams(data, publicKeyParams),
SM2DefaultCurve.C1_LENGTH,
SM3DigestCipher.SM3_HASH_LENGTH
);
}
/**
* 使用SM2私钥解密(密文为C1C3C2格式).
* 密文开头有0x04, 表示未压缩, 有些工具加密的密文前面没有0x04, 可以尝试手工增加或者去掉实现兼容.
*
* @param privateKeyParams SM2私钥
* @param data 密文数据, 密文为C1C3C2格式, C1区域为随机公钥点数据(ASN.1格式), C2为密文数据, C3为摘要数据(SM3).
* @param cryptoAlgorithm 加密算法(SM2Cipher.CRYPTO_ALGORITHM_SM2)
* @return 原文
*/
public static byte[] decryptFromC1C3C2(byte[] data, ECPrivateKeyParameters privateKeyParams, String cryptoAlgorithm) throws InvalidCipherTextException {
return BaseBCCipher.decryptBySM2PrivateKeyParams(
BaseBCCipher.sm2CiphertextC1C3C2ToC1C2C3(
data,
SM2DefaultCurve.C1_LENGTH,
SM3DigestCipher.SM3_HASH_LENGTH
),
privateKeyParams);
}
/**
* 使用SM2公钥加密(密文为C1C2C3 DER格式).
*
* @param publicKeyParams SM2公钥
* @param data 原文数据
* @param cryptoAlgorithm 加密算法(SM2Cipher.CRYPTO_ALGORITHM_SM2)
* @return 密文, 密文为C1C2C3 DER格式(SM2密码算法使用规范 GM/T 0009-2012)
*/
public static byte[] encryptToDER(byte[] data, ECPublicKeyParameters publicKeyParams, String cryptoAlgorithm) throws InvalidCipherTextException, IOException {
return BaseBCCipher.sm2CipherTextC1C2C3ToDEREncoded(
BaseBCCipher.encryptBySM2PublicKeyParams(data, publicKeyParams),
SM2DefaultCurve.CURVE_LENGTH,
SM3DigestCipher.SM3_HASH_LENGTH
);
}
/**
* 使用SM2私钥解密(密文为C1C2C3 DER格式).
*
* @param privateKeyParams SM2私钥
* @param data 密文数据, 密文为C1C2C3 DER格式(SM2密码算法使用规范 GM/T 0009-2012)
* @param cryptoAlgorithm 加密算法(SM2Cipher.CRYPTO_ALGORITHM_SM2)
* @return 原文
*/
public static byte[] decryptFromDER(byte[] data, ECPrivateKeyParameters privateKeyParams, String cryptoAlgorithm) throws CommonCryptoException, InvalidCipherTextException {
return BaseBCCipher.decryptBySM2PrivateKeyParams(
BaseBCCipher.derEncodedToSM2CipherTextC1C2C3(
data
),
privateKeyParams);
}
/**
* 修复非标准的DER编码的签名数据.
*
* 20230320:
* 发现某签名服务器签名出来的DER格式签名不标准, 当R值偏大时, r[0] >= 0x80, 使得整个大数字变成了负数, 而R和S值是不能
* 小于1的(见org.bouncycastle.crypto.signers.SM2Signer#verifySignature方法). 在标准的DER格式中, 遇到这种情况, 应该在前面
* 增加一个字节0x00, 以保证数值为正整数. 顺带一提, RS格式的签名数据, 不会在前面追加0x00, 因为它要严格保证32+32字节.
*
* @param der DER编码的签名数据
* @return 修复后的DER编码的签名数据, 修复失败返回原值
*/
public static byte[] fixDerSign(byte[] der) {
return NonStandardDataFixer.fixDerSign(der);
}
/**
* @deprecated Use SM2Cipher#fixDerSign
*/
@Deprecated
public static byte[] tryFixBadDerSignData(byte[] der) {
return NonStandardDataFixer.fixDerSign(der);
}
}