处理入参STMSI得到iv
This commit is contained in:
@@ -1,27 +1,34 @@
|
||||
package com.cscn;
|
||||
|
||||
import javacard.framework.APDU;
|
||||
import javacard.framework.ISO7816;
|
||||
import javacard.framework.ISOException;
|
||||
import javacard.framework.JCSystem;
|
||||
import javacard.framework.Util;
|
||||
//import javacard.security.RandomData;
|
||||
|
||||
|
||||
/**
|
||||
* 仅做一次“自检调用”:
|
||||
* 1) ctx.init(KEY, IV); Enc(Input) == EncExpected ?
|
||||
* 2) ctx.init(KEY, IV); Enc(Enc(Input)) == Input ?
|
||||
* Response: 2字节 [encMatch, dblEncRestored],1=真,0=假
|
||||
*/
|
||||
public final class Method {
|
||||
public class Method {
|
||||
// ======= 已按你提供的数据填充 =======
|
||||
|
||||
// Key: 32字节
|
||||
private static final byte[] KEY32 = {
|
||||
|
||||
// todo 写固定值在代码里了
|
||||
// 加密密钥0: 32字节
|
||||
private static final byte[] ZUC256_ENC_KEY_0 = {
|
||||
(byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
|
||||
(byte)0x38,(byte)0x39,(byte)0x61,(byte)0x62,(byte)0x63,(byte)0x64,(byte)0x65,(byte)0x66,
|
||||
(byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
|
||||
(byte)0x38,(byte)0x39,(byte)0x61,(byte)0x62,(byte)0x63,(byte)0x64,(byte)0x65,(byte)0x66
|
||||
(byte)0x38,(byte)0x39,(byte)0x61,(byte)0x62,(byte)0x63,(byte)0x64,(byte)0x65,(byte)0x66,
|
||||
};
|
||||
|
||||
// todo 写固定值在代码里了
|
||||
// 加密密钥1: 32字节
|
||||
private static final byte[] ZUC256_ENC_KEY_1 = {
|
||||
(byte)0x61,(byte)0x62,(byte)0x63,(byte)0x64,(byte)0x65,(byte)0x66,(byte)0x67,(byte)0x68,
|
||||
(byte)0x69,(byte)0x6A,(byte)0x6B,(byte)0x6C,(byte)0x6D,(byte)0x6E,(byte)0x6F,(byte)0x70,
|
||||
(byte)0x71,(byte)0x72,(byte)0x73,(byte)0x74,(byte)0x75,(byte)0x76,(byte)0x77,(byte)0x78,
|
||||
(byte)0x79,(byte)0x7A,(byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,(byte)0x35,
|
||||
};
|
||||
|
||||
// IV
|
||||
@@ -30,43 +37,53 @@ public final class Method {
|
||||
// (byte)0x38,(byte)0x39,(byte)0x61,(byte)0x62,(byte)0x63,(byte)0x64,(byte)0x65,(byte)0x66,
|
||||
// (byte)0x67,(byte)0xC3,(byte)0x1C,(byte)0xB3,(byte)0xD3,(byte)0x5D,(byte)0xB7
|
||||
// };
|
||||
private static final byte[] IV25 = {
|
||||
(byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
|
||||
(byte)0x38,(byte)0x39,(byte)0x61,(byte)0x62,(byte)0x63,(byte)0x64,(byte)0x65,(byte)0x66,
|
||||
(byte)0x67,(byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,(byte)0x35,(byte)0x36,
|
||||
(byte)0x37
|
||||
// private static final byte[] IV25 = {
|
||||
// (byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
|
||||
// (byte)0x38,(byte)0x39,(byte)0x61,(byte)0x62,(byte)0x63,(byte)0x64,(byte)0x65,(byte)0x66,
|
||||
// (byte)0x67,(byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,(byte)0x35,(byte)0x36,
|
||||
// (byte)0x37
|
||||
// };
|
||||
|
||||
// STMSI:0,1,2,3,4,5; 10B 0x00; 9B 0x01
|
||||
private static final byte[] IV_MASK_25 = {
|
||||
(byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01, // 0-8, 0x01 9B
|
||||
(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00, (byte)0x00,(byte)0x00,(byte)0x00, // 9–18 0x00 10B
|
||||
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF // 19–24 STMSI 6B
|
||||
};
|
||||
|
||||
// Input: 明文(38字节)
|
||||
private static final byte[] INPUT = {
|
||||
(byte)0x5A,(byte)0x55,(byte)0x43,(byte)0x32,(byte)0x35,(byte)0x36,(byte)0xE5,(byte)0xAF,
|
||||
(byte)0xB9,(byte)0xE7,(byte)0xA7,(byte)0xB0,(byte)0xE5,(byte)0x8A,(byte)0xA0,(byte)0xE8,
|
||||
(byte)0xA7,(byte)0xA3,(byte)0xE5,(byte)0xAF,(byte)0x86,(byte)0xE6,(byte)0xB5,(byte)0x8B,
|
||||
(byte)0xE8,(byte)0xAF,(byte)0x95,(byte)0x3A,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,
|
||||
(byte)0x35,(byte)0x36,(byte)0x37,(byte)0x38,(byte)0x39,(byte)0x30
|
||||
};
|
||||
|
||||
// EncResult: 期望密文(38字节)
|
||||
private static final byte[] ENC_EXPECTED = {
|
||||
(byte)0x6C,(byte)0xEE,(byte)0x3C,(byte)0xFA,(byte)0xDE,(byte)0xBB,(byte)0xCB,(byte)0xE5,
|
||||
(byte)0x33,(byte)0x51,(byte)0x07,(byte)0x07,(byte)0x90,(byte)0x25,(byte)0x93,(byte)0x27,
|
||||
(byte)0x94,(byte)0xF5,(byte)0x18,(byte)0x70,(byte)0xEF,(byte)0x71,(byte)0x72,(byte)0x7D,
|
||||
(byte)0xBA,(byte)0x8D,(byte)0xBF,(byte)0x4F,(byte)0x61,(byte)0xC9,(byte)0xA8,(byte)0xE9,
|
||||
(byte)0xFF,(byte)0x19,(byte)0xF9,(byte)0xF9,(byte)0xE2,(byte)0xD2
|
||||
};
|
||||
// // Input: 明文(38字节)
|
||||
// private static final byte[] INPUT = {
|
||||
// (byte)0x5A,(byte)0x55,(byte)0x43,(byte)0x32,(byte)0x35,(byte)0x36,(byte)0xE5,(byte)0xAF,
|
||||
// (byte)0xB9,(byte)0xE7,(byte)0xA7,(byte)0xB0,(byte)0xE5,(byte)0x8A,(byte)0xA0,(byte)0xE8,
|
||||
// (byte)0xA7,(byte)0xA3,(byte)0xE5,(byte)0xAF,(byte)0x86,(byte)0xE6,(byte)0xB5,(byte)0x8B,
|
||||
// (byte)0xE8,(byte)0xAF,(byte)0x95,(byte)0x3A,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,
|
||||
// (byte)0x35,(byte)0x36,(byte)0x37,(byte)0x38,(byte)0x39,(byte)0x30
|
||||
// };
|
||||
//
|
||||
// // EncResult: 期望密文(38字节)
|
||||
// pri
|
||||
//
|
||||
// vate static final byte[] ENC_EXPECTED = {
|
||||
// (byte)0x6C,(byte)0xEE,(byte)0x3C,(byte)0xFA,(byte)0xDE,(byte)0xBB,(byte)0xCB,(byte)0xE5,
|
||||
// (byte)0x33,(byte)0x51,(byte)0x07,(byte)0x07,(byte)0x90,(byte)0x25,(byte)0x93,(byte)0x27,
|
||||
// (byte)0x94,(byte)0xF5,(byte)0x18,(byte)0x70,(byte)0xEF,(byte)0x71,(byte)0x72,(byte)0x7D,
|
||||
// (byte)0xBA,(byte)0x8D,(byte)0xBF,(byte)0x4F,(byte)0x61,(byte)0xC9,(byte)0xA8,(byte)0xE9,
|
||||
// (byte)0xFF,(byte)0x19,(byte)0xF9,(byte)0xF9,(byte)0xE2,(byte)0xD2
|
||||
// };
|
||||
|
||||
// ======================================
|
||||
|
||||
|
||||
// 输入数据缓冲区最大值
|
||||
static final short MAX_DATA_BLOCK_SIZE = 128;
|
||||
// 运行时缓冲:放RAM,避免写EEPROM
|
||||
byte[] ctx_buf;
|
||||
short ctx_buflen;
|
||||
|
||||
//todo test
|
||||
byte[] buf1; // Enc(Input)
|
||||
//todo test
|
||||
byte[] buf2; // Enc(Enc(Input)) -> 应为 Input
|
||||
// //todo test
|
||||
// byte[] buf1; // Enc(Input)
|
||||
// //todo test
|
||||
// byte[] buf2; // Enc(Enc(Input)) -> 应为 Input
|
||||
|
||||
// LFSR: 原 int[16] -> hi/lo 各 16
|
||||
public short[] LFSR_hi;
|
||||
@@ -95,6 +112,7 @@ public final class Method {
|
||||
|
||||
byte[] extract_iv_last8;
|
||||
byte[] extracted_iv_23;
|
||||
byte[] mix_iv_25;
|
||||
|
||||
short[] add64_tmp;
|
||||
|
||||
@@ -157,20 +175,31 @@ public final class Method {
|
||||
short[] finishZuc256EncryptCtx_ks;
|
||||
byte[] finishZuc256EncryptCtx_keystreamBytes;
|
||||
|
||||
byte[] randomByte;
|
||||
static final byte[] seed = { (byte)0x12, (byte)0x77, (byte)0x56 };//rand seed
|
||||
// rand instance
|
||||
// RandomData rng;
|
||||
|
||||
public Method(){//RandomData rng) {
|
||||
// rng = RandomData.getInstance(RandomData.ALG_PSEUDO_RANDOM);
|
||||
// rng.setSeed(seed, (short)0, (short)seed.length);
|
||||
|
||||
randomByte = JCSystem.makeTransientByteArray((short)1, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
|
||||
public Method() {
|
||||
// key list tmp buffer, lenth must equal with key_store(flash)!
|
||||
update_key_buf = JCSystem.makeTransientByteArray((short)120, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
// 算法内部使用23Byte IV
|
||||
extracted_iv_23 = JCSystem.makeTransientByteArray((short)23, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
// 临时存储拼接25B IV buffer
|
||||
mix_iv_25 = JCSystem.makeTransientByteArray((short)25, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
|
||||
ctx_buf = JCSystem.makeTransientByteArray((short)4, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
LFSR_hi = JCSystem.makeTransientShortArray((short)16, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
LFSR_lo = JCSystem.makeTransientShortArray((short)16, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
// todo buf1 if not use, delete please
|
||||
buf1 = JCSystem.makeTransientByteArray(MAX_DATA_BLOCK_SIZE, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
// todo buf2 if not use, delete please
|
||||
buf2 = JCSystem.makeTransientByteArray(MAX_DATA_BLOCK_SIZE, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
// // todo buf1 if not use, delete please
|
||||
// buf1 = JCSystem.makeTransientByteArray(MAX_DATA_BLOCK_SIZE, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
// // todo buf2 if not use, delete please
|
||||
// buf2 = JCSystem.makeTransientByteArray(MAX_DATA_BLOCK_SIZE, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
|
||||
stmsi = JCSystem.makeTransientByteArray((short)6, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
location_data = JCSystem.makeTransientByteArray((short)5, JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
|
||||
@@ -255,32 +284,40 @@ public final class Method {
|
||||
}
|
||||
|
||||
|
||||
//todo test
|
||||
public void testZuc256(APDU apdu) {
|
||||
// //todo test
|
||||
// public void testZuc256(APDU apdu) {
|
||||
//
|
||||
// byte[] apduBuf = apdu.getBuffer();
|
||||
//
|
||||
// // 第一次:Enc(Input)
|
||||
// initZuc256EncryptCtx(ZUC256_ENC_KEY_1, IV25);
|
||||
// updateZuc256EncryptCtx(INPUT, (short) INPUT.length, buf1);
|
||||
// finishZuc256EncryptCtx(buf1, (short) INPUT.length); // 若 Input 长度为 4 的倍数则通常无副作用,留着更稳妥
|
||||
//
|
||||
// boolean encMatch = (Util.arrayCompare(buf1, (short)0, ENC_EXPECTED, (short)0, (short)INPUT.length) == 0);
|
||||
//
|
||||
// // 第二次:Enc(Enc(Input)) 应还原 Input
|
||||
// initZuc256EncryptCtx(ZUC256_ENC_KEY_1, IV25);
|
||||
// updateZuc256EncryptCtx(buf1, (short) INPUT.length, buf2);
|
||||
// finishZuc256EncryptCtx(buf2, (short) INPUT.length);
|
||||
// boolean dblOk = (Util.arrayCompare(buf2, (short)0, INPUT, (short)0, (short)INPUT.length) == 0);
|
||||
//
|
||||
// // 返回 2 字节结果:[encMatch, dblOk],1=真, 0=假
|
||||
// apduBuf[0] = (byte)(encMatch ? 1 : 0);
|
||||
// apduBuf[1] = (byte)(dblOk ? 1 : 0);
|
||||
// short outLen = 2;
|
||||
//
|
||||
// apdu.setOutgoing();
|
||||
// apdu.setOutgoingLength(outLen);
|
||||
// apdu.sendBytes((short)0, outLen);
|
||||
// }
|
||||
|
||||
byte[] apduBuf = apdu.getBuffer();
|
||||
|
||||
// 第一次:Enc(Input)
|
||||
initZuc256EncryptCtx(KEY32, IV25);
|
||||
updateZuc256EncryptCtx(INPUT, (short) INPUT.length, buf1);
|
||||
finishZuc256EncryptCtx(buf1, (short) INPUT.length); // 若 Input 长度为 4 的倍数则通常无副作用,留着更稳妥
|
||||
|
||||
boolean encMatch = (Util.arrayCompare(buf1, (short)0, ENC_EXPECTED, (short)0, (short)INPUT.length) == 0);
|
||||
|
||||
// 第二次:Enc(Enc(Input)) 应还原 Input
|
||||
initZuc256EncryptCtx(KEY32, IV25);
|
||||
updateZuc256EncryptCtx(buf1, (short) INPUT.length, buf2);
|
||||
finishZuc256EncryptCtx(buf2, (short) INPUT.length);
|
||||
boolean dblOk = (Util.arrayCompare(buf2, (short)0, INPUT, (short)0, (short)INPUT.length) == 0);
|
||||
|
||||
// 返回 2 字节结果:[encMatch, dblOk],1=真, 0=假
|
||||
apduBuf[0] = (byte)(encMatch ? 1 : 0);
|
||||
apduBuf[1] = (byte)(dblOk ? 1 : 0);
|
||||
short outLen = 2;
|
||||
|
||||
apdu.setOutgoing();
|
||||
apdu.setOutgoingLength(outLen);
|
||||
apdu.sendBytes((short)0, outLen);
|
||||
/**
|
||||
* 拼接6B STMSI与IV_MASK为25B IV
|
||||
*/
|
||||
private void mix_stmsi_iv_25B(byte[] stmsi) {
|
||||
Util.arrayCopyNonAtomic(IV_MASK_25, (short)0, mix_iv_25, (short)0, (short)25);
|
||||
Util.arrayCopyNonAtomic(stmsi, (short)0, mix_iv_25, (short)19, (short)6);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,12 +325,15 @@ public final class Method {
|
||||
* 输入: stmsi[6], data[5]
|
||||
* 输出: out[5]
|
||||
*/
|
||||
private void encryptLocationZuc256(byte[] stmsi, byte[] data, byte[] out) {
|
||||
initZuc256EncryptCtx(KEY32, IV25);
|
||||
private void encryptLocationZuc256(byte[] stmsi, byte[] data, byte[] out, byte[] chosenKey) {
|
||||
mix_stmsi_iv_25B(stmsi);
|
||||
initZuc256EncryptCtx(chosenKey, mix_iv_25);
|
||||
updateZuc256EncryptCtx(data, (short) 5, out);
|
||||
finishZuc256EncryptCtx(out, (short) 5); // 若 Input 长度为 4 的倍数则通常无副作用,留着更稳妥
|
||||
finishZuc256EncryptCtx(out, (short) 5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* APDU处理函数
|
||||
*/
|
||||
@@ -314,13 +354,32 @@ public final class Method {
|
||||
// data
|
||||
Util.arrayCopyNonAtomic(buffer, (short)(off + 9), location_data, (short)0, (short)5);
|
||||
|
||||
// === 生成 fakedata ===
|
||||
encryptLocationZuc256(stmsi, location_data, location_res_data);
|
||||
byte[] chosenKey;
|
||||
// 产生随机数,选取Key1 or Key2
|
||||
// rng.generateData(randomByte, (short) 0, (short) 1);
|
||||
// byte rnd = randomByte[0];
|
||||
byte rnd = secParam; // todo 临时用输入的安全参数当作随机数值,因本地调试环境不支持RandomData
|
||||
// 随机数模2运算结果
|
||||
byte mod2 = (byte) (rnd & 0x01);
|
||||
// 取 rnd 的低5bit 左移到高5bit位置, 填入回参的 密钥选取字节(1B)
|
||||
byte resKeyRandByte = (byte) ((rnd & 0x1F) << 3);
|
||||
// 行动分支
|
||||
if (mod2 == 0) {
|
||||
chosenKey = ZUC256_ENC_KEY_0;
|
||||
resKeyRandByte = (byte)(resKeyRandByte | 0x00); // 选取第一条 b2 b1 b0 填 0 0 0 todo 待确认
|
||||
} else {
|
||||
chosenKey = ZUC256_ENC_KEY_1;
|
||||
resKeyRandByte = (byte)(resKeyRandByte | 0x01); // 选取第一条 b2 b1 b0 填 0 0 1 todo 待确认
|
||||
}
|
||||
|
||||
|
||||
// === 生成 zuc256加密 ===
|
||||
encryptLocationZuc256(stmsi, location_data, location_res_data, chosenKey);
|
||||
|
||||
// === 出参组装 ===
|
||||
buffer[(short)(off + 0)] = (byte)0xA1; // 类型
|
||||
buffer[(short)(off + 1)] = (byte)0x06; // 长度
|
||||
buffer[(short)(off + 2)] = (byte)0x01; // 密钥选取
|
||||
buffer[(short)(off + 2)] = resKeyRandByte; // 密钥选取
|
||||
Util.arrayCopyNonAtomic(location_res_data, (short)0, buffer, (short)(off + 3), (short)5);
|
||||
|
||||
return (short)8; // 出参总长度
|
||||
|
||||
22
Src/com/cscn/RandomGenerator.java
Normal file
22
Src/com/cscn/RandomGenerator.java
Normal file
@@ -0,0 +1,22 @@
|
||||
//package com.cscn;
|
||||
//
|
||||
//import javacard.security.RandomData;
|
||||
//
|
||||
//public class RandomGenerator {
|
||||
// private final RandomData random;
|
||||
//
|
||||
// //构造函数
|
||||
// public RandomGenerator()
|
||||
// {
|
||||
// //类当中有getInstance的都要先调用这个函数获取对象实例才能使用其他方法,不然6F00
|
||||
// random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
|
||||
// }
|
||||
//
|
||||
// //产生length长度的随机数并返回
|
||||
// public final byte[] GenrateSecureRand(short length, byte[] out)
|
||||
// {
|
||||
// //生成4bit的随机数
|
||||
// random.generateData(out, (short)0, (short)length);
|
||||
// return out;
|
||||
// }
|
||||
//}
|
||||
@@ -4,6 +4,7 @@ import javacard.framework.APDU;
|
||||
import javacard.framework.Applet;
|
||||
import javacard.framework.ISO7816;
|
||||
import javacard.framework.ISOException;
|
||||
//import javacard.security.RandomData;
|
||||
|
||||
/**
|
||||
* @author liuww
|
||||
@@ -12,7 +13,7 @@ import javacard.framework.ISOException;
|
||||
public class XwSecurity extends Applet {
|
||||
|
||||
//todo test
|
||||
public static final byte INS_PROCESS_DATA_TEST = (byte)0xE3;
|
||||
// public static final byte INS_PROCESS_DATA_TEST = (byte)0xE3;
|
||||
|
||||
public static final byte INS_LOCATION_ENCRYPT = (byte)0xCA;
|
||||
|
||||
@@ -28,11 +29,10 @@ public class XwSecurity extends Applet {
|
||||
|
||||
public XwSecurity(byte[] bArray, short bOffset, byte bLength) {
|
||||
// TODO Auto-generated constructor stub
|
||||
method = new Method(); //todo new?
|
||||
method = new Method();//rng); //todo new?
|
||||
// key store -> flash
|
||||
key_store_byte = new byte[120];
|
||||
|
||||
register(bArray, (short)(bOffset + 1), bArray[bOffset]);
|
||||
}
|
||||
|
||||
public static void install(byte[] bArray, short bOffset, byte bLength)
|
||||
@@ -71,10 +71,10 @@ public class XwSecurity extends Applet {
|
||||
// break;
|
||||
|
||||
|
||||
//todo test
|
||||
case INS_PROCESS_DATA_TEST:
|
||||
method.testZuc256(apdu);
|
||||
break;
|
||||
// //todo test
|
||||
// case INS_PROCESS_DATA_TEST:
|
||||
// method.testZuc256(apdu);
|
||||
// break;
|
||||
|
||||
|
||||
case INS_LOCATION_ENCRYPT:
|
||||
|
||||
Reference in New Issue
Block a user