nRF52832——唯一 ID 与加密解密

2024-03-13 22:04
文章标签 解密 加密 id 唯一 nrf52832

本文主要是介绍nRF52832——唯一 ID 与加密解密,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

nRF52832——唯一 ID 与加密解密

  • 唯一 ID 概念
    • 唯一 ID 作用
    • 读取唯一 ID
  • 唯一 ID 用于加密
    • TEA 加密算法
    • 唯一 ID 的加密和解密


唯一 ID 概念

唯一 ID 作用

nRF52xx 微控制器提供一组 64 位的唯一 ID 号,这个唯一身份标识所提供的 ID 值对任意一个 nRF52xx 微控制器,在任何情况下都是唯一的。用户在何种情况下,都不能修改这个身份标识。按照用户不同的用法,可以以字节(8 位)为单位读取,也可以以半字(16 位)或者全字(32 位)读取。对应唯一ID 号,常见的应用场合如下面几种:

  • 用来作为序列号;
  • 用来作为密码,在编写闪存时,将此唯一标识与软件加解密算法结合使用,提高代码在闪 存存储器内的安全性;
  • 用来激活带安全机制的自举过程;

读取唯一 ID

设备唯一 ID 保存存在寄存器 FICR 中:工厂信息配置寄存器(FICR)是在工厂预先编程的,用户不能删除。这些寄存器包含特定于芯片的信息和配置。

寄存器名称偏移地址描述
DEVICE ID[0]0x060设备 identifier
DEVICE ID[1]0x064设备 identitier

因此识别芯片中的唯一 ID 的方式就是读取寄存器 DEVICEID 内的值,因为这个参数值是不能修改的,出厂的时候由厂家固化的。因此寄存器 DEVICEID 为只读寄存器,我们在串口例子基础上就行修改,因此工程结构不就行修改。读取了唯一 ID 的寄存器值后,通过串口打印输出,来进行演示。编写程序如下所示:


#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "app_uart.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf.h"
#include "bsp.h"
#if defined (UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined (UARTE_PRESENT)
#include "nrf_uarte.h"
#endif//#define ENABLE_LOOPBACK_TEST  /**< if defined, then this example will be a loopback test, which means that TX should be connected to RX to get data loopback. */#define MAX_TEST_DATA_BYTES     (15U)                /**< max number of test bytes to be used for tx and rx. */
#define UART_TX_BUF_SIZE 256                         /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256                         /**< UART RX buffer size. */void uart_error_handle(app_uart_evt_t * p_event)
{if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR){APP_ERROR_HANDLER(p_event->data.error_communication);}else if (p_event->evt_type == APP_UART_FIFO_ERROR){APP_ERROR_HANDLER(p_event->data.error_code);}
}#define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED/*** @brief Function for main application entry.*/
int main(void)
{uint32_t err_code;uint32_t id1,id2;id1=NRF_FICR->DEVICEID[0]; //读取id低31位id2=NRF_FICR->DEVICEID[1];//读取id高31位const app_uart_comm_params_t comm_params ={RX_PIN_NUMBER,TX_PIN_NUMBER,RTS_PIN_NUMBER,CTS_PIN_NUMBER,UART_HWFC,false,
#if defined (UART_PRESENT)NRF_UART_BAUDRATE_115200
#elseNRF_UARTE_BAUDRATE_115200
#endif};APP_UART_FIFO_INIT(&comm_params,UART_RX_BUF_SIZE,UART_TX_BUF_SIZE,uart_error_handle,APP_IRQ_PRIORITY_LOWEST,err_code);APP_ERROR_CHECK(err_code);while (1){printf("打印id:%lx%lx\r\n",id1,id2);nrf_delay_ms(1000);}}

唯一 ID 用于加密

TEA 加密算法

唯一 ID 常用的场合就是加密,我们可以采用一个简单的加密算法对 ID 号进行加密。那么如果要正确运行程序就需要对唯一 ID 进行正确解密。

常用的代码加密方案一般有两种。

  • 通过某种硬件手段防止单片机 FLASH 中的代码被读出,比如禁止读取、或者关闭下载接口;
  • 就算代码能被读出来,把它烧到另一个芯片中,也无法正常运行(与特定芯片紧紧绑定)。

以目前的技术水平来说,不论如何禁止,似乎都有人可以把程序从芯片内部读取出来。那么就算被窃取者读取了程序的二进制文件,烧到另一个同型号的处理器芯片里,也必须无法运行。要实现这一目的,首先要有一个与单片机唯一绑定的东西,那么这就需要唯一 ID 号了,每一片芯片 ID 都不相同,并且全世界保存唯一。

研发者由唯一 ID 号通过加密算法计算得到检验码,然后向使用者下发。使用者可将此码通过专用编写的上位机把效验码烧写器写入到芯片的 EEPROM 中。 在代码中,可以在多个位置对 EEPROM 中的校验码进行比对,一致则正常运行,否则宕机。 比如在程序有最前面,一开始就进行鉴权,如果失败则向用户显示“无权限”等信息,停止程序运行;或是在程序中比较关键的条件分支中,这样如果程序被人破译,比如反汇编,通过修改一些条件判断,强行使其正常运行。因为程序中鉴权的地方越多,这势必让破解者费一些周折,但是也不能过多的地方出现检验码,避免被统计识别。 对于唯一 ID 的加密原理如下图

在这里插入图片描述
本节讲采用在安全学领域中常见的 TEA 加密算法进行加密和解密。所谓的 TEA(Tiny Encryption Algorithm)是一种分组加密算法,它的实现非常简单,通常只需要很精短的几行代码就可以实现,因此非常适合用单片机的加密中。

TEA 算法最初是由剑桥计算机实验室的 David Wheeler 和 Roger Needham 在 1994 年设计 的。TEA 算法使用 64 位的明文分组和 128 位的密钥,它使用 Feistel 分组加密框架,需要进行 64 轮 迭代。该算法使用了一个神秘常数δ作为倍数,它来源于黄金比率,以保证每一轮加密都不相同。但 δ的精确值似乎并不重要,这里 TEA 把它定义为 δ=「(√5 - 1)231」(也就是程序中的 0×9E3779B9)。

Tea 算法秘钥为 16 字节,每次分块处理的数据是 8 个字节,两个 32 位数据。加密过程中,加法运算和减法运算用作可逆的操作,算法轮流使用异或运算提供非线性特性,双移位操作使秘钥和数据的所有比特重复地混合,最多 16 轮循环就能使数据或密钥的单个比特的变化扩展到接近 32 比特. 因此 ,当循环轮数达到 16 轮以上时 ,该算法具有很强的抗差分攻击能力 ,128 比特密钥长度可以抗击穷举搜索攻击,该算法设计者推荐算法迭代次数为 32 轮。

唯一 ID 的加密和解密

下面简单的演示如何对唯一 ID 进行加密,搭建加密工程如下图
在这里插入图片描述

tea.c 代码如下:

#include "tea.h"void encrypt (uint32_t* v, uint32_t* k) 
{uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */uint32_t delta=0x9e3779b9;                     /* a key schedule constant */uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */for (i=0; i < 32; i++) {                       /* basic cycle start */sum += delta;v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  }                                              /* end cycle */v[0]=v0; v[1]=v1;
}void decrypt (uint32_t* v, uint32_t* k) 
{uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */uint32_t delta=0x9e3779b9;                     /* a key schedule constant */uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */for (i=0; i<32; i++) {                         /* basic cycle start */v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);sum -= delta;                                   }                                              /* end cycle */v[0]=v0; v[1]=v1;
}

主函数中,设置一组加密密码 key,本例简单的设置为 0x1234 作为密码。然后读取设备的唯一 ID 号,对唯一 ID 号进行 tea 加密。加密完成后的 ID 号可以作为程序加密的效验码。为了验证加密是否成功,再对加密后的唯一 ID 号进行解密。对比读取的唯一 ID 号和解密后的唯一 ID 号,如果两者相同,则证明加密算法正确。具体代码如下所示:


#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "app_uart.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf.h"
#include "bsp.h"
#if defined (UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined (UARTE_PRESENT)
#include "nrf_uarte.h"
#endif
#include "tea.h"//#define ENABLE_LOOPBACK_TEST  /**< if defined, then this example will be a loopback test, which means that TX should be connected to RX to get data loopback. */#define MAX_TEST_DATA_BYTES     (15U)                /**< max number of test bytes to be used for tx and rx. */
#define UART_TX_BUF_SIZE 256                         /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256                         /**< UART RX buffer size. */void uart_error_handle(app_uart_evt_t * p_event)
{if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR){APP_ERROR_HANDLER(p_event->data.error_communication);}else if (p_event->evt_type == APP_UART_FIFO_ERROR){APP_ERROR_HANDLER(p_event->data.error_code);}
}#define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED/*** @brief Function for main application entry.*/
int main(void)
{uint32_t err_code;uint32_t id[2];uint32_t key[]={0x1234,0x1234,0x1234,0x1234};  //密码id[0]=NRF_FICR->DEVICEID[0]; //读取id低31位id[1]=NRF_FICR->DEVICEID[1];//读取id高31位const app_uart_comm_params_t comm_params ={RX_PIN_NUMBER,TX_PIN_NUMBER,RTS_PIN_NUMBER,CTS_PIN_NUMBER,UART_HWFC,false,
#if defined (UART_PRESENT)NRF_UART_BAUDRATE_115200
#elseNRF_UARTE_BAUDRATE_115200
#endif};APP_UART_FIFO_INIT(&comm_params,UART_RX_BUF_SIZE,UART_TX_BUF_SIZE,uart_error_handle,APP_IRQ_PRIORITY_LOWEST,err_code);APP_ERROR_CHECK(err_code);while (1){printf("打印id:%lx%lx\r\n",id[0],id[1]);encrypt(id,key);//加密,工程的验证码printf("加密id:%lx%lx\r\n",id[0],id[1]);decrypt(id,key);//解密printf("解密id:%lx%lx\r\n",id[0],id[1]);printf("-------------------\r\n");nrf_delay_ms(1000); }}

这篇关于nRF52832——唯一 ID 与加密解密的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/806336

相关文章

如何通过try-catch判断数据库唯一键字段是否重复

《如何通过try-catch判断数据库唯一键字段是否重复》在MyBatis+MySQL中,通过try-catch捕获唯一约束异常可避免重复数据查询,优点是减少数据库交互、提升并发安全,缺点是异常处理开... 目录1、原理2、怎么理解“异常走的是数据库错误路径,开销比普通逻辑分支稍高”?1. 普通逻辑分支 v

SQLServer中生成雪花ID(Snowflake ID)的实现方法

《SQLServer中生成雪花ID(SnowflakeID)的实现方法》:本文主要介绍在SQLServer中生成雪花ID(SnowflakeID)的实现方法,文中通过示例代码介绍的非常详细,... 目录前言认识雪花ID雪花ID的核心特点雪花ID的结构(64位)雪花ID的优势雪花ID的局限性雪花ID的应用场景

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1

解密SQL查询语句执行的过程

《解密SQL查询语句执行的过程》文章讲解了SQL语句的执行流程,涵盖解析、优化、执行三个核心阶段,并介绍执行计划查看方法EXPLAIN,同时提出性能优化技巧如合理使用索引、避免SELECT*、JOIN... 目录1. SQL语句的基本结构2. SQL语句的执行过程3. SQL语句的执行计划4. 常见的性能优

一文解密Python进行监控进程的黑科技

《一文解密Python进行监控进程的黑科技》在计算机系统管理和应用性能优化中,监控进程的CPU、内存和IO使用率是非常重要的任务,下面我们就来讲讲如何Python写一个简单使用的监控进程的工具吧... 目录准备工作监控CPU使用率监控内存使用率监控IO使用率小工具代码整合在计算机系统管理和应用性能优化中,监

使用zip4j实现Java中的ZIP文件加密压缩的操作方法

《使用zip4j实现Java中的ZIP文件加密压缩的操作方法》本文介绍如何通过Maven集成zip4j1.3.2库创建带密码保护的ZIP文件,涵盖依赖配置、代码示例及加密原理,确保数据安全性,感兴趣的... 目录1. zip4j库介绍和版本1.1 zip4j库概述1.2 zip4j的版本演变1.3 zip4

MySQL逻辑删除与唯一索引冲突解决方案

《MySQL逻辑删除与唯一索引冲突解决方案》本文探讨MySQL逻辑删除与唯一索引冲突问题,提出四种解决方案:复合索引+时间戳、修改唯一字段、历史表、业务层校验,推荐方案1和方案3,适用于不同场景,感兴... 目录问题背景问题复现解决方案解决方案1.复合唯一索引 + 时间戳删除字段解决方案2:删除后修改唯一字

python生成随机唯一id的几种实现方法

《python生成随机唯一id的几种实现方法》在Python中生成随机唯一ID有多种方法,根据不同的需求场景可以选择最适合的方案,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习... 目录方法 1:使用 UUID 模块(推荐)方法 2:使用 Secrets 模块(安全敏感场景)方法

mybatis执行insert返回id实现详解

《mybatis执行insert返回id实现详解》MyBatis插入操作默认返回受影响行数,需通过useGeneratedKeys+keyProperty或selectKey获取主键ID,确保主键为自... 目录 两种方式获取自增 ID:1. ​​useGeneratedKeys+keyProperty(推

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数