嵌入式开发中的设备加密---MD5软件加密

一、MD5算法介绍

MD5(Message-Digest Algorithm 5)是一种广泛使用的密码散列函数,它可以将任意长度的数据(消息)计算出一个128位的固定长度的散列值(消息摘要)。MD5加密的原理如下:

1.1数据填充:

将原始消息填充至64位的整数倍。填充方式是在消息末尾添加1个1,然后添加若干个0,直到消息长度等于448 bits (mod 512)。

1.2追加数据长度:

将原始消息的长度(以bits为单位)以64位的形式添加到上一步的结果之后。

1.3MD寄存器初始化:

MD5算法使用4个32位的寄存器A、B、C、D来存储中间结果,初始值分别为:
A = 0x67452301
B = 0xefcdab89
C = 0x98badcfe
D = 0x10325476

1.4四轮循环计算:

对填充和追加长度后的消息进行4轮非线性运算,每轮使用不同的布尔函数。每轮都包含16个步骤,每个步骤都更新寄存器A、B、C、D的值。

1.5输出:

经过4轮运算后,4个寄存器的值即为最终的128位MD5散列值。
MD5算法的优点是计算速度快,广泛应用于文件校验、数字签名等场景。但是它存在一些安全隐患,如存在碰撞攻击,即不同的消息可能计算出相同的摘要

1.6示例

假设我们有一个字符串"Hello, world!"作为输入消息。步骤如下:

(1)原始数据填充:

原始消息长度为 13 bytes (104 bits),填充 1 个 1 和 55 个 0 (占 64 bits),得到 168 bits,

(2)数据长度追加:

最后添加原始消息长度 104 bits,得到总长度 272 bits

(3)初始化寄存器:

A = 0x67452301
B = 0xefcdab89
C = 0x98badcfe
D = 0x10325476

(4)四轮循环计算:

进行4轮非线性运算,每轮 16 步,共 64 步。这个过程比较复杂,涉及到一些位运算和布尔函数,就不详细展开了。
最终得到 MD5 散列值:
A = 0xe10adc3e
B = 0x5771cf43
C = 0x4b0455e5
D = 0x1d8a9e34
综合 A、B、C、D 的值,得到最终的 MD5 散列值为:e10adc3e5771cf434b0455e51d8a9e34

这个 128 位的散列值就是对原始消息"Hello,world!"进行 MD5 加密后得到的结果。需要注意的是,MD5 算法是确定性的,对同样的输入消息,计算出的 MD5 值永远是相同的。

二、获取嵌入式设备的唯一编号

在linux开发板中,/proc/cpuinfo是一个在Linux系统中提供CPU相关信息的特殊文件。当我们查看这个文件时,可以获取到丰富的CPU信息,其中Serial代表当前开发板的CPU唯一编号,因此我们只要获取得到该编号,并对该编号进行加密,理论上使得某些可执行文件只可以在该开发板运行。
在这里插入图片描述
下列为获取该编号的API,直接调用获取返回结果即为CPU编号:

char* get_cpu_serial() 											// 获取 CPU 序列号的函数
{
    FILE *file;
    char line[256];
    char *serial = NULL;

    
    file = fopen("/proc/cpuinfo", "r");							// 打开 /proc/cpuinfo 文件
    if (file == NULL) 
	{
        perror("Error opening /proc/cpuinfo"); 
        return NULL;
    }

    // 逐行读取文件内容
    while (fgets(line, sizeof(line), file) != NULL) 
	{
        if (strncmp(line, "Serial", strlen("Serial")) == 0) 	// 比较每行的前缀是否是 "Serial"
		{
            
            line[strcspn(line, "\n")] = '\0';					// 移除行尾的换行符
            
            
            char *colon_pos = strchr(line, ':');				// 查找行中的冒号位置
            if (colon_pos != NULL) 
			{               
                char *serial_start = colon_pos + 1;				
                while (*serial_start == ' ') serial_start++;	// 跳过冒号和后面的所有空格,定位到实际的序列号开始位置           
                serial = (char*)malloc(strlen(serial_start) + 1);
                strcpy(serial, serial_start);					// 分配内存并复制序列号字符串
                           
                char *end = serial + strlen(serial) - 1;
                while (end > serial && *end == ' ') end--;
                *(end + 1) = '\0';								// 去除末尾的空格,分配结束标志
                break;
            }
        }
    }

    fclose(file);
    return serial; 												// 返回序列号字符串
}

三、MD5算法相关库的安装

openssl库的安装

(1)openssl官网下载最新安装包即可。https://openssl-library.org/source/
(2)tar -zxvf openssl-1.1.1c.tar.gz
(3)cd openssl-1.1.1s
(4)./config
(5)make
(6)sudo make install
(7)openssl -version提示:error while loading shared libraries: libssl.so.3: cannot open shared object file
原因:没有把安装的ssl中libssl.so.3链接到/usr/lib中导致找不到
解决:
(1)whereis openssl首先确定我们是安装了openssl
(2)sudo find / -name libssl.so.3
(3)sudo find / -name libcrypto.so.3
(4)openssl依赖于ssl与crypto。
使用sudo find / -name libssl.so.3
与sudo find / -name libcrypto.so.3查看ssl与crypto所在目录。
(5)在/usr/lib生成二者软连接:
sudo ln -s /usr/local/lib64/libssl.so.3 /usr/lib/libssl.so.3
sudo ln -s /usr/local/lib64/libcrypto.so.3 /usr/lib/libcrypto.so.3
(6)openssl -version查看版本信息

在这里插入图片描述
在这里插入图片描述

四、使用MD5算法对CPU编号进行加密

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/md5.h>

char* get_cpu_serial() 											// 获取 CPU 序列号的函数
{
    FILE *file;
    char line[256];
    char *serial = NULL;

    
    file = fopen("/proc/cpuinfo", "r");							// 打开 /proc/cpuinfo 文件
    if (file == NULL) 
	{
        perror("Error opening /proc/cpuinfo"); 
        return NULL;
    }

    // 逐行读取文件内容
    while (fgets(line, sizeof(line), file) != NULL) 
	{
        if (strncmp(line, "Serial", strlen("Serial")) == 0) 	// 比较每行的前缀是否是 "Serial"
		{
            
            line[strcspn(line, "\n")] = '\0';					// 移除行尾的换行符
            
            
            char *colon_pos = strchr(line, ':');				// 查找行中的冒号位置
            if (colon_pos != NULL) 
			{               
                char *serial_start = colon_pos + 1;				
                while (*serial_start == ' ') serial_start++;	// 跳过冒号和后面的所有空格,定位到实际的序列号开始位置           
                serial = (char*)malloc(strlen(serial_start) + 1);
                strcpy(serial, serial_start);					// 分配内存并复制序列号字符串
                           
                char *end = serial + strlen(serial) - 1;
                while (end > serial && *end == ' ') end--;
                *(end + 1) = '\0';								// 去除末尾的空格,分配结束标志
                break;
            }
        }
    }

    fclose(file);
    return serial; 												// 返回序列号字符串
}

void md5_encrypt(const char *input, char *output) {
    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5_CTX ctx;
    
    MD5_Init(&ctx);
    MD5_Update(&ctx, input, strlen(input));
    MD5_Final(digest, &ctx);
    
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
        sprintf(output + (i * 2), "%02x", digest[i]);
    }
}

int main() {
    char* cpu_serial = get_cpu_serial();
    char encode_cpu_serial[MD5_DIGEST_LENGTH * 2 + 1];
    
    md5_encrypt(cpu_serial, encode_cpu_serial);
    
    printf("Original data: %s\n", cpu_serial);
    printf("Encrypted MD5 hash: %s\n", encode_cpu_serial);
    
    return 0;
}

gcc test.c -o test -lssl -lcrypto编译运行即可。这里我是在虚拟机运行的,虚拟机没有Serial选项,我是对其他字段进行加密的。
在这里插入图片描述

  • 19
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

￴ㅤ￴￴ㅤ9527超级帅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值