银联常用PinBlock算法

简介:PinBlock 算法是对账号和密码进行相应规则的转换,再将他们进行异或得出一个16进制字符串

需jar包
bcprov-jdk15on-1.59.jar
commons-lang3-3.9.jar

package com;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

public class UnionPayUtil {
    private static final int PIN_MIN_LENGTH = 4;
    private static final int PIN_MAX_LENGTH = 12;
    private static final int HEXADECIMAL = 16;
    /**
     * DES/3SDE算法PIN BLOCK大小为8
     * SM4算法PIN BLOCK大小为16
     */
    private static final int PIN_BLOCK_SIZE = 16;

    /**
     * 生成 PIN Block
     * @param pin
     * @return
     */
    private static byte[] pinBlock(String pin) {
        int pinLength = pin.length();
        if (pinLength < PIN_MIN_LENGTH || pinLength > PIN_MAX_LENGTH) {
            throw new IllegalArgumentException("Pin should be 4 to 12 digits long");
        }

        /**
         * PIN 格式 16BYTE 大小
         * 1BYTE PIN长度 + 15BYTE Pin
         * Pin不足部分右补F
         */
        byte[] pinBlock = new byte[PIN_BLOCK_SIZE];
        //如果是奇数右补F转换成如果不足12位右补F,补到12位长度
        pin = StringUtils.rightPad(pin,PIN_MAX_LENGTH,'F');
        //先处理PIN BLOCK 长度
        pinBlock[0] = (byte) pinLength;
        //处理PIN
        for (int i = 0; i <= pin.length() - 1; i = i + 2) {
            int pinBlockIndex = (i / 2) + 1;
            pinBlock[pinBlockIndex] = (byte) Integer.parseInt(pin.substring(i, i + 2), HEXADECIMAL);
        }

        /**
         * 不足32位补,需要补的位长度为PinBlock减去PIN长度域的长度和PIN数据长度
         */

        int blockIndex = (pin.length() / 2) + 1;
        for (int i = blockIndex; i <= PIN_BLOCK_SIZE - 1; i++) {
            pinBlock[i] = (byte) 0xFF;
        }
        return pinBlock;
    }

    /**
     * 格式
     * 2BYTE %H0000
     * 14BYTE 取主账号的右12位(不包括最右边的校验位),主账号不足12位左补0
     *
     * @param mAccNo 主账号
     * @return
     */
    private static byte[] pan(String mAccNo) {
        /**
         * 不足12位左补0,后面要取右12位,不包括校验位,全长是不足13位的就需要补
         */
        StringUtils.leftPad(mAccNo, 13, '0');
        byte[] panByte = new byte[PIN_BLOCK_SIZE];
        //截取右12位,包括校验位是13位
        String pan = StringUtils.left(StringUtils.right(mAccNo, 12 + 1), 12);
        /**
         * 2BYTE %H0000
         * 14BYTE 取主账号的右12位(不包括最右边的校验位),主账号不足12位左补0
         */
        //初始化左边为0区域
        int leftSize = PIN_BLOCK_SIZE - 12 / 2;
        for (int i = 0; i <= leftSize - 1; i++) {
            panByte[i] = (byte) 0x00;
        }
        int panIndex = 0;
        for (int i = leftSize; i <= PIN_BLOCK_SIZE - 1; i++, panIndex+=2) {
            String a = pan.substring(panIndex, panIndex + 2);
            panByte[i] = (byte) Integer.parseInt(a, HEXADECIMAL);
        }
        return panByte;
    }

    /**
     * @param pin    Personal Identification Number
     * @param mAccNo Main account number
     * @return
     */
    private static byte[] pinBlock(String pin, String mAccNo) {
        byte[] pingBlock = pinBlock(pin);
        byte[] pan = pan(mAccNo);
        byte[] tByte = new byte[PIN_BLOCK_SIZE];
        for (int i = 0; i < PIN_BLOCK_SIZE; i++) {
            tByte[i] = (byte) (pingBlock[i] ^ pan[i]);
        }
        return tByte;
    }

    public static void main(String[] args) {
        String pin = "123456";
        String accNo = "123456789012345678";
        byte[] pinb = pinBlock(pin, accNo);
        System.out.println(ByteUtils.toHexString(pinb));
    }
}

结果

06123456ffffffffffff9876fedcba98

JAR包地址
链接:https://pan.baidu.com/s/1J3Ff9XXMpX7UoCUDGdh94A
提取码:92ro

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值