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();
//            }
//        }
//
//
//
}

Java实现3DES加密--及ANSI X9.8 Format标准 PIN PAN获取PIN BlOCK的更多相关文章

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

    ANSI X9.8标准 PIN xor PAN获取PIN BlOCK 之前看到几篇介绍,把ANSI说成16个字节,真心扯淡,各种误人子弟,真正的ANSI算法其实是8个字节,具体格式如下: (1) AN ...

  2. Java中3DES加密解密与其他语言(如C/C++)通信

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  3. 如何用Java进行3DES加密解

    原文地址: http://weavesky.com/2008/01/05/java-3des/ 最近一个合作商提出使用3DES交换数据,本来他们有现成的代码,可惜只有.net版本,我们的服务器都是Li ...

  4. c#加密,java解密(3DES加密)

    c#代码 using System; using System.Security; using System.Security.Cryptography; using System.IO; using ...

  5. 【推荐】JAVA基础◆浅谈3DES加密解密

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  6. 3DES加密

    本文介绍了3DES加密特性,加密特点,3DES是对称加密,用一个密钥对内容进行加密,必须使用相同的密钥进行解密, 密钥必须配置,而且长度为24位,不足24位,用0位进行补全,本文也顺带介绍了其它加密算 ...

  7. C# 3Des加密解密

      第三方的加密规则约定:加密经过3DES加密后的Base64 编码 最近在对接一个第三方接口,请求参数和响应参数全采用3des加密规则,由于我是用.NET对接的,而第三方是Java开发的,所以两种程 ...

  8. JAVA和C# 3DES加密解密

    最近 一个项目.net 要调用JAVA的WEB SERVICE,数据采用3DES加密,涉及到两种语言3DES一致性的问题, 下面分享一下, 这里的KEY采用Base64编码,便用分发,因为Java的B ...

  9. C# Java 3DES加密解密 扩展及修正\0 问题

    注: C#已亲测及做扩展, Java 部分未做验证 /// <summary> /// 3DES加密解密 /// ------------------------------------- ...

随机推荐

  1. jaspersoft studio 的初级入门(一)

    前言 最近的工作涉及到企业的报表生成功能,于是就想用此篇博客来记录我的学习历程.进入Jasperreport项目的官网发现有一个软件叫Jaspersoft studio的,它的版本也是6.3.1跟Ja ...

  2. 理解angularJs中的$on,$broadcast,$emit

    $emit作用是将一个事件从子作用域广播至父作用域,直至根作用域.(包括自己) $emit有两个参数name和args,name就是需要广播的名字,args是一个或者多个参数. $broadcast的 ...

  3. eclipse中使用Maven管理java工程设置jdk版本为jdk1.8

    使用Maven管理Java工程时,maven可以自动下载工程中依赖的jar包,这对于大型的项目非常方便.但在初次使用eclipse新建maven工程时遇到一些问题,我的jdk安装的是1.8版本,在配置 ...

  4. Shrio认证详解+自定义Realm

    Authentication(身份认证)是Shiro权限控制的第一步,用来告诉系统你就是你. 在提交认证的时候,我们需要给系统提交两个信息: Principals:是一个表示用户的唯一属性,可以是用户 ...

  5. 【Regular Expression】RE分类及案例

    背景知识 正则表达式分为三类:基础正则表达式.扩展正则表达式.Perl正则表达式(Perl内建) 通俗来说,这三个一个比一个强大,支持的规则匹配字符更多 1.匹配IP ip addr | grep - ...

  6. 给MySQL_5.7 配置环境变量

    给MySQL_5.7   配置环境变量... 1.右键我的电脑--选择属性 2.选择高级系统设置 3.根据MySQL的安装路径.来配置MYSQL_HOME环境变量 找到MySQL5.7的安装根目录 4 ...

  7. 手机自带输入法emoji表情的输入,提交及显示——纯前端解决方案

    很早之前就遇到过需要前端支持用户输入并提交emoji表情的问题,一直没有尝试去解决,今天再一次狭路相逢,该来的躲不过,那就着手解决吧. 大多数emoji表情都是4字节的utf-16编码(辅助平面字符, ...

  8. spring MVC处理请求过程及配置详解

    本文主要梳理下Spring MVC处理http请求的过程,以及配置servlet及业务application需要的常用标签,及其包含的意义. spring MVC处理请求过程 首先看一个整体图 简单说 ...

  9. 又想起Solaris

    想起曾几何时,学习的第一个UNIX-like操作系统.只可惜,从来都是在此操作系统上用C语言编程,而没有用过Sun公司的java. 又几何时,Sun公司慢慢不行了.再后来过了几年,Sun公司把Ultr ...

  10. [js高手之路]深入浅出webpack教程系列5-插件使用之html-webpack-plugin配置(中)

    上文我们讲到了options的配置和获取数据的方式,本文,我们继续深入options的配置 一.html-webpack-plugin插件中的options除了自己定义了一些基本配置外,我们是可以任意 ...