I Love mcu
欢迎光临我爱单片机博客!

STC15F104W单片机模拟加密芯片代码

#include <STC15F104W.h>  // STC15F104W单片机头文件
#include <intrins.h>     // 包含_nop_()等 intrinsic 函数
/**
 * 基于STC15F104W的加密芯片模拟
 * 利用STC15F104W内置EEPROM存储密钥和加密数据
 * 功能特性:
 * 1. 数据加密存储
 * 2. 密钥管理
 * 3. 数据完整性校验
 * 4. 断电数据保持
 */
// EEPROM地址定义
#define EEPROM_KEY_ADDR 0x00  // 密钥存储地址,占用8字节
#define EEPROM_DATA_ADDR 0x10  // 数据存储起始地址
#define EEPROM_SIZE 128  // STC15F104W内置EEPROM大小(128字节)
// 密钥长度
#define KEY_LENGTH 8  // 密钥长度为8字节
/**
 * 延时函数
 * @param ms 延时毫秒数
 * @note 该延时函数适用于12MHz晶振的STC15F104W
 */
void Delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 120; j++);  // 循环120次约为1ms
}
/**
 * 写EEPROM
 * @param addr EEPROM地址
 * @param dat 要写入的数据
 * @note STC15F104W的EEPROM操作需要使用IAP指令
 * @note 每次写入后需要延时5ms以确保数据写入完成
 */
void EEPROM_Write(unsigned char addr, unsigned char dat)
{
    IAP_CONTR = 0x80;  // 使能IAP操作,设置等待时间为0
    IAP_CMD = 0x02;    // 设置为写命令
    IAP_ADDRH = addr >> 8;  // 设置地址高8位
    IAP_ADDRL = addr;       // 设置地址低8位
    IAP_DATA = dat;         // 设置要写入的数据
    IAP_TRIG = 0x5A;   // 触发IAP操作,第一个触发字节
    IAP_TRIG = 0xA5;   // 触发IAP操作,第二个触发字节
    _nop_();           // 空操作,确保操作完成
    IAP_CONTR = 0x00;  // 禁用IAP操作,关闭IAP功能
}
/**
 * 读EEPROM
 * @param addr EEPROM地址
 * @return 读取的数据
 * @note STC15F104W的EEPROM操作需要使用IAP指令
 */
unsigned char EEPROM_Read(unsigned char addr)
{
    unsigned char dat;
    IAP_CONTR = 0x80;  // 使能IAP操作,设置等待时间为0
    IAP_CMD = 0x01;    // 设置为读命令
    IAP_ADDRH = addr >> 8;  // 设置地址高8位
    IAP_ADDRL = addr;       // 设置地址低8位
    IAP_TRIG = 0x5A;   // 触发IAP操作,第一个触发字节
    IAP_TRIG = 0xA5;   // 触发IAP操作,第二个触发字节
    _nop_();           // 空操作,确保操作完成
    dat = IAP_DATA;    // 读取数据
    IAP_CONTR = 0x00;  // 禁用IAP操作,关闭IAP功能
    return dat;
}
/**
 * 简单的异或加密算法
 * @param data 要加密的数据
 * @param len 数据长度
 * @param key 密钥
 * @param key_len 密钥长度
 * @note 异或加密是一种对称加密算法,相同的密钥可以用于加密和解密
 * @note 当密钥长度小于数据长度时,会循环使用密钥
 */
void encrypt_data(unsigned char *data, unsigned char len, unsigned char *key, unsigned char key_len)
{
    unsigned char i;
    for (i = 0; i < len; i++)
    {
        data[i] ^= key[i % key_len];  // 异或加密,使用循环密钥
    }
}
/**
 * 简单的异或解密算法
 * @param data 要解密的数据
 * @param len 数据长度
 * @param key 密钥
 * @param key_len 密钥长度
 * @note 由于异或运算的特性,加密和解密使用相同的算法
 */
void decrypt_data(unsigned char *data, unsigned char len, unsigned char *key, unsigned char key_len)
{
    // 异或加密和解密使用相同的算法
    // 因为 A ^ B ^ B = A,所以再次异或相同的密钥即可解密
    encrypt_data(data, len, key, key_len);
}
/**
 * 计算CRC校验值
 * @param data 数据
 * @param len 数据长度
 * @return CRC校验值
 * @note 使用CRC-8算法,多项式为0x31 (x^8 + x^5 + x^4 + 1)
 * @note CRC校验用于检测数据传输或存储过程中的错误
 */
unsigned char calculate_crc(unsigned char *data, unsigned char len)
{
    unsigned char crc = 0x00;  // 初始CRC值
    unsigned char i, j;
    for (i = 0; i < len; i++)
    {
        crc ^= data[i];  // 与当前数据字节异或
        for (j = 0; j < 8; j++)  // 处理每个比特位
        {
            if (crc & 0x80)  // 如果最高位为1
                crc = (crc << 1) ^ 0x31;  // 左移并与多项式异或
            else
                crc <<= 1;  // 左移
        }
    }
    return crc;  // 返回计算得到的CRC值
}
/**
 * 从EEPROM读取密钥
 * @param key 密钥缓冲区
 * @note 从EEPROM的密钥存储区域读取8字节密钥
 */
void read_key(unsigned char *key)
{
    unsigned char i;
    for (i = 0; i < KEY_LENGTH; i++)
    {
        key[i] = EEPROM_Read(EEPROM_KEY_ADDR + i);  // 依次读取8字节密钥
    }
}
/**
 * 向EEPROM写入密钥
 * @param key 密钥
 * @note 向EEPROM的密钥存储区域写入8字节密钥
 * @note 每次写入后需要延时5ms以确保数据写入完成
 */
void write_key(unsigned char *key)
{
    unsigned char i;
    for (i = 0; i < KEY_LENGTH; i++)
    {
        EEPROM_Write(EEPROM_KEY_ADDR + i, key[i]);  // 依次写入8字节密钥
        Delay_ms(5);  // EEPROM写入需要延时
    }
}
/**
 * 验证密钥
 * @param key 要验证的密钥
 * @return 验证结果,0成功,1失败
 * @note 比较输入密钥与存储在EEPROM中的密钥是否一致
 */
unsigned char verify_key(unsigned char *key)
{
    unsigned char stored_key[KEY_LENGTH];
    unsigned char i;
    read_key(stored_key);  // 读取存储的密钥
    for (i = 0; i < KEY_LENGTH; i++)
    {
        if (key[i] != stored_key[i])  // 逐字节比较
            return 1;  // 验证失败
    }
    return 0;  // 验证成功
}
/**
 * 更改密钥
 * @param old_key 旧密钥
 * @param new_key 新密钥
 * @return 操作结果,0成功,1失败
 * @note 只有提供正确的旧密钥才能更改密钥
 */
unsigned char change_key(unsigned char *old_key, unsigned char *new_key)
{
    // 验证旧密钥
    if (verify_key(old_key))
        return 1;  // 旧密钥验证失败
    // 写入新密钥
    write_key(new_key);
    return 0;  // 密钥更改成功
}
/**
 * 写入数据到加密芯片
 * @param addr 数据地址(相对于数据存储区起始地址)
 * @param data 数据
 * @param len 数据长度
 * @return 操作结果,0成功,1失败
 * @note 数据会先加密再存储,并在数据末尾添加CRC校验值
 */
unsigned char write_data(unsigned char addr, unsigned char *data, unsigned char len)
{
    unsigned char key[KEY_LENGTH];
    unsigned char i;
    unsigned char crc;
    // 检查地址和长度是否合法
    // 预留1字节用于存储CRC校验值
    if (addr + len + 1 > (EEPROM_SIZE – EEPROM_DATA_ADDR))
        return 1;  // 地址或长度超出范围
    // 读取密钥
    read_key(key);
    // 加密数据
    encrypt_data(data, len, key, KEY_LENGTH);
    // 计算CRC校验值
    crc = calculate_crc(data, len);
    // 写入加密后的数据
    for (i = 0; i < len; i++)
    {
        EEPROM_Write(EEPROM_DATA_ADDR + addr + i, data[i]);
        Delay_ms(5);  // 延时确保写入完成
    }
    // 写入CRC校验值
    EEPROM_Write(EEPROM_DATA_ADDR + addr + len, crc);
    Delay_ms(5);  // 延时确保写入完成
    return 0;  // 写入成功
}
/**
 * 从加密芯片读取数据
 * @param addr 数据地址(相对于数据存储区起始地址)
 * @param data 数据缓冲区
 * @param len 数据长度
 * @return 操作结果,0成功,1失败,2 CRC校验错误
 * @note 读取数据后会先验证CRC,然后解密
 */
unsigned char read_data(unsigned char addr, unsigned char *data, unsigned char len)
{
    unsigned char key[KEY_LENGTH];
    unsigned char i;
    unsigned char stored_crc, calculated_crc;
    // 检查地址和长度是否合法
    if (addr + len + 1 > (EEPROM_SIZE – EEPROM_DATA_ADDR))
        return 1;  // 地址或长度超出范围
    // 读取密钥
    read_key(key);
    // 读取加密数据
    for (i = 0; i < len; i++)
    {
        data[i] = EEPROM_Read(EEPROM_DATA_ADDR + addr + i);
    }
    // 读取存储的CRC校验值
    stored_crc = EEPROM_Read(EEPROM_DATA_ADDR + addr + len);
    // 计算读取数据的CRC校验值
    calculated_crc = calculate_crc(data, len);
    // 验证CRC校验值
    if (stored_crc != calculated_crc)
        return 2;  // CRC校验错误
    // 解密数据
    decrypt_data(data, len, key, KEY_LENGTH);
    return 0;  // 读取成功
}
/**
 * 加密芯片初始化
 * 首次使用时设置默认密钥
 * @note 检查密钥存储区域是否为空白(全0xFF),如果是则设置默认密钥
 */
void crypto_chip_init(void)
{
    unsigned char default_key[KEY_LENGTH] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};
    unsigned char i;
    unsigned char blank_check = 0xFF;
    // 检查密钥是否已设置
    for (i = 0; i < KEY_LENGTH; i++)
    {
        blank_check &= EEPROM_Read(EEPROM_KEY_ADDR + i);
    }
    // 如果密钥未设置(EEPROM为全0xFF),设置默认密钥
    if (blank_check == 0xFF)
    {
        write_key(default_key);
    }
}
/**
 * 主函数
 * @note 测试加密芯片的基本功能
 */
void main(void)
{
    unsigned char test_data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};  // 测试数据
    unsigned char read_data_buf[8];  // 存储读取的数据
    unsigned char i;  // 循环变量
    unsigned char result;  // 操作结果
    // 初始化加密芯片
    crypto_chip_init();
    // 测试写入数据
    result = write_data(0x00, test_data, 8);
    if (result == 0)
    {
        // 写入成功,测试读取数据
        result = read_data(0x00, read_data_buf, 8);
        if (result == 0)
        {
            // 读取成功,验证读取的数据是否与写入的数据一致
            for (i = 0; i < 8; i++)
            {
                if (test_data[i] != read_data_buf[i])
                {
                    // 数据不一致,处理错误
                    // 实际应用中可以添加错误处理代码
                }
            }
        }
        else if (result == 1)
        {
            // 地址或长度错误
        }
        else if (result == 2)
        {
            // CRC校验错误
        }
    }
    while (1);  // 程序循环
}
赞(1) 打赏
分享到

评论 抢沙发

我爱单片机博客

单片机开发、学习、交流与分享博客!

关于我们联系我们

登录

找回密码

注册