在进行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;
}