银联POS工作密钥生成

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

根据银联POS终端应用规范,我们了解到POS交易中保函两类密钥:
密钥加密密钥 key encryption key; KEK和工作密钥 working key; WK
而工作密钥有包括:PIN加密密钥、 MAC计算的密钥和磁道数据加密密钥

关于以上密钥的定义,银联规范中是这样解释的:

密钥加密密钥 key encryption key; KEK
POS终端工作时对工作密钥进行加密的密钥,由专门人员设置并直接保存在系统硬件中,只能使用,
不能读取,该密钥必须与加密算法放在同一加密芯片里,又称终端主密钥。

工作密钥 working key; WK
也称为数据密钥,通常指PIN加密密钥、 MAC计算的密钥和磁道数据加密密钥。 工作密钥必须经常
更新。在联机更新的报文中对工作密钥必须用密钥加密密钥( KEK)加密,形成密文后进行传输。

密钥加密密钥,我们也称之为主密钥,为32位的16进制字符串

在规范里,讲到第62域,用法一:终端密钥,域描述中写到:

*POS中心向POS终端约定的新工作密钥,若长度域不为024或040或056或060或84,将认为该域格式有误。
在POS终端签到的应答消息中,本域的长度应为24或40或56或60或84个字节,存放由POS中心产生的POS终端新工作密钥。
对于单倍长密钥算法,前12个字节为PIN的工作密钥的密文, 后12个字节为MAC的工作密钥的密文。(其中,前8个字节是密文,后4个字节是checkvalue;前8个字节解出明文后,对8个数值0做单倍长密钥算法,取结果的前四位与checkvalue 的值比较应该是一致的)。
对于双倍长密钥算法,前20个字节为PIN的工作密钥的密文,后20个字节为MAC的工作密钥的密文。(其中,“ PIN工作密钥”前16个字节是密文,后4个字节是checkvalue;前16个字节解出明文后,对8个数值0做双倍长密钥算法,取结果的前四位与checkvalue 的值比较应该是一致的;“ MAC工作密钥”前8个字节是密文,再8个字节是二进制零,后4个字节是checkvalue;前8个字节解出明文后,对8个数值0做单倍长密钥算法,取结果的前四位与checkvalue 的值比较应该是一致的)。
对于支持磁道加密的签到报文本域长度为60字节,采用双倍长密钥算法,前20个字节为PIN的工作密钥的密文,中间20个字节为MAC的工作密钥,后面20个字节为TDK的工作密钥的密文。(其中,“ PIN工作密钥”前16个字节是密文,后4个字节是checkvalue;前16个字节解出明文后,对8个数值0做双倍长密钥算法, 取结果的前四位与checkvalue 的值比较应该是一致的;“ MAC工作密钥”前8个字节是密文,再8个字节是二进制零,后4个字节是checkvalue;前8个字节解出明文后,对8个数值0做单倍长密钥算法,取结果的前四位与checkvalue 的值比较应该是一致的;“ TDK工作密钥”前16个字节是密文,后4个字节是checkvalue;前16个字节解出明文后,对8个数值0做双倍长密钥算法,取结果的前四位与checkvalue的值比较应该是一致的)*

在这里我就按最复杂的第三种来实现(java):
第一步:获取终端的主密钥,我们采用随机生成的方式来生成,生成的主密钥需要手动设置到POS机中

public static String randomHexString(int len)  {
    try {
            StringBuffer result = new StringBuffer();
            for(int i=0;i<len;i++) {
                result.append(Integer.toHexString(new Random().nextInt(16)));
            }
            return result.toString().toUpperCase();
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
    return null;
}

第二步,POS终端签到,获取工作密钥
1、生成PIN的工作密钥:

String pik = KeyUtil.randomHexString(32);

2、拿主密钥对PIN工作密钥进行双倍长加密,生成前16位的密文

String pikEnc = DesUtil.doubleDesEncrypt(minKey, pik);

3、拿PIN工作密钥对8个数值0做双倍长加密,生成checkValue

String checkValue = DesUtil.doubleDesEncrypt(pik, "0000000000000000").substring(0,8); 

4、拼接,生成最终要返回的结果

String pik = pikEnc + checkValue;

TDK工作密钥和PIN工作密钥生成规则一样

MAC工作密钥生成:

String mak = KeyUtil.randomHexString(16);
String makEnc = DesUtil.doubleDesEncrypt(minKey, mak);
String checkValue = DesUtil.desEncrypt(mak, "0000000000000000").substring(0,8); //单倍长加密
String mak = makEnc + "0000000000000000"  + checkValue;

附:双倍长加密算法:

public static String doubleDesEncrypt(String key,String data) throws Exception{
    return bytesToHexString(doubleDesEncrypt(hexStringToByte(key), hexStringToByte(data)));
}
public static byte[] doubleDesEncrypt(byte[] key,byte[] data) throws Exception{
    byte[] result = null;
    if(key.length != 16) {
        throw new Exception("expected length of des key is 16! [" + key.length +"]");
    }
    // 拆分密钥
    byte[] keyLeft = new byte[8];
    byte[] keyRight = new byte[8];
    System.arraycopy(key, 0, keyLeft, 0, 8);
    System.arraycopy(key, 8, keyRight, 0, 8);
    // 使用Left进行加密
    byte[] tmp = desEncrypt(keyLeft, data);
    tmp = desDecrypt(keyRight, tmp);
    result = desEncrypt(keyLeft, tmp);
    return result;
}

单倍长加密算法:

public static String desEncrypt(String key,String data) throws Exception{
    return bytesToHexString(desEncrypt(hexStringToByte(key), hexStringToByte(data)));
}
public static byte[] desDecrypt(byte[] key,byte[] data) throws Exception{
    return des(key, data, Cipher.DECRYPT_MODE);
}
private static byte[] des(byte[] key,byte[] data,int opmode) throws Exception{
        byte[] result = null;
        try {
            // 数据长度必须为8的倍数
            if(data.length%8 != 0) {
                throw new Exception("expected length of des data must multiple of 8! [" + data.length +"]");
            }
            SecretKeyFactory keyFactory;
            DESKeySpec dks = new DESKeySpec(key);
            keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretkey = keyFactory.generateSecret(dks);
            //创建Cipher对象
            Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
            //初始化Cipher对象
            cipher.init(opmode, secretkey);
            result = new byte[data.length];
            // 如果数据超过8位,循环每8位进行加解密,然后进行拼接
            int offset = 0;
            for (int i = 0; i < data.length/8; i++) {
                // 需要处理的数据逐8位取出
                byte[] tmp = new byte[8];
                System.arraycopy(data, offset, tmp, 0, 8);
                // 进行加解密计算
                byte[] tmpResult = cipher.doFinal(tmp);
                // 放入返回结果中
                System.arraycopy(tmpResult, 0, result, offset, 8);

                offset += 8;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new SeaException(e);
        }
        return result;
    }
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
您可以使用第三方库来生成支持支付宝、微信和银联的二维码。其中,常用的库包括zxing和QrCode-Generator。 首先,确保您已经在您的Java项目中引入了相关的库。对于zxing,您可以在Maven中添加以下依赖项: ```xml <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.4.0</version> </dependency> ``` 对于QrCode-Generator,您可以在Maven中添加以下依赖项: ```xml <dependency> <groupId>net.glxn.qrgen</groupId> <artifactId>javase</artifactId> <version>2.0</version> </dependency> ``` 接下来,您可以使用下面的示例代码生成包含支付宝、微信和银联支付链接的二维码: ```java import com.google.zxing.BarcodeFormat; import com.google.zxing.MultiFormatWriter; import com.google.zxing.common.BitMatrix; import net.glxn.qrgen.QRCode; import net.glxn.qrgen.image.ImageType; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class QRCodeGenerator { public static void main(String[] args) { generateQRCode("alipay://xxxxxxx", "alipay_qrcode.png"); generateQRCode("weixin://xxxxxxx", "weixin_qrcode.png"); generateQRCode("unionpay://xxxxxxx", "unionpay_qrcode.png"); } private static void generateQRCode(String text, String filePath) { try { // 使用zxing生成二维码 BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, 200, 200); File qrCodeFile = new File(filePath); MatrixToImageWriter.writeToFile(bitMatrix, "PNG", qrCodeFile); // 使用QrCode-Generator生成二维码 QRCode.from(text).to(ImageType.PNG).writeTo(new FileOutputStream(filePath)); System.out.println("二维码生成成功:" + filePath); } catch (Exception e) { System.out.println("二维码生成失败:" + e.getMessage()); } } } ``` 以上代码会生成三个二维码,分别对应支付宝、微信和银联支付链接。您可以将链接替换为实际的支付链接,并指定生成的二维码文件路径。请注意,您可能还需要处理相关的支付逻辑来生成正确的支付链接。 希望能对您有所帮助!如有任何疑问,请随时追问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值