密码转PIN及MAC算法

1 篇文章 0 订阅
1 篇文章 0 订阅

 

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.security.InvalidKeyException;

import java.security.NoSuchAlgorithmException;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.SecureRandom;

 

import javax.crypto.BadPaddingException;

import javax.crypto.Cipher;

import javax.crypto.IllegalBlockSizeException;

import javax.crypto.Mac;

import javax.crypto.NoSuchPaddingException;

import javax.crypto.SecretKey;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

 

import org.apache.log4j.Logger;

 

import cia.broker.common.function.BrokerCommFunc;

 

/**

 * Description: 密码转PIN

 * 

 * (C) Copyright of China UnionPay Co., Ltd. 2010.

 * @author leoyan

 */

public class SoftSecProc {

/**

* 日志

*/

private static final Logger logger = Logger.getLogger(SoftSecProc.class);

 

/**

* 卡号密码转PIN -- 密码解密

* @param encStr

* @param key

* @return

* @throws CIAException

*/

public String decryptedPin(String encStr, PrivateKey key) throws Exception {

String clrPin = null;

Base64Coder base64 = new Base64Coder();

 

try {

byte[] cryptPin = base64.decode(encStr.getBytes());

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",

new org.bouncycastle.jce.provider.BouncyCastleProvider());

cipher.init(Cipher.DECRYPT_MODE, key);

int blockSize = cipher.getBlockSize();

ByteArrayOutputStream bout = new ByteArrayOutputStream(64);

int j = 0;

while (cryptPin.length - j * blockSize > 0) {

bout.write(cipher.doFinal(cryptPin, j * blockSize, blockSize));

j++;

}

// 加密后的密码

byte[] data = bout.toByteArray();

// 转换成16进制

clrPin = BrokerCommFunc.Hex2Str(data);

} catch (Exception ex) {

logger.error(ex);

throw new Exception(ex);

}

return clrPin;

}

 

/**

* 卡号密码转PIN -- 加密

* @param plainDataByte

* @return

* @throws CIAException

*/

public String encryptedDataByGwCert(byte[] plainDataByte, PublicKey publicKey) throws Exception {

String encData = null;

Base64Coder base64 = new Base64Coder();

// 参数检查

if (plainDataByte == null) {

return null;

}

try {

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",

new org.bouncycastle.jce.provider.BouncyCastleProvider());

cipher.init(Cipher.ENCRYPT_MODE, publicKey);

int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024

// 加密块大小为127

// byte,加密后为128个byte;因此共有2个加密块,第一个127

// byte第二个为1个byte

int outputSize = cipher.getOutputSize(plainDataByte.length);// 获得加密块加密后块大小

int leavedSize = plainDataByte.length % blockSize;

int blocksSize = leavedSize != 0

? plainDataByte.length / blockSize + 1

: plainDataByte.length / blockSize;

// 加密后的数据定义

byte[] data = new byte[outputSize * blocksSize];

int i = 0;

while (plainDataByte.length - i * blockSize > 0) {

if (plainDataByte.length - i * blockSize > blockSize)

cipher.doFinal(plainDataByte, i * blockSize, blockSize, data, i * outputSize);

else

cipher.doFinal(plainDataByte, i * blockSize, plainDataByte.length - i

* blockSize, data, i * outputSize);

i++;

}

// 对加密后的数据进行编码

byte[] raw = base64.encode(data);

encData = new String(raw);

 

} catch (Exception ex) {

logger.error(ex);

throw new Exception(ex);

}

return encData;

}

 

/**

* 卡号密码转PIN -- 根据卡号加密

* @param clrPin

* @param sPan

* @return

* @throws CIAException

*/

public String encryptedPin(String clrPin, String pan, PublicKey publicKey) throws Exception {

String encPin = null;

Base64Coder base64 = new Base64Coder();

// 参数判断

if (clrPin == null || clrPin.trim().equals("") || pan == null || pan.trim().equals("")) {

return null;

}

try {

/* 生成PIN Block */

byte[] pinBlock = pin2PinBlockWithCardNO(clrPin, pan);

// 加密开始

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",

new org.bouncycastle.jce.provider.BouncyCastleProvider());

cipher.init(Cipher.ENCRYPT_MODE, publicKey);

int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024

// 加密块大小为127

// byte,加密后为128个byte;因此共有2个加密块,第一个127

// byte第二个为1个byte

int outputSize = cipher.getOutputSize(pinBlock.length);// 获得加密块加密后块大小

int leavedSize = pinBlock.length % blockSize;

int blocksSize = leavedSize != 0 ? pinBlock.length / blockSize + 1 : pinBlock.length

/ blockSize;

// 加密后的数据

byte[] data = new byte[outputSize * blocksSize];

int i = 0;

while (pinBlock.length - i * blockSize > 0) {

if (pinBlock.length - i * blockSize > blockSize) {

cipher.doFinal(pinBlock, i * blockSize, blockSize, data, i * outputSize);

} else {

cipher.doFinal(pinBlock, i * blockSize, pinBlock.length - i * blockSize, data,

i * outputSize);

}

// 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了OutputSize所以只好用dofinal方法。

 

i++;

}

// 对密码进行编码

byte[] raw = base64.encode(data);

encPin = new String(raw);

 

} catch (Exception ex) {

logger.error(ex);

throw new Exception(ex);

}

return encPin;

}

 

/**

* 产生MAC

* @param inputByte

* @param inputkey

* @param algorithm

*            "DES" "AES"

* @return

* @throws CIAException

*/

public byte[] genmac(byte[] inputByte, byte[] inputkey, String algorithm) throws Exception {

try {

Mac mac = Mac.getInstance("HmacMD5");

SecretKey key = new SecretKeySpec(inputkey, algorithm);

mac.init(key);

 

byte[] macCode = mac.doFinal(inputByte);

return macCode;

} catch (Exception ex) {

logger.error(ex);

throw new Exception(ex);

}

}

 

/**

* 二进制转换成十六进制

* @param b

* @return

*/

public String byte2hex(byte[] b) {

String hs = "";

String stmp;

for (byte aB : b) {

stmp = (Integer.toHexString(aB & 0XFF));

if (stmp.length() == 1) {

hs = hs + "0" + stmp;

} else {

hs = hs + stmp;

}

}

 

return hs.toLowerCase();

}

public byte[] hex2byte(byte[] b) {

if ((b.length % 2) != 0) {

throw new IllegalArgumentException("长度不是偶数");

}

byte[] b2 = new byte[b.length / 2];

for (int n = 0; n < b.length; n += 2) {

String item = new String(b, n, 2);

b2[n / 2] = (byte) Integer.parseInt(item, 16);

}

return b2;

}

 

/**

* 使用DES算法产生MAC

* @param inputByte

* @param inputkey

* @return

* @throws IOException

*/

public String genMac(byte[] macData, byte[] macKey) {

try {

// get a instance of Mac, using HmacMD5 algorithm

Mac mac = Mac.getInstance("DES",

new org.bouncycastle.jce.provider.BouncyCastleProvider());

// init the IV of the algorithm, 8 bytes. may read from file

byte[] ivInitKey = {0X00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

IvParameterSpec spec = new IvParameterSpec(ivInitKey);

// the secrete key bytes of the Mac validation, May read from file too

byte[] keyBytes = new byte[8];

// "82A6672F3B05AC25" MAC = 39:92:72:EB

// MAC KEY

BrokerCommFunc.Str2Hex(macKey, keyBytes, 16);

// generate the secrete Key Object using secrete bytes and DESede algorithm

SecretKey key = new SecretKeySpec(keyBytes, "DES");

// init Mac

mac.init(key, spec);

 

byte[] macCode = mac.doFinal(macData);

System.out.println("MAC = [" + byte2hex(macCode) + "]");

return byte2hex(macCode);

} catch (Exception ex) {

ex.printStackTrace();

return null;

}

}

 

public static void main(String[] args) throws Exception {

String inputStr = "0220 196222600113522102649 000000 000000000011 1201123145 004023 5311 00 0800207900 0800040000 00000000 020790048140001";

byte[] bMacTmp = inputStr.getBytes();

/* 去掉mac域 */

byte[] bReqMac = new byte[bMacTmp.length - 8];

for (int i = 0; i < bMacTmp.length - 8; i++) {

bReqMac[i] = bMacTmp[i];

}

 

SoftSecProc macProc = new SoftSecProc();

byte[] MAC = new byte[8];

String mac = macProc.DecMACKey(inputStr.getBytes(), "4944AB7E278E7F89".getBytes());

System.out.println("mac=[" + mac + "]");

mac = macProc.DecMACKey(bReqMac, "4944AB7E278E7F89".getBytes());

System.out.println("mac=[" + mac + "]");

BrokerCommFunc.Str2Hex(mac.getBytes(), MAC, mac.getBytes().length);

System.out.println(new String(MAC));

 

byte[] MACKey = new byte[16];

BrokerCommFunc.Hex2Str(MAC, MACKey, 8);

System.out.println("MAC=" + new String(MACKey));

 

String aaaa = macProc.genMac(inputStr.getBytes(), "4944AB7E278E7F89".getBytes());

MACKey = new byte[16];

BrokerCommFunc.Hex2Str(aaaa.getBytes(), MACKey, 8);

System.out.println("MAC=" + new String(MACKey));

 

System.out.println("DESede解密");

String rlt = macProc.decDESede("33333333333333333333333333333333",

macProc.hex2byte("0A06BB727EE3B97E".getBytes()));

System.out.println("正确结果:[D338F73E98250775];计算结果:[" + rlt + "]");

System.out.println("DESede加密");

rlt = macProc.encDESede("33333333333333333333333333333333",

macProc.hex2byte(rlt.getBytes()));

System.out.println("正确结果:[0A06BB727EE3B97E];计算结果:[" + rlt + "]");

}

 

/**

* 计算MAC,使用DES加密算法

* @param inputByte

* @param inputkey

* @return

*/

public String DecMACKey(byte[] inputByte, byte[] inputkey) {

 

try {

// Base64Coder base64 = new Base64Coder();

byte[] BMK = new byte[8];

BrokerCommFunc.Str2Hex(inputkey, BMK, 16);

SecretKey key = new SecretKeySpec(BMK, "DES");

Cipher cipher = Cipher.getInstance("DES");

cipher.init(Cipher.ENCRYPT_MODE, key);

byte[] cc = cipher.doFinal(inputByte);

byte[] MACKey = new byte[16];

BrokerCommFunc.Hex2Str(cc, MACKey, 8);

String DecMAK = new String(MACKey);

return DecMAK;

} catch (Exception ex) {

ex.printStackTrace();

return null;

}

 

}

/**

* 校验MAC

* @param inputByte

* @param inputkey

* @param inputmac

* @param algorithm

*            "DES" "AES"

* @return

* @throws Exception

*/

public boolean checkmac(byte[] inputByte, byte[] inputkey, String inputmac, String algorithm)

throws Exception {

try {

java.security.Security

.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

Mac mac = Mac.getInstance(algorithm);

byte[] keyBytes = new byte[8];

// MAC KEY

BrokerCommFunc.Str2Hex(inputkey, keyBytes, inputkey.length);

SecretKey key = new SecretKeySpec(keyBytes, algorithm);

mac.init(key);

 

byte[] macCode = mac.doFinal(inputByte);

String strMacCode = byte2hex(macCode);

System.out.println("MAC = [" + strMacCode + "]; inputmac=[" + inputmac + "]");

 

if (strMacCode.equals(inputmac)) {

return true;

} else {

return false;

}

} catch (Exception ex) {

logger.error(ex);

return false;

}

}

 

/**

* 消费密码转PIN Block(加入卡号)

* @param aPin

*            消费密码

* @param aCardNO

*            卡号

* @return PIN Block

*/

public byte[] pin2PinBlockWithCardNO(String aPin, String aCardNO) {

byte[] tPinByte = pin2PinBlock(aPin);

if (aCardNO.length() == 11) {

aCardNO = "00" + aCardNO;

} else if (aCardNO.length() == 12) {

aCardNO = "0" + aCardNO;

}

byte[] tPanByte = formatPan(aCardNO);

byte[] tByte = new byte[8];

for (int i = 0; i < 8; i++) {

tByte[i] = (byte) (tPinByte[i] ^ tPanByte[i]);

}

return tByte;

}

 

/**

* 消费密码转PIN Block

* @param aPin

*            消费密码

* @param aCardNO

*            卡号

* @return PIN Block

*/

private byte[] pin2PinBlock(String aPin) {

int tTemp = 1;

int tPinLen = aPin.length();

 

byte[] tByte = new byte[8];

try {

/*******************************************************************

* if (tPinLen > 9) { tByte[0] = (byte) Integer.parseInt(new Integer(tPinLen)

* .toString(), 16); } else { tByte[0] = (byte) Integer.parseInt(new Integer(tPinLen)

* .toString(), 10); }

******************************************************************/

tByte[0] = (byte) Integer.parseInt(new Integer(tPinLen).toString(), 10);

if (tPinLen % 2 == 0) {

for (int i = 0; i < tPinLen;) {

String a = aPin.substring(i, i + 2);

tByte[tTemp] = (byte) Integer.parseInt(a, 16);

if (i == (tPinLen - 2)) {

if (tTemp < 7) {

for (int x = (tTemp + 1); x < 8; x++) {

tByte[x] = (byte) 0xff;

}

}

}

tTemp++;

i = i + 2;

}

} else {

for (int i = 0; i < tPinLen - 1;) {

String a;

a = aPin.substring(i, i + 2);

tByte[tTemp] = (byte) Integer.parseInt(a, 16);

if (i == (tPinLen - 3)) {

String b = aPin.substring(tPinLen - 1) + "F";

tByte[tTemp + 1] = (byte) Integer.parseInt(b, 16);

if ((tTemp + 1) < 7) {

for (int x = (tTemp + 2); x < 8; x++) {

tByte[x] = (byte) 0xff;

}

}

}

tTemp++;

i = i + 2;

}

}

} catch (Exception e) {

}

 

return tByte;

}

 

/**

* 对卡号进行格式化

* @param aPan

*            卡号

* @return 格式化后的卡号

*/

private byte[] formatPan(String aPan) {

int tPanLen = aPan.length();

byte[] tByte = new byte[8];;

int temp = tPanLen - 13;

try {

tByte[0] = (byte) 0x00;

tByte[1] = (byte) 0x00;

for (int i = 2; i < 8; i++) {

String a = aPan.substring(temp, temp + 2);

tByte[i] = (byte) Integer.parseInt(a, 16);

temp = temp + 2;

}

} catch (Exception e) {

}

return tByte;

}

 

/**

* 对传入的Byte数组进行PKCS#1填充

* @param aBytesText

*            欲进行PKCS#1填充的Byte数组

* @param aBlockSize

*            区块大小

* @return 经过PKCS#1填充后的Byte数组,大小等于传入的区块大小。<br>

*         若传入的Byte数组长度超过(填充区块大小-3)时无法进行填充作业,将回传null。

*/

private static byte[] addPKCS1Padding(byte[] aBytesText, int aBlockSize) {

if (aBytesText.length > (aBlockSize - 3)) {

// 传入的Byte数组长度超过(填充区块大小-3)

return null;

}

SecureRandom tRandom = new SecureRandom();

byte[] tAfterPaddingBytes = new byte[aBlockSize];

tRandom.nextBytes(tAfterPaddingBytes);

tAfterPaddingBytes[0] = 0x00;

tAfterPaddingBytes[1] = 0x02;

int i = 2;

for (; i < aBlockSize - 1 - aBytesText.length; i++) {

if (tAfterPaddingBytes[i] == 0x00) {

tAfterPaddingBytes[i] = (byte) tRandom.nextInt();

}

}

tAfterPaddingBytes[i] = 0x00;

System.arraycopy(aBytesText, 0, tAfterPaddingBytes, (i + 1), aBytesText.length);

 

return tAfterPaddingBytes;

}

 

/**

* DESede解密(DESede/ECB/NoPadding)

* @param desKey

*            十六进制编码的KEY

* @param data

*            被加密的数据

* @return 返回十六进制的解密结果

*/

public String decDESede(String desKey, byte[] data) {

Cipher c1 = null;

try {

c1 = Cipher.getInstance("DESede/ECB/NoPadding",

new org.bouncycastle.jce.provider.BouncyCastleProvider());

} catch (NoSuchAlgorithmException e) {

logger.error("DESede/ECB/NoPadding NoSuchAlgorithmException", e);

return "";

} catch (NoSuchPaddingException e) {

logger.error("DESede/ECB/NoPadding NoSuchPaddingException", e);

return "";

}

SecretKeySpec sk = new SecretKeySpec(hex2byte(desKey.getBytes()), "DESede");

try {

c1.init(Cipher.DECRYPT_MODE, sk);

} catch (InvalidKeyException e) {

logger.error("DESede/ECB/NoPadding InvalidKeyException", e);

return "";

}

byte encode[] = null;

try {

encode = c1.doFinal(data);

} catch (IllegalBlockSizeException e) {

logger.error("IllegalBlockSizeException", e);

return "";

} catch (BadPaddingException e) {

logger.error("BadPaddingException", e);

return "";

}

String rlt = byte2hex(encode).toUpperCase();

logger.info("desKey=[" + desKey + "];input data=[" + byte2hex(data) + "]; 解密=[" + rlt + "]");

return rlt;

}

 

/**

* DESede加密(DESede/ECB/NoPadding)

* @param desKey

*            十六进制编码的KEY

* @param data

*            被加密的数据

* @return 返回十六进制的解密结果

*/

public String encDESede(String desKey, byte[] data) {

Cipher c1 = null;

try {

c1 = Cipher.getInstance("DESede/ECB/NoPadding",

new org.bouncycastle.jce.provider.BouncyCastleProvider());

} catch (NoSuchAlgorithmException e) {

logger.error("DESede/ECB/NoPadding NoSuchAlgorithmException", e);

return "";

} catch (NoSuchPaddingException e) {

logger.error("DESede/ECB/NoPadding NoSuchPaddingException", e);

return "";

}

SecretKeySpec sk = new SecretKeySpec(hex2byte(desKey.getBytes()), "DESede");

try {

c1.init(Cipher.ENCRYPT_MODE, sk);

} catch (InvalidKeyException e) {

logger.error("DESede/ECB/NoPadding InvalidKeyException", e);

return "";

}

byte encode[] = null;

try {

encode = c1.doFinal(data);

} catch (IllegalBlockSizeException e) {

logger.error("IllegalBlockSizeException", e);

return "";

} catch (BadPaddingException e) {

logger.error("BadPaddingException", e);

return "";

}

String rlt = byte2hex(encode).toUpperCase();

logger.info("desKey=[" + desKey + "];input data=[" + byte2hex(data) + "]; 解密=[" + rlt + "]");

return rlt;

}

 

// public String encryptedDataByGwCert(byte[] plainDataByte, PublicKey publicKey)

 

}




补充调用的公共方法: 
public static boolean Str2Hex(byte in[], byte out[], int len) {
byte asciiCode[] = {10, 11, 12, 13, 14, 15};
if (len > in.length)
return false;
if (len % 2 != 0)
return false;
byte temp[] = new byte[len];
for (int i = 0; i < len; i++)
if (in[i] >= 48 && in[i] <= 57)
temp[i] = (byte) (in[i] - 48);
else if (in[i] >= 65 && in[i] <= 70)
temp[i] = asciiCode[in[i] - 65];
else if (in[i] >= 97 && in[i] <= 102)
temp[i] = asciiCode[in[i] - 97];
else
return false;

for (int i = 0; i < len / 2; i++)
out[i] = (byte) (temp[2 * i] * 16 + temp[2 * i + 1]);

return true;
}

public static boolean Hex2Str(byte in[], byte out[], int len) {
byte asciiCode[] = {65, 66, 67, 68, 69, 70};
if (len > in.length)
return false;
byte temp[] = new byte[2 * len];
for (int i = 0; i < len; i++) {
temp[2 * i] = (byte) ((in[i] & 0xf0) / 16);
temp[2 * i + 1] = (byte) (in[i] & 0xf);
}

for (int i = 0; i < 2 * len; i++)
if (temp[i] <= 9 && temp[i] >= 0)
out[i] = (byte) (temp[i] + 48);
else
out[i] = asciiCode[temp[i] - 10];

return true;
}


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值