20 changed files with 1731 additions and 1 deletions
Binary file not shown.
Binary file not shown.
@ -1,3 +1,6 @@
|
||||
# open-JSD-8034 |
||||
|
||||
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