You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于DES/AES对称密钥的Java Card小程序签名验签实现问询

Java Card 基于对称密钥的签名验签实现(AES/DES,无RSA)

核心原理说明

对称密钥体系下的“签名验签”本质是使用**消息认证码(MAC)**机制:通信双方共享对称密钥,发送方用密钥对消息生成MAC值(相当于“签名”),接收方用同一密钥对消息重新计算MAC并与收到的MAC比对,一致则验证通过。和非对称签名不同,这种方式不具备抗抵赖性,但完全满足消息完整性、真实性的验证需求,符合你的要求。

常用的对称MAC算法有:

  • AES-MAC(基于AES密钥,推荐,安全性更高)
  • DES-MAC/3DES-MAC(基于DES/3DES密钥)

代码实现(以AES-MAC为例)

以下是完整的Java Card小程序代码,包含密钥初始化、MAC生成、MAC验证功能:

package com.example.symmetricmac;

import javacard.framework.*;
import javacard.security.*;
import javacardx.crypto.*;

public class SymmetricMACApplet extends Applet {
    // APDU指令常量
    private static final byte INS_GENERATE_MAC = (byte) 0x01;
    private static final byte INS_VERIFY_MAC = (byte) 0x02;
    private static final byte INS_SET_KEY = (byte) 0x03;

    // 算法与密钥参数
    private static final byte AES_KEY_LENGTH = (byte) 16; // 128位AES密钥
    private final AESKey aesKey;
    private final MAC mac;

    private SymmetricMACApplet() {
        // 初始化AES密钥对象
        aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false);
        // 初始化AES-MAC对象(使用ISO9797_ALG3_MAC算法,对应AES-CBC-MAC)
        mac = MAC.getInstance(MAC.ALG_AES_MAC_128_ISO9797_3, false);
    }

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new SymmetricMACApplet().register();
    }

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return;
        }

        byte[] buffer = apdu.getBuffer();
        byte ins = buffer[ISO7816.OFFSET_INS];

        switch (ins) {
            case INS_SET_KEY:
                setAESKey(apdu);
                break;
            case INS_GENERATE_MAC:
                generateMAC(apdu);
                break;
            case INS_VERIFY_MAC:
                verifyMAC(apdu);
                break;
            default:
                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    /**
     * 设置AES密钥(从APDU数据段导入)
     */
    private void setAESKey(APDU apdu) {
        byte[] buffer = apdu.getBuffer();
        short len = apdu.setIncomingAndReceive();
        // 验证密钥长度是否为128位(16字节)
        if (len != AES_KEY_LENGTH) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        // 导入密钥材料
        aesKey.setKey(buffer, ISO7816.OFFSET_CDATA);
    }

    /**
     * 生成消息MAC(签名)
     */
    private void generateMAC(APDU apdu) {
        byte[] buffer = apdu.getBuffer();
        short len = apdu.setIncomingAndReceive();
        if (len <= 0) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        // 初始化MAC,绑定密钥
        mac.init(aesKey, MAC.MODE_ISO9797_M3);
        // 输入消息数据
        mac.update(buffer, ISO7816.OFFSET_CDATA, len);
        // 生成MAC值(长度为16字节,AES-MAC默认长度)
        short macLen = mac.doFinal(buffer, ISO7816.OFFSET_CDATA, (short)0, buffer, (short)0);
        // 将MAC值返回给终端
        apdu.setOutgoingAndSend((short)0, macLen);
    }

    /**
     * 验证MAC(验签)
     */
    private void verifyMAC(APDU apdu) {
        byte[] buffer = apdu.getBuffer();
        short len = apdu.setIncomingAndReceive();
        // 消息长度 + MAC长度(16字节)必须大于16
        if (len <= AES_KEY_LENGTH) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        short msgLen = (short)(len - AES_KEY_LENGTH);
        // 初始化MAC
        mac.init(aesKey, MAC.MODE_ISO9797_M3);
        // 输入消息部分
        mac.update(buffer, ISO7816.OFFSET_CDATA, msgLen);
        // 验证MAC:将收到的MAC与计算出的MAC比对
        boolean isValid = mac.verify(buffer, (short)(ISO7816.OFFSET_CDATA + msgLen), AES_KEY_LENGTH);
        if (isValid) {
            ISOException.throwIt(ISO7816.SW_NO_ERROR);
        } else {
            ISOException.throwIt((short)0x6982); // 验证失败状态码
        }
    }
}

代码核心部分讲解

  1. 密钥与MAC初始化

    • 在Applet构造函数中,用KeyBuilder创建AES密钥对象,指定密钥类型为AES、长度128位;
    • 用MAC.getInstance创建AES-MAC实例,选用ALG_AES_MAC_128_ISO9797_3算法,这是符合标准的AES-CBC-MAC实现。
  2. APDU指令处理

    • INS_SET_KEY:从终端导入16字节的AES密钥,注意Java Card中密钥一旦设置完成就不可导出(除非密钥对象创建时允许);
    • INS_GENERATE_MAC:接收终端发送的消息,用密钥生成MAC并返回;
    • INS_VERIFY_MAC:接收终端发送的「消息+MAC」数据,重新计算消息的MAC并与收到的MAC比对,返回验证结果。
  3. DES/3DES适配说明
    如果要改用DES或3DES,只需修改几个参数:

    • 密钥类型改为KeyBuilder.TYPE_DES或KeyBuilder.TYPE_DES3,长度对应KeyBuilder.LENGTH_DES_64(DES)或KeyBuilder.LENGTH_DES3_192(3DES);
    • MAC算法改为MAC.ALG_DES_MAC_ISO9797_1(DES-MAC)或MAC.ALG_DES3_MAC_ISO9797_1(3DES-MAC)。

基础使用流程

  1. 安装小程序:用JCDK工具将编译后的CAP文件安装到Java Card模拟器或实体卡;
  2. 设置密钥:发送INS_SET_KEY指令,传入16字节的AES密钥;
  3. 生成签名(MAC):发送INS_GENERATE_MAC指令,传入要签名的消息,接收返回的MAC值;
  4. 验证签名:发送INS_VERIFY_MAC指令,传入「消息+MAC」的拼接数据,根据返回的状态码判断验证是否通过。

注意事项

  • Java Card内存有限,避免使用过大的数组,处理长消息时可分多次调用mac.update;
  • 密钥的安全性至关重要,建议通过安全通道导入密钥,避免明文传输;
  • 不同的MAC算法可能有不同的输出长度,需根据算法调整代码中的长度参数。

内容的提问来源于stack exchange,提问作者bujji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:44:58