首页 技术 正文
技术 2022年11月15日
0 收藏 346 点赞 2,829 浏览 6512 个字

1, 采用银联ANSI X9.8标准 PIN xor PAN获取PIN BlOCK

2, 采用3Des进行加密

参考:

des和3Des加密算法实现

要点:因为3DES是对称加密算法,key是24位,当只有16位时,后8位取key的前8位

ANSI X9.8标准 PIN xor PAN获取PIN BlOCK

(1) ANSI X9.8 Format(不带主账号信息)

PIN(个人识别码 Personal Identity Number)总共有8个byte长度,分为两个部分;(类似数据包的格式)

1:Byte1 记录PIN的长度

2:Byte2-Byte8 6-12位(字符)PIN(每个字符占4个BIT,不足8位右补F)

例如:明文PIN为 123456,

则PIN BLOCK为 0x06 0x12 0x34 0x56 0xFF 0xFF 0xFF 0xFF

0x06记录了PIN的长度为6,后边不足16位均以F补齐,然后转换为BCD码(BCD码为8位二进制数为一个单元,也就是一个Byte的大小也是一个十六进制数HEX的占用长度)。

2)ANSI X9.8 Format带主帐号信息)
PIN BLOCK 格式:等于 PIN 按位异或主帐号
PIN 格式:(与1中的格式类似)
Byte 1 PIN的长度
Byte 2 – Byte 3/4/5/6/7 4–12个PIN(每个PIN占4个BIT)
Byte4/5/6/7/8 – Byte 8 FILLER “F” (每个“F“占4个BIT)

PAN(主帐号 Primary Account Number)同样包含8个byte,格式如下:
Byte 1 — Byte 2 0x00 0x00
Byte 3 — Byte 8 12个主帐号字符(最后一位为校验位)
12位字符主帐号的取法:取主帐号的右12位(不包括最右边的校验位),不足12位左补“0X00”。

例子:

明文 PIN:123456,
主帐号 PAN:123456789012345678
截取下的主帐号为:678901234567 (最后一位校验位8的前12位字符为截取的主帐号)

则用于PIN加密的主帐号为:0x00 0x00 0x67 0x89 0x01 0x23 0x45 0x67
则 PIN BLOCK (PIN按位异或主帐号PAN)

即是为:  0x06 0x12 0x34 0x56 0xFF 0xFF 0xFF 0xFF
异或上:  0x00 0x00 0x67 0x89 0x01 0x23 0x45 0x67
结果为:  0x06 0x12 0x53 0xDF 0xFE 0xDC 0xBA 0x98

——————————————–Java代码的实现——————————-

package com.bstek.tools;import java.security.Security;import javax.crypto.Cipher;import javax.crypto.spec.SecretKeySpec;/** * 加密  3Des算法实现 *1: A---使用3Des解密B----得到C *2:pinblock 采用银联标准生成  pin^accNo *3:使用C加密pinblock得到最终的密码 * @author yangw@eastcom.com * */public class NewThreeDes {    static {        Security.addProvider(new com.sun.crypto.provider.SunJCE());    }    public static final String HTMK="C4F6E5A15B356D435BBC61E2ACFF6A42"; //A    public static final String HPIN="5B35E077D48BF7E308219B550E6DD1FE"; //B    /**     * 3DES加密     * @param password 明文     * @param secretKey 密钥     * @return 16进制形式的字符串     * @throws Exception     */    public static String encrypt(byte[] password,byte[] secretKey) throws Exception {        SecretKeySpec key = new SecretKeySpec(secretKey, "DESede");        Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding"); // TripleDES/ECB/NoPadding        cipher.init(Cipher.ENCRYPT_MODE, key);        byte[] cipherText = cipher.doFinal(password);        return byte2HexStr(cipherText);    }    /**     * 3DES解密     * @param password 密文     * @return byte[]形式的明文     * @throws Exception     */    public static byte[] decrypt(String password,byte[] keyBytes) throws Exception {        byte[] input = hexStr2Bytes(password);        SecretKeySpec key = new SecretKeySpec(keyBytes, "DESede");        Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");        cipher.init(Cipher.DECRYPT_MODE, key);        return  cipher.doFinal(input);    }    /**     *  十六进制转成二进制     * @param src     * @return     */    public static byte[] hexStr2Bytes(String src) {        int m = 0, n = 0;        int l = src.length() / 2;        byte[] ret = new byte[l];        for (int i = 0; i < l; i++) {            m = i * 2 + 1;            n = m + 1;            ret[i] = uniteBytes(src.substring(i * 2, m), src.substring(m, n));        }        return ret;    }    private static byte uniteBytes(String src0, String src1) {        byte b0 = Byte.decode("0x" + src0).byteValue();        b0 = (byte) (b0 << 4);        byte b1 = Byte.decode("0x" + src1).byteValue();        byte ret = (byte) (b0 | b1);        return ret;    }    /**     *     * 十六进制字符串转换成byte[]     * @param hexStr 待转换的字符串     * @param length  hexStr必须达到的长度     * @param isLeft 左边补还是右边补     * @param hexStr 填充的字符     */    public static byte[] hexStr2Str(String hexStr) {         // 因为3DES是对称加密算法,key是24位,当只有16位时,后8位取key的前8位        StringBuffer sb=new StringBuffer(hexStr);        sb.append(hexStr.substring(0,16));//字符串是16位, 就是8位byte        hexStr=sb.toString();        // 转换的过程        String str = "0123456789ABCDEF";        char[] hexs = hexStr.toCharArray();        byte[] bytes = new byte[hexStr.length() / 2];        int n;        for (int i = 0; i < bytes.length; i++) {            n = str.indexOf(hexs[2 * i]) * 16;            n += str.indexOf(hexs[2 * i + 1]);            bytes[i] = (byte) (n & 0xff);        }       return bytes;    }    /**     * bytes转换成十六进制字符串     */    public static String byte2HexStr(byte[] b) {        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();    }    /**     *     * @param src0     * @param src1     * @return     */    private static byte uniteBytes(byte src0, byte src1) {         byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 })).byteValue();         _b0 = (byte) (_b0 << 4);         byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 })).byteValue();         byte ret = (byte) (_b0 ^ _b1);         return ret;     }    /**     *  对pin进行加密     * @param pin     * @return     */    private static byte[] getHPin(String pin) {         byte arrPin[] = pin.getBytes();         byte encode[] = new byte[8];         encode[0] = (byte) 0x06;         encode[1] = (byte) uniteBytes(arrPin[0], arrPin[1]);         encode[2] = (byte) uniteBytes(arrPin[2], arrPin[3]);         encode[3] = (byte) uniteBytes(arrPin[4], arrPin[5]);         encode[4] = (byte) 0xFF;         encode[5] = (byte) 0xFF;         encode[6] = (byte) 0xFF;         encode[7] = (byte) 0xFF;         return encode;     }    /**     * PIN加密的主帐号     * @param accno     * @return     */    private static byte[] getHAccno(String accno) {         int len = accno.length();         byte arrTemp[] = accno.substring(len < 13 ? 0 : len - 13, len - 1).getBytes();         byte arrAccno[] = new byte[12];         for (int i = 0; i < 12; i++) {           arrAccno[i] = (i <= arrTemp.length ? arrTemp[i] : (byte) 0x00);         }         byte encode[] = new byte[8];         encode[0] = (byte) 0x00;         encode[1] = (byte) 0x00;         encode[2] = (byte) uniteBytes(arrAccno[0], arrAccno[1]);         encode[3] = (byte) uniteBytes(arrAccno[2], arrAccno[3]);         encode[4] = (byte) uniteBytes(arrAccno[4], arrAccno[5]);         encode[5] = (byte) uniteBytes(arrAccno[6], arrAccno[7]);         encode[6] = (byte) uniteBytes(arrAccno[8], arrAccno[9]);         encode[7] = (byte) uniteBytes(arrAccno[10], arrAccno[11]);         return encode;     }    /**     * PIN BLOCK (PIN按位异或主帐号PAN)     * @param pin 密码     * @param accno 账号     * /** *     ANSI X9.8 Format(带主帐号信息)*    PIN BLOCK 格式:等于 PIN 按位异或主帐号    PIN 格式:(与1中的格式类似)    Byte 1 PIN的长度    Byte 2 – Byte 3/4/5/6/7 4--12个PIN(每个PIN占4个BIT)    Byte4/5/6/7/8 – Byte 8 FILLER “F” (每个“F“占4个BIT)    PAN(主帐号 Primary Account Number)同样包含8个byte,格式如下:    Byte 1 — Byte 2 0x00 0x00    Byte 3 — Byte 8 12个主帐号字符(最后一位为校验位)    12位字符主帐号的取法:取主帐号的右12位(不包括最右边的校验位),不足12位左补“0X00”。 * @author yangw@eastcom.com * @return * */     public static byte[] process(String pin, String accno) {         byte arrPin[] = getHPin(pin);         byte arrAccno[] = getHAccno(accno);         byte arrRet[] = new byte[8];         //PIN BLOCK 格式等于 PIN 按位异或 主帐号;         for (int i = 0; i < 8; i++) {           arrRet[i] = (byte) (arrPin[i] ^ arrAccno[i]);         }         return arrRet;     }     /**      * 初始化密钥      */     public static byte[]  initSecretKey() throws Exception{         byte[] init= hexStr2Str(HTMK); //将字符串转成16进制的byte[]数组         return decrypt(HPIN,init); //用 HTMK解密HPIN     }     /**      * 对账号和密码进行加密,生成加密后的密码      * @param accNo  账号或者卡号      * @param passwd 密码      * @return      * @throws Exception      */     public static String generatePasswd(String accNo,String passwd) throws Exception{         byte[] secretKeyBytes=initSecretKey(); //得到密钥         byte[] pinblock = process(passwd,accNo);         System.out.println(secretKeyBytes.length);        // 因为3DES是对称加密算法,key是24位,当只有16位时,后8位取key的前8位        byte[] temp = new byte[24];        System.arraycopy(secretKeyBytes, 0, temp, 0, secretKeyBytes.length);        System.arraycopy(secretKeyBytes, 0, temp, secretKeyBytes.length, 8);        return encrypt(pinblock,temp);     }////     public static void printHexString(String hint, byte[] b) {//         System.out.print(hint);//         for (int i = 0; i < b.length; i++) {//           String hex = Integer.toHexString(b[i] & 0xFF);//           if (hex.length() == 1) {//             hex = '0' + hex;//           }//           System.out.print(hex.toUpperCase() + " ");//         }//         System.out.println("");//       }//     public static void main(String[] args) {//            try {//                // 81098C8B11986FD4//                System.out.println(generatePasswd("6228480478316226677","000000"));////            } catch (Exception e) {//                e.printStackTrace();//            }//        }//////}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,088
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,564
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,413
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,186
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,822
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,905