密钥交换之后获得银行提供的:银行RSA签名公钥RSA.bank.public.key,接受报文验签使用;银行DES加密私钥DES.bank.private.key,加密报文使用。还有之前自己生成的RSA签名私钥RSA.private.key,报文签名使用。下面以签到为例把报文签名、加密以及接受报文后解密、验签写上:
签到http入口:
/**
* @Auther zhangxingbo
* @Date 2020/11/30
* @Description:建行银企直连签到
* @Version 1.0
**/
@ApiOperation(value = "建行银企直连签到", notes = "建行银企直连签到")
@GetMapping("/CCBSignIn")
public ResponseModel<JSONObject> signIn(){
try {
log.info("建行银企直连签到");
RspSign signIn = signServiceImpl.signIn();
JSONObject joo = new JSONObject();
joo.put("signIn", signIn);
return new ResponseModel<>(joo);
} catch (Exception e){
log.error("建行银企直连签到异常",e);
return new ResponseModel<>(HttpStatus.INTERNAL_SERVER_ERROR.value(),HttpStatus.INTERNAL_SERVER_ERROR.name());
}
}
签到构造报文、签名、解析
/**
* @Auther qijw
* @Date 2020/11/16
* @Description:签到构造报文、签名、解析
* @Version 1.0
**/
public RspSign sign(String sysCode) {
try {
log.info("建行银企直连签到sysCode:{}", sysCode);
//构造请求报文
String reqXml = getSign(sysCode);
//签名,加密,发送请求
String resultXml = signAndEncryp(reqXml);
//解析响应
return JaxbUtil.converyToJavaBean(resultXml, RspSign.class);
} catch (Exception e) {
log.error("建行银企直连签到异常", e);
return null;
}
}
构造接口签到的请求报文,使用实体类bean传入P1OPME001、电子银行合约编号、时间等必要字段
/**
* 构造接口签到的请求报文
*/
public String getSign(String sysCode) {
try {
log.info("建行银企直连签到报文");
BankProperties BankProperties = new BankProperties();
CCBSign cCBSign = new CCBSign();
Head head = BankProperties.createHead();
//签到P1OPME001,签退P1OPME002
head.setSysTxCode(sysCode);
cCBSign.setHead(head);
String xmlStr = JaxbUtil.ojbectToXmlWithCDATA(BankConstants.elements, CCBSign.class, cCBSign);
return xmlStr;
} catch (Exception e) {
log.error("建行银企直连签到报文出错,错误信息:" + e.getMessage(), e);
return null;
}
}
签名,加密,发送请求,解析报文,验签
/**
* 签名,加密,发送请求,解析报文,验签
*/
public String signAndEncryp(String reqXml) {
try {
//数字签名算法为:MD5withRSA
String signature = RSASignUtil.sign(reqXml, bankKeyConfig.priRSAKey);
//DESede (3DES):DES 对称密钥由银行生成,用于对交易报文和文件内容的加解密
String data = DESedeUtil.encryptWithDESede(reqXml, bankKeyConfig.Des_KEY);
//向建行银企直连发送请求
String reqs = httpUtil.sendRequest(data, signature, CommonBankConstants.REQUEST_CHARSET_UTF8);
if (null != reqs) {
return reqs;
} else {
log.info("建行银企直连签名,加密,发送请求异常");
}
} catch (Exception e) {
log.error("建行银企直连签名,加密,发送请求错误", e);
return null;
}
return null;
}
MD5withRSA签名
/**
* MD5withRSA签名
*
* @param data 待签名数据
* @return 签名
*/
public static String sign(String data , String private_Key) throws Exception {
byte[] keyBytes = getPrivateKey(private_Key).getEncoded();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey key = keyFactory.generatePrivate(keySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(key);
signature.update(data.getBytes());
return new String(Base64.encodeBase64(signature.sign()));
}
DESede加密,还原密钥方法网上有。不知道的自己搜一下
public static final String KEY_ALGORITHM = "DESede";
/**
* 加密/解密算法 /工作模式 /填充方式
* Java 6支持PKCS5PADDING填充方式
* Bouncy Castle支持PKCS7Padding填充方式
*/
public static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";
/**
* DESede/ECB/PKCS5Padding加密
* @param data 待加密数据
* @param key 密钥
* @return byte[] 加密数据
* @throws Exception
*/
public static String encrypt(String data, String key) throws Exception{
try {
//还原密钥
Key k = toKey(key);
//加密
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, k);
return Base64Util.getInstance().base64Encode(cipher.doFinal(data.getBytes("UTF-8")));
} catch (Exception e){
log.error("DESede加密错误",e);
}
return null;
}
发送请求报文,获得返回报文,解密、验签
/**
* 建行银企直连,发送请求报文,获得返回报文,解密、验签
*
* @param data
* @return
*/
public String sendRequest(String data, String signature, String charset) {
log.info("请求建行银企直连请求报文请求参数:{}", data);
HttpClient myclient = null;
PostMethod httppost = null;
String repcontent = "";
try {
myclient = new HttpClient(); // 构建http客户端
httppost = new PostMethod(bankKeyConfig.bankServerUrl); // 加密端口
httppost.addParameter("chanl_cust_no", bankKeyConfig.CHANL_CUST_NO);
httppost.addParameter("xml", data);
httppost.addParameter("signature", signature);
log.info("发送给银企直连服务数据:{}",data);
// 获得http返回码
int returnFlag = myclient.executeMethod(httppost);
InputStream postResult = httppost.getResponseBodyAsStream();
byte[] bytes = inputStream2byte(postResult);
byte[] len_byte = new byte[10];
System.arraycopy(bytes,0,len_byte,0,10);
repcontent = new String(len_byte);
log.info("请求建行银企直连秘钥传输报文返回结果:{}", repcontent);
//成功响应: 数字签名的长度(固定长度 10 个字节) +数字签名数据+加密后的数据。
if (null != bytes && repcontent.startsWith("00")) {
//数字签名的长度(固定长度 10 个字节) +数字签名数据+加密后的数据
int signLenth = Integer.valueOf(repcontent.substring(0, BankConstants.LENGTH));
byte[] signByte = new byte[signLenth];
System.arraycopy(bytes,10,signByte,0,signLenth);
//返回后的签名
String sign = new String(Base64.encodeBase64(signByte),"UTF-8");
//加密后报文的长度
int srcLength = bytes.length - signLenth - 10;
byte[] scrByte = new byte[srcLength];
System.arraycopy(bytes,signLenth + 10,scrByte,0,srcLength);
//返回的解密后的报文
repcontent = DESedeUtil.decrypt(scrByte, bankKeyConfig.Des_KEY);
//将解密后的报文与签名验签
if (null != repcontent && RSASignUtil.verify(sign, repcontent, bankKeyConfig.RSA_KEY)) {
return repcontent;
} else {
log.error("请求建行银企直连验签出错:{} :{}", sign, repcontent);
}
}else {//失败响应: 6 位错误代码+错误信息,所有信息均不需要进行加密,以字节流返回。
log.error("请求建行银企直连秘钥传输报文出错:",repcontent);
return repcontent;
}
log.info("请求建行银企直连报文返回结果:{}", bytes);
return repcontent;
} catch (Exception e) {
log.error("请求建行银企直连报文出错,错误信息:" + e.getMessage(), e);
} finally {
try {
// 释放http连接
httppost.releaseConnection();
myclient.getHttpConnectionManager().closeIdleConnections(0);
} catch (Exception e2) {
log.error("银企直联释放http连接报错:{}", e2.getMessage());
}
myclient = null;
httppost = null;
}
return null;
}
byte[]数组用的比较少,如果有更好更简洁的方法请联系我,谢谢!
DES解密
/**
* 解密
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密数据
* @throws Exception
*/
public static String decrypt(byte[] data, String key){
try {
//还原密钥
Key k = toKey(key);
//加密
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, k);
return new String(cipher.doFinal(data));
} catch (Exception e){
log.error("DESede解密错误",e);
System.out.printf("");
}
return null;
}
RSA验签
/**
* 验签
*
* @param srcData 原始字符串
* @param sign 签名
* @return 是否验签通过
*/
public static boolean verify(String sign, String srcData ,String public_Key) throws Exception {
byte[] keyBytes = getPublicKey(public_Key).getEncoded();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey key = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initVerify(key);
signature.update(srcData.getBytes());
return signature.verify(Base64.decodeBase64(sign.getBytes()));
}
不过当时写代码时,比较实诚,业务代码一行接着一行,比如对前端请求的参数合理性校验都会在业务代码中进行。就拿参数校验来说,前端请求过来的参数合理性判断,好的办法就是定义一个实体类来封装请求参数,使用 @Valid 注解结合java validation、hibernate validation注解进行校验。注意:如果是实体类中还包含实体类,内部的实体类得加上 @Valid 注解标签,否则内部封装类得
针对 naturalOrder() ,API 的介绍是这么写的:“Returns a comparator that compares {@link Comparable} objects in natural”。说白了就是将之前提倡的 compare 比较表达式给替换了,改由 Comparator.源码参考: 在编码中,如果我们使用了 compare 比较表达式,即“(e1, e2) -> e1
BCL协议,即Oracle Binary Code License Agreement,协议规定你可以使用JDK,但是不能进行修改。私用和商用都可以,但是JDK中的某些商业特性,是需要付费才可以使用的。OTN协议,即Oracle Technology Network License Agreement,目前新发布的JDK用的都是这个协议,可以私用,商用需要付费。1、使用包括8u201/8u202及
IntelliJ IDEA配置Java文件自动生成注释描述文件, 在IDEA环境中,打开File->Settings ,弹出对话框依次选择:Editor>File and Code Templates > Includes > File Header,参考下图: 记得要点击按钮“OK”或者“Apply”哦,设置完成后,重启IDEA(不然不生效哦),之后新建的Ja
如今的Java项目开发,Springboot/Springcloud、Swagger已经成为了标配,下面我们来说说如何在项目中引入Swagger…… 引入Swagger只需要以下3步,即可使用Swagger提供的功能,并不复杂。2、创建SwaggerConfig文件,并且实现 createRestApi() 方法 3、在 Controller 接口文件中,注解 Swagger 信息 通过上面3个步
开发项目时,为了对参数进行安全、合法性校验,往往我们会通过大量的业务代码来进行,今天我们介绍通过注解的方式来实现对接口参数的校验。我们来瞧瞧Controller接口上参数类的写法 使用 CompanyInfoAddParam 类来接受请求的参数,注意:一定要在方法中添加 @Valid 注解,否则所有的校验注解都不会生效。通过上面的注解,即可在项目中实现对请求参数安全、合法性校验,而无需再使用传统方
如果我们有需求需要将Java类的属性及值生成URL格式数据并且按照ASCII码排序,这种需求在项目中特别是和第三方系统进行对接的时候有使用场景。
支持最新166、188、199号段的验证,同时支持165、172、174、191、195 等号段的验证。
提供加密,解密,生成密钥对等方法。txt"; /** * * 生成密钥对 * * * @return KeyPair * * @throws EncryptException */ public static KeyPair generateKeyPair() throws Exception { try { KeyPairGenerator keyPairGen = KeyPairGenerat
很多博客都有写关于Java判断上传文件是否为图片的问题,搜索出来的绝大多数都是复制式的,千篇一律的都是根据后缀名来判断,这种方式是有很多缺陷的,如果我将一个文本文件的后缀名改为".
异常参考如下: 这个异常就是将List 转为 Map时因为 key重复导致的,其实我们只需要在转化时加个判断,便解决这个问题。
TIOBE 近日公布了今年 11 月最受欢迎编程语言排行榜 ,在 Tiobe 的最新指数中,最值得关注是 Python 继续持续增长,已经超过 Java 成为第二受欢迎语言。
往往正确的选择开发工具,对于开发工作会有明显的效果提升,今天分享一下一些常用且覆盖面大的工具。IntelliJ IDEA 官网地址:https://www.com/idea/,下载可以免费试用一个月,后期得付费购买,如果需破解方法可以百度或者淘宝。是滴,很多使用 MySQL 做为项目DB的开发团队,数据库工具首选 Navicat Premium。实际上功能很强大也很全面,官方首页是这么介绍的:“N
1、解压 2、移动到 /usr/local 目录下 3、进入并查看Java Jdk 目录 4、配置Java环境变量 编辑/etc/profile 文件 如果提示 vim 命令未安装,执行 yum -y install vim 即可,也可以使用 vi 命令编辑文件。1、输入 java -version 命令,如果正确,输入Java版本信息 2、输入javac命令,输出 Java 编译相关参数,如下图
身份证号码格式判断在日常开发工作中比较常见,而检验身份证号码格式是否正确的核心则在于正则表达式,很多的身份证号码格式校验代码都不太全面,或者说兼容性不太好。经过使用中检验和对正则表达式多次修复,现将校验代码分享给大家。
谈到加密和解密,日常中用的比较多的大多为 Des 和 Rsa,两种加解密算法由于实现机制不一样,使用场景也不一样。相较于 Des,Rsa需要更多的性能开销,而且场景也不一样,Rsa一般更多用于对外公开接口加解密、签名使用,而 Des 更多使用场景为非公开接口加解密,比如数据通信传输敏感数据加密、存储到数据库的敏感数据进行加密,例如敏感数据、身份证号、手机号码、第三方平台账号相关信息等类似使用场景。
微信用户在关注、取消关注、点击菜单等相关操作时,如果配置了回调接口,微信会将这些事件信息回传到开发者配置指定的URL地址。其中,某些事件推送在发生后,是允许开发者回复用户的,某些则不允许,详细内容如下: 1关注/取消关注事件 2扫描带参数二维码事件 3上报地理位置事件 4自定义菜单事件 5点击菜单拉取消息时的事件推送 6点击菜单跳转链接时的事件推送 参考地址:https://developers.
1、将数据长度过大的数据类型在返回时,手动改为String类型以字符串的形式输出,这样全部被当成字符串输出自然不会被科学计数法,问题得到解决。但是这样的解决方式比较低级,给编码也带来了很大的麻烦,业务代码中会遇到类型转换处理,明显这样的做法不优雅,比较笨!
这几年中国在移动互联网这块发展非常迅猛,各种创业公司、小团队如雨后春笋般冒出来,对Java开发这几年中国在移动互联网这块发展非常迅猛,各种创业公司、小团队如雨后春笋般冒出来,对Java开发的需要变大。但存在人才发展跟不上市场的需求的现状,相对应的给优秀Java人才开出的薪资待遇随之水涨船高。但存在人才发展跟不上市场的需求的现状,相对应的给优秀Java人才开出的薪资待遇随之水涨船高。