NXP Mifare1(M1卡)算法JAVA代码实现

文章介绍了使用JAVA实现Mifare文档中KeyA和KeyB到DKeyA和DKeyB的转换,以及生成PASSWORD的过程,重点涉及Triple-DES的CBC无填充加密模式,以及字节处理和翻转的细节。在转换和加密过程中,作者遇到了初始字段配置、6字节到8字节转换和字节顺序翻转等问题,并提供了相应的解决方案。

        根据《AN02105_Mifare generate pwd》文档,用JAVA代码实现了下输入KeyA、KeyB转换成对应的DKeyA、DKeyB,并生成对应的PASSWORD的过程。

        这块网上现成的JAVA代码比较少,踩了几天坑,现在记录下踩坑的经历。

        踩坑一:Triple-DES算法

        需按照以下配置进行:

public static String desEncrypt(byte[] key, byte[] data) {
    return performDes(Cipher.ENCRYPT_MODE, key, data);
}

public static String desDecrypt(byte[] key, byte[] data) {
    return performDes(Cipher.DECRYPT_MODE, key, data);
}

protected static String performDes(int opMode, byte[] key, byte[] data) {
    try {
        byte[] iv = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
        Cipher des = Cipher.getInstance("DESede/CBC/NoPadding");
        SecretKeyFactory desKeyFactory = SecretKeyFactory.getInstance("DESede");
        SecretKey desKey = desKeyFactory.generateSecret(new DESedeKeySpec(key));
        des.init(opMode, desKey, new IvParameterSpec(iv));
        byte[] ret = des.doFinal(iv);
        ret = reverseByteArray(ret);
        return byteArrayToHexStr(ret);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

        关键是初始的输入字段、CBC算法以及输出结果补全的规则,即DESede/CBC/NoPadding配置。

        踩坑二:KeyA、KeyB 6字节转8字节

        需要严格按照规范中的逻辑来实现,当时网上找了段C语言的代码,存在问题,最终实现如下。

for (int i = 0; i < keyA.length; i++) {
    //填写dKeyA的前6个字节
    if (i < 6) {
        dKeyA[i] = (byte) ((keyA[i] << 1) & 0xff);
    }
    //填写dKeyA的第7个字节
    if (i < 6) {
        dKeyA[6] |= ((keyA[i] >> 7) & 1) << (6 - i);
    }
}
//填写dKeyA的第8个字节
dKeyA[7] = 0x00;

for (int i = 0; i < keyB.length; i++) {
    //填写dKeyA的第2个字节
    if (i < 6) {
        dKeyB[1] |= ((keyB[i] >> 7) & 1) << (i + 1);
    }
    //填写dKeyA的后6个字节
    if (i < 6) {
        dKeyB[2 + i] = (byte) ((keyB[i] << 1) & 0xff);
    }
}
//填写dKeyA的第1个字节
dKeyB[0] = 0x00;

       

         踩坑三:DKeyA、DKeyB、PASSWORD翻转

        这点最坑,就是输出的DKeyA、DKeyB、PASSWORD这三个字段都需要进行字节前后翻转后输出,不然无法生成跟规范中一致的结果。规范里也没有特别明确的写到这一点,在实现的时候需要多加注意。附上字节翻转的代码。

public static byte[] reverseByteArray(byte[] bytesOriginal) {
    byte[] rst = new byte[bytesOriginal.length];
    for (int i = 0; i < bytesOriginal.length; i++) {
        rst[bytesOriginal.length - i - 1] = bytesOriginal[i];
    }
    return rst;
}

        

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值