STM32H533RE 使用GCM模式加密

#include "stm32h533xx.h"

#define SET_BIT(x,bit)        ((x) |= (bit))
#define CLEAR_BIT(x,bit)      ((x) &= (~(bit)))
#define CRYP_OPERATINGMODE_ENCRYPT                   0x00000000U     /*!< Encryption mode(Mode 1)  */
#define CRYP_OPERATINGMODE_KEYDERIVATION             AES_CR_MODE_0   /*!< Key derivation mode  only used when performing ECB and CBC decryptions (Mode 2) */
#define CRYP_OPERATINGMODE_DECRYPT                   AES_CR_MODE_1   /*!< Decryption    (Mode 3)    */
#define CRYP_PHASE_INIT                              0x00000000U     /*!< GCM/GMAC (or CCM) init phase */
#define CRYP_PHASE_HEADER                            AES_CR_GCMPH_0  /*!< GCM/GMAC or CCM header phase */
#define CRYP_PHASE_PAYLOAD                           AES_CR_GCMPH_1  /*!< GCM(/CCM) payload phase      */
#define CRYP_PHASE_FINAL                             AES_CR_GCMPH    /*!< GCM/GMAC or CCM  final phase */
#define CRYP_DATAWIDTHUNIT_WORD   0x00000000U  /*!< By default, size unit is word */
#define CRYP_DATAWIDTHUNIT_BYTE   0x00000001U  /*!< By default, size unit is byte */
#define CRYP_HEADERWIDTHUNIT_WORD   0x00000000U  /*!< By default, header size unit is word */
#define CRYP_HEADERWIDTHUNIT_BYTE   0x00000001U  /*!< By default, header size unit is byte */
#define CRYP_AES_ECB            0x00000000U                       /*!< Electronic codebook chaining algorithm                   */
#define CRYP_AES_CBC            AES_CR_CHMOD_0                    /*!< Cipher block chaining algorithm                          */
#define CRYP_AES_CTR            AES_CR_CHMOD_1                    /*!< Counter mode chaining algorithm                          */
#define CRYP_AES_GCM_GMAC       (AES_CR_CHMOD_0 | AES_CR_CHMOD_1) /*!< Galois counter mode - Galois message authentication code */
#define CRYP_AES_CCM            AES_CR_CHMOD_2                    /*!< Counter with Cipher Mode                                 */
#define CRYP_KEYSIZE_128B         0x00000000U          /*!< 128-bit long key */
#define CRYP_KEYSIZE_256B         AES_CR_KEYSIZE       /*!< 256-bit long key */
#define CRYP_KEYMODE_NORMAL         0x00000000U         /*!< Normal key usage, Key registers are freely usable */
#define CRYP_KEYMODE_SHARED         AES_CR_KMOD_1       /*!< Shared key */
#define CRYP_KEYMODE_WRAPPED        AES_CR_KMOD_0       /*!< Only for SAES, Wrapped key: to encrypt or decrypt AES keys */
#define CRYP_DATATYPE_32B      0x00000000U
#define CRYP_DATATYPE_16B      AES_CR_DATATYPE_0
#define CRYP_DATATYPE_8B       AES_CR_DATATYPE_1
#define CRYP_DATATYPE_1B       AES_CR_DATATYPE

#define CRYP_NO_SWAP           CRYP_DATATYPE_32B      /*!< 32-bit data type (no swapping)        */
#define CRYP_HALFWORD_SWAP     CRYP_DATATYPE_16B      /*!< 16-bit data type (half-word swapping) */
#define CRYP_BYTE_SWAP         CRYP_DATATYPE_8B       /*!< 8-bit data type (byte swapping)       */
#define CRYP_BIT_SWAP          CRYP_DATATYPE_1B       /*!< 1-bit data type (bit swapping)        */
#define CRYP_IT_CCFIE     AES_IER_CCFIE  /*!< Computation Complete interrupt enable */
#define CRYP_IT_RWEIE     AES_IER_RWEIE  /*!< Read or write Error interrupt enable  */
#define CRYP_IT_KEIE      AES_IER_KEIE   /*!< Key error interrupt enable  */
#define CRYP_IT_RNGEIE    AES_IER_RNGEIE /*!< Rng error interrupt enable  */
#define CRYP_FLAG_BUSY       AES_SR_BUSY                   /*!< GCM process suspension forbidden also set when 
                                                             transferring a shared key from SAES peripheral  */
#define CRYP_FLAG_WRERR      (AES_SR_WRERR | 0x80000000U)  /*!< Write Error flag  */
#define CRYP_FLAG_RDERR      (AES_SR_RDERR | 0x80000000U)  /*!< Read error  flag  */
#define CRYP_FLAG_CCF        AES_ISR_CCF                   /*!< Computation completed flag as  AES_ISR_CCF    */
#define CRYP_FLAG_KEYVALID   AES_SR_KEYVALID               /*!< Key Valid flag          */
#define CRYP_FLAG_KEIF       AES_ISR_KEIF                  /*!<Key error interrupt flag */
#define CRYP_FLAG_RWEIF      AES_ISR_RWEIF                 /*!<Read or write error Interrupt flag */
#define CRYP_FLAG_RNGEIF     AES_ISR_RNGEIF                /*!<RNG error interrupt flag           */
#define CRYP_CLEAR_CCF      AES_ICR_CCF    /*!< Computation Complete Flag Clear */
#define CRYP_CLEAR_RWEIF    AES_ICR_RWEIF  /*!< Clear Error Flag : RWEIF in AES_ISR and
                                              both RDERR and WRERR flags in AES_SR */
#define CRYP_CLEAR_KEIF     AES_ICR_KEIF   /*!< Clear Key Error Flag: KEIF in AES_ISR */
#define CRYP_CLEAR_RNGEIF   AES_ICR_RNGEIF /*!< Clear rng Error Flag: RNGEIF in AES_ISR */
#define CRYP_KEYIVCONFIG_ALWAYS  0x00000000U            /*!< Peripheral Key and IV configuration to do systematically */
#define CRYP_KEYIVCONFIG_ONCE    0x00000001U            /*!< Peripheral Key and IV configuration to do only once      */
#define CRYP_KEYNOCONFIG         0x00000002U            /*!< Peripheral Key configuration to not do */
#define CRYP_IVCONFIG_ONCE       0x00000004U            /*!< Peripheral IV configuration do once for interleave mode */


/**
 * @func AESReset
 * @brief AES重置
 * @retval 无
 */
static void AESReset(void)
{
    SET_BIT(AES->CR,AES_CR_IPRST); //重置AES
    CLEAR_BIT(AES->CR,AES_CR_IPRST)
}

/**
 * @func GcmOpen
 * @brief GCM算法硬件使能
 * @param dir 0-加密 1-解密
 * @retval 无
 */
static void GcmOpen(uint8_t dir) 
{
    uint32_t cr_value = 0U;
    AESReset(); // 重置AES
    /* 设置: DINR不交换, KEY长度128bit, GCM算法, 正常KEY模式 */
    cr_value = (uint32_t)(CRYP_NO_SWAP | CRYP_KEYSIZE_128B | CRYP_AES_GCM_GMAC |     CRYP_KEYMODE_NORMAL);
    MODIFY_REG(AES->CR, AES_CR_KMOD | AES_CR_DATATYPE | AES_CR_KEYSIZE | AES_CR_CHMOD, cr_value);
    if (0U == dir) 
    {
        MODIFY_REG(AES->CR, AES_CR_MODE, CRYP_OPERATINGMODE_ENCRYPT); // 设置加密模式
    } 
    else 
    {
        MODIFY_REG(AES->CR, AES_CR_MODE, CRYP_OPERATINGMODE_DECRYPT); // 设置解密模式
    }
}

/**  
 * @func SetKey  
 * @brief 设置秘钥,目前支持128bit的秘钥长度,其余长度等待拓展  
 * @param 秘钥值  
 * @param 秘钥长度(字节为单位),仅支持128bit  
 * @retval 无  
 */  
static void SetKey(const uint8_t *ekey, uint8_t keyLen) 
{  
    uint32_t temp_key[4] = {0U};  
    if (KEY_SIZE == keyLen)
    {  
        memcpy(temp_key, ekey, 16U); // 确保秘钥32位对齐  
        my_memreverse((uint8_t *)temp_key, 4U, 4U); // 每四个字节内存反序  
        /* 输入 Key */  
        AES->KEYR3 = temp_key[0];  
        AES->KEYR2 = temp_key[1];  
        AES->KEYR1 = temp_key[2];  
        AES->KEYR0 = temp_key[3];  
    } 
    else 
    {  
        return; // None  
    }  
}  
  
/**  
 * @func SetIV
 * @brief 写入初始化向量,目前支持96bit的向量长度和32bit的默认 Counter值  
 * @param IV值  
 * @param IV长度(字节为单位), 仅支持96bit  
 * @retval 无  
 */  
static void SetIV(const uint8_t *iv, uint8_t ivLen) 
{  
    uint32_t temp_iv[3] = {0U};  
    if (12U == ivLen) 
    {  
        memcpy(temp_iv, iv, 12U); // 确保IV32位对齐  
        my_memreverse((uint8_t *)temp_iv, 4U, 3U); // 每四个字节内存反序  
        /* 输入IV */  
        AES->IVR3 = temp_iv[0];  
        AES->IVR2 = temp_iv[1];  
        AES->IVR1 = temp_iv[2];  
        AES->IVR0 = 0x02; // 标准  
    } 
    else 
    {  
        return; // None  
    }  
}
/**  
 * @func InitPhase  
 * @brief GCM加密设置初始化阶段  
 * @param 秘钥值  
 * @param 秘钥长度(字节为单位)  
 * @param IV值  
 * @param IV长度(字节为单位), 仅支持96bit  
 * @retval 无  
 */  
static void InitPhase  (const uint8_t *ekey, uint8_t keyLen, uint8_t *iv, uint8_t ivLen) {  
    uint16_t wait_timer = 0U;  
    MODIFY_REG(AES->CR, AES_CR_GCMPH, CRYP_PHASE_INIT); // 设置GCM为初始化阶段  
    SetKey(ekey, keyLen); // 设置秘钥  
    SetIV(iv, ivLen); // 设置初始化向量  
  
    /* 等待KEYVALID flag生效密钥加载完成 */  
    wait_timer = 1000U;  
    while (READ_BIT(AES->SR, AES_SR_KEYVALID) == 0) {  
        halWdgReset();  
        if (--wait_timer == 0U) {  
            AESReset(); // 计算超时重置AES  
            break;  
        }  
        halMcuWaitUs(1);  
    }  
    SET_BIT(AES->CR, AES_CR_EN); // 设置EN开始计算哈希密钥。计算完成后,EN会自动清除。  
  
    /* 等待AES_ISR寄存器中的CCF标志被设置,表示GCM哈希子密钥(H)计算完成 */  
    wait_timer = 1000U;  
    while (READ_BIT(AES->ISR, AES_ISR_CCF) == 0U) {  
        halWdgReset();  
        if (--wait_timer == 0U) { // 实测进入循环1次  
            AESReset(); // 计算超时重置AES  
            break;  
        }  
        halMcuWaitUs(1);  
    }  
    SET_BIT(AES->ICR, AES_ICR_CCF); // 清除CCF标志  
}  
  
/**  
 * @func halHeaderPhase  
 * @brief GCM附加头部数据,如果是最后一个块,并且块中的AAD小于16字节,则用零填充块的其余部分,  
 *        如果没有AAD (即Len(A)=0),则可以跳过此阶段。  
 * @param aad  
 * @param aad长度(字节为单位),可任意长度  
 * @retval 无  
 */  
static void HeaderPhase(uint8_t *aad, uint16_t aadLen) {  
    uint16_t wait_timer = 0U;  
    uint32_t loopcounter = 0U; // 循环计数器  
    uint32_t temp_add[4] = {0U}; // 存储AAD值,内存对齐  
    uint8_t last_block_len = 0U; // 最后一个块的数据长度  
    uint8_t temp_arr[16] = {0}; // 临时数组,存储未16字节对齐时AAD的值  
  
    /* 如果aadLen==0,则可以跳过此阶段,在头部不设置任何数据 */  
    if (aadLen != 0U) {  
        MODIFY_REG(AES->CR, AES_CR_GCMPH, CRYP_PHASE_HEADER); // 设置GCM头部阶段  
        SET_BIT(AES->CR, AES_CR_EN); // 设置EN开始输入header。计算完成后,EN会自动清除。  
  
        /* 如果aadLen是16字节整数倍直接数据处理,否则先处理完整的块,再处理最后一个不完整块并进行填充,用0填充 */  
        last_block_len = aadLen % PLAINTEXT_SIZE; // 最后一个块的数据长度(一个块为128bit)  
        if (last_block_len == 0U) { // ADD长度为16整数倍  
            /* 不填充 */  
            for (loopcounter = 0U; (loopcounter < (aadLen / 4U)); loopcounter += 4U) {  
                memcpy(temp_add, (aad + (4 * loopcounter)), 16U); // 确保ADD32位对齐  
                my_memreverse((uint8_t *)temp_add, 4U, 4U); // 每四个字节内存反序  
                /* 写入数据寄存器 */  
                AES->DINR = temp_add[0];  
                AES->DINR = temp_add[1];  
                AES->DINR = temp_add[2];  
                AES->DINR = temp_add[3];  
  
                /* 等待AES_ISR寄存器中的CCF标志被设置,表示ADD写入成功 */  
                wait_timer = 1000U;  
                while (READ_BIT(AES->ISR, AES_ISR_CCF) == 0U) {  
                    halWdgReset();  
                    if (--wait_timer == 0U) { // 实测进入循环1次  
                        AESReset(); // 计算超时重置AES  
                        break;  
                    }  
                    halMcuWaitUs(1);  
                }  
                SET_BIT(AES->ICR, AES_ICR_CCF); // 清除CCF标志  
            }  
        } else {  
            /* 先处理完整的块 */  
            for (loopcounter = 0U; (loopcounter < ((aadLen / PLAINTEXT_SIZE) * 4U)); loopcounter += 4U) {  
                memcpy(temp_add, (aad + (4 * loopcounter)), 16U); // 确保ADD32位对齐  
                my_memreverse((uint8_t *)temp_add, 4U, 4U); // 每四个字节内存反序  
                /* 写入数据寄存器 */  
                AES->DINR = temp_add[0];  
                AES->DINR = temp_add[1];  
                AES->DINR = temp_add[2];  
                AES->DINR = temp_add[3];  
  
                /* 等待AES_ISR寄存器中的CCF标志被设置,表示ADD写入成功 */  
                wait_timer = 1000U;  
                while (READ_BIT(AES->ISR, AES_ISR_CCF) == 0U) {  
                    halWdgReset();  
                    if (--wait_timer == 0U) { // 实测进入循环1次  
                        AESReset(); // 计算超时重置AES  
                        break;  
                    }  
                    halMcuWaitUs(1);  
                }  
                SET_BIT(AES->ICR, AES_ICR_CCF); // 清除CCF标志  
            }  
  
            /* 处理不完整块,写入最后一个完整四字节 */  
            memcpy(temp_arr, (aad + (aadLen - last_block_len)), last_block_len); // 将最后一块的值放入暂存数组中  
            for (uint8_t i = last_block_len; i < 16U; i++) {  
                temp_arr[i] = 0U; // 未满16字节部分用0填充  
            }  
            my_memreverse((uint8_t *)temp_arr, 4U, 4U); // 每四个字节内存反序  
            memcpy(temp_add, temp_arr, 16U); // 确保ADD32位对齐  
            /* 写入数据寄存器 */  
            AES->DINR = temp_add[0];  
            AES->DINR = temp_add[1];  
            AES->DINR = temp_add[2];  
            AES->DINR = temp_add[3];  
  
            /* 等待AES_ISR寄存器中的CCF标志被设置,表示ADD写入成功 */  
            wait_timer = 1000U;  
            while (READ_BIT(AES->ISR, AES_ISR_CCF) == 0U) {  
                halWdgReset();  
                if (--wait_timer == 0U) { // 实测进入循环1次  
                    AESReset(); // 计算超时重置AES  
                    break;  
                }  
                halMcuWaitUs(1);  
            }  
            SET_BIT(AES->ICR, AES_ICR_CCF); // 清除CCF标志  
        }  
    } else {  
        /* Workaround 1: only AES, before re-enabling the peripheral, datatype can be configured.*/  
        MODIFY_REG(AES->CR, AES_CR_DATATYPE, CRYP_NO_SWAP);  
        MODIFY_REG(AES->CR, AES_CR_GCMPH, CRYP_PHASE_HEADER); // 设置GCM头部阶段  
    }  
}

下面是一个使用golang中的crypto库进行AES GCM模式加密文件的示例代码: ```go package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "fmt" "io" "io/ioutil" "os" ) func main() { // 读取原始文件 data, err := ioutil.ReadFile("plaintext.txt") if err != nil { panic(err) } // 随机生成16字节的密钥 key := make([]byte, 16) if _, err := io.ReadFull(rand.Reader, key); err != nil { panic(err) } // 创建GCM加密器 block, err := aes.NewCipher(key) if err != nil { panic(err) } aesgcm, err := cipher.NewGCM(block) if err != nil { panic(err) } // 随机生成12字节的IV iv := make([]byte, 12) if _, err := io.ReadFull(rand.Reader, iv); err != nil { panic(err) } // 使用GCM加密数据 ciphertext := aesgcm.Seal(nil, iv, data, nil) // 将密钥和IV写入文件开头 output := append(key, iv...) // 将加密数据写入文件尾部 output = append(output, ciphertext...) // 将加密结果写入文件 err = ioutil.WriteFile("ciphertext.bin", output, 0644) if err != nil { panic(err) } fmt.Println("Encryption complete.") } ``` 这个示例代码中,我们首先读取要加密的文件的内容。然后,我们使用crypto库中提供的`aes.NewCipher`函数创建一个AES加密器,并使用这个加密器创建一个GCM加密器。接下来,我们随机生成一个16字节的密钥和一个12字节的IV,然后使用GCM加密器对原始数据进行加密。最后,我们将密钥和IV写入加密文件的开头,将加密数据写入文件的尾部。 注意,在实际应用中,我们应该使用更加安全的方式来生成密钥和IV,例如使用密码学安全的伪随机数生成器。此外,我们也应该对加密文件进行适当的保护,例如使用密码或者其他的访问控制措施。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值