Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@
<version>${org.springframework}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework}</version>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public interface YopConstants {
*/
String YOP_ENCRYPT_V1 = "yop-encrypt-v1";
String SM4_CBC_PKCS5PADDING = "SM4/CBC/PKCS5Padding";
String SM4_ECB_PKCS5PADDING = "SM4/ECB/PKCS5Padding";
String SM2 = "SM2";
String AES = "AES";
String AES_ECB_PKCS5PADDING = "AES/ECB/PKCS5Padding";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
*/
package com.yeepay.yop.sdk.utils;

import com.yeepay.yop.sdk.service.common.YopClientBuilder;
import com.yeepay.yop.sdk.service.common.YopClientImpl;
import com.yeepay.yop.sdk.service.common.request.YopRequest;
import com.yeepay.yop.sdk.service.common.response.YopResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -63,4 +67,13 @@ private static void doLoadSpiClass(String spiClass) {
}
}

public static void main(String[] args) {
YopClientImpl yopClient = YopClientBuilder.builder().build();
final YopRequest yopRequest = new YopRequest("/rest/v2.0/yop/platform/certs", "GET");
yopRequest.getRequestConfig().setAppKey("您的国密appKey");
yopRequest.addParameter("certType", "SM2");
final YopResponse response = yopClient.request(yopRequest);
assert null != response;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.Map;

import static com.yeepay.yop.sdk.YopConstants.SM4_CBC_PKCS5PADDING;
import static com.yeepay.yop.sdk.YopConstants.SM4_ECB_PKCS5PADDING;

/**
* title: 对称加密器<br>
Expand Down Expand Up @@ -61,6 +62,7 @@ protected Map<String, Cipher> initialValue() {
Map<String, Cipher> map = Maps.newHashMap();
try {
map.put(SM4_CBC_PKCS5PADDING, Cipher.getInstance(SM4_CBC_PKCS5PADDING, BouncyCastleProvider.PROVIDER_NAME));
map.put(SM4_ECB_PKCS5PADDING, Cipher.getInstance(SM4_ECB_PKCS5PADDING, BouncyCastleProvider.PROVIDER_NAME));
map.put(ALGORITHM_NAME_GCM_NOPADDING, Cipher.getInstance(ALGORITHM_NAME_GCM_NOPADDING, BouncyCastleProvider.PROVIDER_NAME));
} catch (Exception e) {
throw new YopClientException("SystemError, YopSm4Encryptor InitFail, ex:", e);
Expand All @@ -71,7 +73,7 @@ protected Map<String, Cipher> initialValue() {

@Override
public List<String> supportedAlgs() {
return Arrays.asList(SM4_CBC_PKCS5PADDING, ALGORITHM_NAME_GCM_NOPADDING);
return Arrays.asList(SM4_CBC_PKCS5PADDING, SM4_ECB_PKCS5PADDING, ALGORITHM_NAME_GCM_NOPADDING);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,25 @@ public static boolean verifySign(String data, String signature, BCECPublicKey pu
}
}

/**
* sm2密钥进行签名验证-withId
*
* @param data
* @param signature
* @param publicKey
* @return
*/
public static boolean verifySignWithId(String data, String signature, BCECPublicKey publicKey, byte[] withId) {
try {
byte[] signByte = Encodes.decodeBase64(signature);
byte[] dataByte = data.getBytes(Charsets.UTF_8);
return verifyWithId(publicKey, dataByte, encodeSM2SignToDER(signByte), withId);
} catch (IOException e) {
throw new YopClientException("UnexpectedError, VerifySign Fail, data:" +
data + ", sign:" + signature + ", key:" + publicKey + ", ex:", e);
}
}

/**
* 把64字节的纯R+S字节数组编码成DER编码
*
Expand Down Expand Up @@ -232,6 +251,35 @@ public static byte[] sign(BCECPrivateKey priKey, byte[] srcData) throws CryptoEx
return rawSign;
}

/**
* 签名-withId
*
* @param priKey 私钥
* @param srcData 原文
* @return 64字节的纯R+S字节流
* @throws CryptoException
*/
public static byte[] signWithId(BCECPrivateKey priKey, byte[] srcData, byte[] withId) throws CryptoException {
ECParameterSpec parameterSpec = priKey.getParameters();
ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
parameterSpec.getN(), parameterSpec.getH());
ECPrivateKeyParameters priKeyParameters = new ECPrivateKeyParameters(priKey.getD(), domainParameters);
//der编码后的签名值
byte[] derSign = sign(priKeyParameters, withId, srcData);

//der解码过程
ASN1Sequence as = DERSequence.getInstance(derSign);
byte[] rBytes = ((ASN1Integer) as.getObjectAt(0)).getValue().toByteArray();
byte[] sBytes = ((ASN1Integer) as.getObjectAt(1)).getValue().toByteArray();
//由于大数的补0规则,所以可能会出现33个字节的情况,要修正回32个字节
rBytes = fixToCurveLengthBytes(rBytes);
sBytes = fixToCurveLengthBytes(sBytes);
byte[] rawSign = new byte[rBytes.length + sBytes.length];
System.arraycopy(rBytes, 0, rawSign, 0, rBytes.length);
System.arraycopy(sBytes, 0, rawSign, rBytes.length, sBytes.length);
return rawSign;
}

/**
* 签名
*
Expand Down Expand Up @@ -272,6 +320,22 @@ public static boolean verify(BCECPublicKey pubKey, byte[] srcData, byte[] sign)
return verify(pubKeyParameters, null, srcData, sign);
}

/**
* 验签
*
* @param pubKey 公钥
* @param srcData 原文
* @param sign DER编码的签名值
* @return
*/
public static boolean verifyWithId(BCECPublicKey pubKey, byte[] srcData, byte[] sign, byte[] withId) {
ECParameterSpec parameterSpec = pubKey.getParameters();
ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
parameterSpec.getN(), parameterSpec.getH());
ECPublicKeyParameters pubKeyParameters = new ECPublicKeyParameters(pubKey.getQ(), domainParameters);
return verify(pubKeyParameters, withId, srcData, sign);
}

/**
* 验签
*
Expand Down
11 changes: 11 additions & 0 deletions yop-java-sdk-test/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
</dependency>

<!-- test dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand All @@ -44,6 +49,12 @@
<artifactId>jmh-generator-annprocess</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.5</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright: Copyright (c)2011
* Company: 易宝支付(YeePay)
*/

package com.yeepay.yop.sdk.config.provider.db;

import com.yeepay.yop.sdk.auth.credentials.YopCredentials;
import com.yeepay.yop.sdk.auth.credentials.provider.YopCredentialsProviderRegistry;
import com.yeepay.yop.sdk.base.auth.credentials.provider.YopBaseCredentialsProvider;
import com.yeepay.yop.sdk.base.config.YopAppConfig;
import com.yeepay.yop.sdk.config.enums.CertStoreType;
import com.yeepay.yop.sdk.config.provider.file.YopCertConfig;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;

/**
* title: 示例:从数据库加载密钥配置 <br>
* description: 描述<br>
* Copyright: Copyright (c)2014<br>
* Company: 易宝支付(YeePay)<br>
*
* @author wdc
* @version 1.0.0
* @since 2024/12/12
*/
@Component// 该注解依赖spring包, Maven坐标: org.springframework:spring-context:xxx
public class YopDbCredentialsProvider extends YopBaseCredentialsProvider {

// 1、表结构简单设计
// |-------id--------|appKey-------|-----certType-----|-----certValue-----|
// | 1 |app_001|RSA2048|xxxxxxxxxx|
// | 2 |app_002|SM2|xxxxxxxxxx|

// 2、此处模拟数据库存储
Map<String, String[]> mockDbStore = new HashMap<>();
{
mockDbStore.put("app_001", new String[]{"1", "app_001", "RSA2048", "app_001的密钥串xxxxxx"});
mockDbStore.put("app_002", new String[]{"2", "app_002", "SM2", "app_002的密钥串xxxxxx"});
}

// 3、借助spring 方式, 在provider构造好后,保证系统启动时注册该自定义provider为单例
@PostConstruct
public void init() {
YopCredentialsProviderRegistry.registerProvider(this);
}

// 4、指定默认的appKey,当请求时没指定appKey时,会使用该appKey
@Override
public String getDefaultAppKey() {
// 此处简单硬编码,可以根据自身情况指定
return "app_001";
}

// 5、模拟从数据库查询
private YopCertConfig mockFindCertConfigByAppKey(String appKey) {
YopCertConfig yopCertConfig = new YopCertConfig();
String[] dbRow = mockDbStore.get(appKey);
yopCertConfig.setStoreType(CertStoreType.STRING);
yopCertConfig.setCertType(CertTypeEnum.parse(dbRow[2]));
yopCertConfig.setValue(dbRow[3]);
return yopCertConfig;
}

// 6、实现根据appKey和certType,构造调用身份
@Override
public YopCredentials<?> getCredentials(String appKey, String credentialType) {
// 兼容默认appKey的场景
appKey = useDefaultIfBlank(appKey);

// 构造调用身份
YopAppConfig yopAppConfig = new YopAppConfig();
yopAppConfig.setAppKey(appKey);

// 从数据库加载密钥配置
YopCertConfig yopCertConfig = mockFindCertConfigByAppKey(appKey);

// 装载调用身份
List<YopCertConfig> isvPrivateKeys = new LinkedList<>();
isvPrivateKeys.add(yopCertConfig);
yopAppConfig.setIsvPrivateKey(isvPrivateKeys);
return buildCredentials(yopAppConfig, credentialType);
}


// 7、实现支持的密钥类型,此处根据实际情况返回即可
@Override
public List<CertTypeEnum> getSupportCertTypes(String appKey) {
Set<CertTypeEnum> result = new HashSet<>();
// 从数据库加载支持的密钥类型列表
for (Map.Entry<String, String[]> appCert : mockDbStore.entrySet()) {
result.add(CertTypeEnum.parse(appCert.getValue()[2]));
}
return new ArrayList<>(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@
import com.yeepay.yop.sdk.service.common.request.YopRequest;
import com.yeepay.yop.sdk.service.common.response.YopResponse;
import com.yeepay.yop.sdk.service.common.response.YosUploadResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.junit.Ignore;
import org.junit.Test;

import java.security.PrivateKey;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
* title: <br>
Expand Down Expand Up @@ -84,13 +88,26 @@ appKey, new PKICredentialsItem(getPrivateKey(
"MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg/WsUu5NQDTDJjjaXWLlNfBNZhamXAqCLcyLPSHDSD4qgCgYIKoEcz1UBgi2hRANCAAQUC8TdvSHnCXGlQzm62w+sqHK8wt/ZDXmuhyU4qOEJ8jRMiTzQWoX8BC0fB7ggzWIobHrJouBgnEm3AxVhShpZ",
CertTypeEnum.SM2)
, CertTypeEnum.SM2)));
request.addParameter("parentMerchantNo", "1234321");
request.addParameter("orderId", "1234321");
request.addParameter("orderAmount", "100.05");
request.addParameter("notifyUrl", "https://xxx.com/notify");
try {
request.addParameter("parentMerchantNo", "1234321");
request.addParameter("orderId", "1234321");
request.addParameter("orderAmount", "100.05");
request.addParameter("notifyUrl", "https://xxx.com/notify");
} catch (Exception e) {
throw new RuntimeException(e);
}
assertTheRequest(yopClient, request);
}

@Test
public void testCaused() {
try {
throw new RuntimeException("1", new RuntimeException("2", new RuntimeException("3")));
} catch (RuntimeException e) {
System.out.println(Arrays.stream(ExceptionUtils.getThrowables(e)).map(t -> t.getClass().getCanonicalName() + ":" + t.getMessage()).collect(Collectors.joining(",")));
}
}

@Test
public void singleUpload() {
System.setProperty("yop.sdk.http", "true");//2021-12-08T11:59:16Z,d48782ac-93c1-466e-b417-f7a71e4965f0
Expand Down
Loading