#include "rfidfunction.h" #include "sm3.h" #include "sm4.h" #include #include // 计算校验和并输出 void RFIDFunction::CheckSumOut(unsigned char* buf, unsigned char len) { unsigned char i; unsigned char checksum; checksum = 0; for (i = 0; i < (len - 1); i++) { checksum ^= buf[i]; // 逐位异或计算校验和 } buf[len - 1] = (unsigned char)~checksum; // 取反作为校验和 } // 检查输入的校验和是否正确 bool RFIDFunction::CheckSumIn(unsigned char* buf, unsigned char len) { unsigned char i; unsigned char checksum; checksum = 0; for (i = 0; i < (len - 1); i++) { checksum ^= buf[i]; // 逐位异或计算校验和 } if (buf[len - 1] == (unsigned char)~checksum) // 比较校验和 { return true; // 校验和正确 } return false; // 校验和错误 } // 将十六进制字符串转换为字节数组 void hexStrToByte(const QByteArray& hexIn, unsigned char* dest) { int sourceLen = hexIn.size(); unsigned char* source = (unsigned char*)hexIn.constData(); short i; unsigned char highByte, lowByte; for (i = 0; i < sourceLen; i += 2) { highByte = toupper(source[i]); // 高位 lowByte = toupper(source[i + 1]); // 低位 if (highByte > 0x39) { highByte -= 0x37; // A-F转换 } else { highByte -= 0x30; // 0-9转换 } if (lowByte > 0x39) { lowByte -= 0x37; // A-F转换 } else { lowByte -= 0x30; // 0-9转换 } dest[i / 2] = (highByte << 4) | lowByte; // 合并高低位 } return; } // 检测输入的字符是否是有效的16进制字符 bool isValidHex(const QByteArray& input) { int length = input.size(); // 获取输入的长度 for (int i = 0; i < length; ++i) // 使用传统的for循环 { char c = input[i]; // 获取当前字符 // 检查字符是否在0-9, A-F, a-f范围内 if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) { return false; // 如果有无效字符,返回false } } return true; // 所有字符均有效,返回true } void sleepMs(unsigned int msec) { QTime dieTime = QTime::currentTime().addMSecs(msec); while( QTime::currentTime() < dieTime ) QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } RFIDFunction::RFIDFunction(QObject *parent) : QObject(parent),m_SerialPort(NULL) { m_SerialSate = initSerialPortAndOpen("COM3"); // 初始化串口 } RFIDFunction::~RFIDFunction() { if (m_SerialPort) { if (m_SerialPort->isOpen()) { m_SerialPort->close(); } delete m_SerialPort; m_SerialPort = nullptr; } } /*** * @描述 : 创建读写卡的密码(Key_A和Key_B) * @入参 : info 生成密码的数据 * @输出 : 无 * @返回 : 密钥的原始数据 */ const QByteArray RFIDFunction::createPassword(const QByteArray& info) { if (info.isEmpty()) { return ""; // 如果输入为空,返回空 } int inputSize = info.size(); if (inputSize > 8192) { return ""; // 如果输入大小超过限制,返回空 } //先用SM3对原始数据进行哈希生成 unsigned char hashDataOrigin[32] = { 0 }; SM3::sm3Hash((unsigned char*)info.data(), inputSize, hashDataOrigin); // 生成哈希 //接着使用哈希生成SM4加密密钥 unsigned char sm4Key[16] = { 0 }; unsigned char sm4IV[16] = { 0 }; int index_1 = 0; int index_2 = 0; for (int i = 0; i < 32; i++) { if (i % 2 == 0) { sm4Key[index_1++] = hashDataOrigin[i]; // 偶数位作为SM4密钥 } else { sm4IV[index_2++] = hashDataOrigin[i]; // 奇数位作为SM4初始向量 } } //再用SM4对原始数据进行加密 unsigned char out[8192] = {0}; sm4_context sm4Ctx; SM4::sm4_setkey_enc(&sm4Ctx, sm4Key); // 设置SM4加密密钥 SM4::sm4_crypt_cbc(&sm4Ctx, SM4_ENCRYPT, inputSize, sm4IV, (unsigned char*)info.data(), out); // 执行SM4加密 //最后再用SM3对加密后的数据取哈希 unsigned char hashEncrypted[32] = { 0 }; SM3::sm3Hash(out, inputSize, hashEncrypted); // 生成加密数据的哈希 index_1 = 0; char key[16] = { 0 }; for (int i = 0; i < 32; i++) { if (i % 2 != 0)//取哈希的奇数位作为最终的密码 { key[index_1++] = hashEncrypted[i]; } } return QByteArray(key,16).toHex(); // 返回最终的密码 } bool RFIDFunction::getSerialState() { return m_SerialSate; // 返回串口状态 } RFIDFunction::ErrorCode RFIDFunction::initSerialPortAndOpen(const QString& portName, BaudRateType baudRate, DataBitsType setDataBits, StopBitsType stopBits, ParityType parity) { m_SerialPort = new Posix_QextSerialPort("/dev/ttyO3",QextSerialBase::Polling); // 创建串口对象 m_SerialPort->setPortName(portName); // 设置串口名称 m_SerialPort->setBaudRate((BaudRateType)baudRate); // 设置波特率 m_SerialPort->setDataBits(setDataBits); // 设置数据位 m_SerialPort->setStopBits(stopBits); // 设置停止位 m_SerialPort->setParity(parity); // 设置校验位 m_SerialPort->setFlowControl(FLOW_OFF); if (m_SerialPort->open(QIODevice::ReadWrite)) // 打开串口 { return Serial_Error; // 打开失败,返回串口错误 } return No_Error; // 打开成功,返回无错误 } RFIDFunction::ErrorCode RFIDFunction::setOriginPassword(const QByteArray& psw) { unsigned char com[32] = { 0 }; // 命令数组 com[0] = 0x03; // 命令头 com[1] = 0x0B; // 数据长度 com[2] = 0xC4; // 命令类型 com[3] = 0x20; // 额外数据 unsigned char hexOut[32] = { 0 }; // 存储转换后的十六进制数据 hexStrToByte(psw, hexOut); // 将密码转换为字节数组 memcpy(com + 4, hexOut, 6); // 将密码添加到命令中 CheckSumOut(com, com[1]); // 计算校验和 //QByteArray AAA = QByteArray((char*)com, com[1]).toHex(); // 转换为十六进制字符串 if (m_SerialPort->isOpen()) // 检查串口是否打开 { qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令 if (len != com[1]) // 检查发送长度 { return Send_Data_Error; // 发送错误 } // 等待请求完成 sleepMs(200); QByteArray readData = m_SerialPort->readAll(); // 读取返回数据 unsigned char revData[32] = { 0 }; // 存储返回数据 memcpy(revData, readData.data(), readData.size()); // 复制返回数据 if ((revData[0] == 0x03) && (revData[1] == 0x08) && (revData[2] == 0xC4) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包 { bool status = CheckSumIn(revData, revData[1]); //计算校验和 if (status) { if (revData[4] == 0x00) //写数据块成功 { return No_Error; // 返回无错误 } } else { return Received_Data_Check_Error; // 校验和错误 } } else { return Received_Data_Error; // 返回数据错误 } } return Serial_Error; // 串口错误 } RFIDFunction::ErrorCode RFIDFunction::setWriteAndReadPassword(const QByteArray& writePassword, const QByteArray& readPassword, KeyFunction keyFunc) { if (writePassword.isEmpty() || readPassword.isEmpty()) { return Data_Is_Empty_Error; // 如果密码为空,返回错误 } unsigned char com[32] = { 0 }; // 命令数组 com[0] = 0x03; // 命令头 com[1] = 0x15; // 数据长度 com[2] = 0xC3; // 命令类型 com[3] = 0x20; // 额外数据 unsigned char hexOut[32] = { 0 }; // 存储转换后的十六进制数据 hexStrToByte(writePassword.toHex(), hexOut); // 将写密码转换为字节数组 memcpy(com + 4, hexOut, 6); // 将写密码添加到命令中 switch (keyFunc) // 根据密钥功能设置命令 { case RFIDFunction::KeyA_Same_KeyB: /* * 控制如下:KEYA,KEYB 可以用来读 、写 、增值 、减值 、更改扇区密钥 */ com[10] = 0xFF; // 设置KEYA和KEYB相同 com[11] = 0x07; // 设置权限 com[12] = 0x80; // 设置操作 com[13] = 0x69; // 设置结束标志 break; case RFIDFunction::KeyB_Control_KeyA: /* 控制如下:KEYA 可以读数据块 、减值 、查询余额 KEYB 可以读写数据块 、增值 、减值 、查询余额 KEYA 、KEYB 不可读,KEYA,KEYB 由 KEYB 修改 */ com[10] = 0x08; // 设置KEYB控制KEYA com[11] = 0x77; // 设置权限 com[12] = 0x8F; // 设置操作 com[13] = 0x69; // 设置结束标志 break; default: break; } memset(hexOut, 0, 32); // 清空hexOut hexStrToByte(readPassword.toHex(), hexOut); // 将读密码转换为字节数组 memcpy(com + 14, hexOut, 6); // 将读密码添加到命令中 CheckSumOut(com, com[1]); // 计算校验和 QByteArray AAA = QByteArray((char*)com, com[1]).toHex(); // 转换为十六进制字符串 if (m_SerialPort->isOpen()) // 检查串口是否打开 { qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令 if (len != com[1]) // 检查发送长度 { return Send_Data_Error; // 发送错误 } // 等待请求完成 sleepMs(200); QByteArray readData = m_SerialPort->readAll(); // 读取返回数据 unsigned char revData[32] = { 0 }; // 存储返回数据 memcpy(revData, readData.data(), readData.size()); // 复制返回数据 if ((revData[0] == 0x03) && (revData[1] == 0x08) && (revData[2] == 0xC3) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包 { bool status = CheckSumIn(revData, revData[1]); //计算校验和 if (status) { if (revData[4] == 0x00) //写数据块成功 { return No_Error; // 返回无错误 } } else { return Received_Data_Check_Error; // 校验和错误 } } else { return Received_Data_Error; // 返回数据错误 } } return Serial_Error; // 串口错误 } RFIDFunction::ErrorCode RFIDFunction::setEncryptedBlock(KeyType type, ControlBlock block) { unsigned char com[32] = { 0 }; // 命令数组 com[0] = 0x01; // 命令头 com[1] = 0x08; // 数据长度 switch (type)//只有两种密码,A和B { case RFIDFunction::KEY_A: com[2] = 0xA5; // 设置为KEY_A break; case RFIDFunction::KEY_B: com[2] = 0x5A; // 设置为KEY_B break; default: com[2] = 0xA5; // 默认设置为KEY_A break; } com[3] = 0x20; // 额外数据 memcpy(com + 4, &block, 1); // 将加密块添加到命令中 com[5] = 0x01;//蜂鸣器开 0x00不开 com[6] = 0x00;//保留 CheckSumOut(com, com[1]); // 计算校验和 QByteArray AAA = QByteArray((char*)com, com[1]).toHex(); // 转换为十六进制字符串 if (m_SerialPort->isOpen()) // 检查串口是否打开 { qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令 if (len != com[1]) // 检查发送长度 { return Send_Data_Error; // 发送错误 } // 等待请求完成 sleepMs(200); QByteArray readData = m_SerialPort->readAll(); // 读取返回数据 unsigned char revData[32] = { 0 }; // 存储返回数据 memcpy(revData, readData.data(), readData.size()); // 复制返回数据 if ((revData[0] == 0x01) && (revData[1] == 0x08) && (revData[2] == com[2]) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包 { bool status = CheckSumIn(revData, revData[1]); //计算校验和 if (status) { if (revData[4] == 0x00) //写数据块成功 { return No_Error; // 返回无错误 } } else { return Received_Data_Check_Error; // 校验和错误 } } else { return Received_Data_Error; // 返回数据错误 } } return Serial_Error; // 串口错误 } RFIDFunction::ErrorCode RFIDFunction::writeDataToBlock(KeyType type, DataBlock block, const QByteArray& data) { if (data.isEmpty()) { return Data_Is_Empty_Error; // 如果数据为空,返回错误 } unsigned char com[32] = { 0 }; // 命令数组 com[0] = 0x01; // 命令头 com[1] = 0x17; // 数据长度 switch (type)//只有两种密码,A和B { case RFIDFunction::KEY_A: com[2] = 0xA4; // 设置为KEY_A break; case RFIDFunction::KEY_B: com[2] = 0x5B; // 设置为KEY_B break; default: com[2] = 0xA4; // 默认设置为KEY_A break; } com[3] = 0x20; // 额外数据 memcpy(com + 4, &block, 1); // 将数据块添加到命令中 com[5] = 0x01;//蜂鸣器开 0x00不开 unsigned char hexOut[32] = { 0 }; // 存储转换后的十六进制数据 memset(hexOut, 0, 32); // 清空hexOut if (!isValidHex(data)) // 检查数据是否合法 { return Data_Is_Illegal_Error; // 数据非法 } hexStrToByte(data, hexOut); // 将数据转换为字节数组 memcpy(com + 6, hexOut, 16); // 将数据添加到命令中 CheckSumOut(com, com[1]); // 计算校验和 if (m_SerialPort->isOpen()) // 检查串口是否打开 { qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令 if (len != com[1]) // 检查发送长度 { return Send_Data_Error; // 发送错误 } // 等待请求完成 sleepMs(200); QByteArray readData = m_SerialPort->readAll(); // 读取返回数据 unsigned char revData[32] = { 0 }; // 存储返回数据 memcpy(revData, readData.data(), readData.size()); // 复制返回数据 if ((revData[0] == 0x01) && (revData[1] == 0x08) && (revData[2] == com[2]) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包 { bool status = CheckSumIn(revData, revData[1]); //计算校验和 if (status) { if (revData[4] == 0x00) //写数据块成功 { return No_Error; // 返回无错误 } } else { return Received_Data_Check_Error; // 校验和错误 } } else { return Received_Data_Error; // 返回数据错误 } } return Serial_Error; // 串口错误 } RFIDFunction::ErrorCode RFIDFunction::readDataFromBlock(KeyType type, DataBlock block, QByteArray& data) { unsigned char com[32] = { 0 }; // 命令数组 com[0] = 0x01; // 命令头 com[1] = 0x08; // 数据长度 switch (type)//只有两种密码,A和B { case RFIDFunction::KEY_A: com[2] = 0xA3; // 设置为KEY_A break; case RFIDFunction::KEY_B: com[2] = 0x5C; // 设置为KEY_B break; default: com[2] = 0xA3; // 默认设置为KEY_A break; } com[3] = 0x20; // 额外数据 memcpy(com + 4, &block, 1); // 将数据块添加到命令中 com[5] = 0x01;//蜂鸣器开 0x00不开 com[6] = 0x00;//保留 CheckSumOut(com, com[1]); // 计算校验和 if (m_SerialPort->isOpen()) // 检查串口是否打开 { qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令 if (len != com[1]) // 检查发送长度 { return Send_Data_Error; // 发送错误 } // 等待请求完成 sleepMs(200); QByteArray readData = m_SerialPort->readAll(); // 读取返回数据 //QByteArray AAA = readData.toHex(); // 转换为十六进制字符串 unsigned char revData[32] = { 0 }; // 存储返回数据 memcpy(revData, readData.data(), readData.size()); // 复制返回数据 if ((revData[0] == 0x01) && (revData[1] == 0x16) && (revData[2] == com[2]) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包 { bool status = CheckSumIn(revData, revData[1]); //计算校验和 if (status) { if (revData[4] == 0x00) //写数据块成功 { data = QByteArray::fromHex(readData.mid(3,16)); return No_Error; // 返回无错误 } } else { return Received_Data_Check_Error; // 校验和错误 } } else { return Received_Data_Error; // 返回数据错误 } } return Serial_Error; // 串口错误 } RFIDFunction::ErrorCode RFIDFunction::setWorkMode(WorkMode mode, DataBlock block, UploadMode uploadMode) { unsigned char com[32] = { 0 }; // 命令数组 com[0] = 0x03; // 命令头 com[1] = 0x08; // 数据长度 com[2] = 0xC1; // 工作模式 com[3] = 0x20; // 设备号数据 memcpy(com + 4, &mode, 1); // 将工作模式添加到命令中 switch (mode) { case RFIDFunction::Command_Mode: com[5] = 0x00; com[6] = 0x00; break; case RFIDFunction::Auto_Read_Card_Num_Mode: com[5] = 0x00; com[6] = uploadMode; break; case RFIDFunction::Auto_Read_Data_Mode: case RFIDFunction::Auto_Read_Card_Num_Data_Mode: default: com[5] = block; com[6] = uploadMode; break; } CheckSumOut(com, com[1]); // 计算校验和 if (m_SerialPort->isOpen()) // 检查串口是否打开 { qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令 if (len != com[1]) // 检查发送长度 { return Send_Data_Error; // 发送错误 } // 等待请求完成 sleepMs(200); QByteArray readData = m_SerialPort->readAll(); // 读取返回数据 QByteArray AAA = readData.toHex(); // 转换为十六进制字符串 unsigned char revData[32] = { 0 }; // 存储返回数据 memcpy(revData, readData.data(), readData.size()); // 复制返回数据 if ((revData[0] == 0x03) && (revData[1] == 0x08) && (revData[2] == com[2]) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包 { bool status = CheckSumIn(revData, revData[1]); //计算校验和 if (status) { if (revData[4] == 0x00) //写数据块成功 { return No_Error; // 返回无错误 } } else { return Received_Data_Check_Error; // 校验和错误 } } else { return Received_Data_Error; // 返回数据错误 } } return Serial_Error; // 串口错误 } RFIDFunction::ErrorCode RFIDFunction::getReaderAddress(QByteArray& psw) { unsigned char com[32] = { 0 }; // 命令数组 com[0] = 0x02; // 命令头 com[1] = 0x08; // 数据长度 com[2] = 0xB0; // 命令类型 com[3] = 0x00; // 额外数据 com[4] = 0x00; // 额外数据 com[5] = 0x00; // 额外数据 com[6] = 0x00; // 额外数据 CheckSumOut(com, com[1]); // 计算校验和 QByteArray AAA = QByteArray((char*)com, com[1]).toHex(); // 转换为十六进制字符串 if (m_SerialPort->isOpen()) // 检查串口是否打开 { qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令 if (len != com[1]) // 检查发送长度 { return Send_Data_Error; // 发送错误 } // 等待请求完成 sleepMs(200); QByteArray readData = m_SerialPort->readAll(); // 读取返回数据 unsigned char revData[32] = { 0 }; // 存储返回数据 memcpy(revData, readData.data(), readData.size()); // 复制返回数据 if ((revData[0] == 0x02) && (revData[1] == 0x08) && (revData[2] == com[2])) //判断是否为写数据返回的数据包 { bool status = CheckSumIn(revData, revData[1]); //计算校验和 if (status) { if (revData[4] == 0x00) //写数据块成功 { psw = QByteArray::fromHex(QByteArray(revData[5], 1)); return No_Error; // 返回无错误 } } else { return Received_Data_Check_Error; // 校验和错误 } } else { return Received_Data_Error; // 返回数据错误 } } return Serial_Error; // 串口错误 }