最近项目中对升级的程序需要做认证,确保升级的数据包是本项目的升级程序包。

数字签名:对某个数据块的签名,就是计算数据块的Hash值,然后使用私钥对hash值进行加密,结果就叫数字签名,Hash值就是数据块的数字指纹。

签名验证:数据接收者拿到原始数据块与数字签名后,接受者也会使用相同的Hash算法得到Hash值,然后使用公钥解密得到原始的数据指纹,比较2个值,就可以判定数据块签名之后有没有被篡改。

Hash算法常见的有:MD5,SHA,哈希算法也类似摘要算法,是一个单向的散列函数,它解决在某一特定时间内,无法查找经Hash操作后生成特定HASH值的原信息块,哈希算法输入一个长度不固定的信息块,返回一个固定长度的结果。

步骤:

1.将生产的程序使用MD5算出一个MD5值,将此值使用RSA私钥进行加密,得到数字签名。将此值附加在升级程序后面。

2.升级程序时,将升级程序和数字签名一起发送给需要升级的设备。

3.设备收到后,对升级程序计算出一个MD5值。

4.将收到的数字签名使用RSA的公钥进行解密,得到接收到的MD5值。

5.如果两个MD5相等,则认证通过(程序升级成功),否则认证失败(程序升级失败)。

加密算法采用RSA,以下是转载的RSA C语言的实现博文,经过实践,修改了几处错误。感谢博主的分享。

PEM文件有以下格式

PEM私钥文件格式
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
生成该密钥的Linux命令:openssl genrsa -out privateKey.pem 1024
读取该密钥的Linux Openssl API 函数文件读取:
RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **rsa, pem_password_cb *cb, void *u)
读取该密钥的Linux Openssl API 函数内存读取:
RSA *PEM_read_bio_RSAPrivateKey(BIO *bio, RSA **rsa, pem_password_cb *cb, void *u)

PEM私钥文件格式(经过口令加密)
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,FCD22C6C17CF034C
-----END RSA PRIVATE KEY-----
生成该密钥的Linux命令:openssl genrsa -des3 -out privateKey.pem 1024
enter后会要求输入口令(最少四位)
读取该密钥的Linux Openssl API 函数文件读取:
RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **rsa, pem_password_cb *cb, void *u)
读取该密钥的Linux Openssl API 函数内存读取:
RSA *PEM_read_bio_RSAPrivateKey(BIO *bio, RSA **rsa, pem_password_cb *cb, void *u)

PEM公钥文件格式
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
生成该密钥的Linux命令:openssl rsa -in privateKey.pem -pubout -out publicKey.pem
读取该密钥的Linux Openssl API 函数文件读取:
RSA *PEM_read_RSA_PUBKEY(FILE *fp, RSA **rsa, pem_password_cb *cb, void *u)
读取该密钥的Linux Openssl API 函数内存读取:
RSA *PEM_read_bio_PUBKEY(BIO *bio, RSA **rsa, pem_password_cb *cb, void *u)

PEM RSAPublicKey公钥文件格式
-----BEGIN RSA PUBLIC KEY-----
-----END RSA PUBLIC KEY-----
生成该密钥的Linux命令:openssl rsa -in privateKey.pem -RSAPublicKey_out -out publicKey.pem
读取该密钥的Linux Openssl API 函数文件读取:
RSA *PEM_read_RSAPublicKey(FILE *fp, RSA **rsa, pem_password_cb *cb, void *u)
读取该密钥的Linux Openssl API 函数内存读取:
RSA *PEM_read_bio_RSAPublicKey(BIO *bio, RSA **rsa, pem_password_cb *cb, void *u)

RSA加密API
int RSA_public_encrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding)
参数说明:
flen: 加密信息的长度
from: 要加密信息
to: 加密后的信息
padding: 填充方式( RSA_PKCS1_PADDING ,RSA_PKCS1_OAEP_PADDING,RSA_SSLV23_PADDING,RSA_NO_PADDING)
(注:flen会根据不同的填充方式大小会有变化参考)

RSA解密API
int RSA_private_decrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding)
参数说明:
flen: 解密密文的长度
from: 要解密信息
to: 解密后的信息
padding: 填充方式( RSA_PKCS1_PADDING ,RSA_PKCS1_OAEP_PADDING,RSA_SSLV23_PADDING,RSA_NO_PADDING)
(注:flen填写的是密钥长度可用RSA_size(rsa)函数得到)

RSA编程示例(PEM文件方式)
#include <openssl/rsa.h>
#include <openssl/pem.h>
 
#define PUBLICKEY "publicKey.pem"
#define PRIVATEKEY "privateKey.pem"
 
#define PASS "8888" //口令
 
int main(int argc, char *argv[])
{
    FILE *fp = NULL;
    RSA *publicRsa = NULL;
    RSA *privateRsa = NULL;
    if ((fp = fopen(PUBLICKEY, "r")) == NULL) 
    {
        printf("public key path error\n");
        return -1;
    }     
   
    if ((publicRsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL)) == NULL) 
    {
        printf("PEM_read_RSA_PUBKEY error\n");
        return -1;
    }
    fclose(fp);
    
    if ((fp = fopen(PRIVATEKEY, "r")) == NULL) 
    {
        printf("private key path error\n");
        return -1;
    }
    OpenSSL_add_all_algorithms();//密钥有经过口令加密需要这个函数
    if ((privateRsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, (char *)PASS)) == NULL) 
    {
        printf("PEM_read_RSAPrivateKey error\n");
        return NULL;
    }
    fclose(fp);        
    
    unsigned char *source = (unsigned char *)"123456789";
        
    int rsa_len = RSA_size(publicRsa);
 
    unsigned char *encryptMsg = (unsigned char *)malloc(rsa_len);
    memset(encryptMsg, 0, rsa_len);
         
    int len = strlen(source );
    if (RSA_public_encrypt(len, source, encryptMsg, publicRsa, RSA_PKCS1_PADDING) < 0)
        printf("RSA_public_encrypt error\n");
    else 
    {
        rsa_len = RSA_size(privateRsa);
        unsigned char *decryptMsg = (unsigned char *)malloc(rsa_len);
        memset(decryptMsg, 0, rsa_len);
        
        int mun =  RSA_private_decrypt(rsa_len, encryptMsg, decryptMsg, privateRsa, RSA_PKCS1_PADDING);
        //解密后的长度 mun
        if ( mun < 0)
            printf("RSA_private_decrypt error\n");
        else
            printf("RSA_private_decrypt %s\n", decryptMsg);
    }    
    
    RSA_free(publicRsa);
    RSA_free(privateRsa);
    return 0;
}

RSA编程示例(PEM内存方式)
#include <cstdio>
#include <cstring>
#include <openssl/rsa.h>
#include <openssl/pem.h>
 
const char *publicKey = "-----BEGIN PUBLIC KEY-----\n\
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDnal1HozHfmZ3B1TITmbjCNKOs\n\
49S+urgJ2P0/T36qN5w+r1jGhZKr54QDI5oXEk+9arlKxDW8kufwGjaTV3i3hyGS\n\
jYv4wNXhPeZAyAQ1vlloLMT6oA0PKe9/l8+mAr1QPEW9fMixAc/0UzPVospjkpfr\n\
YULcrKcH2Oaou5DZ0QIDAQAB\n\
-----END PUBLIC KEY-----";
 
const char *privateKey = "-----BEGIN RSA PRIVATE KEY-----\n\
Proc-Type: 4,ENCRYPTED\n\
DEK-Info: DES-EDE3-CBC,DF3BD9835CA1186D\n\
\n\
pomWi9/hjscwDDzH5CEpcj8nCumOQpl/2Gk2YynA47qfhxt12glNjgWl5Eaevk2L\n\
bG1t85sPqEvYxAe+ZxZdP6fot+sAg4SUUwSvBMwa7s3XjVhHjf/+hOIjb0skHvp/\n\
p0eOoUgytX7FrNNYEpUFI+eiPob79fgQMq/rypGJ//G6GXLMYixWw2+PyPa1x2PQ\n\
WdBaTpZK3gmDqmu6jR3ieKOahVVO4fEGB5etvB5i1aAh0mT4Wu+ejv2LgIRr2xor\n\
r8LkQZvI/TryZ0sNLe7LlC1bz/Hw8hLBDPprhWaUcSEk6MMgh3LKA2y/pGpFdIYN\n\
Ncj/c+YqEsO+I0KOtPQ1fXlXd1hH1H1rkJxuaNanF0UInUuupV3fP+7cvmfyHM4m\n\
aix8ROt1/Ghau41JDZGYmwk2qgKjUw4zz3eYOMQKl6row3pzhDxbvoMp0Qvfje1J\n\
RYpKMy8skG9pY1l4i1CC98aESC2a7FzjUNcY3f5Jt+QznO15xXxxuJZ8+xNqtIh2\n\
U348rlrQ8OxS1YBJCr+wjesdBdQAiY6X1YB9tljPs7AhlTLo78pHtQac521xOA8j\n\
IcbfkuTIrMIwYBOtM6SJHkB1TgPdPWx+haEy79Ct2yDnvpPqOiFz8i8TG8AQY53l\n\
5xKxxJ9CmPqw+Ua3DAWPaxAMaJFteRbl5Lv/2MvxV9Mu3T0W4B3ij+Gg5aw81v5Y\n\
KTH2KxruYAF5Q70QG8CAR8Vkvdczw940y8nb9pvcixmqYcaaeM9DLaTbycn/AeCt\n\
3UM0R0vvu039Ix5uhXUtVMjhTeUnvNObwEcKM8Grv1oPV3zmTJ5hJg==\n\
-----END RSA PRIVATE KEY-----";
 
#define PASS "8888" //口令
 
int main(int argc, char *argv[])
{
    BIO *bio = NULL;
    RSA *publicRsa = NULL;
    RSA *privateRsa = NULL;
    if ((bio = BIO_new_mem_buf((void *)publicKey, -1)) == NULL)
    {
        printf("BIO_new_mem_buf publicKey error\n");
        return -1;
    }     
   
    if ((publicRsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL)) == NULL) 
    {
        printf("PEM_read_bio_RSA_PUBKEY error\n");
        return -1;
    }
    BIO_free_all(bio);
    
    if ((bio = BIO_new_mem_buf((void *)privateKey, -1)) == NULL)
    {
        printf("BIO_new_mem_buf privateKey error\n");
        return -1;
    }
    OpenSSL_add_all_algorithms();//密钥有经过口令加密需要这个函数
    if ((privateRsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, (char *)PASS)) == NULL) 
    {
        printf("PEM_read_RSAPrivateKey error\n");
        return NULL;
    }
    BIO_free_all(bio);
    
    unsigned char *source = (unsigned char *)"123456789";
        
    int rsa_len = RSA_size(publicRsa);
 
    unsigned char *encryptMsg = (unsigned char *)malloc(rsa_len);
    memset(encryptMsg, 0, rsa_len);
         
    int len = strlen(source );
         
    if (RSA_public_encrypt(len, source, encryptMsg, publicRsa, RSA_PKCS1_PADDING) < 0)
        printf("RSA_public_encrypt error\n");
    else 
    {
        rsa_len = RSA_size(privateRsa);
        unsigned char *decryptMsg = (unsigned char *)malloc(rsa_len);
        memset(decryptMsg, 0, rsa_len);
        
        int mun =  RSA_private_decrypt(rsa_len, encryptMsg, decryptMsg, privateRsa, RSA_PKCS1_PADDING);
        //mun:解密后的明文的长度
        if ( mun < 0)
            printf("RSA_private_decrypt error\n");
        else
            printf("RSA_private_decrypt %s\n", decryptMsg);
    }    
    
    RSA_free(publicRsa);
    RSA_free(privateRsa);
    return 0;
}

RSA编程示例(PEM文件方式多线程测试样例)
#include <cstdio>
#include <cstring>
#include <pthread.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#define PRIKEY "prikey.pem"
#define PUBKEY "pubkey.pem"
 
RSA *publicRsa = NULL;
RSA *privateRsa = NULL;
 
void* rsaThreadOne(void* param)
{    
    unsigned char *source = (unsigned char *)param;
        
    int rsa_len = RSA_size(publicRsa);
 
    unsigned char *encryptMsg = (unsigned char *)malloc(rsa_len);
    memset(encryptMsg, 0, rsa_len);
         
    int len = rsa_len - 11;
         
    if (RSA_public_encrypt(len, source, encryptMsg, publicRsa, RSA_PKCS1_PADDING) < 0)
    {
        printf("rsaThreadOne RSA_public_encrypt error\n");
        return 0;
    }
        
    rsa_len = RSA_size(privateRsa);
    unsigned char *decryptMsg = (unsigned char *)malloc(rsa_len);
    memset(decryptMsg, 0, rsa_len);
    
    int mun =  RSA_private_decrypt(rsa_len, encryptMsg, decryptMsg, privateRsa, RSA_PKCS1_PADDING);
 
    if ( mun < 0)
    {
        printf("rsaThreadOne RSA_private_decrypt error\n");
        return 0;
    }
    else 
    {
        printf("rsaThreadOne %s\n", decryptMsg);
    }
    
    return 0;
}
 
void* rsaThreadTwo(void* param)
{    
    unsigned char *source = (unsigned char *)param;
        
    int rsa_len = RSA_size(publicRsa);
 
    unsigned char *encryptMsg = (unsigned char *)malloc(rsa_len);
    memset(encryptMsg, 0, rsa_len);
         
    int len = rsa_len - 11;
         
    if (RSA_public_encrypt(len, source, encryptMsg, publicRsa, RSA_PKCS1_PADDING) < 0)
    {
        printf("rsaThreadTwo RSA_public_encrypt error\n");
        return 0;
    }
 
    rsa_len = RSA_size(privateRsa);
    unsigned char *decryptMsg = (unsigned char *)malloc(rsa_len);
    memset(decryptMsg, 0, rsa_len);
    
    int mun =  RSA_private_decrypt(rsa_len, encryptMsg, decryptMsg, privateRsa, RSA_PKCS1_PADDING);
 
    if ( mun < 0)
    {
        printf("rsaThreadTwo RSA_private_decrypt error\n");
        return 0;
    }
    else 
    {
        printf("rsaThreadTwo %s\n", decryptMsg);
    }    
    return 0;
}
 
int main(int argc, char *argv[])
{
    FILE *fp = NULL;
    if ((fp = fopen(PUBKEY, "r")) == NULL) 
    {
        printf("pubkey_path error\n");
        return -1;
    }     
   
    if ((publicRsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL)) == NULL) 
    {
            printf("PEM_read_RSA_PUBKEY error\n");
            return -1;
    }
    fclose(fp);
    
    if ((fp = fopen(PRIKEY, "r")) == NULL) 
    {
        printf("prikey_path error\n");
        return -1;
        }
    OpenSSL_add_all_algorithms();//密钥有经过口令加密需要这个函数
    if ((privateRsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, (char *)"8888")) == NULL) 
    {
        printf("PEM_read_RSAPrivateKey error\n");
        return NULL;
    }
    fclose(fp);
        
    pthread_t tid1 ;
    pthread_t tid2 ;
 
    pthread_create(&tid1, NULL, rsaThreadOne, (void *)"123456789");
    pthread_create(&tid2, NULL, rsaThreadTwo, (void *)"987654321");
        
    pthread_join(tid1,NULL);    
    pthread_join(tid2,NULL);
         
    return 0;
}

注:编译时需加上库

gcc -I../include rsatest.c -L . -lcrypto -lssl

相应参考文章、文档
--------------------- 
作者:aqlick12 
来源:CSDN 
原文:https://blog.csdn.net/aqlick12/article/details/78480505 
版权声明:本文为博主原创文章,转载请附上博文链接!

Linux 中对升级程序进行数字认证相关推荐

  1. 在Red Hat Linux中自动运行程序

    在Red Hat Linux中自动运行程序 1.开机启动时自动运行程序 Linux加载后, 它将初始化硬件和设备驱动, 然后运行第一个进程init.init根据配置文件继续引导过程,启动其它进程.通常 ...

  2. gcc -pthread_错误-在GCC Linux中使用C程序未定义对'pthread_create'的引用

    gcc -pthread 在Linux中修复对'pthread_create'的未定义引用 (Fixing undefined reference to 'pthread_create' in Lin ...

  3. 如何在Linux中安装应用程序

    如果您喜欢这些文章,欢迎点击此处订阅本Blog <script type="text/javascript"> </script> <script s ...

  4. linux名字的由来,Linux中的nice程序名字的由来

    Linux中nice程序的作用,想必大家都知道,就是通过一个 -20到19 的数字,来控制CPU分配到这个进程的时间片得多少.数字越小,CPU分配的时间片越多,也就是所谓的优先级越高. 我其实第一眼看 ...

  5. linux各种小程序源码,Linux中的小程序—— 进度条

    在说正事之前,首先科普一下在什么是回车什么是换行? 我们通常所说的回车就是从一行的末尾跳到另一行的开头,但事实上这却是由回车和换行两个动作所完成的,也就是键盘上所完成的工作.但实际上,回车是光标重回开 ...

  6. Linux中的mate程序的进程,终端下以后台模式运行Linux程序的过程详解

    这是一个简短但是非常有用的教程:它向你展示从终端运行Linux应用程序的同时,如何保证终端仍然可以操作. 在Linux中有许多方式可以打开一个终端,这主要取决于你的发行版的选择和桌面环境. Linux ...

  7. 在linux中运行安卓程序

    文章目录 摘要 前言 安装 Andrion Studio 创建和管理虚拟设备 安装和添加文件 其他 使用命令行启动模拟器 参考 摘要 出于需求,我需要一台安卓模拟器.我选择使用Android Stud ...

  8. 如何在 Linux 中运行 DOS 程序!

    导读 传统的 DOS 操作系统支持的许多非常优秀的应用程序: 文字处理,电子表格,游戏和其它的程序.但是一个应用程序太老了,并不意味着它没用了. 如今有很多理由去运行一个旧的 DOS 应用程序.或许是 ...

  9. linux中如何升级python版本号,linux的python版本升级

    可利用Linux自带下载工具wget下载,如下所示: #tar -zxvf Python-2.7.13.tgz 进入解压缩后的文件 #cd Python-2.7.13 在编译前先在/usr/local ...

最新文章

  1. matplotlib如何绘制两点间连线_机器学习:Python常用库——Matplotlib库
  2. 微信公众平台消息接口PHP版
  3. C语言中positive用法,sprintf - C语言库函数
  4. 简易排水简车的制作 TurnipBit 系列教程
  5. ios打包报错:User interaction is not allowed
  6. 安装 | MatlabR2019b: License Manager Error -8. License checkout failed.
  7. Git 基础(八)—— Github 的使用(账号管理)
  8. socket 源码分析
  9. 如何在Cadence Virtuoso中自定义快捷键?
  10. Listen1 - 让你畅享全网音乐!你值得拥有!
  11. 4r照片尺寸是多大_数码照片4D、4R、6RW是什么意思?4R照片尺寸是多大图片?
  12. java_232_GOF23设计模式_建造者模式详解_练习
  13. 设置和取消Word文档打开密码的三种方法
  14. 技术方向决策的几点思考
  15. 通俗的讲,网络爬虫到底是什么?
  16. 普元中间件部署应用程序
  17. 股票查询接口功能是什么?
  18. VM虚拟机中鼠标左键点击失效解决方案
  19. ZOJ Gold Coins2345
  20. 三十二 我在软件园的那些日子里

热门文章

  1. 【高端定制】属于自己的背单词软件
  2. CBK精准扶贫走进广东省暨全国代理商大会圆满落幕
  3. python 将带数字的拼音转换为带声调的拼音
  4. 分享||元器件类别分类的标准
  5. 全国计算机等级考试一级试题2,全国计算机等级考试一级试题
  6. C++开发报错之 “模块计算机类型x64与目标计算机x86类型冲突”
  7. 快餐行业(网上订餐)如何与网络相结合?
  8. 漏洞小总结:浏览器里那些奇怪的逻辑
  9. python在土木工程中的应用_大数据技术及其在土木工程中的应用
  10. saxon 处理xslt