20 changed files with 1731 additions and 1 deletions
Binary file not shown.
Binary file not shown.
@ -1,3 +1,6 @@ |
|||||||
# open-JSD-8034 |
# open-JSD-8034 |
||||||
|
|
||||||
JSD-8034 国密(SM2/SM3)签名和加解密单点登录 开源任务材料 |
JSD-8034 国密(SM2/SM3)签名和加解密单点登录 开源任务材料 |
||||||
|
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ |
||||||
|
仅作为开发者学习参考使用!禁止用于任何商业用途!\ |
||||||
|
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。 |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,25 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<plugin> |
||||||
|
<id>com.fr.plugin.hjcd.sso</id> |
||||||
|
<name><![CDATA[单点登陆jsd8034]]></name> |
||||||
|
<active>yes</active> |
||||||
|
<version>1.1.4</version> |
||||||
|
<env-version>10.0</env-version> |
||||||
|
<jartime>2018-07-31</jartime> |
||||||
|
<vendor>mqh</vendor> |
||||||
|
<description><![CDATA[单点登陆jsd8034]]></description> |
||||||
|
<change-notes><![CDATA[单点登陆jsd8034]]></change-notes> |
||||||
|
<main-package>com.fr.plugin.hjcd</main-package> |
||||||
|
<prefer-packages> |
||||||
|
<prefer-package>com.fanruan.api</prefer-package> |
||||||
|
<prefer-package>org.bouncycastle</prefer-package> |
||||||
|
</prefer-packages> |
||||||
|
<lifecycle-monitor class="com.fr.plugin.hjcd.PluginMonitor"/> |
||||||
|
<extra-core> |
||||||
|
<LocaleFinder class="com.fr.plugin.hjcd.LocaleFinder"/> |
||||||
|
</extra-core> |
||||||
|
<extra-decision> |
||||||
|
<GlobalRequestFilterProvider class="com.fr.plugin.hjcd.request.OAuthLogin"/> |
||||||
|
</extra-decision> |
||||||
|
<function-recorder class="com.fr.plugin.hjcd.LocaleFinder"/> |
||||||
|
</plugin> |
@ -0,0 +1,37 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C), 2018-2020 |
||||||
|
* Project: starter |
||||||
|
* FileName: LocaleFinder |
||||||
|
* Author: Louis |
||||||
|
* Date: 2020/8/31 22:19 |
||||||
|
*/ |
||||||
|
package com.fr.plugin.hjcd; |
||||||
|
|
||||||
|
import com.fr.intelli.record.Focus; |
||||||
|
import com.fr.intelli.record.Original; |
||||||
|
import com.fr.record.analyzer.EnableMetrics; |
||||||
|
import com.fr.stable.fun.impl.AbstractLocaleFinder; |
||||||
|
|
||||||
|
import static com.fr.plugin.hjcd.config.SsoConfig.PLUGIN_ID; |
||||||
|
|
||||||
|
/** |
||||||
|
* <Function Description><br> |
||||||
|
* <LocaleFinder> |
||||||
|
* |
||||||
|
* @author fr.open |
||||||
|
* @since 1.0.0 |
||||||
|
*/ |
||||||
|
@EnableMetrics |
||||||
|
public class LocaleFinder extends AbstractLocaleFinder { |
||||||
|
|
||||||
|
@Override |
||||||
|
@Focus(id = PLUGIN_ID, text = "Plugin-hjcd", source = Original.PLUGIN) |
||||||
|
public String find() { |
||||||
|
return "com/fr/plugin/hjcd/locale/lang"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int currentAPILevel() { |
||||||
|
return CURRENT_LEVEL; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C), 2018-2021 |
||||||
|
* Project: starter |
||||||
|
* FileName: PluginMonitor |
||||||
|
* Author: Louis |
||||||
|
* Date: 2021/3/30 15:10 |
||||||
|
*/ |
||||||
|
package com.fr.plugin.hjcd; |
||||||
|
|
||||||
|
import com.fr.plugin.context.PluginContext; |
||||||
|
import com.fr.plugin.hjcd.config.SsoConfig; |
||||||
|
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* <Function Description><br> |
||||||
|
* <PluginMonitor> |
||||||
|
* |
||||||
|
* @author fr.open |
||||||
|
* @since 1.0.0 |
||||||
|
*/ |
||||||
|
public class PluginMonitor extends AbstractPluginLifecycleMonitor { |
||||||
|
public PluginMonitor() { |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void afterRun(PluginContext pluginContext) { |
||||||
|
SsoConfig.getInstance(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void beforeStop(PluginContext pluginContext) { |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C), 2018-2021 |
||||||
|
* Project: starter |
||||||
|
* FileName: SsoConfig |
||||||
|
* Author: Louis |
||||||
|
* Date: 2021/3/30 9:38 |
||||||
|
*/ |
||||||
|
package com.fr.plugin.hjcd.config; |
||||||
|
|
||||||
|
import com.fanruan.api.util.StringKit; |
||||||
|
import com.fr.config.*; |
||||||
|
import com.fr.config.holder.Conf; |
||||||
|
import com.fr.config.holder.factory.Holders; |
||||||
|
|
||||||
|
/** |
||||||
|
* <Function Description><br> |
||||||
|
* <SsoConfig> |
||||||
|
* |
||||||
|
* @author fr.open |
||||||
|
* @since 1.0.0 |
||||||
|
*/ |
||||||
|
@Visualization(category = "Plugin-hjcd_Group") |
||||||
|
public class SsoConfig extends DefaultConfiguration { |
||||||
|
public static final String PLUGIN_ID = "com.fr.plugin.hjcd.sso"; |
||||||
|
|
||||||
|
private static volatile SsoConfig config = null; |
||||||
|
@Identifier(value = "uriBase", name = "Plugin-hjcd_Config_UriBase", description = "Plugin-hjcd_Config_UriBase_Description", status = Status.SHOW) |
||||||
|
private final Conf<String> uriBase = Holders.simple(StringKit.EMPTY); |
||||||
|
@Identifier(value = "channelId", name = "Plugin-hjcd_Config_ChannelId", description = "Plugin-hjcd_Config_ChannelId_Description", status = Status.SHOW) |
||||||
|
private final Conf<String> channelId = Holders.simple(StringKit.EMPTY); |
||||||
|
@Identifier(value = "publicKey", name = "Plugin-hjcd_Config_PublicKey", description = "Plugin-hjcd_Config_PublicKey_Description", status = Status.SHOW) |
||||||
|
private final Conf<String> publicKey = Holders.simple(StringKit.EMPTY); |
||||||
|
|
||||||
|
public static SsoConfig getInstance() { |
||||||
|
if (config == null) { |
||||||
|
config = ConfigContext.getConfigInstance(SsoConfig.class); |
||||||
|
} |
||||||
|
return config; |
||||||
|
} |
||||||
|
|
||||||
|
public String getUriBase() { |
||||||
|
return uriBase.get(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setUriBase(String uriBase) { |
||||||
|
this.uriBase.set(uriBase); |
||||||
|
} |
||||||
|
|
||||||
|
public String getChannelId() { |
||||||
|
return channelId.get(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setChannelId(String channelId) { |
||||||
|
this.channelId.set(channelId); |
||||||
|
} |
||||||
|
|
||||||
|
public String getPublicKey() { |
||||||
|
return publicKey.get(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setPublicKey(String publicKey) { |
||||||
|
this.publicKey.set(publicKey); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,231 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C), 2018-2021 |
||||||
|
* Project: starter |
||||||
|
* FileName: OAuthLogin |
||||||
|
* Author: Louis |
||||||
|
* Date: 2021/3/30 22:09 |
||||||
|
*/ |
||||||
|
package com.fr.plugin.hjcd.request; |
||||||
|
|
||||||
|
import com.fanruan.api.decision.user.UserKit; |
||||||
|
import com.fanruan.api.i18n.I18nKit; |
||||||
|
import com.fanruan.api.log.LogKit; |
||||||
|
import com.fanruan.api.net.NetworkKit; |
||||||
|
import com.fanruan.api.net.http.HttpKit; |
||||||
|
import com.fanruan.api.util.StringKit; |
||||||
|
import com.fr.data.NetworkHelper; |
||||||
|
import com.fr.decision.authority.data.User; |
||||||
|
import com.fr.decision.config.FSConfig; |
||||||
|
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; |
||||||
|
import com.fr.decision.mobile.terminal.TerminalHandler; |
||||||
|
import com.fr.decision.webservice.bean.authentication.LoginClientBean; |
||||||
|
import com.fr.decision.webservice.utils.ControllerFactory; |
||||||
|
import com.fr.decision.webservice.utils.DecisionServiceConstants; |
||||||
|
import com.fr.decision.webservice.utils.DecisionStatusService; |
||||||
|
import com.fr.decision.webservice.utils.controller.AuthenticController; |
||||||
|
import com.fr.decision.webservice.v10.login.LoginService; |
||||||
|
import com.fr.decision.webservice.v10.register.RegisterService; |
||||||
|
import com.fr.decision.webservice.v10.user.UserService; |
||||||
|
import com.fr.json.JSONObject; |
||||||
|
import com.fr.plugin.context.PluginContexts; |
||||||
|
import com.fr.plugin.hjcd.config.SsoConfig; |
||||||
|
import com.fr.plugin.hjcd.sm2utils.SM2Utils; |
||||||
|
import com.fr.plugin.hjcd.sm2utils.Util; |
||||||
|
import com.fr.stable.StringUtils; |
||||||
|
import com.fr.stable.fun.Authorize; |
||||||
|
import com.fr.stable.web.Device; |
||||||
|
import com.fr.store.Converter; |
||||||
|
|
||||||
|
import javax.servlet.FilterChain; |
||||||
|
import javax.servlet.FilterConfig; |
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import javax.servlet.http.HttpServletResponse; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import static com.fr.plugin.hjcd.config.SsoConfig.PLUGIN_ID; |
||||||
|
|
||||||
|
/** |
||||||
|
* <Function Description><br> |
||||||
|
* <OAuthLogin> |
||||||
|
* |
||||||
|
* @author fr.open |
||||||
|
* @since 1.0.0 |
||||||
|
*/ |
||||||
|
@Authorize(callSignKey = PLUGIN_ID) |
||||||
|
public class OAuthLogin extends AbstractGlobalRequestFilterProvider { |
||||||
|
|
||||||
|
public static final String ACCESSTOKEN = "Accesstoken"; |
||||||
|
private SsoConfig config; |
||||||
|
|
||||||
|
/** |
||||||
|
* 过滤器名称 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String filterName() { |
||||||
|
return "hjcdFilter"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 过滤规则 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String[] urlPatterns() { |
||||||
|
return new String[]{"/decision", "/decision/view/form", "/decision/view/report", "/decision/v10/entry/access/*"}; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 过滤器初始化 |
||||||
|
* |
||||||
|
* @param filterConfig |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void init(FilterConfig filterConfig) { |
||||||
|
this.config = SsoConfig.getInstance(); |
||||||
|
super.init(filterConfig); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 过滤器处理 |
||||||
|
* |
||||||
|
* @param request |
||||||
|
* @param response |
||||||
|
* @param filterChain |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) { |
||||||
|
try { |
||||||
|
if (operation(request, response)) { |
||||||
|
filterChain.doFilter(request, response); |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
LogKit.error(e.getMessage(), e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 用户验证登陆操作 |
||||||
|
* |
||||||
|
* @param req |
||||||
|
* @param res |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
private boolean operation(HttpServletRequest req, HttpServletResponse res) throws Exception { |
||||||
|
String token = NetworkKit.getHTTPRequestParameter(req, ACCESSTOKEN); |
||||||
|
if (StringKit.isBlank(token)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
String username = getUsername(token); |
||||||
|
if (StringKit.isEmpty(username) || !UserKit.existUsername(username)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
if (!PluginContexts.currentContext().isAvailable()) { |
||||||
|
LogKit.error(I18nKit.getLocText("Plugin-hjcd_Licence_Expired")); |
||||||
|
return true; |
||||||
|
} |
||||||
|
loginFR(req, res, username); |
||||||
|
res.sendRedirect(removeToken(req)); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 移除url的token参数 |
||||||
|
* |
||||||
|
* @param request |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private String removeToken(HttpServletRequest request) { |
||||||
|
String url = getOriginalURL(request); |
||||||
|
if (StringUtils.contains(url, ACCESSTOKEN)) { |
||||||
|
return url.substring(0, url.indexOf(ACCESSTOKEN) - 1); |
||||||
|
} |
||||||
|
return url; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 得到请求url和参数 |
||||||
|
* |
||||||
|
* @param request |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private String getOriginalURL(HttpServletRequest request) { |
||||||
|
StringBuffer url = request.getRequestURL(); |
||||||
|
if (StringKit.isNotBlank(request.getQueryString())) { |
||||||
|
url.append("?").append(request.getQueryString()); |
||||||
|
} |
||||||
|
return url.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public Boolean loginFR(HttpServletRequest req, HttpServletResponse res, String userName) { |
||||||
|
try { |
||||||
|
User user = UserService.getInstance().getUserByUserName(userName); |
||||||
|
if (user == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
String token = LoginService.getInstance().login(req, res, userName); |
||||||
|
Device device = NetworkHelper.getDevice(req); |
||||||
|
TerminalHandler terminal = TerminalHandler.getTerminal(req, device); |
||||||
|
AuthenticController authenticController = ControllerFactory.getInstance().getAuthenticController(user.getId()); |
||||||
|
//已登录禁止登录
|
||||||
|
authenticController.verifySingleLoginStatus(user.getUserName(), terminal, token); |
||||||
|
RegisterService.getInstance().checkLicExpireSoon(user); |
||||||
|
LoginClientBean clientBean = new LoginClientBean(req, device, terminal); |
||||||
|
clientBean.setUsername(user.getUserName()); |
||||||
|
clientBean.setToken(token); |
||||||
|
clientBean.setValidity(-1);//默认就是-1了
|
||||||
|
clientBean.setUserId(user.getId()); |
||||||
|
//后登录踢出先登录
|
||||||
|
authenticController.logoutSingleLoginInvalidUser(user.getUserName(), terminal); |
||||||
|
addLoginStatus(token, clientBean, FSConfig.getInstance().getLoginConfig().getLoginTimeout()); |
||||||
|
req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token); |
||||||
|
return true; |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private void addLoginStatus(String token, LoginClientBean clientBean, long timeout) throws Exception { |
||||||
|
DecisionStatusService.loginStatusService().put(token, clientBean, (Converter<LoginClientBean>) var1 -> new String[]{var1.getUsername()}, timeout); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 通过凭证获得username |
||||||
|
* |
||||||
|
* @param token |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private String getUsername(String token) throws Exception { |
||||||
|
LogKit.info("hjcd-OAuthLogin-getUsername-token:{}", token); |
||||||
|
Map<String, String> params = new HashMap<>(); |
||||||
|
params.put("channelid", SsoConfig.getInstance().getChannelId()); |
||||||
|
params.put("Encrypted", encryptData(token)); |
||||||
|
String url = HttpKit.buildUrl(this.config.getUriBase(), params); |
||||||
|
LogKit.info("hjcd-OAuthLogin-getUsername-url:{}", url); |
||||||
|
String userRes = HttpKit.post(url, new HashMap<>()); |
||||||
|
LogKit.info("hjcd-OAuthLogin-getUsername-userRes:{}", userRes); |
||||||
|
JSONObject result = new JSONObject(userRes); |
||||||
|
if (StringKit.equals(result.getString("status"), "0")) { |
||||||
|
return result.getString("workcode"); |
||||||
|
} |
||||||
|
return StringKit.EMPTY; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据加密处理 |
||||||
|
* |
||||||
|
* @param token |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private String encryptData(String token) throws Exception { |
||||||
|
String publicKey = SsoConfig.getInstance().getPublicKey(); |
||||||
|
String data = SsoConfig.getInstance().getChannelId() + "-" + token; |
||||||
|
//SM2非对称加密
|
||||||
|
return SM2Utils.encrypt(Util.hexToByte(publicKey), data.getBytes(StandardCharsets.UTF_8)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
package com.fr.plugin.hjcd.sm2utils; |
||||||
|
|
||||||
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; |
||||||
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters; |
||||||
|
import org.bouncycastle.crypto.params.ECPublicKeyParameters; |
||||||
|
import org.bouncycastle.math.ec.ECPoint; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
|
||||||
|
public class Cipher { |
||||||
|
private int ct; |
||||||
|
private ECPoint p2; |
||||||
|
private SM3Digest sm3keybase; |
||||||
|
private SM3Digest sm3c3; |
||||||
|
private byte key[]; |
||||||
|
private byte keyOff; |
||||||
|
|
||||||
|
public Cipher() { |
||||||
|
this.ct = 1; |
||||||
|
this.key = new byte[32]; |
||||||
|
this.keyOff = 0; |
||||||
|
} |
||||||
|
|
||||||
|
private void Reset() { |
||||||
|
this.sm3keybase = new SM3Digest(); |
||||||
|
this.sm3c3 = new SM3Digest(); |
||||||
|
|
||||||
|
byte p[] = Util.byteConvert32Bytes(p2.getX().toBigInteger()); |
||||||
|
this.sm3keybase.update(p, 0, p.length); |
||||||
|
this.sm3c3.update(p, 0, p.length); |
||||||
|
|
||||||
|
p = Util.byteConvert32Bytes(p2.getY().toBigInteger()); |
||||||
|
this.sm3keybase.update(p, 0, p.length); |
||||||
|
this.ct = 1; |
||||||
|
NextKey(); |
||||||
|
} |
||||||
|
|
||||||
|
private void NextKey() { |
||||||
|
SM3Digest sm3keycur = new SM3Digest(this.sm3keybase); |
||||||
|
sm3keycur.update((byte) (ct >> 24 & 0xff)); |
||||||
|
sm3keycur.update((byte) (ct >> 16 & 0xff)); |
||||||
|
sm3keycur.update((byte) (ct >> 8 & 0xff)); |
||||||
|
sm3keycur.update((byte) (ct & 0xff)); |
||||||
|
sm3keycur.doFinal(key, 0); |
||||||
|
this.keyOff = 0; |
||||||
|
this.ct++; |
||||||
|
} |
||||||
|
|
||||||
|
public ECPoint Init_enc(SM2 sm2, ECPoint userKey) { |
||||||
|
AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair(); |
||||||
|
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate(); |
||||||
|
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic(); |
||||||
|
BigInteger k = ecpriv.getD(); |
||||||
|
ECPoint c1 = ecpub.getQ(); |
||||||
|
this.p2 = userKey.multiply(k); |
||||||
|
Reset(); |
||||||
|
return c1; |
||||||
|
} |
||||||
|
|
||||||
|
public void Encrypt(byte data[]) { |
||||||
|
this.sm3c3.update(data, 0, data.length); |
||||||
|
for (int i = 0; i < data.length; i++) { |
||||||
|
if (keyOff == key.length) { |
||||||
|
NextKey(); |
||||||
|
} |
||||||
|
data[i] ^= key[keyOff++]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void Init_dec(BigInteger userD, ECPoint c1) { |
||||||
|
this.p2 = c1.multiply(userD); |
||||||
|
Reset(); |
||||||
|
} |
||||||
|
|
||||||
|
public void Decrypt(byte data[]) { |
||||||
|
for (int i = 0; i < data.length; i++) { |
||||||
|
if (keyOff == key.length) { |
||||||
|
NextKey(); |
||||||
|
} |
||||||
|
data[i] ^= key[keyOff++]; |
||||||
|
} |
||||||
|
|
||||||
|
this.sm3c3.update(data, 0, data.length); |
||||||
|
} |
||||||
|
|
||||||
|
public void Dofinal(byte c3[]) { |
||||||
|
byte p[] = Util.byteConvert32Bytes(p2.getY().toBigInteger()); |
||||||
|
this.sm3c3.update(p, 0, p.length); |
||||||
|
this.sm3c3.doFinal(c3, 0); |
||||||
|
Reset(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
package com.fr.plugin.hjcd.sm2utils; |
||||||
|
|
||||||
|
import org.bouncycastle.crypto.generators.ECKeyPairGenerator; |
||||||
|
import org.bouncycastle.crypto.params.ECDomainParameters; |
||||||
|
import org.bouncycastle.crypto.params.ECKeyGenerationParameters; |
||||||
|
import org.bouncycastle.math.ec.ECCurve; |
||||||
|
import org.bouncycastle.math.ec.ECFieldElement; |
||||||
|
import org.bouncycastle.math.ec.ECFieldElement.Fp; |
||||||
|
import org.bouncycastle.math.ec.ECPoint; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
import java.security.SecureRandom; |
||||||
|
|
||||||
|
public class SM2 { |
||||||
|
//测试参数
|
||||||
|
// public static final String[] ecc_param = {
|
||||||
|
|
||||||
|
// };
|
||||||
|
|
||||||
|
//正式参数
|
||||||
|
public static String[] ecc_param = { |
||||||
|
"xxxxx" |
||||||
|
}; |
||||||
|
public final BigInteger ecc_p; |
||||||
|
public final BigInteger ecc_a; |
||||||
|
public final BigInteger ecc_b; |
||||||
|
public final BigInteger ecc_n; |
||||||
|
public final BigInteger ecc_gx; |
||||||
|
public final BigInteger ecc_gy; |
||||||
|
public final ECCurve ecc_curve; |
||||||
|
public final ECPoint ecc_point_g; |
||||||
|
public final ECDomainParameters ecc_bc_spec; |
||||||
|
public final ECKeyPairGenerator ecc_key_pair_generator; |
||||||
|
public final ECFieldElement ecc_gx_fieldelement; |
||||||
|
public final ECFieldElement ecc_gy_fieldelement; |
||||||
|
public SM2() { |
||||||
|
this.ecc_p = new BigInteger(ecc_param[0], 16); |
||||||
|
this.ecc_a = new BigInteger(ecc_param[1], 16); |
||||||
|
this.ecc_b = new BigInteger(ecc_param[2], 16); |
||||||
|
this.ecc_n = new BigInteger(ecc_param[3], 16); |
||||||
|
this.ecc_gx = new BigInteger(ecc_param[4], 16); |
||||||
|
this.ecc_gy = new BigInteger(ecc_param[5], 16); |
||||||
|
|
||||||
|
this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx); |
||||||
|
this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy); |
||||||
|
|
||||||
|
this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b); |
||||||
|
this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement); |
||||||
|
|
||||||
|
this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n); |
||||||
|
|
||||||
|
ECKeyGenerationParameters ecc_ecgenparam; |
||||||
|
ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom()); |
||||||
|
|
||||||
|
this.ecc_key_pair_generator = new ECKeyPairGenerator(); |
||||||
|
this.ecc_key_pair_generator.init(ecc_ecgenparam); |
||||||
|
} |
||||||
|
|
||||||
|
public static SM2 Instance() { |
||||||
|
return new SM2(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package com.fr.plugin.hjcd.sm2utils; |
||||||
|
|
||||||
|
public class SM2KeyPair { |
||||||
|
|
||||||
|
/** |
||||||
|
* 公钥 |
||||||
|
*/ |
||||||
|
private String publicKey; |
||||||
|
|
||||||
|
/** |
||||||
|
* 私钥 |
||||||
|
*/ |
||||||
|
private String privateKey; |
||||||
|
|
||||||
|
SM2KeyPair(String publicKey, String privateKey) { |
||||||
|
this.publicKey = publicKey; |
||||||
|
this.privateKey = privateKey; |
||||||
|
} |
||||||
|
|
||||||
|
public String getPublicKey() { |
||||||
|
return publicKey; |
||||||
|
} |
||||||
|
|
||||||
|
public String getPrivateKey() { |
||||||
|
return privateKey; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,94 @@ |
|||||||
|
package com.fr.plugin.hjcd.sm2utils; |
||||||
|
|
||||||
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; |
||||||
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters; |
||||||
|
import org.bouncycastle.crypto.params.ECPublicKeyParameters; |
||||||
|
import org.bouncycastle.math.ec.ECPoint; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.math.BigInteger; |
||||||
|
|
||||||
|
public class SM2Utils { |
||||||
|
//生成随机秘钥对
|
||||||
|
public static SM2KeyPair generateKeyPair() { |
||||||
|
SM2 sm2 = SM2.Instance(); |
||||||
|
AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair(); |
||||||
|
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate(); |
||||||
|
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic(); |
||||||
|
BigInteger privateKey = ecpriv.getD(); |
||||||
|
ECPoint publicKey = ecpub.getQ(); |
||||||
|
System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded())); |
||||||
|
System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray())); |
||||||
|
return new SM2KeyPair(Util.byteToHex(publicKey.getEncoded(false)), Util.byteToHex(privateKey.toByteArray())); |
||||||
|
} |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
System.out.println(SM2Utils.generateKeyPair()); |
||||||
|
} |
||||||
|
|
||||||
|
//数据加密
|
||||||
|
public static String encrypt(byte[] publicKey, byte[] data) throws IOException { |
||||||
|
if (publicKey == null || publicKey.length == 0) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
if (data == null || data.length == 0) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
byte[] source = new byte[data.length]; |
||||||
|
System.arraycopy(data, 0, source, 0, data.length); |
||||||
|
|
||||||
|
Cipher cipher = new Cipher(); |
||||||
|
SM2 sm2 = SM2.Instance(); |
||||||
|
ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey); |
||||||
|
|
||||||
|
ECPoint c1 = cipher.Init_enc(sm2, userKey); |
||||||
|
cipher.Encrypt(source); |
||||||
|
byte[] c3 = new byte[32]; |
||||||
|
cipher.Dofinal(c3); |
||||||
|
|
||||||
|
// System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));
|
||||||
|
// System.out.println("C2 " + Util.byteToHex(source));
|
||||||
|
// System.out.println("C3 " + Util.byteToHex(c3));
|
||||||
|
//C1 C2 C3拼装成加密字串
|
||||||
|
return Util.byteToHex(c1.getEncoded(false)) + Util.byteToHex(source) + Util.byteToHex(c3); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//数据解密
|
||||||
|
public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException { |
||||||
|
if (privateKey == null || privateKey.length == 0) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
if (encryptedData == null || encryptedData.length == 0) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
//加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
|
||||||
|
String data = Util.byteToHex(encryptedData); |
||||||
|
/***分解加密字串 |
||||||
|
* (C1 = C1标志位2位 + C1实体部分128位 = 130) |
||||||
|
* (C3 = C3实体部分64位 = 64) |
||||||
|
* (C2 = encryptedData.length * 2 - C1长度 - C2长度) |
||||||
|
*/ |
||||||
|
byte[] c1Bytes = Util.hexToByte(data.substring(0, 130)); |
||||||
|
int c2Len = encryptedData.length - 97; |
||||||
|
byte[] c2 = Util.hexToByte(data.substring(130, 130 + 2 * c2Len)); |
||||||
|
byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len, 194 + 2 * c2Len)); |
||||||
|
|
||||||
|
SM2 sm2 = SM2.Instance(); |
||||||
|
BigInteger userD = new BigInteger(1, privateKey); |
||||||
|
|
||||||
|
//通过C1实体字节来生成ECPoint
|
||||||
|
ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes); |
||||||
|
Cipher cipher = new Cipher(); |
||||||
|
cipher.Init_dec(userD, c1); |
||||||
|
cipher.Decrypt(c2); |
||||||
|
cipher.Dofinal(c3); |
||||||
|
|
||||||
|
//返回解密结果
|
||||||
|
return c2; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,269 @@ |
|||||||
|
package com.fr.plugin.hjcd.sm2utils; |
||||||
|
|
||||||
|
|
||||||
|
public class SM3 { |
||||||
|
public static final byte[] iv = {0x73, (byte) 0x80, 0x16, 0x6f, 0x49, |
||||||
|
0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7, |
||||||
|
(byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30, |
||||||
|
(byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3, |
||||||
|
(byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e, |
||||||
|
0x4e}; |
||||||
|
|
||||||
|
public static int[] Tj = new int[64]; |
||||||
|
|
||||||
|
static { |
||||||
|
for (int i = 0; i < 16; i++) { |
||||||
|
Tj[i] = 0x79cc4519; |
||||||
|
} |
||||||
|
|
||||||
|
for (int i = 16; i < 64; i++) { |
||||||
|
Tj[i] = 0x7a879d8a; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static byte[] CF(byte[] V, byte[] B) { |
||||||
|
int[] v, b; |
||||||
|
v = convert(V); |
||||||
|
b = convert(B); |
||||||
|
return convert(CF(v, b)); |
||||||
|
} |
||||||
|
|
||||||
|
private static int[] convert(byte[] arr) { |
||||||
|
int[] out = new int[arr.length / 4]; |
||||||
|
byte[] tmp = new byte[4]; |
||||||
|
for (int i = 0; i < arr.length; i += 4) { |
||||||
|
System.arraycopy(arr, i, tmp, 0, 4); |
||||||
|
out[i / 4] = bigEndianByteToInt(tmp); |
||||||
|
} |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
private static byte[] convert(int[] arr) { |
||||||
|
byte[] out = new byte[arr.length * 4]; |
||||||
|
byte[] tmp = null; |
||||||
|
for (int i = 0; i < arr.length; i++) { |
||||||
|
tmp = bigEndianIntToByte(arr[i]); |
||||||
|
System.arraycopy(tmp, 0, out, i * 4, 4); |
||||||
|
} |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
public static int[] CF(int[] V, int[] B) { |
||||||
|
int a, b, c, d, e, f, g, h; |
||||||
|
int ss1, ss2, tt1, tt2; |
||||||
|
a = V[0]; |
||||||
|
b = V[1]; |
||||||
|
c = V[2]; |
||||||
|
d = V[3]; |
||||||
|
e = V[4]; |
||||||
|
f = V[5]; |
||||||
|
g = V[6]; |
||||||
|
h = V[7]; |
||||||
|
|
||||||
|
int[][] arr = expand(B); |
||||||
|
int[] w = arr[0]; |
||||||
|
int[] w1 = arr[1]; |
||||||
|
|
||||||
|
for (int j = 0; j < 64; j++) { |
||||||
|
ss1 = (bitCycleLeft(a, 12) + e + bitCycleLeft(Tj[j], j)); |
||||||
|
ss1 = bitCycleLeft(ss1, 7); |
||||||
|
ss2 = ss1 ^ bitCycleLeft(a, 12); |
||||||
|
tt1 = FFj(a, b, c, j) + d + ss2 + w1[j]; |
||||||
|
tt2 = GGj(e, f, g, j) + h + ss1 + w[j]; |
||||||
|
d = c; |
||||||
|
c = bitCycleLeft(b, 9); |
||||||
|
b = a; |
||||||
|
a = tt1; |
||||||
|
h = g; |
||||||
|
g = bitCycleLeft(f, 19); |
||||||
|
f = e; |
||||||
|
e = P0(tt2); |
||||||
|
|
||||||
|
/*System.out.print(j+" "); |
||||||
|
System.out.print(Integer.toHexString(a)+" "); |
||||||
|
System.out.print(Integer.toHexString(b)+" "); |
||||||
|
System.out.print(Integer.toHexString(c)+" "); |
||||||
|
System.out.print(Integer.toHexString(d)+" "); |
||||||
|
System.out.print(Integer.toHexString(e)+" "); |
||||||
|
System.out.print(Integer.toHexString(f)+" "); |
||||||
|
System.out.print(Integer.toHexString(g)+" "); |
||||||
|
System.out.print(Integer.toHexString(h)+" "); |
||||||
|
System.out.println("");*/ |
||||||
|
} |
||||||
|
// System.out.println("");
|
||||||
|
|
||||||
|
int[] out = new int[8]; |
||||||
|
out[0] = a ^ V[0]; |
||||||
|
out[1] = b ^ V[1]; |
||||||
|
out[2] = c ^ V[2]; |
||||||
|
out[3] = d ^ V[3]; |
||||||
|
out[4] = e ^ V[4]; |
||||||
|
out[5] = f ^ V[5]; |
||||||
|
out[6] = g ^ V[6]; |
||||||
|
out[7] = h ^ V[7]; |
||||||
|
|
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
private static int[][] expand(int[] B) { |
||||||
|
int W[] = new int[68]; |
||||||
|
int W1[] = new int[64]; |
||||||
|
for (int i = 0; i < B.length; i++) { |
||||||
|
W[i] = B[i]; |
||||||
|
} |
||||||
|
|
||||||
|
for (int i = 16; i < 68; i++) { |
||||||
|
W[i] = P1(W[i - 16] ^ W[i - 9] ^ bitCycleLeft(W[i - 3], 15)) |
||||||
|
^ bitCycleLeft(W[i - 13], 7) ^ W[i - 6]; |
||||||
|
} |
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++) { |
||||||
|
W1[i] = W[i] ^ W[i + 4]; |
||||||
|
} |
||||||
|
|
||||||
|
int arr[][] = new int[][]{W, W1}; |
||||||
|
return arr; |
||||||
|
} |
||||||
|
|
||||||
|
private static byte[] bigEndianIntToByte(int num) { |
||||||
|
return back(Util.intToBytes(num)); |
||||||
|
} |
||||||
|
|
||||||
|
private static int bigEndianByteToInt(byte[] bytes) { |
||||||
|
return Util.byteToInt(back(bytes)); |
||||||
|
} |
||||||
|
|
||||||
|
private static int FFj(int X, int Y, int Z, int j) { |
||||||
|
if (j >= 0 && j <= 15) { |
||||||
|
return FF1j(X, Y, Z); |
||||||
|
} else { |
||||||
|
return FF2j(X, Y, Z); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static int GGj(int X, int Y, int Z, int j) { |
||||||
|
if (j >= 0 && j <= 15) { |
||||||
|
return GG1j(X, Y, Z); |
||||||
|
} else { |
||||||
|
return GG2j(X, Y, Z); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 逻辑位运算函数
|
||||||
|
private static int FF1j(int X, int Y, int Z) { |
||||||
|
int tmp = X ^ Y ^ Z; |
||||||
|
return tmp; |
||||||
|
} |
||||||
|
|
||||||
|
private static int FF2j(int X, int Y, int Z) { |
||||||
|
int tmp = ((X & Y) | (X & Z) | (Y & Z)); |
||||||
|
return tmp; |
||||||
|
} |
||||||
|
|
||||||
|
private static int GG1j(int X, int Y, int Z) { |
||||||
|
int tmp = X ^ Y ^ Z; |
||||||
|
return tmp; |
||||||
|
} |
||||||
|
|
||||||
|
private static int GG2j(int X, int Y, int Z) { |
||||||
|
int tmp = (X & Y) | (~X & Z); |
||||||
|
return tmp; |
||||||
|
} |
||||||
|
|
||||||
|
private static int P0(int X) { |
||||||
|
int y = rotateLeft(X, 9); |
||||||
|
y = bitCycleLeft(X, 9); |
||||||
|
int z = rotateLeft(X, 17); |
||||||
|
z = bitCycleLeft(X, 17); |
||||||
|
int t = X ^ y ^ z; |
||||||
|
return t; |
||||||
|
} |
||||||
|
|
||||||
|
private static int P1(int X) { |
||||||
|
int t = X ^ bitCycleLeft(X, 15) ^ bitCycleLeft(X, 23); |
||||||
|
return t; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 对最后一个分组字节数据padding |
||||||
|
* |
||||||
|
* @param in |
||||||
|
* @param bLen 分组个数 |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static byte[] padding(byte[] in, int bLen) { |
||||||
|
int k = 448 - (8 * in.length + 1) % 512; |
||||||
|
if (k < 0) { |
||||||
|
k = 960 - (8 * in.length + 1) % 512; |
||||||
|
} |
||||||
|
k += 1; |
||||||
|
byte[] padd = new byte[k / 8]; |
||||||
|
padd[0] = (byte) 0x80; |
||||||
|
long n = in.length * 8 + bLen * 512; |
||||||
|
byte[] out = new byte[in.length + k / 8 + 64 / 8]; |
||||||
|
int pos = 0; |
||||||
|
System.arraycopy(in, 0, out, 0, in.length); |
||||||
|
pos += in.length; |
||||||
|
System.arraycopy(padd, 0, out, pos, padd.length); |
||||||
|
pos += padd.length; |
||||||
|
byte[] tmp = back(Util.longToBytes(n)); |
||||||
|
System.arraycopy(tmp, 0, out, pos, tmp.length); |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 字节数组逆序 |
||||||
|
* |
||||||
|
* @param in |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private static byte[] back(byte[] in) { |
||||||
|
byte[] out = new byte[in.length]; |
||||||
|
for (int i = 0; i < out.length; i++) { |
||||||
|
out[i] = in[out.length - i - 1]; |
||||||
|
} |
||||||
|
|
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
public static int rotateLeft(int x, int n) { |
||||||
|
return (x << n) | (x >> (32 - n)); |
||||||
|
} |
||||||
|
|
||||||
|
private static int bitCycleLeft(int n, int bitLen) { |
||||||
|
bitLen %= 32; |
||||||
|
byte[] tmp = bigEndianIntToByte(n); |
||||||
|
int byteLen = bitLen / 8; |
||||||
|
int len = bitLen % 8; |
||||||
|
if (byteLen > 0) { |
||||||
|
tmp = byteCycleLeft(tmp, byteLen); |
||||||
|
} |
||||||
|
|
||||||
|
if (len > 0) { |
||||||
|
tmp = bitSmall8CycleLeft(tmp, len); |
||||||
|
} |
||||||
|
|
||||||
|
return bigEndianByteToInt(tmp); |
||||||
|
} |
||||||
|
|
||||||
|
private static byte[] bitSmall8CycleLeft(byte[] in, int len) { |
||||||
|
byte[] tmp = new byte[in.length]; |
||||||
|
int t1, t2, t3; |
||||||
|
for (int i = 0; i < tmp.length; i++) { |
||||||
|
t1 = (byte) ((in[i] & 0x000000ff) << len); |
||||||
|
t2 = (byte) ((in[(i + 1) % tmp.length] & 0x000000ff) >> (8 - len)); |
||||||
|
t3 = (byte) (t1 | t2); |
||||||
|
tmp[i] = (byte) t3; |
||||||
|
} |
||||||
|
|
||||||
|
return tmp; |
||||||
|
} |
||||||
|
|
||||||
|
private static byte[] byteCycleLeft(byte[] in, int byteLen) { |
||||||
|
byte[] tmp = new byte[in.length]; |
||||||
|
System.arraycopy(in, byteLen, tmp, 0, in.length - byteLen); |
||||||
|
System.arraycopy(in, 0, tmp, in.length - byteLen, byteLen); |
||||||
|
return tmp; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
package com.fr.plugin.hjcd.sm2utils; |
||||||
|
|
||||||
|
import org.bouncycastle.util.encoders.Hex; |
||||||
|
|
||||||
|
public class SM3Digest { |
||||||
|
/** |
||||||
|
* SM3值的长度 |
||||||
|
*/ |
||||||
|
private static final int BYTE_LENGTH = 32; |
||||||
|
|
||||||
|
/** |
||||||
|
* SM3分组长度 |
||||||
|
*/ |
||||||
|
private static final int BLOCK_LENGTH = 64; |
||||||
|
|
||||||
|
/** |
||||||
|
* 缓冲区长度 |
||||||
|
*/ |
||||||
|
private static final int BUFFER_LENGTH = BLOCK_LENGTH * 1; |
||||||
|
|
||||||
|
/** |
||||||
|
* 缓冲区 |
||||||
|
*/ |
||||||
|
private byte[] xBuf = new byte[BUFFER_LENGTH]; |
||||||
|
|
||||||
|
/** |
||||||
|
* 缓冲区偏移量 |
||||||
|
*/ |
||||||
|
private int xBufOff; |
||||||
|
|
||||||
|
/** |
||||||
|
* 初始向量 |
||||||
|
*/ |
||||||
|
private byte[] V = SM3.iv.clone(); |
||||||
|
|
||||||
|
private int cntBlock = 0; |
||||||
|
|
||||||
|
public SM3Digest() { |
||||||
|
} |
||||||
|
|
||||||
|
public SM3Digest(SM3Digest t) { |
||||||
|
System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length); |
||||||
|
this.xBufOff = t.xBufOff; |
||||||
|
System.arraycopy(t.V, 0, this.V, 0, t.V.length); |
||||||
|
} |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
byte[] md = new byte[32]; |
||||||
|
byte[] msg1 = "ererfeiisgod".getBytes(); |
||||||
|
SM3Digest sm3 = new SM3Digest(); |
||||||
|
sm3.update(msg1, 0, msg1.length); |
||||||
|
sm3.doFinal(md, 0); |
||||||
|
String s = new String(Hex.encode(md)); |
||||||
|
System.out.println(s.toUpperCase()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* SM3结果输出 |
||||||
|
* |
||||||
|
* @param out 保存SM3结构的缓冲区 |
||||||
|
* @param outOff 缓冲区偏移量 |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public int doFinal(byte[] out, int outOff) { |
||||||
|
byte[] tmp = doFinal(); |
||||||
|
System.arraycopy(tmp, 0, out, 0, tmp.length); |
||||||
|
return BYTE_LENGTH; |
||||||
|
} |
||||||
|
|
||||||
|
public void reset() { |
||||||
|
xBufOff = 0; |
||||||
|
cntBlock = 0; |
||||||
|
V = SM3.iv.clone(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 明文输入 |
||||||
|
* |
||||||
|
* @param in 明文输入缓冲区 |
||||||
|
* @param inOff 缓冲区偏移量 |
||||||
|
* @param len 明文长度 |
||||||
|
*/ |
||||||
|
public void update(byte[] in, int inOff, int len) { |
||||||
|
int partLen = BUFFER_LENGTH - xBufOff; |
||||||
|
int inputLen = len; |
||||||
|
int dPos = inOff; |
||||||
|
if (partLen < inputLen) { |
||||||
|
System.arraycopy(in, dPos, xBuf, xBufOff, partLen); |
||||||
|
inputLen -= partLen; |
||||||
|
dPos += partLen; |
||||||
|
doUpdate(); |
||||||
|
while (inputLen > BUFFER_LENGTH) { |
||||||
|
System.arraycopy(in, dPos, xBuf, 0, BUFFER_LENGTH); |
||||||
|
inputLen -= BUFFER_LENGTH; |
||||||
|
dPos += BUFFER_LENGTH; |
||||||
|
doUpdate(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
System.arraycopy(in, dPos, xBuf, xBufOff, inputLen); |
||||||
|
xBufOff += inputLen; |
||||||
|
} |
||||||
|
|
||||||
|
private void doUpdate() { |
||||||
|
byte[] B = new byte[BLOCK_LENGTH]; |
||||||
|
for (int i = 0; i < BUFFER_LENGTH; i += BLOCK_LENGTH) { |
||||||
|
System.arraycopy(xBuf, i, B, 0, B.length); |
||||||
|
doHash(B); |
||||||
|
} |
||||||
|
xBufOff = 0; |
||||||
|
} |
||||||
|
|
||||||
|
private void doHash(byte[] B) { |
||||||
|
byte[] tmp = SM3.CF(V, B); |
||||||
|
System.arraycopy(tmp, 0, V, 0, V.length); |
||||||
|
cntBlock++; |
||||||
|
} |
||||||
|
|
||||||
|
private byte[] doFinal() { |
||||||
|
byte[] B = new byte[BLOCK_LENGTH]; |
||||||
|
byte[] buffer = new byte[xBufOff]; |
||||||
|
System.arraycopy(xBuf, 0, buffer, 0, buffer.length); |
||||||
|
byte[] tmp = SM3.padding(buffer, cntBlock); |
||||||
|
for (int i = 0; i < tmp.length; i += BLOCK_LENGTH) { |
||||||
|
System.arraycopy(tmp, i, B, 0, B.length); |
||||||
|
doHash(B); |
||||||
|
} |
||||||
|
return V; |
||||||
|
} |
||||||
|
|
||||||
|
public void update(byte in) { |
||||||
|
byte[] buffer = new byte[]{in}; |
||||||
|
update(buffer, 0, 1); |
||||||
|
} |
||||||
|
|
||||||
|
public int getDigestSize() { |
||||||
|
return BYTE_LENGTH; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
package com.fr.plugin.hjcd.sm2utils; |
||||||
|
|
||||||
|
public class Test { |
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception { |
||||||
|
|
||||||
|
String info = "xxxx";// 渠道id-token参数
|
||||||
|
|
||||||
|
String publickey = "xxxx"; |
||||||
|
// 将信息加密,公钥的字节码需要使用util里的hexToByte方法
|
||||||
|
String encrypt = SM2Utils.encrypt(Util.hexToByte(publickey), info.getBytes("utf-8")); |
||||||
|
|
||||||
|
System.out.println("加密后信息:" + encrypt); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,616 @@ |
|||||||
|
package com.fr.plugin.hjcd.sm2utils; |
||||||
|
|
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
|
||||||
|
public class Util { |
||||||
|
/** |
||||||
|
* 用于建立十六进制字符的输出的小写字符数组 |
||||||
|
*/ |
||||||
|
private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', |
||||||
|
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; |
||||||
|
/** |
||||||
|
* 用于建立十六进制字符的输出的大写字符数组 |
||||||
|
*/ |
||||||
|
private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', |
||||||
|
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; |
||||||
|
|
||||||
|
/** |
||||||
|
* 整形转换成网络传输的字节流(字节数组)型数据 |
||||||
|
* |
||||||
|
* @param num 一个整型数据 |
||||||
|
* @return 4个字节的自己数组 |
||||||
|
*/ |
||||||
|
public static byte[] intToBytes(int num) { |
||||||
|
byte[] bytes = new byte[4]; |
||||||
|
bytes[0] = (byte) (0xff & (num >> 0)); |
||||||
|
bytes[1] = (byte) (0xff & (num >> 8)); |
||||||
|
bytes[2] = (byte) (0xff & (num >> 16)); |
||||||
|
bytes[3] = (byte) (0xff & (num >> 24)); |
||||||
|
return bytes; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 四个字节的字节数据转换成一个整形数据 |
||||||
|
* |
||||||
|
* @param bytes 4个字节的字节数组 |
||||||
|
* @return 一个整型数据 |
||||||
|
*/ |
||||||
|
public static int byteToInt(byte[] bytes) { |
||||||
|
int num = 0; |
||||||
|
int temp; |
||||||
|
temp = (0x000000ff & (bytes[0])) << 0; |
||||||
|
num = num | temp; |
||||||
|
temp = (0x000000ff & (bytes[1])) << 8; |
||||||
|
num = num | temp; |
||||||
|
temp = (0x000000ff & (bytes[2])) << 16; |
||||||
|
num = num | temp; |
||||||
|
temp = (0x000000ff & (bytes[3])) << 24; |
||||||
|
num = num | temp; |
||||||
|
return num; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 长整形转换成网络传输的字节流(字节数组)型数据 |
||||||
|
* |
||||||
|
* @param num 一个长整型数据 |
||||||
|
* @return 4个字节的自己数组 |
||||||
|
*/ |
||||||
|
public static byte[] longToBytes(long num) { |
||||||
|
byte[] bytes = new byte[8]; |
||||||
|
for (int i = 0; i < 8; i++) { |
||||||
|
bytes[i] = (byte) (0xff & (num >> (i * 8))); |
||||||
|
} |
||||||
|
|
||||||
|
return bytes; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 大数字转换字节流(字节数组)型数据 |
||||||
|
* |
||||||
|
* @param n |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static byte[] byteConvert32Bytes(BigInteger n) { |
||||||
|
byte tmpd[] = (byte[]) null; |
||||||
|
if (n == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
if (n.toByteArray().length == 33) { |
||||||
|
tmpd = new byte[32]; |
||||||
|
System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32); |
||||||
|
} else if (n.toByteArray().length == 32) { |
||||||
|
tmpd = n.toByteArray(); |
||||||
|
} else { |
||||||
|
tmpd = new byte[32]; |
||||||
|
for (int i = 0; i < 32 - n.toByteArray().length; i++) { |
||||||
|
tmpd[i] = 0; |
||||||
|
} |
||||||
|
System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length); |
||||||
|
} |
||||||
|
return tmpd; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 换字节流(字节数组)型数据转大数字 |
||||||
|
* |
||||||
|
* @param b |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static BigInteger byteConvertInteger(byte[] b) { |
||||||
|
if (b[0] < 0) { |
||||||
|
byte[] temp = new byte[b.length + 1]; |
||||||
|
temp[0] = 0; |
||||||
|
System.arraycopy(b, 0, temp, 1, b.length); |
||||||
|
return new BigInteger(temp); |
||||||
|
} |
||||||
|
return new BigInteger(b); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 根据字节数组获得值(十六进制数字) |
||||||
|
* |
||||||
|
* @param bytes |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static String getHexString(byte[] bytes) { |
||||||
|
return getHexString(bytes, true); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 根据字节数组获得值(十六进制数字) |
||||||
|
* |
||||||
|
* @param bytes |
||||||
|
* @param upperCase |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static String getHexString(byte[] bytes, boolean upperCase) { |
||||||
|
String ret = ""; |
||||||
|
for (int i = 0; i < bytes.length; i++) { |
||||||
|
ret += Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1); |
||||||
|
} |
||||||
|
return upperCase ? ret.toUpperCase() : ret; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 打印十六进制字符串 |
||||||
|
* |
||||||
|
* @param bytes |
||||||
|
*/ |
||||||
|
public static void printHexString(byte[] bytes) { |
||||||
|
for (int i = 0; i < bytes.length; i++) { |
||||||
|
String hex = Integer.toHexString(bytes[i] & 0xFF); |
||||||
|
if (hex.length() == 1) { |
||||||
|
hex = '0' + hex; |
||||||
|
} |
||||||
|
System.out.print("0x" + hex.toUpperCase() + ","); |
||||||
|
} |
||||||
|
System.out.println(""); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Convert hex string to byte[] |
||||||
|
* |
||||||
|
* @param hexString the hex string |
||||||
|
* @return byte[] |
||||||
|
*/ |
||||||
|
public static byte[] hexStringToBytes(String hexString) { |
||||||
|
if (hexString == null || hexString.equals("")) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
hexString = hexString.toUpperCase(); |
||||||
|
int length = hexString.length() / 2; |
||||||
|
char[] hexChars = hexString.toCharArray(); |
||||||
|
byte[] d = new byte[length]; |
||||||
|
for (int i = 0; i < length; i++) { |
||||||
|
int pos = i * 2; |
||||||
|
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); |
||||||
|
} |
||||||
|
return d; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Convert char to byte |
||||||
|
* |
||||||
|
* @param c char |
||||||
|
* @return byte |
||||||
|
*/ |
||||||
|
public static byte charToByte(char c) { |
||||||
|
return (byte) "0123456789ABCDEF".indexOf(c); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将字节数组转换为十六进制字符数组 |
||||||
|
* |
||||||
|
* @param data byte[] |
||||||
|
* @return 十六进制char[] |
||||||
|
*/ |
||||||
|
public static char[] encodeHex(byte[] data) { |
||||||
|
return encodeHex(data, true); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将字节数组转换为十六进制字符数组 |
||||||
|
* |
||||||
|
* @param data byte[] |
||||||
|
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式 |
||||||
|
* @return 十六进制char[] |
||||||
|
*/ |
||||||
|
public static char[] encodeHex(byte[] data, boolean toLowerCase) { |
||||||
|
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将字节数组转换为十六进制字符数组 |
||||||
|
* |
||||||
|
* @param data byte[] |
||||||
|
* @param toDigits 用于控制输出的char[] |
||||||
|
* @return 十六进制char[] |
||||||
|
*/ |
||||||
|
protected static char[] encodeHex(byte[] data, char[] toDigits) { |
||||||
|
int l = data.length; |
||||||
|
char[] out = new char[l << 1]; |
||||||
|
// two characters form the hex value.
|
||||||
|
for (int i = 0, j = 0; i < l; i++) { |
||||||
|
out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; |
||||||
|
out[j++] = toDigits[0x0F & data[i]]; |
||||||
|
} |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将字节数组转换为十六进制字符串 |
||||||
|
* |
||||||
|
* @param data byte[] |
||||||
|
* @return 十六进制String |
||||||
|
*/ |
||||||
|
public static String encodeHexString(byte[] data) { |
||||||
|
return encodeHexString(data, true); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将字节数组转换为十六进制字符串 |
||||||
|
* |
||||||
|
* @param data byte[] |
||||||
|
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式 |
||||||
|
* @return 十六进制String |
||||||
|
*/ |
||||||
|
public static String encodeHexString(byte[] data, boolean toLowerCase) { |
||||||
|
return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将字节数组转换为十六进制字符串 |
||||||
|
* |
||||||
|
* @param data byte[] |
||||||
|
* @param toDigits 用于控制输出的char[] |
||||||
|
* @return 十六进制String |
||||||
|
*/ |
||||||
|
protected static String encodeHexString(byte[] data, char[] toDigits) { |
||||||
|
return new String(encodeHex(data, toDigits)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将十六进制字符数组转换为字节数组 |
||||||
|
* |
||||||
|
* @param data 十六进制char[] |
||||||
|
* @return byte[] |
||||||
|
* @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常 |
||||||
|
*/ |
||||||
|
public static byte[] decodeHex(char[] data) { |
||||||
|
int len = data.length; |
||||||
|
|
||||||
|
if ((len & 0x01) != 0) { |
||||||
|
throw new RuntimeException("Odd number of characters."); |
||||||
|
} |
||||||
|
|
||||||
|
byte[] out = new byte[len >> 1]; |
||||||
|
|
||||||
|
// two characters form the hex value.
|
||||||
|
for (int i = 0, j = 0; j < len; i++) { |
||||||
|
int f = toDigit(data[j], j) << 4; |
||||||
|
j++; |
||||||
|
f = f | toDigit(data[j], j); |
||||||
|
j++; |
||||||
|
out[i] = (byte) (f & 0xFF); |
||||||
|
} |
||||||
|
|
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将十六进制字符转换成一个整数 |
||||||
|
* |
||||||
|
* @param ch 十六进制char |
||||||
|
* @param index 十六进制字符在字符数组中的位置 |
||||||
|
* @return 一个整数 |
||||||
|
* @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常 |
||||||
|
*/ |
||||||
|
protected static int toDigit(char ch, int index) { |
||||||
|
int digit = Character.digit(ch, 16); |
||||||
|
if (digit == -1) { |
||||||
|
throw new RuntimeException("Illegal hexadecimal character " + ch |
||||||
|
+ " at index " + index); |
||||||
|
} |
||||||
|
return digit; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 数字字符串转ASCII码字符串 |
||||||
|
* |
||||||
|
* @param content 字符串 |
||||||
|
* @return ASCII字符串 |
||||||
|
*/ |
||||||
|
public static String StringToAsciiString(String content) { |
||||||
|
String result = ""; |
||||||
|
int max = content.length(); |
||||||
|
for (int i = 0; i < max; i++) { |
||||||
|
char c = content.charAt(i); |
||||||
|
String b = Integer.toHexString(c); |
||||||
|
result = result + b; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 十六进制转字符串 |
||||||
|
* |
||||||
|
* @param hexString 十六进制字符串 |
||||||
|
* @param encodeType 编码类型4:Unicode,2:普通编码 |
||||||
|
* @return 字符串 |
||||||
|
*/ |
||||||
|
public static String hexStringToString(String hexString, int encodeType) { |
||||||
|
String result = ""; |
||||||
|
int max = hexString.length() / encodeType; |
||||||
|
for (int i = 0; i < max; i++) { |
||||||
|
char c = (char) hexStringToAlgorism(hexString |
||||||
|
.substring(i * encodeType, (i + 1) * encodeType)); |
||||||
|
result += c; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 十六进制字符串装十进制 |
||||||
|
* |
||||||
|
* @param hex 十六进制字符串 |
||||||
|
* @return 十进制数值 |
||||||
|
*/ |
||||||
|
public static int hexStringToAlgorism(String hex) { |
||||||
|
hex = hex.toUpperCase(); |
||||||
|
int max = hex.length(); |
||||||
|
int result = 0; |
||||||
|
for (int i = max; i > 0; i--) { |
||||||
|
char c = hex.charAt(i - 1); |
||||||
|
int algorism = 0; |
||||||
|
if (c >= '0' && c <= '9') { |
||||||
|
algorism = c - '0'; |
||||||
|
} else { |
||||||
|
algorism = c - 55; |
||||||
|
} |
||||||
|
result += Math.pow(16, max - i) * algorism; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 十六转二进制 |
||||||
|
* |
||||||
|
* @param hex 十六进制字符串 |
||||||
|
* @return 二进制字符串 |
||||||
|
*/ |
||||||
|
public static String hexStringToBinary(String hex) { |
||||||
|
hex = hex.toUpperCase(); |
||||||
|
String result = ""; |
||||||
|
int max = hex.length(); |
||||||
|
for (int i = 0; i < max; i++) { |
||||||
|
char c = hex.charAt(i); |
||||||
|
switch (c) { |
||||||
|
case '0': |
||||||
|
result += "0000"; |
||||||
|
break; |
||||||
|
case '1': |
||||||
|
result += "0001"; |
||||||
|
break; |
||||||
|
case '2': |
||||||
|
result += "0010"; |
||||||
|
break; |
||||||
|
case '3': |
||||||
|
result += "0011"; |
||||||
|
break; |
||||||
|
case '4': |
||||||
|
result += "0100"; |
||||||
|
break; |
||||||
|
case '5': |
||||||
|
result += "0101"; |
||||||
|
break; |
||||||
|
case '6': |
||||||
|
result += "0110"; |
||||||
|
break; |
||||||
|
case '7': |
||||||
|
result += "0111"; |
||||||
|
break; |
||||||
|
case '8': |
||||||
|
result += "1000"; |
||||||
|
break; |
||||||
|
case '9': |
||||||
|
result += "1001"; |
||||||
|
break; |
||||||
|
case 'A': |
||||||
|
result += "1010"; |
||||||
|
break; |
||||||
|
case 'B': |
||||||
|
result += "1011"; |
||||||
|
break; |
||||||
|
case 'C': |
||||||
|
result += "1100"; |
||||||
|
break; |
||||||
|
case 'D': |
||||||
|
result += "1101"; |
||||||
|
break; |
||||||
|
case 'E': |
||||||
|
result += "1110"; |
||||||
|
break; |
||||||
|
case 'F': |
||||||
|
result += "1111"; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* ASCII码字符串转数字字符串 |
||||||
|
* |
||||||
|
* @param content ASCII字符串 |
||||||
|
* @return 字符串 |
||||||
|
*/ |
||||||
|
public static String AsciiStringToString(String content) { |
||||||
|
String result = ""; |
||||||
|
int length = content.length() / 2; |
||||||
|
for (int i = 0; i < length; i++) { |
||||||
|
String c = content.substring(i * 2, i * 2 + 2); |
||||||
|
int a = hexStringToAlgorism(c); |
||||||
|
char b = (char) a; |
||||||
|
String d = String.valueOf(b); |
||||||
|
result += d; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将十进制转换为指定长度的十六进制字符串 |
||||||
|
* |
||||||
|
* @param algorism int 十进制数字 |
||||||
|
* @param maxLength int 转换后的十六进制字符串长度 |
||||||
|
* @return String 转换后的十六进制字符串 |
||||||
|
*/ |
||||||
|
public static String algorismToHexString(int algorism, int maxLength) { |
||||||
|
String result = ""; |
||||||
|
result = Integer.toHexString(algorism); |
||||||
|
|
||||||
|
if (result.length() % 2 == 1) { |
||||||
|
result = "0" + result; |
||||||
|
} |
||||||
|
return patchHexString(result.toUpperCase(), maxLength); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 字节数组转为普通字符串(ASCII对应的字符) |
||||||
|
* |
||||||
|
* @param bytearray byte[] |
||||||
|
* @return String |
||||||
|
*/ |
||||||
|
public static String byteToString(byte[] bytearray) { |
||||||
|
String result = ""; |
||||||
|
char temp; |
||||||
|
|
||||||
|
int length = bytearray.length; |
||||||
|
for (int i = 0; i < length; i++) { |
||||||
|
temp = (char) bytearray[i]; |
||||||
|
result += temp; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 二进制字符串转十进制 |
||||||
|
* |
||||||
|
* @param binary 二进制字符串 |
||||||
|
* @return 十进制数值 |
||||||
|
*/ |
||||||
|
public static int binaryToAlgorism(String binary) { |
||||||
|
int max = binary.length(); |
||||||
|
int result = 0; |
||||||
|
for (int i = max; i > 0; i--) { |
||||||
|
char c = binary.charAt(i - 1); |
||||||
|
int algorism = c - '0'; |
||||||
|
result += Math.pow(2, max - i) * algorism; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 十进制转换为十六进制字符串 |
||||||
|
* |
||||||
|
* @param algorism int 十进制的数字 |
||||||
|
* @return String 对应的十六进制字符串 |
||||||
|
*/ |
||||||
|
public static String algorismToHEXString(int algorism) { |
||||||
|
String result = ""; |
||||||
|
result = Integer.toHexString(algorism); |
||||||
|
|
||||||
|
if (result.length() % 2 == 1) { |
||||||
|
result = "0" + result; |
||||||
|
|
||||||
|
} |
||||||
|
result = result.toUpperCase(); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* HEX字符串前补0,主要用于长度位数不足。 |
||||||
|
* |
||||||
|
* @param str String 需要补充长度的十六进制字符串 |
||||||
|
* @param maxLength int 补充后十六进制字符串的长度 |
||||||
|
* @return 补充结果 |
||||||
|
*/ |
||||||
|
static public String patchHexString(String str, int maxLength) { |
||||||
|
String temp = ""; |
||||||
|
for (int i = 0; i < maxLength - str.length(); i++) { |
||||||
|
temp = "0" + temp; |
||||||
|
} |
||||||
|
str = (temp + str).substring(0, maxLength); |
||||||
|
return str; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将一个字符串转换为int |
||||||
|
* |
||||||
|
* @param s String 要转换的字符串 |
||||||
|
* @param defaultInt int 如果出现异常,默认返回的数字 |
||||||
|
* @param radix int 要转换的字符串是什么进制的,如16 8 10. |
||||||
|
* @return int 转换后的数字 |
||||||
|
*/ |
||||||
|
public static int parseToInt(String s, int defaultInt, int radix) { |
||||||
|
int i = 0; |
||||||
|
try { |
||||||
|
i = Integer.parseInt(s, radix); |
||||||
|
} catch (NumberFormatException ex) { |
||||||
|
i = defaultInt; |
||||||
|
} |
||||||
|
return i; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将一个十进制形式的数字字符串转换为int |
||||||
|
* |
||||||
|
* @param s String 要转换的字符串 |
||||||
|
* @param defaultInt int 如果出现异常,默认返回的数字 |
||||||
|
* @return int 转换后的数字 |
||||||
|
*/ |
||||||
|
public static int parseToInt(String s, int defaultInt) { |
||||||
|
int i = 0; |
||||||
|
try { |
||||||
|
i = Integer.parseInt(s); |
||||||
|
} catch (NumberFormatException ex) { |
||||||
|
i = defaultInt; |
||||||
|
} |
||||||
|
return i; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 十六进制串转化为byte数组 |
||||||
|
* |
||||||
|
* @return the array of byte |
||||||
|
*/ |
||||||
|
public static byte[] hexToByte(String hex) |
||||||
|
throws IllegalArgumentException { |
||||||
|
if (hex.length() % 2 != 0) { |
||||||
|
throw new IllegalArgumentException(); |
||||||
|
} |
||||||
|
char[] arr = hex.toCharArray(); |
||||||
|
byte[] b = new byte[hex.length() / 2]; |
||||||
|
for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) { |
||||||
|
String swap = "" + arr[i++] + arr[i]; |
||||||
|
int byteint = Integer.parseInt(swap, 16) & 0xFF; |
||||||
|
b[j] = new Integer(byteint).byteValue(); |
||||||
|
} |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 字节数组转换为十六进制字符串 |
||||||
|
* |
||||||
|
* @param b byte[] 需要转换的字节数组 |
||||||
|
* @return String 十六进制字符串 |
||||||
|
*/ |
||||||
|
public static String byteToHex(byte b[]) { |
||||||
|
if (b == null) { |
||||||
|
throw new IllegalArgumentException( |
||||||
|
"Argument b ( byte array ) is null! "); |
||||||
|
} |
||||||
|
String hs = ""; |
||||||
|
String stmp = ""; |
||||||
|
for (int n = 0; n < b.length; n++) { |
||||||
|
stmp = Integer.toHexString(b[n] & 0xff); |
||||||
|
if (stmp.length() == 1) { |
||||||
|
hs = hs + "0" + stmp; |
||||||
|
} else { |
||||||
|
hs = hs + stmp; |
||||||
|
} |
||||||
|
} |
||||||
|
return hs.toUpperCase(); |
||||||
|
} |
||||||
|
|
||||||
|
public static byte[] subByte(byte[] input, int startIndex, int length) { |
||||||
|
byte[] bt = new byte[length]; |
||||||
|
for (int i = 0; i < length; i++) { |
||||||
|
bt[i] = input[i + startIndex]; |
||||||
|
} |
||||||
|
return bt; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
Plugin-hjcd=Sso Plugin |
||||||
|
Plugin-hjcd_Group=Sso Plugin |
||||||
|
Plugin-hjcd_Config_UriBase=Uri Base |
||||||
|
Plugin-hjcd_Config_UriBase_Description=Uri Base |
||||||
|
Plugin-hjcd_Licence_Expired=Sso Plugin Licence Expired |
||||||
|
Plugin-hjcd_Config_ChannelId=Channel Id |
||||||
|
Plugin-hjcd_Config_ChannelId_Description=Channel Id |
||||||
|
Plugin-hjcd_Config_PublicKey=Public Key |
||||||
|
Plugin-hjcd_Config_PublicKey_Description=Public Key |
@ -0,0 +1,9 @@ |
|||||||
|
Plugin-hjcd=\u5355\u70B9\u767B\u9646\u63D2\u4EF6 |
||||||
|
Plugin-hjcd_Group=\u5355\u70B9\u767B\u9646\u63D2\u4EF6 |
||||||
|
Plugin-hjcd_Config_UriBase=token\u6821\u9A8C\u63A5\u53E3\u5730\u5740 |
||||||
|
Plugin-hjcd_Config_UriBase_Description=token\u6821\u9A8C\u63A5\u53E3\u5730\u5740 |
||||||
|
Plugin-hjcd_Licence_Expired=\u5355\u70B9\u767B\u9646\u63D2\u4EF6\u8BB8\u53EF\u8FC7\u671F |
||||||
|
Plugin-hjcd_Config_ChannelId=\u6E20\u9053ID |
||||||
|
Plugin-hjcd_Config_ChannelId_Description=\u6E20\u9053ID |
||||||
|
Plugin-hjcd_Config_PublicKey=\u52A0\u5BC6SM2\u516C\u94A5 |
||||||
|
Plugin-hjcd_Config_PublicKey_Description=\u52A0\u5BC6SM2\u516C\u94A5 |
Loading…
Reference in new issue