我用到的场景:密钥注入
使用说明:
1、从STORM导出SN和公钥,放在SN.csv里,把SN.csv和插件全放在个性化目录下
2、运行插件会自动生成index+SN.txt文件,内容为sn+","+ ikeyespk+","+kcv+","+ksn+","+group_name+","+to_string(index);
3、index+SN.csv文件需要处理下格式,再导入STORM系统,再由STORM注入IPEK。(index为16进制)
不用设备和其它工位。全部SN对应的IPEK生成完成后,SN.csv里对应的SN行的状态会改为PASS,如果需要重新生成,删除这一列,重新运行插件即可。
源码
cpp
// SCPMReader.cpp : Defines the initialization routines for the DLL.
//
#include <stdlib.h>
#include "pch.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
//#include "httpclient/json.h" //#include 是以当前文件所在路径为当前目录
//#ifdef _AFXDLL
//#pragma comment(lib,"httpclient/jsoncpp_static.lib") //#pragma comment 是以当前工程所在路径为当前目录
//#else
//#pragma comment(lib,"httpclient/jsoncpp_static_MT.lib") //#pragma comment 是以当前工程所在路径为当前目录
//#endif
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static bool isSuccess = false;
static string sn = "";
static string session_public_key_hex = "";
static string ikeyespk = "";
static string kcv = "";
static string ksn = "";
static string group_name = "";
static string other = "";//其它自定义参数
struct DeviceInfo {
std::string sn;
std::string session_public_key;
std::string group_name;
std::string index;
std::string ikeyespk;
std::string kcv;
std::string ksn;
};
std::vector<DeviceInfo> loadDeviceData(const std::string& filename) {
std::vector<DeviceInfo> devices;
std::ifstream file(filename);
std::string line;
if (!file.is_open()) {
std::cerr << "无法打开文件: " << filename << std::endl;
return devices;
}
while (std::getline(file, line)) {
std::stringstream ss(line);
std::string item;
std::vector<std::string> tokens;
while (std::getline(ss, item, ',')) {
tokens.push_back(item);
}
if (tokens.size() == 2) {
DeviceInfo device = { tokens[0], tokens[1] };
devices.push_back(device);
}
else {
std::cerr << "格式错误: " << line << std::endl;
}
}
file.close();
return devices;
}
bool StartsWith(const string& str, const string& prefix)
{
if (str.size() < prefix.size())
{
return false;
}
return str.compare(0, prefix.size(), prefix) == 0;
}
#include <iomanip>
bool halInjectKey(int index=0)
{
char SnFileName[5000] = { 0 };
GetPrivateProfileString("CFG_FILE", "SnFileName", "SN.csv", SnFileName, 5000, CONFIG_FILE_NAME);
//index 转16进制字符串 4位 不足补0 大写
std::stringstream ss;
ss << std::uppercase // 大写 HEX
<< std::hex
<< std::setw(2) // 宽度
<< std::setfill('0') // 不足补0
<< index;
std::string hexIndex = ss.str();
{
std::string filePath2 = hexIndex + SnFileName;
logger.INFO_F("halInjectKey filePath2=" + filePath2 + P(index));
// 追加模式打开
ofstream fout(filePath2, ios::app);
if (!fout.is_open())
{
logger.ERROR_F("打开文件失败");
return -1;
}
// 追加一行
string line = sn + "," + ikeyespk + "," + kcv + "," + ksn + "," + group_name + "," + hexIndex;
fout << line << endl;
logger.INFO_F("追加一行为:" + line);
fout.close();
}
{
std::string filePath = SnFileName;
// 读取所有行 并找到当前SN所在行
vector<string> lines;
ifstream fin(filePath);
string line;
int i = 0;
while (getline(fin, line))
{
lines.push_back(line);
if (StartsWith(line, sn))
{
logger.INFO_F("SN匹配成功,行(从0开始):" + P(i));
lines[i] = "PASS," + lines[i];
logger.INFO_F("替换指定行内容为:" + lines[i]);
}
else {
i++;
}
}
fin.close();
// ======================
// 写回文件
// ======================
ofstream fout(filePath);
for (const auto& l : lines)
{
fout << l << endl;
}
fout.close();
cout << "替换完成" << endl;
}
return true;
//char buffer[2000] = { 0 }; // 足够大的缓冲区来存储返回的数据
//GetPrivateProfileString("PLUGIN", "other", ",\"type\":1,\"algorithm\":4", buffer, sizeof(buffer), CONFIG_FILE_NAME);
//other = string(buffer);
//char recvBuff[5000] = { 0 };
//int recvLen = sizeof(recvBuff);
//string json="{\"function\":\"key_injection\",\"index\":"+to_string(index) + ",\"group_name\":\"" + group_name + "\",\"ikeyespk\":\"" + ikeyespk + "\",\"kcv\":\"" + kcv + "\",\"ksn\":\"" + ksn + "\""+other+"}";
//if (ERR_SUCCESS == mySocket.SendAndRecv(json.c_str(), json.length(), recvBuff, &recvLen, 5000))
//{
// Json::Reader reader;
// Json::Value value;
// if (reader.parse(recvBuff, value))
// {
// string message = value["message"].asString();
// if (!message._Equal("success")) { return false; }
// return true;
// }
// else { logger.ERROR_F(FUN_LINE" response json parse error!"); }
//}
//return false;
}
//hCard 没意义
//pCmd {class,ins,p1,?,lc,dataStart}
// P1=1 TUSN 只是赋值
// P1=2 KEY 只是赋值
// P1=3 KCV 赋值 并写入TUSN和KEY 返回 成功 2个字节[0x90,00] 失败其它
// P1=0x20 读TUSN 返回 8个字节0+TUSN+2个字节[0x90,00]
//if success return 0
int SendAPDU2(HANDLE hCard, const char *pCmd, int nCmdLen, char *pRsp, int& nRspLen, const char* pPath)
{
logger.INFO_F("Enter SendAPDU2");
logger.INFO_F("CMD:"+bytesToHexString((const BYTE*)pCmd, nCmdLen)+" "+P(nRspLen));
nRspLen = 0;
unsigned char swOK[] = { 0x90,0x00 };//正常返回
BYTE isoClass = pCmd[0];
BYTE isoRW = pCmd[1];
BYTE isoP1 = pCmd[2];
BYTE isoP2 = pCmd[3];
if (0x80 == isoClass)
{
if (0xB0 == isoRW) //Read
{
if (0x04 == isoP1)//读POS公钥
{
nRspLen += session_public_key_hex.size(); // pRsp 最大只能存2个字节 我把读的sn放回参数pRsp里 ,执行脚本成功后,点确定 脚本工具会崩溃重启 ,这是脚本工具的问题吧?
memcpy(pRsp, session_public_key_hex.c_str(), session_public_key_hex.size());
logger.INFO_F("读POS公钥:success");
}
else if (0x05 == isoP1)//读SN
{
nRspLen += sn.size();
memcpy(pRsp, sn.c_str(), sn.size());
logger.INFO_F("读SN:success");
}
else
{
logger.ERROR_F("P1 Error");
return -3;
}
}
else if (0xD0 == isoRW) //Write
{
int isoDataLength = pCmd[4];
const char* pDataStart = pCmd + 5;
if (nCmdLen > (255 + 5)) //数据超过255 用2字节表示长度 高字节在前 密钥256字节
{
isoDataLength = pCmd[5]*256+ pCmd[6];
pDataStart = pCmd + 7;
}
if (0x06 == isoP1)//写设备密文密钥
{
ikeyespk = bytesToHexString((const BYTE*)pDataStart, isoDataLength);
logger.INFO_F(to_string(isoP2 ) + "组 写设备密文密钥IPEK:success :"+ ikeyespk);
}
else if (0x07 == isoP1)//写密钥校验值KCV
{
kcv = bytesToHexString((const BYTE*)pDataStart, isoDataLength);
logger.INFO_F(to_string(isoP2 )+"组 KCV:success :"+kcv);
if (!halInjectKey(isoP2)) { return -9; }
logger.INFO_F(to_string(isoP2) + "组注入密钥:success");
}
else if (0x08 == isoP1)//写KSN
{
ksn = bytesToHexString((const BYTE*)pDataStart, isoDataLength);
logger.INFO_F(to_string(isoP2 ) + "组 KSN:success :" + ksn);
}
else if (0x09 == isoP1)//写组名
{
group_name = string(pDataStart);// hexStringToString(pDataStart);//字符串 //bytesToHexString((const BYTE*)pDataStart, isoDataLength);
logger.INFO_F(to_string(isoP2) + "组 group_name:success :" + group_name);
}
else
{
logger.ERROR_F("P1 Error2");
return -3;
}
}
else
{
logger.ERROR_F("RW Error");
return -2;
}
}
else
{
logger.ERROR_F("Class Error");
return -1;
}
memcpy(pRsp+nRspLen,swOK,2);
nRspLen += 2;
logger.INFO_F("SendAPDU2 Success");
return 0;
}
int WINAPI SendAPDU(HANDLE hCard, const char* pCmd, int nCmdLen, char* pRsp, int& nRspLen, const char* pPath)
{
RunCmd(__FUNCTION__);
int ret = -100;
for (int i = 0; i < 5; i++)
{
ret = SendAPDU2(hCard, pCmd, nCmdLen, pRsp, nRspLen, pPath);
if (ret == 0) { isSuccess = true; return ret; }
Sleep(100);
}
isSuccess = false;
return ret;
}
//if success return 0 else non 0.
int WINAPI OpenReader(HANDLE& hCT, const char* ucpCardCT, const int iPersoNo, const char* pPath)
{
logger.INFO_F("Enter OpenReader " + string(ucpCardCT));
RunCmd(__FUNCTION__);
logger.INFO_F("连接:成功 (不连设备)");
//读取sn和公钥session_public_key_hex
char SnFileName[5000] = {0};
GetPrivateProfileString("CFG_FILE", "SnFileName", "SN.csv", SnFileName, 5000, CONFIG_FILE_NAME);
std::string filename = SnFileName;
std::vector<DeviceInfo> devices = loadDeviceData(filename);
if (devices.size() == 0) { logger.ERROR_F(FUN_LINE"未找到有效的sn和公钥session_public_key_hex!请检查文件是否存在或是否全部已经完成。 SnFileName="+string(SnFileName)); return -2; }
for (const auto& device : devices) {
sn = device.sn;
if (sn.length() > 0 && device.session_public_key.length() > 0)
{
std::vector<unsigned char> decoded = base64_decode(device.session_public_key);
std::string decoded_str(decoded.begin(), decoded.end());
session_public_key_hex = decoded_str;
//logger.INFO_F(PS(session_public_key_hex));
logger.INFO_F(P(session_public_key_hex.size()));
logger.INFO_F("session_public_key_hex=" + encodeHexString(session_public_key_hex));
logger.INFO_F(FUN_LINE + "load sn success, " + PS(sn));
return 0;
}
else
{
logger.ERROR_F(FUN_LINE" sn length or session_public_key length error!");
return -1;
}
}
return 0;
}
//成功 返回 0
int WINAPI CloseReader(HANDLE hCT, const char* pPath)
{
logger.INFO_F("Enter CloseReader");
RunCmd(__FUNCTION__ "Final");
return 0;
}
int WINAPI EjectICC(HANDLE hCard,
const char* pStatus,
int nStatusLen,
const char* pPath)
{
logger.INFO_F("Enter EjectICC");
return 0;
}
int WINAPI GetUID(HANDLE hCard, unsigned char *pucUID, int &nUIDLen)
{
logger.INFO_F("Enter GetUID");
return 0;
}
int WINAPI CardReset(HANDLE hCard, unsigned char* pucATR, int& nATRLen, const char* pPath)
{
logger.INFO_F("Enter CardReset");
return 0;
}
int WINAPI RequestICC(HANDLE hCard,
char* pData,
int& nDataLen,
const char* pPath)
{
logger.INFO_F("Enter RequestICC");
return 0;
}