RSA PKCS1 PADDING和UNPADDING 示例

embedded/2025/3/6 20:00:12/

在进行RSA加密和解密时,PKCS1是一种内容填充方法。

openssl的相关代码位于:

https://github.com/openssl/openssl/blob/master/crypto/rsa/rsa_pk1.c

# define RSA_PKCS1_PADDING 1

如果是采用openssl进行相关的RSA操作,只需要在进行解密时设置padding类型即可。

int  result = RSA_public_decrypt(data_len,enc_data,decrypted,rsa,padding);

但是一些情况下,一些比较不怎么的的厂家生产的密码机没有提供padding接口,就需要我们自己实现。

此处实现 一个PKCS1的 操作与反操作。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <openssl/rand.h>/*** RSA PKCS#1 v1.5解填充函数* @param padded     解密后的填充数据块* @param padded_len 数据块长度(等于模长)* @param out_data   输出明文缓冲区(需预分配足够内存)* @return           明文长度(失败返回-1)*/
int pkcs1_unpadding(const unsigned char *padded, int padded_len, unsigned char *out_data) {// 检查基础结构:首字节为0x00,第二字节为0x02‌:ml-citation{ref="2,4" data="citationList"}if (padded_len < 11 || padded[0] != 0x00 || padded[1] != 0x02) {fprintf(stderr, "填充格式错误:无效的块类型标识\n");return -1;}// 查找分隔符0x00的位置(从第三字节开始)‌:ml-citation{ref="2,5" data="citationList"}int sep_pos = -1;for (int i = 2; i < padded_len; i++) {if (padded[i] == 0x00) {sep_pos = i;break;}}// 验证分隔符位置有效性:至少在第10字节之后(PS≥8字节)‌:ml-citation{ref="2,4" data="citationList"}if (sep_pos == -1 || sep_pos - 2 < 8) {fprintf(stderr, "填充格式错误:未找到分隔符或PS长度不足8字节\n");return -1;}// 检查PS部分是否含非法0x00字节‌:ml-citation{ref="2,5" data="citationList"}for (int i = 2; i < sep_pos; i++) {if (padded[i] == 0x00) {fprintf(stderr, "填充格式错误:PS部分存在非法0x00字节\n");return -1;}}// 提取明文数据‌:ml-citation{ref="2,5" data="citationList"}int data_len = padded_len - sep_pos - 1;memcpy(out_data, padded + sep_pos + 1, data_len);return data_len;
}/*** RSA PKCS#1 v1.5填充函数* @param msg       明文数据* @param msg_len   明文长度* @param modulus   模长(RSA密钥位数/8,如2048位密钥为256字节)* @return          填充后的数据块(需调用者释放内存),失败返回NULL*/
unsigned char* pkcs1_padding(const unsigned char *msg, int msg_len, int modulus) {// 检查明文长度限制(最大为 modulus - 11)‌:ml-citation{ref="5" data="citationList"}if (msg_len > modulus - 11) {fprintf(stderr, "明文过长(最大允许长度:%d字节)\n", modulus - 11);return NULL;}// 分配填充后的内存块(长度等于模长)‌:ml-citation{ref="5" data="citationList"}unsigned char *padded = (unsigned char *)malloc(modulus);if (!padded) return NULL;// 填充结构:0x00 || 0x02 || PS(随机非零字节) || 0x00 || 明文 ‌:ml-citation{ref="1,2" data="citationList"}padded[0] = 0x00;          // 固定前缀padded[1] = 0x02;          // 块类型标识(公钥加密)// 计算PS长度:modulus - msg_len - 3(0x00、0x02、分隔符0x00各占1字节)int ps_len = modulus - msg_len - 3;if (ps_len < 8) {          // PS最小长度需≥8字节 ‌:ml-citation{ref="1,5" data="citationList"}fprintf(stderr, "PS长度不足8字节\n");free(padded);return NULL;}// 生成随机非零填充字节(PS)‌:ml-citation{ref="2,3" data="citationList"}if (RAND_bytes(padded + 2, ps_len) != 1) {  // 使用OpenSSL安全随机数‌:ml-citation{ref="5" data="citationList"}fprintf(stderr, "随机数生成失败\n");free(padded);return NULL;}// 确保PS所有字节非零(逐个替换0x00)‌:ml-citation{ref="2" data="citationList"}for (int i = 2; i < ps_len + 2; i++) {while (padded[i] == 0x00) {RAND_bytes(padded + i, 1);}}// 填充分隔符和明文数据padded[ps_len + 2] = 0x00;                 // 分隔符memcpy(padded + ps_len + 3, msg, msg_len); // 原始数据return padded;
}// 示例使用
int main() {//     RAND_poll();// 示例明文(长度需≤245字节,假设模长256字节)const char *plaintext = "Hello PKCS1_PADDING!";int modulus = 256;  // 对应2048位密钥// 执行填充unsigned char *padded = pkcs1_padding((unsigned char*)plaintext, strlen(plaintext), modulus);if (!padded) return -1;// 输出填充结果(前10字节)printf("填充后数据(Hex):");for (int i = 0; i < 10; i++) {printf("%02X ", padded[i]);}printf("...\n");// 解填充操作unsigned char decrypted[256];int decrypted_len = pkcs1_unpadding(padded, modulus, decrypted);if (decrypted_len > 0) {printf("解填充成功:%.*s\n", decrypted_len, decrypted);}return 0;
}


http://www.ppmy.cn/embedded/170554.html

相关文章

分布式日志和责任链路

目录 日志问题 责任链问题 分布式日志 GrayLog简介 部署安装 收集日志 配置Inputs 集成微服务 日志回收策略 搜索语法 搜索语法 自定义展示字段 日志统计仪表盘 创建仪表盘 链路追踪 APM 什么是APM 原理 技术选型 Skywalking简介 部署安装 微服务探针 整合…

React Native 实现滑一点点内容区块指示器也滑一点点

效果图如上&#xff0c;内容滑一点点&#xff0c;指示器也按比例话一点点&#xff0c;列表宽度跟数据有关。 实现思路如下&#xff1a; 1.监听列表滑动事件&#xff0c;获取列表横向滑动距离&#xff0c;假设为A&#xff1b; 2.获取列表的宽度&#xff0c;及列表可滑动的宽度…

我的ChatGPT怎么登不上?

近期&#xff0c;不少用户反馈在使用ChatGPT时遇到登录困难、连接超时等问题。本文将从技术角度分析常见原因&#xff0c;并提供合规、安全的解决方案&#xff0c;同时结合开发者实际需求推荐实用工具&#xff0c;助您高效应对登录障碍。 ChatGPT登录失败的常见原因 网络环境限…

JVM常用概念之对象初始化的成本

在JVM常用概念之新对象实例化博客中我讲到了对象的实例化&#xff0c;主要包含分配&#xff08;TLAB&#xff09;、系统初始化、用户初始化&#xff0c;而我在JVM常用概念之线程本地分配缓冲区&#xff08;ThreadLocal Allocation Buffer&#xff0c;TLAB&#xff09;博客中也讲…

探索 Ubuntu 中的 Hostname 配置与管理

探索 Ubuntu 中的 Hostname 配置与管理 当你搭建一台 Ubuntu 服务器时&#xff0c;Hostname 是你遇到的第一个配置项之一。无论是一个趣味十足的名字&#xff08;比如 “TARDIS”&#xff09;还是一个冷酷无情的描述性标识&#xff08;比如 “webserver-01”&#xff09;&…

如何快速上手RabbitMQ 笔记250304

如何快速上手RabbitMQ 要快速上手 RabbitMQ&#xff0c;可以按照以下步骤进行&#xff0c;从安装到基本使用逐步掌握核心概念和操作&#xff1a; 1. 理解核心概念 Producer&#xff08;生产者&#xff09;&#xff1a;发送消息的程序。Consumer&#xff08;消费者&#xff09…

一文学会Spring

一、Spring简介 Spring的优点 Spring是一个开源免费的框架、容器Spring是一个轻量级的框架&#xff0c;非侵入式的控制反转IOC、面向切面AOP支持事务 Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器 二、IOC 2.1 IOC本质 控制反转IOC&#xff0c;是一种设计思想…

windows 利用nvm 管理node.js 2025最新版

1.首先在下载nvm 下载链接 2. 下载最新版本的nvm 3. 同意协议 注意&#xff1a;选择安装路径 之后一直下一步即可 可以取消勾选 open with Powershell 勾选后它会自动打开Powershell 这里选用cmd 输入以下命令查看是否安装成功 nvm version 查看已经安装的版本 我之前自…