Java实现3DES加密--及ANSI X9.8 Format标准 PIN PAN获取PIN BlOCK
1, 采用银联ANSI X9.8标准 PIN xor PAN获取PIN BlOCK
2, 采用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的更多相关文章
- ANSI X9.8标准 PIN xor PAN获取PIN BlOCK
ANSI X9.8标准 PIN xor PAN获取PIN BlOCK 之前看到几篇介绍,把ANSI说成16个字节,真心扯淡,各种误人子弟,真正的ANSI算法其实是8个字节,具体格式如下: (1) AN ...
- Java中3DES加密解密与其他语言(如C/C++)通信
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- 如何用Java进行3DES加密解
原文地址: http://weavesky.com/2008/01/05/java-3des/ 最近一个合作商提出使用3DES交换数据,本来他们有现成的代码,可惜只有.net版本,我们的服务器都是Li ...
- c#加密,java解密(3DES加密)
c#代码 using System; using System.Security; using System.Security.Cryptography; using System.IO; using ...
- 【推荐】JAVA基础◆浅谈3DES加密解密
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- 3DES加密
本文介绍了3DES加密特性,加密特点,3DES是对称加密,用一个密钥对内容进行加密,必须使用相同的密钥进行解密, 密钥必须配置,而且长度为24位,不足24位,用0位进行补全,本文也顺带介绍了其它加密算 ...
- C# 3Des加密解密
第三方的加密规则约定:加密经过3DES加密后的Base64 编码 最近在对接一个第三方接口,请求参数和响应参数全采用3des加密规则,由于我是用.NET对接的,而第三方是Java开发的,所以两种程 ...
- JAVA和C# 3DES加密解密
最近 一个项目.net 要调用JAVA的WEB SERVICE,数据采用3DES加密,涉及到两种语言3DES一致性的问题, 下面分享一下, 这里的KEY采用Base64编码,便用分发,因为Java的B ...
- C# Java 3DES加密解密 扩展及修正\0 问题
注: C#已亲测及做扩展, Java 部分未做验证 /// <summary> /// 3DES加密解密 /// ------------------------------------- ...
随机推荐
- 第3天:CSS浮动、定位、表格、表单总结
今天学的是浮动.定位.表格.表单等内容,这些是CSS中最容易混淆的知识,有许多小技巧在写代码过程中需要注意.下面是主要知识点: 一.float浮动1.块元素在一行显示2.内联元素支持宽高3.默认内容撑 ...
- Linux桌面环境GNOME实用技巧
GNOME是Linux桌面上主流的集成桌面环境之一,GNOME桌面以其风格简洁.操作便捷而受到Linux用户的欢迎.这里将介绍Linux桌面环境GNOME的操作技巧,在这里拿出来和大家分享一下. 下面 ...
- Android SharedPreferences基本用法
使用SharedPreferences SharedPreferences是Android平台上一个轻量级的存储类, 用来保存应用的一些常用配置. SharedPreferences与Editor简介 ...
- Catalan数——卡特兰数
一.Catalan数的定义 令h(0)=1,h(1)=1,Catalan数满足递归式:h(n) = h(0)*h(n-1) + h(1)*h(n-2) + ... + h(n-1)*h(0) (n& ...
- [读书笔记] 二、条件注解@Conditional,组合注解,元注解
一.条件注解@Conditional,组合注解,元注解 1. @Conditional:满足特定条件创建一个Bean,SpringBoot就是利用这个特性进行自动配置的. 例子: 首先,两个Condi ...
- Mvc分页组件MvcSimplePager代码重构及使用
1 Mvc分页组件MvcSimplePager代码重构 1.1 Intro 1.2 MvcSimplePager 代码优化 1.3 MvcSimplePager 使用 1.4 End Mvc分页组件M ...
- Java基础---String类和基本数据类型包装类
第一讲 String类 一.概述 String是字符串的类类型,用于描述字符串事物.字符串是一个特殊的对象.特殊之处就在于: Stings= new String();和Str ...
- 在Ubuntu16.04上部署LXC容器管理系统的相关步骤
打算安装一个LXC linux容器管理的软件来分配使用资源并配置不同的编程环境,这样就方便大家的使用,步骤如下(宿主机的环境都搭建好了,对应显卡的驱动等): 参考网站: 简单入门和相关指令总结:htt ...
- UICollectionView中Cell左对齐 居中 右对齐 等间距------你想要的,这里都有
支持靠左,居中,靠右,等间距对齐. 靠左等间距.png 居中等间距.png 靠右等间距.png #import <UIKit/UIKit.h> typedef NS_ENUM(NSInte ...
- 最简单实用的JQuery实现banner图中的text打字动画效果!!!
下面,就让小博详细介绍如何实现上面GIF实现的banner图中的文字动画效果,最简单实用的方法(鉴于代码量较小,就内嵌在一个HTML文件中了): 首先,我们要在header导入一个jQuery,并新建 ...