nRF52832——唯一 ID 与加密解密

news2025/1/15 6:59:47

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
#else
        NRF_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
#else
          NRF_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); 
   }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1513859.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java项目:51 springboot基于springboot的社区团购系统设计012

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本基于Spring Boot的社区团购系统主要满足两种用户的需求&#xff0c;这两种用户分别为管理员和用户&#xff0c;下面将对这两种用户分别实现的…

电磁兼容EMC:一文读懂电气放电管选型设计

目录 1 GDT外观结构 2 GDT 常见品牌 3 GDT命名规则 4 GDT工作原理 5 GDT基本特点 6 GDT典型应用 7 GDT电气参数说明 7.1 DC Spark-over Voltage 直流火花放电电压&#xff08;直流击穿电压&#xff09; 7.2 Maximum Impulse Spark-over Voltage 最大冲击火花放电电压&…

Ribbon简单使用

Ribbon是Netflix发布的云中间层服务开源项目&#xff0c;其主要功能是提供客户端实现负载均衡算法。Ribbon客户端组件提供一系列完善的配置项如连接超时&#xff0c;重试等。简单的说&#xff0c;Ribbon是一个客户端负载均衡器&#xff0c;我们可以在配置文件中Load Balancer后…

【DataWhale学习】用免费GPU线上跑StableDiffusion项目实践

用免费GPU线上跑SD项目实践 ​ DataWhale组织了一个线上白嫖GPU跑chatGLM与SD的项目活动&#xff0c;我很感兴趣就参加啦。之前就对chatGLM有所耳闻&#xff0c;是去年清华联合发布的开源大语言模型&#xff0c;可以用来打造个人知识库什么的&#xff0c;一直没有尝试。而SD我…

【数据结构】顺序表的实现

文章目录 **线性表(linear)&#xff1a;****顺序表****下列是需要实现的接口(Seqlist.h)****顺序表的初始化****顺序表的插入数据****顺序表的扩容(为插入数据提供保障)****顺序表的尾插****顺序表的头插****顺序表的删除数据****顺序表的尾删****顺序表的头删****查找指定位置…

下载API文档

在线看&#xff1a;Overview (Java SE 17 & JDK 17) 离线下载&#xff1a;Java Development Kit 17 Documentation

【Sql】MVCC有关问题,以及锁,日志和主从复制原理

目录 MVCC 解决什么问题? 实现原理 隐式字段 undo log Read View(读视图) InnoDB 对 MVCC 的实现 锁 分类 锁升级&#xff1f; InnoDB 的行锁&#xff1f; 死锁避免&#xff1f; 乐观锁和悲观锁 日志 主从复制原理 主从复制的作用 MySQL主从复制解决的问题 涉…

模型量化(二)—— 训练后量化PTQ(全代码)

训练后量化&#xff08;Post-training Quantization&#xff0c;PTQ&#xff09;是一种常见的模型量化技术&#xff0c;它在模型训练完成之后应用&#xff0c;旨在减少模型的大小和提高推理速度&#xff0c;同时尽量保持模型的性能。训练后量化对于部署到资源受限的设备上&…

【阿里云系列】-利用yaml文件部署NacosXxl-job到ACK

背景介绍 随着容器化的技术成熟落地&#xff0c;拥抱各种成熟的容器化集群平台是加速我们落地的必然之路&#xff0c;目前国内以阿里云、华为云、腾讯云为平台的供应商为主&#xff0c;国外则以AWS&#xff0c;Azure为主&#xff0c;让我们借助平台已有的优势进行快速落地提高…

指针【理论知识速成】(3)

一.指针的使用和传值调用&#xff1a; 在了解指针的传址调用前&#xff0c;先来额外了解一下 “传值调用” 1.传值调用&#xff1a; 对于来看这个帖子的你相信代码展示胜过千言万语 #include <stdio.h> #include<assert.h> int convert(int a, int b) {int c 0…

log4j2.xml介绍和使用

log4j2.xml是什么 log4j2.xml 是用于配置 Apache Log4j 2 的 XML 格式配置文件。Log4j 2 是一个用于 Java 应用的流行日志框架&#xff0c;提供灵活的日志管理和配置。在 log4j2.xml 文件中&#xff0c;可以配置日志记录的格式、级别、目的地等。 下面是一些主要节点和属性的…

内容管理平台原来对企业这么重要,看完收藏!

“内容为王”&#xff0c;这是当今数字化时代的一个重要真理。不论是创业新贵、还是行业巨头&#xff0c;纷纷开始深入理解和应用内容管理平台&#xff08;Content Management System&#xff0c;简称CMS&#xff09;&#xff0c;以便更好的管理其大量的内容和信息。 那么&…

网络安全从业人员何去何从

从2024年1月1日开始到今天&#xff0c;基本没有真正放下自己休息过一天。可能很多人会说是卷&#xff0c;其实真正的原因是压力。不仅仅是生活压力还有行业压力。 今年这个行业让很多人开始感到了迷茫&#xff0c;不仅是股市的低迷&#xff0c;更多的来自于各大公司不断的因为…

什么是架构?架构设计原则是哪些?什么是设计模式?设计模式有哪些?

什么是架构?架构设计原则是哪些?什么是设计模式?设计模式有哪些? 架构的本质 架构本身是一种抽象的、来自建筑学的体系结构,其在企业及IT系统中被广泛应用。 架构的本质是对事物复杂性的管理,是对一个企业、一个公司、一个系统复杂的内部关系进行结构化、体系化的抽象,…

Stable-Diffusion的WebUI部署实战

1、环境准备及安装 1.1、linux环境 # 首先&#xff0c;已经预先安装好了anaconda&#xff0c;在这里新建一个环境 conda create -n sdwebui python3.10 # 安装完毕后&#xff0c;激活该环境 conda activate sdwebui# 安装 # 下载stable-diffusion-webui代码 apt install wget…

String 底层是如何实现的?

1、典型回答 String 底层是基于数组实现的&#xff0c;并且数组使用了 final 修饰&#xff0c;不同版本中的数组类型也是不同的&#xff1a; JDK9 之前&#xff08;不含JDK9&#xff09; String 类是使用 char[ ]&#xff08;字符数组&#xff09;实现的但 JDK9 之后&#xf…

C#版开源免费的Bouncy Castle密码库

前言 今天大姚给大家分享一款C#版开源、免费的Bouncy Castle密码库&#xff1a;BouncyCastle。 项目介绍 BouncyCastle是一款C#版开源、免费的Bouncy Castle密码库&#xff0c;开发人员可以通过该项目在他们的 C# 应用程序中使用 Bouncy Castle 提供的各种密码学功能&#x…

如何使用 Langchain、Ollama 和 Streamlit 构建 RAG

一、先决条件&#xff1a;您需要了解什么 在深入讨论技术细节之前&#xff0c;我们先概述一下先决条件。Python 的基础知识至关重要&#xff0c;因为它是我们将使用的主要语言。熟悉机器学习和自然语言处理的基本概念将帮助您更轻松地掌握这些概念。此外&#xff0c;对 Langch…

瑞熙贝通实验室物联网管理平台新升级|支持远程开门视频监控与电源控制以及环境监测

瑞熙贝通实验室智能物联网管控平台&#xff1a;利用“互联网与物联网技术”有机融合&#xff0c;对实验室的用电安全监测、实验室环境异常监测&#xff08;颗粒物监测、明火监测、可燃气体、烟雾监测、温湿度传感器、红外人体感应&#xff09;、实验室人员安全准入、万物互联等…

16、技巧之九: 修改参数,如何让表格翻页滚动到底部?【Selenium+Python3网页自动化总结】

1、问题提出 在网页配置参数时&#xff0c;输入参数名称搜索&#xff0c;搜出来的同名参数结果有多个&#xff0c;分布在一个表格的不同行&#xff0c;表格是动态加载的&#xff0c;需要滚动鼠标才能把所出参数找出来。用selenium怎么实现这种参数修改&#xff1f; 2、网页元素…