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

相关文章

mysql数据库重置表主键id的实现

《mysql数据库重置表主键id的实现》在我们的开发过程中,难免在做测试的时候会生成一些杂乱无章的SQL主键数据,本文主要介绍了mysql数据库重置表主键id的实现,具有一定的参考价值,感兴趣的可以了... 目录关键语法演示案例在我们的开发过程中,难免在做测试的时候会生成一些杂乱无章的SQL主键数据,当我们

SpringBoot3使用Jasypt实现加密配置文件

《SpringBoot3使用Jasypt实现加密配置文件》这篇文章主要为大家详细介绍了SpringBoot3如何使用Jasypt实现加密配置文件功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编... 目录一. 使用步骤1. 添加依赖2.配置加密密码3. 加密敏感信息4. 将加密信息存储到配置文件中5

SpringBoot整合jasypt实现重要数据加密

《SpringBoot整合jasypt实现重要数据加密》Jasypt是一个专注于简化Java加密操作的开源工具,:本文主要介绍详细介绍了如何使用jasypt实现重要数据加密,感兴趣的小伙伴可... 目录jasypt简介 jasypt的优点SpringBoot使用jasypt创建mapper接口配置文件加密

SpringBoot项目使用MDC给日志增加唯一标识的实现步骤

《SpringBoot项目使用MDC给日志增加唯一标识的实现步骤》本文介绍了如何在SpringBoot项目中使用MDC(MappedDiagnosticContext)为日志增加唯一标识,以便于日... 目录【Java】SpringBoot项目使用MDC给日志增加唯一标识,方便日志追踪1.日志效果2.实现步

Java实现MD5加密的四种方式

《Java实现MD5加密的四种方式》MD5是一种广泛使用的哈希算法,其输出结果是一个128位的二进制数,通常以32位十六进制数的形式表示,MD5的底层实现涉及多个复杂的步骤和算法,本文给大家介绍了Ja... 目录MD5介绍Java 中实现 MD5 加密方式方法一:使用 MessageDigest方法二:使用

mysql8.0无备份通过idb文件恢复数据的方法、idb文件修复和tablespace id不一致处理

《mysql8.0无备份通过idb文件恢复数据的方法、idb文件修复和tablespaceid不一致处理》文章描述了公司服务器断电后数据库故障的过程,作者通过查看错误日志、重新初始化数据目录、恢复备... 周末突然接到一位一年多没联系的妹妹打来电话,“刘哥,快来救救我”,我脑海瞬间冒出妙瓦底,电信火苲马扁.

SpringBoot使用Jasypt对YML文件配置内容加密的方法(数据库密码加密)

《SpringBoot使用Jasypt对YML文件配置内容加密的方法(数据库密码加密)》本文介绍了如何在SpringBoot项目中使用Jasypt对application.yml文件中的敏感信息(如数... 目录SpringBoot使用Jasypt对YML文件配置内容进行加密(例:数据库密码加密)前言一、J

Java中的密码加密方式

《Java中的密码加密方式》文章介绍了Java中使用MD5算法对密码进行加密的方法,以及如何通过加盐和多重加密来提高密码的安全性,MD5是一种不可逆的哈希算法,适合用于存储密码,因为其输出的摘要长度固... 目录Java的密码加密方式密码加密一般的应用方式是总结Java的密码加密方式密码加密【这里采用的

使用Python制作一个PDF批量加密工具

《使用Python制作一个PDF批量加密工具》PDF批量加密‌是一种保护PDF文件安全性的方法,通过为多个PDF文件设置相同的密码,防止未经授权的用户访问这些文件,下面我们来看看如何使用Python制... 目录1.简介2.运行效果3.相关源码1.简介一个python写的PDF批量加密工具。PDF批量加密

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密