首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >加密算法和密钥管理

加密算法和密钥管理

原创
作者头像
程序员良许
发布2026-02-28 09:17:35
发布2026-02-28 09:17:35
1090
举报

大家好,我是良许。

在嵌入式系统开发中,数据安全越来越受到重视。

无论是智能家居设备、汽车电子系统,还是工业控制设备,都需要保护敏感数据不被窃取或篡改。

加密算法和密钥管理是保障数据安全的两大核心技术。

今天我们就来聊聊这个话题,看看在嵌入式开发中如何正确使用加密算法,以及如何安全地管理密钥。

1. 加密算法基础

1.1 对称加密算法

对称加密是指加密和解密使用相同密钥的算法。

这类算法的优点是速度快、效率高,非常适合嵌入式系统资源受限的场景。

常见的对称加密算法包括AES、DES、3DES等,其中AES(高级加密标准)是目前最广泛使用的对称加密算法。

在STM32等嵌入式平台上,我们经常使用AES算法来加密敏感数据。

AES支持128位、192位和256位三种密钥长度,密钥越长安全性越高,但计算开销也越大。

对于大多数嵌入式应用来说,AES-128已经足够安全,而且性能表现良好。

举个实际的例子,假设我们要在STM32上加密一段传感器数据,可以使用HAL库提供的加密功能:

代码语言:c
复制
#include "stm32f4xx_hal.h"

CRYP_HandleTypeDef hcryp;

// 初始化AES加密模块
void AES_Init(void)
{
    __HAL_RCC_CRYP_CLK_ENABLE();
    
    hcryp.Instance = CRYP;
    hcryp.Init.DataType = CRYP_DATATYPE_8B;
    hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
    hcryp.Init.Algorithm = CRYP_AES_ECB;
    
    if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    {
        Error_Handler();
    }
}

// AES加密函数
HAL_StatusTypeDef AES_Encrypt(uint8_t *plaintext, uint8_t *key, 
                               uint8_t *ciphertext, uint16_t size)
{
    HAL_StatusTypeDef status;
    
    // 设置密钥
    hcryp.Init.pKey = (uint32_t *)key;
    
    if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    {
        return HAL_ERROR;
    }
    
    // 执行加密
    status = HAL_CRYP_Encrypt(&hcryp, (uint32_t *)plaintext, 
                              size, (uint32_t *)ciphertext, 1000);
    
    return status;
}

// AES解密函数
HAL_StatusTypeDef AES_Decrypt(uint8_t *ciphertext, uint8_t *key, 
                               uint8_t *plaintext, uint16_t size)
{
    HAL_StatusTypeDef status;
    
    hcryp.Init.pKey = (uint32_t *)key;
    
    if (HAL_CRYP_Init(&hcryp) != HAL_OK)
    {
        return HAL_ERROR;
    }
    
    status = HAL_CRYP_Decrypt(&hcryp, (uint32_t *)ciphertext, 
                              size, (uint32_t *)plaintext, 1000);
    
    return status;
}

这段代码展示了如何在STM32上使用硬件加密模块进行AES加密和解密。

需要注意的是,不是所有STM32型号都带有硬件加密模块,如果你的芯片不支持,可以使用软件实现的AES库,比如mbedTLS或者TinyCrypt。

1.2 非对称加密算法

非对称加密使用一对密钥:公钥和私钥。

公钥用于加密,私钥用于解密,或者反过来用于数字签名。

常见的非对称加密算法有RSA、ECC(椭圆曲线加密)等。

非对称加密的优点是密钥分发方便,公钥可以公开传输,不用担心被截获。

但缺点是计算量大,速度慢,不适合加密大量数据。

在嵌入式系统中,我们通常使用非对称加密来交换对称密钥,或者用于数字签名验证固件的完整性。

比如在汽车电子系统中,ECU(电子控制单元)固件更新时,就需要验证固件的数字签名,确保固件来自可信的来源,没有被篡改。

这个过程就用到了非对称加密算法。

代码语言:c
复制
#include "mbedtls/rsa.h"
#include "mbedtls/sha256.h"

// 验证固件签名
int verify_firmware_signature(uint8_t *firmware, uint32_t fw_size,
                               uint8_t *signature, uint8_t *public_key)
{
    mbedtls_rsa_context rsa;
    unsigned char hash[32];
    int ret;
    
    // 计算固件的SHA-256哈希值
    mbedtls_sha256(firmware, fw_size, hash, 0);
    
    // 初始化RSA上下文
    mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
    
    // 导入公钥
    ret = mbedtls_rsa_import_raw(&rsa, 
                                 public_key, 256,     // N
                                 NULL, 0,             // P
                                 NULL, 0,             // Q
                                 NULL, 0,             // D
                                 public_key + 256, 4); // E
    
    if (ret != 0)
    {
        mbedtls_rsa_free(&rsa);
        return -1;
    }
    
    // 验证签名
    ret = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL,
                                   MBEDTLS_RSA_PUBLIC,
                                   MBEDTLS_MD_SHA256,
                                   32, hash, signature);
    
    mbedtls_rsa_free(&rsa);
    
    return ret;
}

这个例子展示了如何使用RSA算法验证固件签名。

实际应用中,我们会先用SHA-256计算固件的哈希值,然后用RSA公钥验证签名是否正确。

如果验证通过,说明固件确实来自可信的发布者,并且没有被篡改。

1.3 哈希算法

哈希算法虽然不是加密算法,但在密码学中同样重要。

哈希算法可以将任意长度的数据转换成固定长度的哈希值,具有单向性和抗碰撞性。

常见的哈希算法有MD5、SHA-1、SHA-256等,其中SHA-256是目前推荐使用的安全哈希算法。

在嵌入式系统中,哈希算法常用于密码存储、数据完整性校验、消息认证码(MAC)等场景。

比如我们在设备上存储用户密码时,不应该直接存储明文密码,而是存储密码的哈希值。

当用户登录时,我们计算输入密码的哈希值,与存储的哈希值比对,如果一致则认证通过。

代码语言:c
复制
#include "mbedtls/sha256.h"
#include <string.h>

// 存储的密码哈希值
uint8_t stored_password_hash[32];

// 设置密码(初始化时调用)
void set_password(const char *password)
{
    mbedtls_sha256((uint8_t *)password, strlen(password), 
                   stored_password_hash, 0);
}

// 验证密码
int verify_password(const char *input_password)
{
    uint8_t input_hash[32];
    
    // 计算输入密码的哈希值
    mbedtls_sha256((uint8_t *)input_password, strlen(input_password), 
                   input_hash, 0);
    
    // 比对哈希值
    if (memcmp(stored_password_hash, input_hash, 32) == 0)
    {
        return 1; // 密码正确
    }
    else
    {
        return 0; // 密码错误
    }
}

这种方式即使数据库被攻击者获取,攻击者也无法直接得到用户的明文密码,因为哈希算法是单向的,无法从哈希值反推出原始密码。

当然,实际应用中我们还会加盐(salt)来进一步提高安全性,防止彩虹表攻击。

2. 密钥管理策略

2.1 密钥生成

密钥的安全性直接决定了加密系统的安全性。

一个好的密钥应该具有足够的随机性和熵值。

在嵌入式系统中,我们可以使用硬件随机数生成器(TRNG)来生成高质量的随机密钥。

STM32系列芯片通常都集成了硬件随机数生成器,我们可以利用它来生成密钥:

代码语言:c
复制
#include "stm32f4xx_hal.h"

RNG_HandleTypeDef hrng;

// 初始化随机数生成器
void RNG_Init(void)
{
    __HAL_RCC_RNG_CLK_ENABLE();
    
    hrng.Instance = RNG;
    
    if (HAL_RNG_Init(&hrng) != HAL_OK)
    {
        Error_Handler();
    }
}

// 生成AES密钥
HAL_StatusTypeDef generate_aes_key(uint8_t *key, uint16_t key_size)
{
    uint32_t random_number;
    HAL_StatusTypeDef status;
    
    for (uint16_t i = 0; i < key_size; i += 4)
    {
        status = HAL_RNG_GenerateRandomNumber(&hrng, &random_number);
        
        if (status != HAL_OK)
        {
            return status;
        }
        
        // 将32位随机数拆分成4个字节
        key[i] = (random_number >> 0) & 0xFF;
        key[i+1] = (random_number >> 8) & 0xFF;
        key[i+2] = (random_number >> 16) & 0xFF;
        key[i+3] = (random_number >> 24) & 0xFF;
    }
    
    return HAL_OK;
}

使用硬件随机数生成器生成的密钥具有很好的随机性,可以有效抵御暴力破解攻击。

如果芯片不支持硬件随机数生成器,我们也可以使用软件方法,比如收集系统运行时的各种不确定因素(如ADC噪声、定时器计数值等)作为熵源来生成随机数。

2.2 密钥存储

密钥的存储是密钥管理中最关键的环节。

如果密钥被攻击者获取,整个加密系统就形同虚设。

在嵌入式系统中,我们有几种常见的密钥存储方案:

第一种是将密钥存储在Flash中。

这是最简单的方法,但安全性较低,因为Flash的内容可以通过调试接口读取。

为了提高安全性,我们可以启用Flash读保护功能,防止通过JTAG或SWD接口读取Flash内容。

代码语言:c
复制
// 在Flash中定义密钥存储区域(使用__attribute__指定地址)
__attribute__((section(".key_section"))) 
const uint8_t aes_key[16] = {
    0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
    0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
};

// 启用Flash读保护
void enable_flash_protection(void)
{
    FLASH_OBProgramInitTypeDef ob_config;
    
    HAL_FLASH_Unlock();
    HAL_FLASH_OB_Unlock();
    
    ob_config.OptionType = OPTIONBYTE_RDP;
    ob_config.RDPLevel = OB_RDP_LEVEL_1; // 设置读保护级别1
    
    if (HAL_FLASHEx_OBProgram(&ob_config) != HAL_OK)
    {
        Error_Handler();
    }
    
    HAL_FLASH_OB_Launch(); // 使配置生效
    HAL_FLASH_OB_Lock();
    HAL_FLASH_Lock();
}

第二种是使用安全元件或加密芯片。

这些专用芯片内部有安全存储区域,密钥存储在芯片内部,永远不会以明文形式暴露出来。

加密操作也在芯片内部完成,即使攻击者物理接触到设备,也很难提取出密钥。

常见的安全芯片有ATECC608、SE050等。

第三种是使用芯片的OTP(一次性可编程)区域或安全存储区域。

比如STM32L5系列芯片提供了TrustZone技术,可以将密钥存储在安全区域,只有安全代码才能访问。

2.3 密钥分发与交换

在实际应用中,我们经常需要在多个设备之间共享密钥,或者动态更新密钥。

密钥分发和交换是一个复杂的问题,需要仔细设计。

对于对称加密,我们可以使用密钥交换协议,比如Diffie-Hellman密钥交换协议。

这个协议允许两个设备在不安全的信道上协商出一个共享密钥,而不用担心被窃听。

代码语言:c
复制
#include "mbedtls/dhm.h"

mbedtls_dhm_context dhm;

// 初始化DH密钥交换
int dhm_init(void)
{
    const char *dhm_P = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
                        "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
                        "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
                        "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
                        "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
                        "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
                        "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
                        "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
                        "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
                        "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
                        "15728E5A8AACAA68FFFFFFFFFFFFFFFF";
    
    const char *dhm_G = "02";
    
    mbedtls_dhm_init(&dhm);
    
    return mbedtls_mpi_read_string(&dhm.P, 16, dhm_P) ||
           mbedtls_mpi_read_string(&dhm.G, 16, dhm_G);
}

// 生成公钥
int dhm_make_public(uint8_t *output, size_t *olen)
{
    int ret;
    
    ret = mbedtls_dhm_make_public(&dhm, 256, output, *olen,
                                  mbedtls_ctr_drbg_random, &ctr_drbg);
    
    if (ret == 0)
    {
        *olen = mbedtls_mpi_size(&dhm.GX);
    }
    
    return ret;
}

// 计算共享密钥
int dhm_calc_secret(uint8_t *peer_public, size_t peer_len,
                    uint8_t *output, size_t *olen)
{
    int ret;
    
    ret = mbedtls_dhm_read_public(&dhm, peer_public, peer_len);
    
    if (ret != 0)
    {
        return ret;
    }
    
    ret = mbedtls_dhm_calc_secret(&dhm, output, *olen, olen,
                                  mbedtls_ctr_drbg_random, &ctr_drbg);
    
    return ret;
}

通过DH密钥交换,两个设备可以各自生成一对公私钥,交换公钥后计算出相同的共享密钥。

这个共享密钥可以用作AES等对称加密算法的密钥。

另一种常见的方案是使用非对称加密来传输对称密钥。

发送方用接收方的公钥加密对称密钥,接收方用自己的私钥解密得到对称密钥。

这种方式结合了非对称加密的密钥分发优势和对称加密的高效性。

2.4 密钥更新与撤销

密钥不应该永久使用,定期更新密钥可以降低密钥泄露的风险。

在嵌入式系统中,我们可以设计密钥更新机制,比如每隔一定时间或者传输一定数量的数据后自动更新密钥。

代码语言:c
复制
#include <time.h>

typedef struct {
    uint8_t key[16];
    time_t creation_time;
    uint32_t usage_count;
} key_info_t;

key_info_t current_key;

#define KEY_LIFETIME_SECONDS (24 * 3600)  // 密钥有效期24小时
#define KEY_USAGE_LIMIT 10000              // 密钥使用次数限制

// 检查是否需要更新密钥
int check_key_update_needed(void)
{
    time_t current_time = time(NULL);
    
    // 检查密钥是否过期
    if (current_time - current_key.creation_time > KEY_LIFETIME_SECONDS)
    {
        return 1;
    }
    
    // 检查密钥使用次数是否超限
    if (current_key.usage_count > KEY_USAGE_LIMIT)
    {
        return 1;
    }
    
    return 0;
}

// 更新密钥
int update_key(void)
{
    // 生成新密钥
    if (generate_aes_key(current_key.key, 16) != HAL_OK)
    {
        return -1;
    }
    
    // 更新密钥信息
    current_key.creation_time = time(NULL);
    current_key.usage_count = 0;
    
    // 保存新密钥到安全存储
    save_key_to_flash(&current_key);
    
    return 0;
}

// 使用密钥进行加密
int encrypt_with_key_management(uint8_t *plaintext, uint8_t *ciphertext, 
                                 uint16_t size)
{
    // 检查是否需要更新密钥
    if (check_key_update_needed())
    {
        if (update_key() != 0)
        {
            return -1;
        }
    }
    
    // 执行加密
    if (AES_Encrypt(plaintext, current_key.key, ciphertext, size) != HAL_OK)
    {
        return -1;
    }
    
    // 增加使用计数
    current_key.usage_count++;
    
    return 0;
}

这个例子展示了一个简单的密钥更新机制,根据时间和使用次数来决定是否更新密钥。

实际应用中,密钥更新还需要考虑与对端设备的同步问题,确保双方使用相同的密钥。

3. 实际应用案例

3.1 安全固件升级

在我之前做汽车电子项目时,ECU固件升级是一个非常重要的功能。

我们需要确保只有经过授权的固件才能被安装到ECU上,防止恶意固件被植入。

整个流程是这样的:首先,固件在发布时会用私钥进行签名。

ECU在接收到新固件后,会用预先存储的公钥验证签名。

只有签名验证通过的固件才会被安装。

同时,固件本身是加密的,使用AES加密,密钥通过安全信道传输到ECU。

代码语言:c
复制
typedef struct {
    uint32_t version;
    uint32_t size;
    uint8_t signature[256];
    uint8_t encrypted_firmware[];
} firmware_package_t;

// 固件升级流程
int firmware_upgrade(firmware_package_t *package)
{
    uint8_t *decrypted_firmware;
    uint8_t aes_key[16];
    
    // 1. 验证固件签名
    if (verify_firmware_signature(package->encrypted_firmware,
                                   package->size,
                                   package->signature,
                                   public_key) != 0)
    {
        printf("Signature verification failed!\n");
        return -1;
    }
    
    // 2. 获取解密密钥(通过安全信道)
    if (get_decryption_key(aes_key) != 0)
    {
        printf("Failed to get decryption key!\n");
        return -1;
    }
    
    // 3. 解密固件
    decrypted_firmware = malloc(package->size);
    if (AES_Decrypt(package->encrypted_firmware, aes_key,
                    decrypted_firmware, package->size) != HAL_OK)
    {
        printf("Firmware decryption failed!\n");
        free(decrypted_firmware);
        return -1;
    }
    
    // 4. 写入Flash
    if (write_firmware_to_flash(decrypted_firmware, package->size) != 0)
    {
        printf("Failed to write firmware to flash!\n");
        free(decrypted_firmware);
        return -1;
    }
    
    free(decrypted_firmware);
    
    printf("Firmware upgrade successful!\n");
    return 0;
}

这种方案结合了非对称加密(数字签名)和对称加密(AES加密固件),既保证了固件来源的可信性,又保护了固件内容不被窃取。

3.2 安全通信

在物联网设备中,设备与云端服务器之间的通信需要加密保护。

我们通常使用TLS/SSL协议来建立安全连接。

TLS协议内部就综合使用了对称加密、非对称加密和哈希算法。

在嵌入式Linux系统上,我们可以使用OpenSSL或mbedTLS库来实现TLS通信:

代码语言:c
复制
#include "mbedtls/net_sockets.h"
#include "mbedtls/ssl.h"

mbedtls_net_context server_fd;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;

// 建立TLS连接
int establish_tls_connection(const char *server_addr, const char *server_port)
{
    int ret;
    
    // 初始化
    mbedtls_net_init(&server_fd);
    mbedtls_ssl_init(&ssl);
    mbedtls_ssl_config_init(&conf);
    
    // 连接服务器
    ret = mbedtls_net_connect(&server_fd, server_addr, server_port,
                              MBEDTLS_NET_PROTO_TCP);
    if (ret != 0)
    {
        printf("Failed to connect to server\n");
        return -1;
    }
    
    // 配置SSL
    ret = mbedtls_ssl_config_defaults(&conf,
                                      MBEDTLS_SSL_IS_CLIENT,
                                      MBEDTLS_SSL_TRANSPORT_STREAM,
                                      MBEDTLS_SSL_PRESET_DEFAULT);
    if (ret != 0)
    {
        printf("Failed to set SSL config\n");
        return -1;
    }
    
    mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
    mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
    mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
    
    ret = mbedtls_ssl_setup(&ssl, &conf);
    if (ret != 0)
    {
        printf("Failed to setup SSL\n");
        return -1;
    }
    
    mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send,
                        mbedtls_net_recv, NULL);
    
    // 执行SSL握手
    while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
    {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
            ret != MBEDTLS_ERR_SSL_WANT_WRITE)
        {
            printf("SSL handshake failed\n");
            return -1;
        }
    }
    
    printf("TLS connection established\n");
    return 0;
}

// 通过TLS发送数据
int tls_send_data(const uint8_t *data, size_t len)
{
    int ret;
    
    while ((ret = mbedtls_ssl_write(&ssl, data, len)) <= 0)
    {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
            ret != MBEDTLS_ERR_SSL_WANT_WRITE)
        {
            printf("Failed to send data\n");
            return -1;
        }
    }
    
    return ret;
}

// 通过TLS接收数据
int tls_receive_data(uint8_t *buffer, size_t max_len)
{
    int ret;
    
    ret = mbedtls_ssl_read(&ssl, buffer, max_len);
    
    if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
        ret == MBEDTLS_ERR_SSL_WANT_WRITE)
    {
        return 0;
    }
    
    if (ret < 0)
    {
        printf("Failed to receive data\n");
        return -1;
    }
    
    return ret;
}

TLS协议在握手阶段使用非对称加密交换密钥,在数据传输阶段使用对称加密保护数据,同时使用哈希算法确保数据完整性。

这种设计兼顾了安全性和性能。

4. 安全实践建议

在实际开发中,我总结了一些加密算法和密钥管理的最佳实践:

第一,永远不要自己实现加密算法。

加密算法的实现非常复杂,稍有不慎就会引入安全漏洞。

应该使用经过广泛验证的加密库,比如mbedTLS、OpenSSL、wolfSSL等。

第二,不要在代码中硬编码密钥。

硬编码的密钥很容易被反编译工具提取出来。

应该使用安全存储方案,比如安全芯片、OTP区域等。

第三,使用足够长的密钥。

对于AES算法,至少使用128位密钥;对于RSA算法,至少使用2048位密钥。

密钥长度直接影响安全强度。

第四,定期更新密钥。

不要让一个密钥永久使用,应该根据实际情况设计密钥更新策略。

第五,保护密钥的整个生命周期。

从密钥生成、存储、使用到销毁,每个环节都要考虑安全性。

特别是密钥销毁时,要确保密钥被彻底清除,不能留下任何痕迹。

第六,使用硬件加密加速器。

现代MCU通常都集成了硬件加密模块,使用硬件加密不仅速度快,而且更安全,因为密钥操作在硬件内部完成,不容易被侧信道攻击。

第七,进行安全测试。

在产品发布前,应该进行充分的安全测试,包括密码学分析、渗透测试等,确保加密系统没有明显的安全漏洞。

加密算法和密钥管理是一个复杂的话题,涉及的知识点很多。

但只要我们遵循安全最佳实践,选择合适的加密方案,就能够为嵌入式系统构建起坚固的安全防线。

在这个万物互联的时代,数据安全变得越来越重要,作为嵌入式开发者,我们有责任保护好用户的数据安全。

更多编程学习资源

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 加密算法基础
    • 1.1 对称加密算法
    • 1.2 非对称加密算法
    • 1.3 哈希算法
  • 2. 密钥管理策略
    • 2.1 密钥生成
    • 2.2 密钥存储
    • 2.3 密钥分发与交换
    • 2.4 密钥更新与撤销
  • 3. 实际应用案例
    • 3.1 安全固件升级
    • 3.2 安全通信
  • 4. 安全实践建议
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档