sdf api
This commit is contained in:
parent
44161e70bb
commit
36bf16353e
@ -2,7 +2,9 @@ package com.sunyard.chsm.sdf;
|
||||
|
||||
|
||||
import com.sunyard.chsm.sdf.context.AlgId;
|
||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.sdf.model.EccSignature;
|
||||
|
||||
|
||||
/**
|
||||
@ -70,6 +72,50 @@ public interface SdfApiService {
|
||||
*/
|
||||
EccKey genKeyPairEcc();
|
||||
|
||||
/**
|
||||
* 外部密钥ECC签名
|
||||
*
|
||||
* @param privateKey ECC私钥
|
||||
* @param pucData 缓冲区指针,用于存放外部输入的数据
|
||||
* @param userId 签名者id
|
||||
* @return pucSignature 返回签名值数据
|
||||
*/
|
||||
EccSignature externalSignWithId(byte[] privateKey, byte[] pucData, byte[] userId);
|
||||
|
||||
EccSignature externalSign(byte[] privateKey, byte[] pucData);
|
||||
|
||||
/**
|
||||
* 外部密钥ECC验证
|
||||
*
|
||||
* @param publicKey ECC公钥
|
||||
* @param pubData 原文
|
||||
* @param userId 签名者id
|
||||
* @param signData 外部签名数据
|
||||
* @return 0 成功; 非0 失败,返回错误代码
|
||||
*/
|
||||
boolean externalVerifyWithId(byte[] publicKey, byte[] pubData, byte[] signData, byte[] userId);
|
||||
|
||||
boolean externalVerify(byte[] publicKey, byte[] pubData, byte[] signData);
|
||||
|
||||
|
||||
/**
|
||||
* 外部密钥ECC公钥加密
|
||||
*
|
||||
* @param publicKey 外部ECC公钥结构
|
||||
* @param pucData 缓冲区指针,用于存放外部输入的数据
|
||||
* @return pucEncData 返回数据密文
|
||||
*/
|
||||
EccCipher externalEncrypt(byte[] publicKey, byte[] pucData);
|
||||
|
||||
/**
|
||||
* 外部密钥ECC私钥解密
|
||||
*
|
||||
* @param privateKey 外部ECC私钥结构
|
||||
* @param encData 缓冲区指针,用于存放输入的数据密文
|
||||
* @return pucData 返回数据明文
|
||||
*/
|
||||
byte[] externalDecrypt(byte[] privateKey, byte[] encData);
|
||||
|
||||
/**
|
||||
* 计算MAC
|
||||
*
|
||||
|
@ -4,16 +4,21 @@ import com.sunyard.chsm.sdf.context.AlgId;
|
||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPriKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import com.sunyard.chsm.sdf.model.EccSignature;
|
||||
import com.sunyard.chsm.sdf.util.LangUtils;
|
||||
import com.sunyard.chsm.utils.gm.BCECUtils;
|
||||
import com.sunyard.chsm.utils.gm.BCSM2Utils;
|
||||
import com.sunyard.chsm.utils.gm.BCSM4Utils;
|
||||
import lombok.SneakyThrows;
|
||||
import org.bouncycastle.crypto.CryptoException;
|
||||
import org.bouncycastle.crypto.InvalidCipherTextException;
|
||||
import org.bouncycastle.crypto.digests.NullDigest;
|
||||
import org.bouncycastle.crypto.digests.SM3Digest;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.crypto.signers.SM2Signer;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
@ -130,6 +135,52 @@ public class BcSdfApiAdaptor implements SdfApiAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccSignature externalSignECC(String sessionHandle, EccPriKey privateKey, byte[] pucData) {
|
||||
ECPrivateKeyParameters pri = BCECUtils.createECPrivateKeyParameters(getD());
|
||||
try {
|
||||
SM2Signer signer = new SM2Signer(new NullDigest());
|
||||
signer.init(true, pri);
|
||||
signer.update(pucData, 0, pucData.length);
|
||||
byte[] signature = signer.generateSignature();
|
||||
return EccSignature.fromBytes(signature);
|
||||
} catch (CryptoException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean externalVerifyECC(String sessionHandle, EccPubKey publicKey, byte[] pucData, EccSignature pucSignature) {
|
||||
ECPublicKeyParameters pub = BCECUtils.createECPublicKeyParameters(publicKey.getX(), publicKey.getY());
|
||||
SM2Signer verifier = new SM2Signer(new NullDigest());
|
||||
verifier.init(false, pub);
|
||||
// 验证数据
|
||||
verifier.update(pucData, 0, pucData.length);
|
||||
return verifier.verifySignature(pucSignature.getRawSignBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccCipher externalEncryptECC(String sessionHandle, EccPubKey pubKey, byte[] pucData) {
|
||||
ECPublicKeyParameters pub = BCECUtils.createECPublicKeyParameters(pubKey.getX(), pubKey.getY());
|
||||
try {
|
||||
byte[] encrypt = BCSM2Utils.encrypt(pub, pucData);
|
||||
return EccCipher.fromBytes(encrypt);
|
||||
} catch (InvalidCipherTextException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] externalDecryptECC(String sessionHandle, EccPriKey pucPrivateKeyEcc, EccCipher pucEncData) {
|
||||
ECPrivateKeyParameters pri = BCECUtils.createECPrivateKeyParameters(getD());
|
||||
try {
|
||||
return BCSM2Utils.decrypt(pri, LangUtils.merge(new byte[]{0x04}, pucEncData.getC1C3C2Bytes()));
|
||||
} catch (InvalidCipherTextException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String importKeyWithISKECC(String sessionHandle, int uiIskIndex, EccCipher eccCipher) {
|
||||
ECPrivateKeyParameters pri = BCECUtils.createECPrivateKeyParameters(getD());
|
||||
@ -159,19 +210,6 @@ public class BcSdfApiAdaptor implements SdfApiAdapter {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EccCipher externalEncryptECC(String sessionHandle, EccPubKey pubKey, byte[] pucData) {
|
||||
ECPublicKeyParameters pub = BCECUtils.createECPublicKeyParameters(pubKey.getX(), pubKey.getY());
|
||||
try {
|
||||
byte[] encrypt = BCSM2Utils.encrypt(pub, pucData);
|
||||
return EccCipher.fromBytes(encrypt);
|
||||
} catch (InvalidCipherTextException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public byte[] symEncrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucData) {
|
||||
|
@ -4,12 +4,14 @@ import com.sun.jna.Pointer;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import com.sunyard.chsm.sdf.context.AlgId;
|
||||
import com.sunyard.chsm.sdf.context.SdrCode;
|
||||
import com.sunyard.chsm.sdf.lib.SdfLibrary;
|
||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPriKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import com.sunyard.chsm.sdf.model.EccSignature;
|
||||
import com.sunyard.chsm.sdf.model.SDF_DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.util.LangUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -17,6 +19,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@ -169,10 +172,11 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
|
||||
|
||||
@Override
|
||||
public int destroyKey(String sessionHandle, String hKeyHandle) {
|
||||
return 0;
|
||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
||||
Pointer keyHandle = KEY_HANDLE_CONTEXT.remove(hKeyHandle);
|
||||
return sdfLibrary.SDF_DestroyKey(hSessionHandle, keyHandle);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EccCipher exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, EccPubKey pubKey, EccCipher pucEncDateIn) {
|
||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
||||
@ -183,6 +187,25 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
|
||||
return EccCipher.fromBytes(pucEncDateOut);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccSignature externalSignECC(String sessionHandle, EccPriKey privateKey, byte[] pucData) {
|
||||
byte[] eccSignature = new byte[128];
|
||||
int uiDataLength = pucData.length;
|
||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
||||
sdfLibrary.SDF_ExternalSign_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_1), privateKey.toSdfData(),
|
||||
pucData, uiDataLength, eccSignature);
|
||||
return EccSignature.fromBytes(eccSignature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean externalVerifyECC(String sessionHandle, EccPubKey publicKey, byte[] pucData, EccSignature pucSignature) {
|
||||
int uiDataLength = pucData.length;
|
||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
||||
int result = sdfLibrary.SDF_ExternalVerify_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_1), publicKey.toSdfData(),
|
||||
pucData, uiDataLength, pucSignature.toSdfData());
|
||||
return Objects.equals(result, SdrCode.SDR_OK.getCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccCipher externalEncryptECC(String sessionHandle, EccPubKey pubKey, byte[] pucData) {
|
||||
byte[] encData = new byte[128 + 32 + 4 + pucData.length];
|
||||
@ -191,6 +214,15 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
|
||||
return EccCipher.fromBytes(encData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] externalDecryptECC(String sessionHandle, EccPriKey priKey, EccCipher pucEncData) {
|
||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
||||
byte[] pucData = new byte[pucEncData.getL()];
|
||||
IntByReference puiLength = new IntByReference();
|
||||
sdfLibrary.SDF_ExternalDecrypt_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_3), priKey.toSdfData(), pucEncData.toSdfData(), pucData, puiLength);
|
||||
return pucData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] symEncrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucData) {
|
||||
|
||||
@ -225,7 +257,7 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter {
|
||||
Pointer hKeyHandle = getKeyHandle(keyHandle);
|
||||
|
||||
int uiMacLength = pucData.length;
|
||||
byte[] pucMac = new byte[uiMacLength];
|
||||
byte[] pucMac = new byte[16];
|
||||
|
||||
IntByReference puiLength = new IntByReference();
|
||||
sdfLibrary.SDF_CalculateMAC(hSessionHandle, hKeyHandle, getAlgId(uiAlg), pucIv, pucData, uiMacLength, pucMac, puiLength);
|
||||
|
@ -4,7 +4,9 @@ import com.sunyard.chsm.sdf.context.AlgId;
|
||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPriKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import com.sunyard.chsm.sdf.model.EccSignature;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
@ -96,9 +98,27 @@ public interface SdfApiAdapter {
|
||||
*/
|
||||
int destroyKey(String sessionHandle, String hKeyHandle);
|
||||
|
||||
|
||||
EccCipher exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, EccPubKey pubKey, EccCipher pucEncDateIn);
|
||||
|
||||
/**
|
||||
* 外部密钥ECC签名
|
||||
*
|
||||
* @param privateKey ECC私钥
|
||||
* @param pucData 缓冲区指针,用于存放外部输入的数据
|
||||
* @return pucSignature 返回签名值数据
|
||||
*/
|
||||
EccSignature externalSignECC(String sessionHandle, EccPriKey privateKey, byte[] pucData);
|
||||
|
||||
/**
|
||||
* 外部密钥ECC验证
|
||||
*
|
||||
* @param publicKey ECC公钥
|
||||
* @param pucData 缓冲区指针,用于存放外部输入的数据
|
||||
* @param pucSignature 缓冲区指针,用于存放输入的签名值数据
|
||||
* @return 0 成功; 非0 失败,返回错误代码
|
||||
*/
|
||||
boolean externalVerifyECC(String sessionHandle, EccPubKey publicKey, byte[] pucData, EccSignature pucSignature);
|
||||
|
||||
/**
|
||||
* 外部密钥ECC公钥加密
|
||||
*
|
||||
@ -108,6 +128,15 @@ public interface SdfApiAdapter {
|
||||
*/
|
||||
EccCipher externalEncryptECC(String sessionHandle, EccPubKey pubKey, byte[] pucData);
|
||||
|
||||
/**
|
||||
* 外部密钥ECC私钥解密
|
||||
*
|
||||
* @param pucPrivateKeyEcc 外部ECC私钥结构
|
||||
* @param pucEncData 缓冲区指针,用于存放输入的数据密文
|
||||
* @return pucData 返回数据明文
|
||||
*/
|
||||
byte[] externalDecryptECC(String sessionHandle, EccPriKey pucPrivateKeyEcc, EccCipher pucEncData);
|
||||
|
||||
/**
|
||||
* 对称加密
|
||||
*
|
||||
|
@ -3,6 +3,7 @@ package com.sunyard.chsm.sdf.model;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -22,8 +23,15 @@ public class EccPriKey {
|
||||
// 私 钥
|
||||
private byte[] D;
|
||||
|
||||
public byte[] toSdfData() {
|
||||
byte[] sdf = new byte[68];
|
||||
System.arraycopy(Hex.decode("00010000"), 0, sdf, 0, 4);
|
||||
System.arraycopy(D, 0, sdf, 36, 32);
|
||||
return sdf;
|
||||
}
|
||||
|
||||
public static EccPriKey fromBytes(byte[] priKey) {
|
||||
Assert.notNull(priKey, "公钥数据不能为null");
|
||||
Assert.notNull(priKey, "私钥数据不能为null");
|
||||
if (Objects.equals(priKey.length, 68)) {
|
||||
// 00010000
|
||||
priKey = Arrays.copyOfRange(priKey, 4, priKey.length);
|
||||
|
@ -4,6 +4,8 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @version V1.0
|
||||
@ -27,5 +29,28 @@ public class EccSignature {
|
||||
return signData;
|
||||
}
|
||||
|
||||
public byte[] toSdfData() {
|
||||
byte[] res = new byte[128];
|
||||
System.arraycopy(r, 0, res, 32, 32);
|
||||
System.arraycopy(s, 0, res, 96, 32);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static EccSignature fromBytes(byte[] sign) {
|
||||
if (sign == null || sign.length == 0) {
|
||||
return null;
|
||||
}
|
||||
if (sign.length == 64) {
|
||||
byte[] r = Arrays.copyOfRange(sign, 0, 32);
|
||||
byte[] s = Arrays.copyOfRange(sign, 32, 64);
|
||||
return new EccSignature(r, s);
|
||||
} else if (sign.length == 128) {
|
||||
byte[] r = Arrays.copyOfRange(sign, 32, 64);
|
||||
byte[] s = Arrays.copyOfRange(sign, 96, 128);
|
||||
return new EccSignature(r, s);
|
||||
} else {
|
||||
throw new IllegalArgumentException("ECC签名数据格式错误");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,294 @@
|
||||
package com.sunyard.chsm.utils.gm;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1Encoding;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.ASN1Primitive;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.crypto.CryptoException;
|
||||
import org.bouncycastle.crypto.CryptoServicesRegistrar;
|
||||
import org.bouncycastle.crypto.Digest;
|
||||
import org.bouncycastle.crypto.digests.SM3Digest;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.crypto.params.ECKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ParametersWithID;
|
||||
import org.bouncycastle.crypto.params.ParametersWithRandom;
|
||||
import org.bouncycastle.crypto.signers.DSAKCalculator;
|
||||
import org.bouncycastle.crypto.signers.RandomDSAKCalculator;
|
||||
import org.bouncycastle.math.ec.ECAlgorithms;
|
||||
import org.bouncycastle.math.ec.ECConstants;
|
||||
import org.bouncycastle.math.ec.ECFieldElement;
|
||||
import org.bouncycastle.math.ec.ECMultiplier;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.bouncycastle.math.ec.FixedPointCombMultiplier;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* 有的国密需求是用户可以自己做预处理,签名验签只是对预处理的结果进行签名和验签
|
||||
*/
|
||||
public class SM2PreprocessSigner implements ECConstants {
|
||||
private static final int DIGEST_LENGTH = 32; // bytes
|
||||
|
||||
private final DSAKCalculator kCalculator = new RandomDSAKCalculator();
|
||||
private Digest digest = null;
|
||||
|
||||
private ECDomainParameters ecParams;
|
||||
private ECPoint pubPoint;
|
||||
private ECKeyParameters ecKey;
|
||||
private byte[] userID;
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param forSigning true表示用于签名,false表示用于验签
|
||||
* @param param
|
||||
*/
|
||||
public void init(boolean forSigning, CipherParameters param) {
|
||||
init(forSigning, new SM3Digest(), param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param forSigning true表示用于签名,false表示用于验签
|
||||
* @param digest SM2算法的话,一般是采用SM3摘要算法
|
||||
* @param param
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public void init(boolean forSigning, Digest digest, CipherParameters param) throws RuntimeException {
|
||||
CipherParameters baseParam;
|
||||
|
||||
if (digest.getDigestSize() != DIGEST_LENGTH) {
|
||||
throw new RuntimeException("Digest size must be " + DIGEST_LENGTH);
|
||||
}
|
||||
this.digest = digest;
|
||||
|
||||
if (param instanceof ParametersWithID) {
|
||||
baseParam = ((ParametersWithID) param).getParameters();
|
||||
userID = ((ParametersWithID) param).getID();
|
||||
} else {
|
||||
baseParam = param;
|
||||
userID = Hex.decode("31323334353637383132333435363738"); // the default value
|
||||
}
|
||||
|
||||
if (forSigning) {
|
||||
if (baseParam instanceof ParametersWithRandom) {
|
||||
ParametersWithRandom rParam = (ParametersWithRandom) baseParam;
|
||||
|
||||
ecKey = (ECKeyParameters) rParam.getParameters();
|
||||
ecParams = ecKey.getParameters();
|
||||
kCalculator.init(ecParams.getN(), rParam.getRandom());
|
||||
} else {
|
||||
ecKey = (ECKeyParameters) baseParam;
|
||||
ecParams = ecKey.getParameters();
|
||||
kCalculator.init(ecParams.getN(), CryptoServicesRegistrar.getSecureRandom());
|
||||
}
|
||||
pubPoint = createBasePointMultiplier().multiply(ecParams.getG(), ((ECPrivateKeyParameters) ecKey).getD()).normalize();
|
||||
} else {
|
||||
ecKey = (ECKeyParameters) baseParam;
|
||||
ecParams = ecKey.getParameters();
|
||||
pubPoint = ((ECPublicKeyParameters) ecKey).getQ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预处理,辅助方法
|
||||
* ZA=H256(ENT LA ∥ IDA ∥ a ∥ b ∥ xG ∥yG ∥ xA ∥ yA)。
|
||||
* M=ZA ∥ M;
|
||||
* e = Hv(M)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] preprocess(byte[] m) {
|
||||
return preprocess(m, 0, m.length);
|
||||
}
|
||||
|
||||
|
||||
public byte[] preprocess(byte[] m, int off, int len) {
|
||||
byte[] z = getZ(userID);
|
||||
digest.update(z, 0, z.length);
|
||||
digest.update(m, off, len);
|
||||
byte[] eHash = new byte[DIGEST_LENGTH];
|
||||
digest.doFinal(eHash, 0);
|
||||
return eHash;
|
||||
}
|
||||
|
||||
public boolean verifySignature(byte[] eHash, byte[] signature) {
|
||||
try {
|
||||
BigInteger[] rs = derDecode(signature);
|
||||
if (rs != null) {
|
||||
return verifySignature(eHash, rs[0], rs[1]);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
digest.reset();
|
||||
}
|
||||
|
||||
public byte[] generateSignature(byte[] eHash) throws CryptoException {
|
||||
BigInteger n = ecParams.getN();
|
||||
BigInteger e = calculateE(eHash);
|
||||
BigInteger d = ((ECPrivateKeyParameters) ecKey).getD();
|
||||
|
||||
BigInteger r, s;
|
||||
|
||||
ECMultiplier basePointMultiplier = createBasePointMultiplier();
|
||||
|
||||
// 5.2.1 Draft RFC: SM2 Public Key Algorithms
|
||||
do // generate s
|
||||
{
|
||||
BigInteger k;
|
||||
do // generate r
|
||||
{
|
||||
// A3
|
||||
k = kCalculator.nextK();
|
||||
|
||||
// A4
|
||||
ECPoint p = basePointMultiplier.multiply(ecParams.getG(), k).normalize();
|
||||
|
||||
// A5
|
||||
r = e.add(p.getAffineXCoord().toBigInteger()).mod(n);
|
||||
}
|
||||
while (r.equals(ZERO) || r.add(k).equals(n));
|
||||
|
||||
// A6
|
||||
BigInteger dPlus1ModN = d.add(ONE).modInverse(n);
|
||||
|
||||
s = k.subtract(r.multiply(d)).mod(n);
|
||||
s = dPlus1ModN.multiply(s).mod(n);
|
||||
}
|
||||
while (s.equals(ZERO));
|
||||
|
||||
// A7
|
||||
try {
|
||||
return derEncode(r, s);
|
||||
} catch (IOException ex) {
|
||||
throw new CryptoException("unable to encode signature: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean verifySignature(byte[] eHash, BigInteger r, BigInteger s) {
|
||||
BigInteger n = ecParams.getN();
|
||||
|
||||
// 5.3.1 Draft RFC: SM2 Public Key Algorithms
|
||||
// B1
|
||||
if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// B2
|
||||
if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// B3 eHash
|
||||
|
||||
// B4
|
||||
BigInteger e = calculateE(eHash);
|
||||
|
||||
// B5
|
||||
BigInteger t = r.add(s).mod(n);
|
||||
if (t.equals(ZERO)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// B6
|
||||
ECPoint q = ((ECPublicKeyParameters) ecKey).getQ();
|
||||
ECPoint x1y1 = ECAlgorithms.sumOfTwoMultiplies(ecParams.getG(), s, q, t).normalize();
|
||||
if (x1y1.isInfinity()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// B7
|
||||
BigInteger expectedR = e.add(x1y1.getAffineXCoord().toBigInteger()).mod(n);
|
||||
|
||||
return expectedR.equals(r);
|
||||
}
|
||||
|
||||
private byte[] digestDoFinal() {
|
||||
byte[] result = new byte[digest.getDigestSize()];
|
||||
digest.doFinal(result, 0);
|
||||
|
||||
reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte[] getZ(byte[] userID) {
|
||||
digest.reset();
|
||||
|
||||
addUserID(digest, userID);
|
||||
|
||||
addFieldElement(digest, ecParams.getCurve().getA());
|
||||
addFieldElement(digest, ecParams.getCurve().getB());
|
||||
addFieldElement(digest, ecParams.getG().getAffineXCoord());
|
||||
addFieldElement(digest, ecParams.getG().getAffineYCoord());
|
||||
addFieldElement(digest, pubPoint.getAffineXCoord());
|
||||
addFieldElement(digest, pubPoint.getAffineYCoord());
|
||||
|
||||
byte[] result = new byte[digest.getDigestSize()];
|
||||
|
||||
digest.doFinal(result, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addUserID(Digest digest, byte[] userID) {
|
||||
int len = userID.length * 8;
|
||||
digest.update((byte) (len >> 8 & 0xFF));
|
||||
digest.update((byte) (len & 0xFF));
|
||||
digest.update(userID, 0, userID.length);
|
||||
}
|
||||
|
||||
private void addFieldElement(Digest digest, ECFieldElement v) {
|
||||
byte[] p = v.getEncoded();
|
||||
digest.update(p, 0, p.length);
|
||||
}
|
||||
|
||||
protected ECMultiplier createBasePointMultiplier() {
|
||||
return new FixedPointCombMultiplier();
|
||||
}
|
||||
|
||||
protected BigInteger calculateE(byte[] message) {
|
||||
return new BigInteger(1, message);
|
||||
}
|
||||
|
||||
protected BigInteger[] derDecode(byte[] encoding)
|
||||
throws IOException {
|
||||
ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(encoding));
|
||||
if (seq.size() != 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BigInteger r = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue();
|
||||
BigInteger s = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue();
|
||||
|
||||
byte[] expectedEncoding = derEncode(r, s);
|
||||
if (!Arrays.constantTimeAreEqual(expectedEncoding, encoding)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new BigInteger[]{r, s};
|
||||
}
|
||||
|
||||
protected byte[] derEncode(BigInteger r, BigInteger s)
|
||||
throws IOException {
|
||||
|
||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||
v.add(new ASN1Integer(r));
|
||||
v.add(new ASN1Integer(s));
|
||||
return new DERSequence(v).getEncoded(ASN1Encoding.DER);
|
||||
}
|
||||
}
|
@ -11,11 +11,18 @@ import com.sunyard.chsm.sdf.context.AlgId;
|
||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPriKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import com.sunyard.chsm.sdf.model.EccSignature;
|
||||
import com.sunyard.chsm.sdf.util.PaddingUtil;
|
||||
import com.sunyard.chsm.service.TmkService;
|
||||
import com.sunyard.chsm.utils.gm.BCECUtils;
|
||||
import com.sunyard.chsm.utils.gm.BCSM3Utils;
|
||||
import com.sunyard.chsm.utils.gm.SM2PreprocessSigner;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.crypto.params.ParametersWithID;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
@ -80,6 +87,57 @@ public class SingleSdfApiService implements SdfApiService, InitializingBean {
|
||||
return sdfApiAdapter.generateKeyPairECC(sessionHandle, AlgId.SGD_SM2_1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccSignature externalSign(byte[] privateKey, byte[] pucData) {
|
||||
return externalSignWithId(privateKey, pucData, new byte[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccSignature externalSignWithId(byte[] privateKey, byte[] pucData, byte[] userId) {
|
||||
EccPriKey sdfEccPrivateKey = EccPriKey.fromBytes(privateKey);
|
||||
SM2PreprocessSigner signer = new SM2PreprocessSigner();
|
||||
CipherParameters keyParameters = BCECUtils.createECPrivateKeyParameters(sdfEccPrivateKey.getD());
|
||||
if (userId != null && userId.length > 0) {
|
||||
keyParameters = new ParametersWithID(keyParameters, userId);
|
||||
}
|
||||
signer.init(true, keyParameters);
|
||||
byte[] preHash = signer.preprocess(pucData);
|
||||
return sdfApiAdapter.externalSignECC(sessionHandle, sdfEccPrivateKey, preHash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean externalVerifyWithId(byte[] publicKey, byte[] pubData, byte[] signData, byte[] userId) {
|
||||
EccPubKey eccPublicKey = EccPubKey.fromBytes(publicKey);
|
||||
CipherParameters parameters = BCECUtils.createECPublicKeyParameters(eccPublicKey.getX(), eccPublicKey.getY());
|
||||
if (userId != null && userId.length > 0) {
|
||||
parameters = new ParametersWithID(parameters, userId);
|
||||
}
|
||||
SM2PreprocessSigner signer = new SM2PreprocessSigner();
|
||||
signer.init(false, parameters);
|
||||
byte[] preHash = signer.preprocess(pubData);
|
||||
EccSignature eccSignature = EccSignature.fromBytes(signData);
|
||||
|
||||
return sdfApiAdapter.externalVerifyECC(sessionHandle, eccPublicKey, preHash, eccSignature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean externalVerify(byte[] publicKey, byte[] pubData, byte[] signData) {
|
||||
return externalVerifyWithId(publicKey, pubData, signData, new byte[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccCipher externalEncrypt(byte[] publicKey, byte[] pucData) {
|
||||
EccPubKey eccPublicKey = EccPubKey.fromBytes(publicKey);
|
||||
return sdfApiAdapter.externalEncryptECC(sessionHandle, eccPublicKey, pucData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] externalDecrypt(byte[] privateKey, byte[] encData) {
|
||||
EccPriKey sdfEccPrivateKey = EccPriKey.fromBytes(privateKey);
|
||||
EccCipher eccCipher = EccCipher.fromBytes(encData);
|
||||
return sdfApiAdapter.externalDecryptECC(sessionHandle, sdfEccPrivateKey, eccCipher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) {
|
||||
checkStatus();
|
||||
|
@ -2,10 +2,18 @@ package com.sunyard.chsm.pool;
|
||||
|
||||
import com.sunyard.chsm.sdf.SdfApiService;
|
||||
import com.sunyard.chsm.sdf.context.AlgId;
|
||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPriKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import com.sunyard.chsm.sdf.model.EccSignature;
|
||||
import com.sunyard.chsm.sdf.util.PaddingUtil;
|
||||
import com.sunyard.chsm.utils.gm.BCECUtils;
|
||||
import com.sunyard.chsm.utils.gm.BCSM3Utils;
|
||||
import com.sunyard.chsm.utils.gm.SM2PreprocessSigner;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.crypto.params.ParametersWithID;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@ -63,6 +71,59 @@ public class LoadBalancedSdfApiService implements SdfApiService {
|
||||
return apply(s -> s.getSdfApiAdapter().generateKeyPairECC(s.getSessionHandle(), AlgId.SGD_SM2_1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccSignature externalSign(byte[] privateKey, byte[] pucData) {
|
||||
return externalSignWithId(privateKey, pucData, new byte[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccSignature externalSignWithId(byte[] privateKey, byte[] pucData, byte[] userId) {
|
||||
EccPriKey sdfEccPrivateKey = EccPriKey.fromBytes(privateKey);
|
||||
SM2PreprocessSigner signer = new SM2PreprocessSigner();
|
||||
CipherParameters keyParameters = BCECUtils.createECPrivateKeyParameters(sdfEccPrivateKey.getD());
|
||||
if (userId != null && userId.length > 0) {
|
||||
keyParameters = new ParametersWithID(keyParameters, userId);
|
||||
}
|
||||
signer.init(true, keyParameters);
|
||||
byte[] preHash = signer.preprocess(pucData);
|
||||
|
||||
return apply(s -> s.getSdfApiAdapter().externalSignECC(s.getSessionHandle(), sdfEccPrivateKey, preHash));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean externalVerifyWithId(byte[] publicKey, byte[] pubData, byte[] signData, byte[] userId) {
|
||||
EccPubKey eccPublicKey = EccPubKey.fromBytes(publicKey);
|
||||
CipherParameters parameters = BCECUtils.createECPublicKeyParameters(eccPublicKey.getX(), eccPublicKey.getY());
|
||||
if (userId != null && userId.length > 0) {
|
||||
parameters = new ParametersWithID(parameters, userId);
|
||||
}
|
||||
SM2PreprocessSigner signer = new SM2PreprocessSigner();
|
||||
signer.init(false, parameters);
|
||||
byte[] preHash = signer.preprocess(pubData);
|
||||
EccSignature eccSignature = EccSignature.fromBytes(signData);
|
||||
|
||||
return apply(s -> s.getSdfApiAdapter().externalVerifyECC(s.getSessionHandle(),
|
||||
eccPublicKey, preHash, eccSignature));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean externalVerify(byte[] publicKey, byte[] pubData, byte[] signData) {
|
||||
return externalVerifyWithId(publicKey, pubData, signData, new byte[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccCipher externalEncrypt(byte[] publicKey, byte[] pucData) {
|
||||
EccPubKey eccPublicKey = EccPubKey.fromBytes(publicKey);
|
||||
return apply(s -> s.getSdfApiAdapter().externalEncryptECC(s.getSessionHandle(), eccPublicKey, pucData));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] externalDecrypt(byte[] privateKey, byte[] encData) {
|
||||
EccPriKey sdfEccPrivateKey = EccPriKey.fromBytes(privateKey);
|
||||
EccCipher eccCipher = EccCipher.fromBytes(encData);
|
||||
return apply(s -> s.getSdfApiAdapter().externalDecryptECC(s.getSessionHandle(), sdfEccPrivateKey, eccCipher));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) {
|
||||
return apply(s -> {
|
||||
|
Loading…
Reference in New Issue
Block a user