输入80E3,可执行算法正确性检验,验证通过,对len=38Bytes明文加密结果符合预期、解密结果符合输入;

输入80E2,可写入密钥到flash,若算法类型、key id, key版本一致,就写入,已满就报错,无记录就写入新记录;
输入80CA,可执行伪位置加密,原封不动将输入的data返回回来。
This commit is contained in:
zcy
2025-09-08 23:46:46 +08:00
parent b41fff9d09
commit 5456e990e6
6 changed files with 231 additions and 127 deletions

View File

@@ -58,6 +58,7 @@ public final class Method {
ctx = new Zuc256EncryptCtx(); // 仅创建一次
}
public void processData(APDU apdu) {
short L = (short) INPUT.length;
byte[] buf1; // Enc(Input)
@@ -92,8 +93,113 @@ public final class Method {
apdu.sendBytes((short)0, outLen);
}
// 本任务不需要更新Key这里留空
public void updateKey(APDU apdu) {
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
/**
* fake数据生成函数
* 输入: stmsi[6], data[5]
* 输出: fakedata[5]
*/
private void makeFakeData(byte[] stmsi, byte[] data, byte[] fakedata) {
// 示例:逐字节异或 stmsi 前5字节
for (short i = 0; i < (short)5; i++) {
fakedata[i] = (byte)(data[i]);
}
}
/**
* APDU处理函数
*/
public short processDataFake(byte[] buffer, short off, short len, byte[] key_store) {
// 至少要有 12 个字节1+1+1+6+5
if (len < (short)12) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
// === 解析入参 ===
byte inType = buffer[(short)(off + 0)]; // 类型 A1
byte inLen = buffer[(short)(off + 1)]; // 长度 0x0C
byte secParam = buffer[(short)(off + 2)]; // 安全参数
// STMSI
byte[] stmsi = JCSystem.makeTransientByteArray((short)6, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
Util.arrayCopyNonAtomic(buffer, (short)(off + 3), stmsi, (short)0, (short)6);
// data
byte[] data = JCSystem.makeTransientByteArray((short)5, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
Util.arrayCopyNonAtomic(buffer, (short)(off + 9), data, (short)0, (short)5);
// === 生成 fakedata ===
byte[] fakedata = JCSystem.makeTransientByteArray((short)5, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
makeFakeData(stmsi, data, fakedata);
// === 出参组装 ===
buffer[(short)(off + 0)] = (byte)0xA1; // 类型
buffer[(short)(off + 1)] = (byte)0x06; // 长度
buffer[(short)(off + 2)] = (byte)0x01; // 密钥选取
Util.arrayCopyNonAtomic(fakedata, (short)0, buffer, (short)(off + 3), (short)5);
return (short)8; // 出参总长度
}
public short updateKey(byte[] buffer, short off, short len, byte[] key_store) {
final short SLOT_SIZE = 40; // 每个槽固定40字节
final short HDR_LEN = 4; // 报文头长度: [0]=keyLenField, [1]=alg, [2]=keyId, [3]=ver
// === 解析头 ===
byte keyLenField = buffer[(short)(off + 0)]; // 包含头部+密钥的总长度
byte alg = buffer[(short)(off + 1)];
byte keyId = buffer[(short)(off + 2)];
byte ver = buffer[(short)(off + 3)];
// 计算实际密钥长度
short realKeyLen = (short)(keyLenField - (byte)3); // 长度字段 = key长度 + 3字节头
if (realKeyLen <= 0) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID); // key长度不合法
}
// 检查APDU长度和key长度是否匹配
if (len != (short)(HDR_LEN + realKeyLen)) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
if (len > SLOT_SIZE) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
// === 将原有 key_store 拷贝到 RAM避免直接覆盖 EEPROM (可选) ===
byte[] key_buf = JCSystem.makeTransientByteArray((short)80, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
Util.arrayCopyNonAtomic(key_store, (short)0, key_buf, (short)0, (short)key_store.length);
// === 遍历槽,找到匹配的 (alg, keyId, ver),否则找空槽 ===
short slots = (short)(key_store.length / SLOT_SIZE);
short target = -1;
for (short i = 0; i < slots; i++) {
short base = (short)(i * SLOT_SIZE);
byte algOld = key_store[(short)(base + 1)];
byte keyIdOld = key_store[(short)(base + 2)];
byte verOld = key_store[(short)(base + 3)];
if (algOld == alg && keyId == keyIdOld && ver == verOld) {
target = i; // 找到已存在的,覆盖它
break;
}
if (key_store[base] == (byte)0x00 && target == -1) {
target = i; // 找到第一个空槽
}
}
if (target == -1) {
ISOException.throwIt(ISO7816.SW_FILE_FULL); // 没有空位
}
// === 覆盖写入本次APDU的头+密钥数据 ===
short base = (short)(target * SLOT_SIZE);
// 先清空槽
Util.arrayFillNonAtomic(key_store, base, SLOT_SIZE, (byte)0x00);
// 再写入APDU传入的头+数据 (len 个字节)
Util.arrayCopyNonAtomic(buffer, off, key_store, base, len);
return 0; // 无返回数据
}
}