银行PIN数据加密

来源:互联网 发布:mysql 时间大于等于 编辑:程序博客网 时间:2024/04/29 12:40
 
PIN加密有3个要素,PIN-KEY,PIN,PAN。
PIN-KEY也就是加密的密钥,这里采用的3DES加密,所以PIN-KEY长度要么是16个字节要么是24个字节,也即是要么采用128位长密钥要么采用192长字节;PIN也就是要加密的明文,这里可能是账户密码,也可能是登录密码的明文;使用PIN加密,在加密之前,首先使用一串数字和PIN异或,然后将异或后的数据拿来进行3DES加密,这样加密出来的数据就是PIN加密结果。通常每次加密时采用的PAN不一样。当时解密的时候也需要取得该PAN进行解密。使用策略模式以方便以后扩展其他加密算法。对接口不满足的可适当通过Adapter调整
实现示例:
/**
 *@(#)EncryRule.java1.02007-10-23
 */
package com.security;
 
/**
 * 数据加密Strategy
 *
 * @author tsimgsong
 * @version 1.0,2007-10-15
 *
 */
public abstract class EncryRule {
      
       /**
        * 明文
        */
       protected String plainText = "";
      
       /**
        * 密文
        */
       protected String encryedText = "";
      
       /**
        * 取密文
        * @return String 密文
        */
       public String getEncryedText(){
              return encryedText;
       }
      
       /**
        * 设置密文
        * @param encryedText 密文
        */
       public void setEncryedText(String encryedText) {
              this.encryedText = encryedText;
       }
      
       /**
        * 取明文
        * @return String 明文
        */
       public String getPlainText(){
              return plainText;
       }
      
       /**
        * 设置明文
        * @param plainText 明文
        */
       public void setPlainText(String plainText){
              this.plainText = plainText;
       }
      
       /**
        * 加密操作
        *
        */
       public abstract void encry();
      
       /**
        * 解密操作
        *
        */
       public abstract void deEncry();
}
 
/**
 *@(#)PinEncry.java1.02007-10-23
 */
package com.security;
import java.lang.reflect.Array;
 
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
 
/**
 * PIN码加密,加密报文通信中需要传输的客户密码
 * <br>
 *
 * @author tsimgsong
 * @version 1.0,2007-10-15
 *
 */
public class PinEncry extends EncryRule {
 
       private static boolean initialized = false;
//     密钥24个字节,192位
       private static String key_pin ;
//     pin和pan的长度,值域长度为30,前面2位长度表示值域的长度
       private static final int LENGTH_PIN = 32;
       private static final int LENGTH_PAN = 32;
       private static final int LENGTH_PWD = 0;
      
//     加密3DES变量
       private static Cipher cipher = null;
//     解密3DES变量
       private static Cipher deCipher = null;
//     加密算法
       private static final String ALGORITHM = "DESede";
      
       private static SecretKey key = null;
       /**
        * "00"+网银流水号+交易日期+客户号+操作员编号
        * <br>&nbsp;&nbsp;&nbsp;&nbsp;前面两位为数据长度,设为定值00,数据30位长,不足左补0,超过30位保留后30个字节
        */
       private String pan = "";
       static {
              if (!initialized) {
                     pinEncryInit();
                     initialized = true;
              }
       }
      
       /**
        *初始化加密要素,从数据库中提取PIN密码
        *
        */
       private static void pinEncryInit() {
                      System.out.println("Pin Encry Parameters Initialize complete:success");
       }
   
       /**
        * 重置加密密钥,从下次使用该功能时生效
        *
        */
       private static void reset() {
              initialized = false;
              System.out.println("Reset Pin Encry Parameters");
              pinEncryInit();
       }
 
       /**
        * PIN码加密
        * <br>对明文进行3DES加密,没8个字节处理一次,对第一个8字节进行3DES加密,后面每8个字节都和前面的加密结果进行异或后3DES加密</br>
        *
        */
       public void encry() {
              encryedText = plainText;
              // PIN nor PAN
              byte[] toBeEncry = null;
              toBeEncry = norProcess(plainText, pan);
//            System.out.println("Before 3DES:"+encryedText +"Base64:"+new sun.misc.BASE64Encoder().encode(encryedText.getBytes()));
              try {                    
//                   明文
//                   密文 存放计算后的数据
                     byte[] encryedData = new byte[toBeEncry.length];
                    
//                   本次需要进行处理的数据 一次最多处理8个字节
                     byte[] encrying = new byte[8];
                    
//                   3DeS需要以字节数组的方式进行加密
                  
              } catch (Exception e) {
                     e.printStackTrace();
 
              }
 
       }
      
       public void deEncry(){
                 byte[] deEncryed = null;
                     try {                    
                           
                            byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(encryedText);     
                            byte[] mDec = new byte[8];
                            deEncryed = new byte[dec.length];
                           
                            System.arraycopy(dec,0,deEncryed,0,dec.length);
                           
                            }
                            encryedText = new sun.misc.BASE64Encoder().encode(deEncryed);
//                          System.out.println("After De3DES :"+encryedText);
                     } catch (Exception e) {
                            e.printStackTrace();
 
                     }
             
             
             
             
              plainText = denorProcess(deEncryed,pan);
       }
      
       /**
        * 数据异或处理<br>
        *
        * @param pin 密码长度(2Byte)+客户密码<br>&nbsp;&nbsp;&nbsp;&nbsp;密钥最长不超过30位,不足部分右补0
        * @param pan "00"+网银流水号+交易日期+客户号+操作员编号
        * <br>&nbsp;&nbsp;&nbsp;&nbsp;前面两位为数据长度,设为定值00,数据30位长,不足左补0,超过30位保留后30个字节
        * @return PIN String Block
        */
       private byte[] norProcess(String pin,String pan){
             
//            异或结果存放
        int[] norNum=new int[LENGTH_PIN];
        byte[] norRes = new byte[LENGTH_PIN];
        byte bb;
        String temp = "";
        String result="";
//        System.out.println("PIN:"+pin);
//        System.out.println("PAN:"+pan);
//        密码不足30位右补0
        for(int i = pin.length() ;i <LENGTH_PIN ;i++){
               pin = pin+"0";
        }
//        pan不足30位左补0
        for(int i = pan.length() ;i<LENGTH_PAN ;i++){
               pan = "0"+pan;
        }
//        pan超过30位去后30位
        if(pan.length() > LENGTH_PAN){
               pan = pan.substring(pan.length()-LENGTH_PAN,pan.length());
        }
 
        for(int i=0;i<LENGTH_PIN;i++){
             norRes[i] =(byte) (pin.charAt(i)^pan.charAt(i));
        }
//        System.out.print("Nor Result:");
//        for(int i = 0 ;i<norRes.length ;i++){
//             System.out.print(Integer.toHexString(norRes[i])+" ");
//        }
//        System.out.println();
        return norRes;//new String(norRes);
    }
 
       /**
        * 异或结果还原处理
        *
        * @param norStr 异或值
        * @param pan "00"+交易日期+交易时间+客户号+操作员编号
        * <br>&nbsp;&nbsp;&nbsp;&nbsp;前面两位为数据长度,设为定值00,数据30位长,不足左补0,超过30位保留后30个字节
        * @return String 异或原串
        */
 private String denorProcess(byte[] norStr,String pan){
        byte[] snNum=norStr;
       
        String result="";
       
//      pan不足30位左补0
        for(int i = pan.length() ;i<LENGTH_PAN ;i++){
               pan = "0"+pan;
        }
       
//        pan超过30位去后30位
        if (pan.length() > LENGTH_PAN) {
                     pan = pan.substring(pan.length() - LENGTH_PAN, pan.length());
              }
             
        int n = 0;
        for(int i=0;i<norStr.length;i++){
            snNum[i]=(byte)(norStr[i]^pan.charAt(i));
        }
 
        for(int k=0;k< norStr.length;k++){
            result+=(char)snNum[k];
        }
//        System.out.println("DeNcry result:"+result);
        return result;
    }
 
 /**
   * 取Pan值
   * @return String
   */
       public String getPan() {
              return pan;
       }
      
       /**
        * 设置Pan值
        * @param pan
        */
       public void setPan(String pan) {
              this.pan = pan;
       }
 
 
}
 
/**
 *@(#)PinEncry.java1.02007-10-23
 */
Package com.security;
/**
 * 数据加密策略
 *
 * @author tsimgsong
 * @version 1.0,2007-10-15
 *
 */
public class EncrySolve {
      
//     加密策略
       static EncryRule rule ;
      
       /**
        * 加密运算
        * @param r 加密策略
        * @param plainText 明文
        * @return String 加密后数据
        */
       public static String encry(EncryRule r,String plainText){
              rule = r;
              rule.setPlainText(plainText);
              rule.encry();
              return rule.getEncryedText();
       }
      
       /**
        * 解密运算
        * @param r 解密策略
        * @param encryedText 密文
        * @return String 明文
        */
       public static String deEncry(EncryRule r,String encryedText){
              rule = r;
              rule.setEncryedText(encryedText);
              rule.deEncry();
              return rule.getPlainText();
       }
      
       /**
        * 取密文
        * @return
        */
       public String getEncryedText(){
              return rule.getEncryedText();
       }
      
       /**
        * 取明文
        * @return
        */
       public String getPlainText(){
              return rule.getPlainText();
       }
 
}
Junit测试:
PinEncry pe = new PinEncry();
              String passwd = "000001";
              int length_passwd = passwd.length() ;
              if(length_passwd<10){
                     passwd = "0"+length_passwd+passwd;
              }else{
                   passwd = ""+length_passwd+passwd;
              }
              PinEncry pe = new PinEncry();
//            组织Pan值 交易日期YYYYMMDD+企业客户号+操作员编号
              String pan = "00";
              pan = "383090020071022799070001";
              pe.setPan(pan);
加密:   
              passwd = (EncrySolve.encry(pe,passwd)); 
        assertEquals(‘X065VL+nZV6/jP8XjJq6FmMH18egeDW852gA2RzTF0Q=’,passwd);
       解密:
passwd=EncrySolve.deEncry(pe,"X065VL+nZV6/jP8XjJq6FmMH18egeDW852gA2RzTF0Q=");
loger.debug(passwd);
 
密码进行加密之前必须计算出密码原文的长度,并以两个字节的长度放置在明文的前面,后面根据密码的长度进行截取。加密后的数据进行了Base64编码。
3DES算法就是进行了3次DES计算,用第一个密钥进行一次加密,用第二个密钥进行一次解密,之后再用第3个密钥进行一次加密,DES加密的密钥长度是64位,如果采用192位密码加密,那个三个密钥分别取依次的64位,如果采用128位密钥,第一个和第三个的密钥相同
 
 
原创粉丝点击