import java.security.SecureRandom;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
public class YFSDEncode {
public static void main(String[] args) {
//System.out.println(isHex16("********************************"));
String pan="6058280000000001";
String pin="12345678";
String key="*********************************";
// String panEncode="0000"+pan.substring(pan.length()-13, pan.length()-1);
// String pin1="0"+pin.length()+pin;
// String pinEncode=String.format("%-16s", pin1).replaceAll(" ", "F");//用F补足16位
// String panAndPinYihuo=hxor(panEncode,pinEncode);
// //System.out.println(panAndPinYihuo);
// byte[] en3DES = encECB3Des(hex2byte(key), hexStr2Str(panAndPinYihuo));
// System.out.println(byte2HexStr(en3DES,16).substring(0, 16));
System.out.println(encode(pan,pin,key));
}
private final static char[] mChars = "0123456789ABCDEF".toCharArray();
/**
* 加密入口
* @param pan 卡号:必须是16到19位的数字
* @param pin 卡密码:必须是6到8位的数字
* @param key 3des加密密钥:必须是32位的0-9 a-f A-F 字符串
* @return 密钥
*/
public static String encode(String pan,String pin,String key){
String outPutStr="";
if(!checkInputParams(pan,pin,key)){
return "输入参数有误:卡号必须是16到19位的数字,卡密码必须是6到8位的数字,加密密钥必须是32位的0-9 a-f A-F 字符串";
}
String panEncode="0000"+pan.substring(pan.length()-13, pan.length()-1);
String pin1="0"+pin.length()+pin;
String pinEncode=String.format("%-16s", pin1).replaceAll(" ", "F");//用F补足16位
String panAndPinYihuo=hxor(panEncode,pinEncode);
byte[] en3DES = encECB3Des(hex2byte(key), hexStr2Str(panAndPinYihuo));
outPutStr=byte2HexStr(en3DES,16).substring(0, 16);
return outPutStr;
}
/**
*
* @param strHex_X
* 0-9 a-f的字符
* @param strHex_Y
* 0-9 a-f的字符
* @return 字符异或
*/
private static String xor(String strHex_X, String strHex_Y) {
// 将x、y转成二进制形式
String anotherBinary = Integer.toBinaryString(Integer.valueOf(strHex_X,
16));
String thisBinary = Integer.toBinaryString(Integer
.valueOf(strHex_Y, 16));
String result = "";
// 判断是否为8位二进制,否则左补零
if (anotherBinary.length() != 8) {
for (int i = anotherBinary.length(); i < 8; i++) {
anotherBinary = "0" + anotherBinary;
}
}
if (thisBinary.length() != 8) {
for (int i = thisBinary.length(); i < 8; i++) {
thisBinary = "0" + thisBinary;
}
}
// 异或运算
for (int i = 0; i < anotherBinary.length(); i++) {
// 如果相同位置数相同,则补0,否则补1
if (thisBinary.charAt(i) == anotherBinary.charAt(i))
result += "0";
else {
result += "1";
}
}
return Integer.toHexString(Integer.parseInt(result, 2)).toUpperCase();
}
/**
*
* @param strHex_X
* 0-9 a-f字符串
* @param strHex_Y
* 0-9 a-f字符串
* @return 字符串异或
*/
private static String hxor(String strHex_X, String strHex_Y) {
String rt = "";
if (strHex_X.length() == 16 && strHex_X.length() == strHex_Y.length()) {
for (int i = 0; i < strHex_X.length(); i++) {
rt = rt
+ xor(strHex_X.substring(i, i + 1),
strHex_Y.substring(i, i + 1));
}
}
return rt;
}
/**
* 输入参数校验
* @param pan 卡号:必须是16到19位的数字
* @param pin 卡密码:必须是6到8位的数字
* @param key 3des加密密钥:必须是32位的0-9 a-f A-F 字符串
* @return
*/
private static boolean checkInputParams(String pan, String pin, String des3Key) {
if (!StringUtils.isNoneBlank(pan, pin, des3Key)) {
return false;
}
if (pan.length() < 16 || pan.length() > 19 || pin.length() < 6
|| pin.length() > 8 || des3Key.length() != 32) {
return false;
}
if (isNumeric(pan) && isNumeric(pin)&&isHex16(des3Key)) {
return true;
}else{
return false;
}
}
/**
* 数字校验
* @param str
* @return
*/
public static boolean isNumeric(String str) {
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNum = pattern.matcher(str);
if (!isNum.matches()) {
return false;
}
return true;
}
/**
* A-F a-f 0-9 字符串校验
* @param str
* @return
*/
public static boolean isHex16(String str) {
Pattern pattern = Pattern.compile("[A-F a-f 0-9]*");
Matcher isNum = pattern.matcher(str);
if (!isNum.matches()) {
return false;
}
return true;
}
/**
* 将16进制字符串转换为byte[]
*
* @param str
* @return
*/
public static byte[] hex2byte(String str) {
if(str == null || str.trim().equals("")) {
return new byte[0];
}
byte[] bytes = new byte[str.length() / 2];
for(int i = 0; i < str.length() / 2; i++) {
String subStr = str.substring(i * 2, i * 2 + 2);
bytes[i] = (byte) Integer.parseInt(subStr, 16);
}
return bytes;
}
/**
*
* 十六进制字符串转换成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转换成十六进制字符串
*
* @param b
* byte[] byte数组
* @param iLen
* int 取前N位处理 N=iLen
* @return String 每个Byte值之间空格分隔
*/
public static String byte2HexStr(byte[] b, int iLen) {
StringBuilder sb = new StringBuilder();
for (int n = 0; n < iLen; n++) {
sb.append(mChars[(b[n] & 0xFF) >> 4]);
sb.append(mChars[b[n] & 0x0F]);
}
return sb.toString().trim().toUpperCase(Locale.US);
}
/**
* 3DES双倍长加密
*
* @author Joey
* @param key
* @param src
* @return
*/
public static byte[] encECB3Des(byte[] key, byte[] src) {
byte[] temp = null;
byte[] temp1 = null;
temp1 = encryptDes(subByte(key, 0, 8), src);
temp = decryptDes(subByte(key, 8, 8), temp1);
temp1 = encryptDes(subByte(key, 0, 8), temp);
return temp1;
}
private static byte[] subByte(byte[] keyData, int begin, int length) {
byte[] key = new byte[length];
for (int i = begin; i < begin + length; i++)
key[i - begin] = keyData[i];
return key;
}
/**
* DES加密
*
*/
public static byte[] encryptDes(byte[] key, byte[] src) {
try {
// 创建一个DESKeySpec对象
DESKeySpec desKey = new DESKeySpec(key);
// 创建一个密匙工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// 将DESKeySpec对象转换成SecretKey对象
SecretKey secretKey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
// 用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// 现在,获取数据并加密
// 正式执行加密操作
return cipher.doFinal(src);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* DES解密
*
* @param key
* @param src
* @return
*/
public static byte[] decryptDes(byte[] key, byte[] src) {
try {
// DES算法要求有一个可信任的随机数源
SecureRandom random = new SecureRandom();
// 创建一个DESKeySpec对象
DESKeySpec desKey = new DESKeySpec(key);
// 创建一个密匙工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// 将DESKeySpec对象转换成SecretKey对象
SecretKey secretKey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
// 用密匙初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, secretKey, random);
// 现在,获取数据并加密
// 正式执行加密操作
return cipher.doFinal(src);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
*************************************卡密码加密方式**************************************
示例 1
例如:卡密码为: 123456 6到8位
假设: 卡号为: 6058280000000001 去掉最后一位,往前取12位 最少16号
截取下的PAN: 828000000000
则用于PIN 加密的卡密码 为: 0000828000000000
PIN BLOCK 为:06123456FFFFFFFF
异或结果为: 0612B6D6FFFFFFFF
工作密钥为: 11111111111111111111111111111111 固定32位
用工作密钥对异或结果做3DES加密:0612B6D6FFFFFFFF
加密结果为: 2874F1E4D15750B7
*************************************调用方法**************************************
/**
* @param args
* @throws ParseException
*/
public static void main(String[] args) throws ParseException {
String key="********************************";
String pan="6058280000000001";
String pin="123456";
System.out.println(YFSDEncode.encode(pan,pin,key));
}