交个朋友吧

openSSL学习-1

上一节【openSSL学习-0】了解openSSL和安装,本节以des.h为例,学习DES分组密码算法

DES

加密分组

  • 调用函数,实现一个分组的加解密(DES-ECB模式)
#include <iostream>
#include "openssl/des.h"

using namespace std;
/*
 * DES-ECB模式加解密测试
 */
int main() {
    //明文
    unsigned char data[]="1234567";
    //密钥
    unsigned char key[]="abcdefg";
    //密文
    unsigned char cip[]={0};
    //输出
    unsigned char out[]={0};
    DES_key_schedule key_sch; //实际存储密钥

    //密钥生成
    DES_set_key((const_DES_cblock*)&key,&key_sch);
    //加密
    DES_ecb_encrypt((const_DES_cblock*)&data,(DES_cblock*)&cip,&key_sch,DES_ENCRYPT);
    cout << "密文:"<<cip<<endl;
    //解密
    DES_ecb_encrypt((const_DES_cblock*)&cip,(DES_cblock*)&out,&key_sch,DES_DECRYPT);
    cout << "明文:" <<out<<endl;

    return 0;
}

image-20221012142432108

加密文件

  • 使用命令:加解密文件
//
// Created by hang shao on 2022/10/12.
//
#include "iostream"
#include "openssl/des.h"
#include "fstream"
using namespace std;

int main(int argc,char* argv[])
{
    string cmd="加密文件:crypt_file 输入文件名 输出文件名 密码(6位)\n";
    cmd += "解密文件:crypt_file 输入文件名 输出文件名 密码(6位)-d\n";
    cout << cmd<<endl;
    //输入判定
    if(argc<4)
    {
        cerr<<"输入错误!"<<endl;
        return -1;
    }

    string  in_file=argv[1];    //输入文件
    string  out_file=argv[2];   //输出文件
    string  password=argv[3];   //密钥
    int is_encrypt=DES_ENCRYPT; //加密
    if(argc>4)
    {
        is_encrypt=DES_DECRYPT;//解密
    }

    //二进制打开输入文件
    ifstream ifs(in_file,ios ::binary);
    if(!ifs)
    {
        cerr << "in_file:"<<in_file<<"打开失败!"<<endl;
        return -1;
    }

    //二进制打开输出文件
    ofstream ofs(out_file,ios ::binary);
    if(!ofs)
    {
        ifs.close();
        cerr << "out_file:"<<out_file<<"打开失败!"<<endl;
        return -1;
    }

    //处理密钥,多出丢掉,少的补0
    int key_size=password.size();
    const_DES_cblock key={0};//少则补0
    if(key_size > sizeof (key))
    {
        key_size=sizeof (key);//多出丢掉
    }
    memcpy(key,password.c_str(),key_size);
    DES_key_schedule key_sch;
    DES_set_key(&key,&key_sch);//设置密钥

    const_DES_cblock in;//输入文件
    DES_cblock out;//输出文件

    //读文件-》加解密文件-》写入文件
    while (!ifs.eof())
    {
        //读文件
        ifs.read((char*)in,sizeof(in));
        int count=ifs.gcount();
        if(count<=0) break;

        //加解密文件
        DES_ecb_encrypt(&in,&out,&key_sch,is_encrypt);

        //写入文件
        ofs.write((char *)out,sizeof(out));
    }

    ifs.close();
    ofs.close();
    return 0;
}

输入命令:

./file_DES test.png cip.png 123456 
./file_DES cip.png out.png 123456 -d

得到的文件:

image-20221013101909994

问题:

这里加密后的密文文件多了6字节,解密后的文件也多了6字节。

优化

原因:

没有丢弃填充(加密时自动补充为8的倍数)的部分

解决方法:

加密前数据手动填充,解密后手动去除填充的部分

填充方法:

image-20221013103041985

//
// Created by hang shao on 2022/10/12.
//
#include "iostream"
#include "openssl/des.h"
#include "fstream"
using namespace std;

int main(int argc,char* argv[])
{
    string cmd="加密文件:crypt_file 输入文件名 输出文件名 密码(6位)\n";
    cmd += "解密文件:crypt_file 输入文件名 输出文件名 密码(6位)-d\n";
    cout << cmd<<endl;
    //输入判定
    if(argc<4)
    {
        cerr<<"输入错误!"<<endl;
        return -1;
    }

    string  in_file=argv[1];    //输入文件
    string  out_file=argv[2];   //输出文件
    string  password=argv[3];   //密钥
    int is_encrypt=DES_ENCRYPT; //加密
    if(argc>4)
    {
        is_encrypt=DES_DECRYPT;//解密
    }

    //二进制打开输入文件
    ifstream ifs(in_file,ios ::binary);
    if(!ifs)
    {
        cerr << "in_file:"<<in_file<<"打开失败!"<<endl;
        return -1;
    }

    //二进制打开输出文件
    ofstream ofs(out_file,ios ::binary);
    if(!ofs)
    {
        ifs.close();
        cerr << "out_file:"<<out_file<<"打开失败!"<<endl;
        return -1;
    }

    //处理密钥,多出丢掉,少的补0
    int key_size=password.size();
    const_DES_cblock key={0};//少则补0
    if(key_size > sizeof (key))
    {
        key_size=sizeof (key);//多出丢掉
    }
    memcpy(key,password.c_str(),key_size);
    DES_key_schedule key_sch;
    DES_set_key(&key,&key_sch);//设置密钥

    const_DES_cblock in;//输入文件
    DES_cblock out;//输出文件

    //获取文件大小
    long long filesize=0;
    ifs.seekg(0,ios::end);//文件指针移到结尾
    filesize=ifs.tellg();
    ifs.seekg(0,ios::beg);//文件指针回到开始
    cout <<"文件大小:"<<filesize<<endl;

    long long read_size=0;
    long long write_size=0;

    //读文件-》加解密文件-》写入文件
    while (!ifs.eof())
    {
        int out_len=sizeof (out);
        //读文件
        ifs.read((char*)in,sizeof(in));
        int count=ifs.gcount();
        if(count<=0) break;
        read_size+=count;

        //PKCS Padding 填充
        //加密到结尾处,填充
        if(read_size==filesize && is_encrypt==DES_ENCRYPT)
        {
            if(filesize%8==0) //填充8个字节的值为8
            {
                //先写入之前的数据
                DES_ecb_encrypt(&in,&out,&key_sch,is_encrypt);
                ofs.write((char *)out,out_len);

                //填充数据8
                memset(in,8,sizeof (in));
            }else
            {
                int padding=8-(filesize%8);//要填充的字节
                //移动位置,填充数据
                memset(in+(filesize%8),padding,padding);
            }
        }
        //加解密文件
        DES_ecb_encrypt(&in,&out,&key_sch,is_encrypt);

        //解密padding
        if(read_size==filesize && is_encrypt==DES_DECRYPT)
        {
            //去除填充数据
            out_len=8-out[7];
        }
        if(out_len<=0) break;

        //写入文件
        ofs.write((char *)out,out_len);
        write_size+=out_len;
    }
    ifs.close();
    ofs.close();
    cout<<"写入大小:"<<write_size<<endl;
    return 0;
}

image-20221013112206429

posted @ 2022-10-16 16:13  PamShao  阅读(148)  评论(0)    收藏  举报