建行专线银企直连签到及查询余额开发过程记录

接上篇《建行专线银企直连秘钥交互开发过程记录》,本篇文章主要是记录:

 

1、如何对建设银行的des对称秘钥和rsa公钥进行解密;

2、如何对签到的请求报文进行加密和对签到的响应报文进行解密;

3、如何对查询余额的请求报文进行加密和对查询余额的响应报文进行解密;

 

  1 package x;
  2 
  3 import java.awt.*;
  4 import java.io.*;
  5 import java.math.BigInteger;
  6 import java.security.*;
  7 import java.security.interfaces.RSAPrivateKey;
  8 import java.security.interfaces.RSAPublicKey;
  9 import java.security.spec.PKCS8EncodedKeySpec;
 10 import java.security.spec.X509EncodedKeySpec;
 11 import java.text.SimpleDateFormat;
 12 import java.util.Date;
 13 
 14 import javax.crypto.Cipher;
 15 import javax.crypto.SecretKey;
 16 import javax.crypto.SecretKeyFactory;
 17 import javax.crypto.spec.DESKeySpec;
 18 import javax.crypto.spec.DESedeKeySpec;
 19 
 20 import com.sun.org.apache.xpath.internal.objects.XString;
 21 import org.apache.commons.codec.binary.Base64;
 22 import sun.misc.BASE64Decoder;
 23 
 24 public class PostDemo {
 25 
 26     private static final String SIGNATURE_ALGORITHM = "MD5withRSA";
 27 
 28     public static void main(String[] args) throws Exception {
 29         //解密建行des对称秘钥和rsa公钥
 30         dectyptCcbKey();
 31 
 32         //生成签到请求
 33         requestSignIn();
 34         //解析签到响应
 35         responseSignIn();
 36 
 37         //生成查询余额请求
 38         requestBalance();
 39         //解析查询余额响应
 40         responseBalance();
 41     }
 42 
 43     /**
 44      * 解密建行des对称秘钥和rsa公钥
 45      * @throws Exception
 46      */
 47     public static void dectyptCcbKey() throws Exception {
 48         // 电子银行合约编号(取后10位,不足10位的,前面补0)+交换当日日期(YYMMDD 6位)
 49         String desKey = getDESKey();
 50         // 建行提供方法处理后8位byte[]
 51         byte[] keyByte = asc2bin(desKey);
 52 
 53         //ccb_des和ccb_pub是通过/interlink/KeyTransfer获取的文件
 54         // 获取建行des对称秘钥,并转换成byte[]
 55         byte[] ccb_des=getContent("D:/CCBKEY/ccb_des.txt");
 56         // 获取建行rsa公钥,并转换成byte[]
 57         byte[] ccb_pub=getContent("D:/CCBKEY/ccb_pub.txt");
 58 
 59         //减去前面000000
 60         byte[] ccb_des_real = new byte[ccb_des.length - 6];
 61         System.arraycopy(ccb_des,6, ccb_des_real,0, ccb_des.length - 6);
 62         //des对称秘钥解密后的base64
 63         byte[] ccbDesDecrypt = decryptKey(ccb_des_real,keyByte);
 64         //保存des对称秘钥解密后的二进制成文件
 65         saveFile(ccbDesDecrypt, "D:/CCBKEY/ccb_des_byte.txt");
 66         //保存des对称秘钥解密后的base64成文件
 67         saveFile(Base64.encodeBase64String(ccbDesDecrypt), "D:/CCBKEY/ccb_des_base64.txt");
 68 
 69         //减去前面000000
 70         byte[] ccb_pub_real = new byte[ccb_pub.length - 6];
 71         System.arraycopy(ccb_pub,6, ccb_pub_real,0, ccb_pub.length - 6);
 72         //建行rsa公钥解密后的base64
 73         byte[] ccbPubDecrypt = decryptKey(ccb_pub_real,keyByte);
 74         //保存建行rsa公钥解密后的二进制成文件
 75         saveFile(ccbPubDecrypt, "D:/CCBKEY/ccb_rsa_pub_byte.txt");
 76         //保存建行rsa公钥解密后的base64成文件
 77         saveFile(Base64.encodeBase64String(ccbPubDecrypt), "D:/CCBKEY/ccb_rsa_pub_base64.txt");
 78     }
 79 
 80     /**
 81      * 生成签到请求
 82      * @throws Exception
 83      */
 84     public static void requestSignIn() throws Exception {
 85         //des对称秘钥解密后的base64
 86         byte[] ccbDesDecrypt = getCcbDes();
 87         String gouxinPriKey = getGouxinPriKey();
 88 
 89         //取的request的xml的base64字符串
 90         String xml = readFile("D:/CCBKEY/签到_request.txt");//原报文xml明文
 91         byte[] xml_encrypt_byte = encrypt(xml.getBytes(), ccbDesDecrypt);
 92         //保存签到request的xml的二进制成文件
 93         saveFile(xml_encrypt_byte,"D:/CCBKEY/签到request的xml的二进制.txt");
 94         String xml_encrypt_string = Base64.encodeBase64String(xml_encrypt_byte);
 95         //保存签到request的xml的base64成文件
 96         saveFile(xml_encrypt_string,"D:/CCBKEY/签到request的xml的base64.txt");
 97 
 98         //取的request的signature的base64字符串
 99         byte[] xml_signature_byte =  sign(xml.getBytes(), gouxinPriKey);
100         //保存签到request的signature的二进制成文件
101         saveFile(xml_signature_byte,"D:/CCBKEY/签到request的signature的二进制.txt");
102         String xml_signature_string = Base64.encodeBase64String(xml_signature_byte);
103         //保存签到request的signature的base64成文件
104         saveFile(xml_signature_string,"D:/CCBKEY/签到request的signature的base64.txt");
105     }
106 
107     /**
108      * 解析签到响应
109      * @throws Exception
110      */
111     public static void responseSignIn() throws Exception{
112         byte[] response_byte = getContent("D:/CCBKEY/签到response.txt");
113         byte[] len_byte = new byte[10];
114         System.arraycopy(response_byte,0, len_byte,0, 10);
115         String sign_len_s = new String(len_byte);
116         //数字签名的长度
117         int sign_len= Integer.parseInt(sign_len_s);
118 
119         //获取数字签名
120         byte[] response_sign_byte = new byte[sign_len];
121         System.arraycopy(response_byte,10, response_sign_byte,0, sign_len);
122         //保存建行签到响应的数字签名的二进制成文件
123         saveFile(response_sign_byte, "D:/CCBKEY/签到response的数字签名的二进制.txt");
124         //保存建行签到响应的数字签名的base64成文件
125         saveFile(Base64.encodeBase64String(response_sign_byte), "D:/CCBKEY/签到response的数字签名的base64.txt");
126 
127         //获取报文密文
128         int response_xml_byte_length = response_byte.length - 10 - sign_len;
129         byte[] response_xml_byte = new byte[response_xml_byte_length];
130         System.arraycopy(response_byte,10 + sign_len, response_xml_byte,0, response_xml_byte_length);
131         //保存建行签到响应的报文密文的二进制成文件
132         saveFile(response_xml_byte, "D:/CCBKEY/签到response的报文密文的二进制.txt");
133         //保存建行签到响应的报文密文的base64成文件
134         saveFile(Base64.encodeBase64String(response_xml_byte), "D:/CCBKEY/签到response的报文密文的base64.txt");
135 
136         //对响应报文解密
137         // 获取建行des对称秘钥,并转换成byte[]
138         byte[] ccb_des = getCcbDes();
139         // 获取建行rsa公钥
140         String ccbPubKey = getCcbPubKey();
141 
142         //建行提供的DES对称密钥对响应报文进行解密,获得响应报文明文
143         byte[] response_decrypt = decrypt(response_xml_byte, ccb_des);
144         boolean isvalid = isValid(response_decrypt, response_sign_byte, ccbPubKey);
145 
146         if(isvalid){
147             String response_decrypt_string = new String(response_decrypt);
148             saveFile(response_decrypt_string, "D:/CCBKEY/签到response的报文明文.txt");
149         }
150         else{
151             saveFile("验证签名失败", "D:/CCBKEY/签到response的报文明文.txt");
152         }
153     }
154 
155     /**
156      * 解析查询余额响应
157      * @throws Exception
158      */
159     public static void requestBalance() throws Exception {
160         //des对称秘钥解密后的base64
161         byte[] ccbDesDecrypt = getCcbDes();
162         String gouxinPriKey = getGouxinPriKey();
163 
164         //取的request的xml的base64字符串
165         String xml = readFile("D:/CCBKEY/查询余额_request.txt");//原报文xml明文
166         byte[] xml_encrypt_byte = encrypt(xml.getBytes(), ccbDesDecrypt);
167         //保存签到request的xml的二进制成文件
168         saveFile(xml_encrypt_byte,"D:/CCBKEY/查询余额request的xml的二进制.txt");
169         String xml_encrypt_string = Base64.encodeBase64String(xml_encrypt_byte);
170         //保存签到request的xml的base64成文件
171         saveFile(xml_encrypt_string,"D:/CCBKEY/查询余额request的xml的base64.txt");
172 
173         //取的request的signature的base64字符串
174         byte[] xml_signature_byte =  sign(xml.getBytes(), gouxinPriKey);
175         //保存签到request的signature的二进制成文件
176         saveFile(xml_signature_byte,"D:/CCBKEY/查询余额request的signature的二进制.txt");
177         String xml_signature_string = Base64.encodeBase64String(xml_signature_byte);
178         //保存签到request的signature的base64成文件
179         saveFile(xml_signature_string,"D:/CCBKEY/查询余额request的signature的base64.txt");
180     }
181 
182     /**
183      * 解析查询余额响应
184      * @throws Exception
185      */
186     public static void responseBalance() throws Exception{
187         byte[] response_byte = getContent("D:/CCBKEY/查询余额response.txt");
188         byte[] len_byte = new byte[10];
189         System.arraycopy(response_byte,0, len_byte,0, 10);
190         String sign_len_s = new String(len_byte);
191         //数字签名的长度
192         int sign_len= Integer.parseInt(sign_len_s);
193 
194         //获取数字签名
195         byte[] response_sign_byte = new byte[sign_len];
196         System.arraycopy(response_byte,10, response_sign_byte,0, sign_len);
197         //保存建行签到响应的数字签名的二进制成文件
198         saveFile(response_sign_byte, "D:/CCBKEY/查询余额response的数字签名的二进制.txt");
199         //保存建行签到响应的数字签名的base64成文件
200         saveFile(Base64.encodeBase64String(response_sign_byte), "D:/CCBKEY/查询余额response的数字签名的base64.txt");
201 
202         //获取报文密文
203         int response_xml_byte_length = response_byte.length - 10 - sign_len;
204         byte[] response_xml_byte = new byte[response_xml_byte_length];
205         System.arraycopy(response_byte,10 + sign_len, response_xml_byte,0, response_xml_byte_length);
206         //保存建行签到响应的报文密文的二进制成文件
207         saveFile(response_xml_byte, "D:/CCBKEY/查询余额response的报文密文的二进制.txt");
208         //保存建行签到响应的报文密文的base64成文件
209         saveFile(Base64.encodeBase64String(response_xml_byte), "D:/CCBKEY/查询余额response的报文密文的base64.txt");
210 
211         //对响应报文解密
212         // 获取建行des对称秘钥,并转换成byte[]
213         byte[] ccb_des = getCcbDes();
214         // 获取建行rsa公钥
215         String ccbPubKey = getCcbPubKey();
216 
217         //建行提供的DES对称密钥对响应报文进行解密,获得响应报文明文
218         byte[] response_decrypt = decrypt(response_xml_byte, ccb_des);
219         boolean isvalid = isValid(response_decrypt, response_sign_byte, ccbPubKey);
220 
221         if(isvalid){
222             String response_decrypt_string = new String(response_decrypt);
223             saveFile(response_decrypt_string, "D:/CCBKEY/查询余额response的报文明文.txt");
224         }
225         else{
226             saveFile("验证签名失败", "D:/CCBKEY/查询余额response的报文明文.txt");
227         }
228     }
229 
230     /**
231      * 从文件中获取我方rsa私钥
232      * @return
233      */
234     public static String getGouxinPriKey(){
235        return readFile("D:/CCBKEY/gouxin_rsa_pri_base64.txt");
236     }
237 
238     /**
239      * 从文件中获取我方rsa公钥
240      * @return
241      */
242     public static String getGouxinPubKey(){
243         return readFile("D:/CCBKEY/gouxin_rsa_pub_base64.txt");
244     }
245 
246     /**
247      * 从文件中获取建行rsa公钥
248      * @return
249      */
250     public static String getCcbPubKey(){
251         return readFile("D:/CCBKEY/ccb_rsa_pub_base64.txt");
252     }
253 
254     /**
255      * 从文件中获取建行des对称秘钥
256      * @return
257      */
258     public static byte[] getCcbDes() throws IOException {
259         return getContent("D:/CCBKEY/ccb_des_byte.txt");
260     }
261 
262     /**
263      * 签名
264      * @param data
265      * @param privateKey
266      * @return
267      * @throws Exception
268      */
269     public static byte[] sign(byte[] data, String privateKey) throws Exception {
270         // 取私钥匙对象
271         PrivateKey priKey = getPrivateKey(privateKey);
272         // 用私钥对信息生成数字签名
273         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
274         signature.initSign(priKey);
275         signature.update(data);
276         return  signature.sign();
277     }
278 
279     /**
280      * RSA验签名检查
281      * @param in
282      * @param signdata
283      * @param publicKey 建行rsa公钥
284      * @return
285      */
286     public static boolean isValid(byte[] in, byte[] signdata, String publicKey) throws Exception {
287         try
288         {
289             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
290             //获取建行公钥
291             PublicKey pubKey = getPublicKey(publicKey);
292             Signature signature = java.security.Signature.getInstance(SIGNATURE_ALGORITHM);
293             signature.initVerify(pubKey);
294             signature.update(in);
295             return signature.verify(signdata);
296         }
297         catch (Exception e)
298         {
299             e.printStackTrace();
300         }
301         return false;
302     }
303 
304     /**
305      * String转私钥PrivateKey
306      * @param key
307      * @return
308      * @throws Exception
309      */
310     public static PrivateKey getPrivateKey(String key) throws Exception {
311         byte[] keyBytes;
312         keyBytes = (new BASE64Decoder()).decodeBuffer(key);
313         PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
314         KeyFactory keyFactory = KeyFactory.getInstance("RSA");
315         PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
316         return privateKey;
317     }
318 
319     /**
320      * String转公钥PublicKey
321      * @param key
322      * @return
323      * @throws Exception
324      */
325     public static PublicKey getPublicKey(String key) throws Exception {
326         byte[] keyBytes;
327         keyBytes = (new BASE64Decoder()).decodeBuffer(key);
328         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
329         KeyFactory keyFactory = KeyFactory.getInstance("RSA");
330         PublicKey publicKey = keyFactory.generatePublic(keySpec);
331         return publicKey;
332     }
333 
334     /**
335      *
336      * @return
337      */
338     private static String getDESKey() {
339         String customerId = "SZ44200009022220201";
340         // 电子银行合约编号取后10位,不足10位,前面补0
341         if (customerId.length() >= 10) {
342             customerId = customerId.substring(customerId.length() - 10, customerId.length());
343         } else {
344             customerId = "0000000000".substring(customerId.length()) + customerId;
345         }
346         // 交换当日日期(YYMMDD)
347         SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
348         String date = sdf.format(new Date());
349         // DES密钥
350         String DESKey = customerId + date;
351         return DESKey;
352     }
353 
354     /**
355      *
356      * @param hexString
357      * @return
358      */
359     private static byte[] asc2bin(String hexString) {
360         byte[] hexbyte = hexString.getBytes();
361         byte[] bitmap = new byte[hexbyte.length / 2];
362         for (int i = 0; i < bitmap.length; i++) {
363             hexbyte[i * 2] -= hexbyte[i * 2] > '9' ? 7 : 0;
364             hexbyte[i * 2 + 1] -= hexbyte[i * 2 + 1] > '9' ? 7 : 0;
365             bitmap[i] = (byte) ((hexbyte[i * 2] << 4 & 0xf0) | (hexbyte[i * 2 + 1] & 0x0f));
366         }
367 
368         return bitmap;
369     }
370 
371     /**
372      *
373      * @param in
374      * @param key_byte
375      * @return
376      * @throws Exception
377      */
378     public static byte[] encryptKey(String in, byte[] key_byte) throws Exception {
379         byte[] enc_data = null;
380         SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
381         SecretKey secretkey = skf.generateSecret(new DESKeySpec(key_byte));
382         byte[] inByte = Base64.decodeBase64(in);
383         Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
384         cipher.init(Cipher.ENCRYPT_MODE, secretkey, new SecureRandom());
385         enc_data = cipher.doFinal(inByte);
386         return enc_data;
387     }
388 
389     /**
390      *
391      * @param in
392      * @param key_byte
393      * @return
394      * @throws Exception
395      */
396     public static byte[] decryptKey(byte[] in, byte[] key_byte) throws Exception {
397         byte[] dec_data = null;
398         SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
399         SecretKey secretkey = skf.generateSecret(new DESKeySpec(key_byte));
400         Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
401         cipher.init(Cipher.DECRYPT_MODE, secretkey);
402         dec_data = cipher.doFinal(in);
403         return dec_data;
404     }
405 
406     /**
407      * DESede加密
408      * @param in
409      * @param key_byte
410      * @return
411      * @throws Exception
412      */
413     public static byte[] encrypt(byte[] in, byte[] key_byte) throws Exception{
414         byte[] enc_data = null;
415         SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
416         SecretKey secretKey = skf.generateSecret(new DESedeKeySpec(key_byte));
417         Cipher cipher = Cipher.getInstance("DESede");
418         cipher.init(Cipher.ENCRYPT_MODE, secretKey, new SecureRandom());
419         enc_data = cipher.doFinal(in);
420         return enc_data;
421     }
422 
423     /**
424      * DESede解密
425      * @param in
426      * @param key_byte
427      * @return
428      * @throws Exception
429      */
430     public static byte[] decrypt(byte[] in, byte[] key_byte) throws Exception{
431         byte[] enc_data = null;
432         SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
433         SecretKey secretKey = skf.generateSecret(new DESedeKeySpec(key_byte));
434         Cipher cipher = Cipher.getInstance("DESede");
435         cipher.init(Cipher.DECRYPT_MODE, secretKey, new SecureRandom());
436         enc_data = cipher.doFinal(in);
437         return enc_data;
438     }
439 
440     /**
441      * 保存文件
442      * @param fileString 文件内容
443      * @param filepath 文件绝对路径
444      */
445     public static void saveFile(String fileString, String filepath){
446         File file = new File(filepath);
447         if (file.exists()) {
448             file.delete();
449         }
450         FileWriter writer;
451         try {
452             writer = new FileWriter(filepath);
453             writer.write(fileString);
454             writer.flush();
455             writer.close();
456         } catch (IOException e) {
457             e.printStackTrace();
458         }
459     }
460 
461     /**
462      * 将字节流转换成文件
463      * @param data 二进制数据
464      * @param filepath 文件绝对路径
465      * @throws Exception
466      */
467     public static void saveFile(byte[] data,String filepath)throws Exception {
468         if (data != null) {
469             File file = new File(filepath);
470             if (file.exists()) {
471                 file.delete();
472             }
473             FileOutputStream fos = new FileOutputStream(file);
474             fos.write(data, 0, data.length);
475             fos.flush();
476             fos.close();
477         }
478     }
479 
480     /**
481      * 根据文件路径读取文件转出byte[]
482      * @param filePath
483      * @return
484      * @throws IOException
485      */
486     public static byte[] getContent(String filePath) throws IOException {
487         File file = new File(filePath);
488         long fileSize = file.length();
489         if (fileSize > Integer.MAX_VALUE) {
490             System.out.println("file too big...");
491             return null;
492         }
493         FileInputStream fi = new FileInputStream(file);
494         byte[] buffer = new byte[(int) fileSize];
495         int offset = 0;
496         int numRead = 0;
497         while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
498             offset += numRead;
499         }
500         // 确保所有数据均被读取
501         if (offset != buffer.length) {
502             throw new IOException("Could not completely read file "
503                     + file.getName());
504         }
505         fi.close();
506         return buffer;
507     }
508 
509     /**
510      * 读取文件内容
511      * @param fileName
512      * @return
513      */
514     public static String readFile(String fileName) {
515         File file = new File(fileName);
516         BufferedReader reader = null;
517         StringBuffer sbf = new StringBuffer();
518         try {
519             reader = new BufferedReader(new FileReader(file));
520             String tempStr;
521             while ((tempStr = reader.readLine()) != null) {
522                 sbf.append(tempStr);
523             }
524             reader.close();
525             return sbf.toString();
526         } catch (IOException e) {
527             e.printStackTrace();
528         } finally {
529             if (reader != null) {
530                 try {
531                     reader.close();
532                 } catch (IOException e1) {
533                     e1.printStackTrace();
534                 }
535             }
536         }
537         return sbf.toString();
538     }
539 }

 

(注:所有请求建设银行的接口都是使用postman手动调用的)

posted @ 2021-08-20 09:52  沙木  阅读(558)  评论(0编辑  收藏  举报