AES格式保持加密C++实现

一.描述

字符集为大小写字母与数字,-*,一共64个字符,-*加密后不变,各字符集加密完后应该还是属于该字符集。

二.思路

首先将字符编码,最大的字符集个数为26,5个比特即可表示,用8个比特表示一个字符,前3个比特为控制位,表示其为哪一种类的字符,后五个比特表示该字符在字符集内的具体数值。用CTC模式进行加密,每次从加密后的counter值中取五位出来与每个字符编码的后5个比特异或进行加密,加密完输出时,根据控制位进行相应的处理使其格式保持。解密就是再加密一次,详情见代码注释。aes的源代码请自行下载。

三.程序源代码

 

//
//  main.cpp
//  csv_ecyt
//
//  Created by 王俊 on 2017/10/29.
//  Copyright © 2017年 王俊. All rights reserved.
//

#include <stdio.h>
#include<string>
#include<iostream>
#include<map>
#include <stdlib.h>
#include <time.h>
using namespace std;
#include"aes.h"
string cm;
u8 ct[16], sct[16], cipherKey[16] = { 0x2c ,0x7e, 0x16, 0x17, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xe7, 0x15, 0x87, 0x09, 0xcf, 0x4f, 0x21 };
u32 int_cm[4]={0,0,0,0},rk[44], bigint[4] = { 0,0,0,0}, sm[4]={0,0,0,0,},cms[4],temp_sm[4];
map<int, int> c_char_int, int_c_char,l_char_int,int_l_char,char_int,int_char;//用于保存字符集与字符之间双向映射的两个map
int find_kind(char a)
//返回值 1是大写字母,2是小写字母,3是数字,4是 - ,5是*,-1出错
{
    if (a >= 'A'&&a <= 'Z')
        return 1;
    if (a >= 'a'&&a <= 'z')
        return 2;
    if (a >= '0'&&a <= '9')
        return 3;
    if (a == '-')
        return 4;
    if (a == '*')
        return 5;
    return -1;
}
void change_to_bigint()
//字符串转化为可加密的0,1编码
// 其思想是用8个bit保存一个字符,前三个比特用于保存种类号,后5个比特用于保存字符集序号,
//组序号与字符在字符串出现的序号相同,组值等于该字符的字符集与int的映射值
{
    unsigned int temp1,kind,sft_cnt=0,count=0;
    for (int i = 0;i < cm.length();i++)
    {
        count = i * 8 / 32;
        sft_cnt = i * 8 - (i * 8 / 32) * 32;
        kind = find_kind(cm[i]);    //获取所属种类
        if(kind==-1)
        {
            cout<<"error:不在字符集内!"<<endl;
            exit(1);
        }
        if (kind == 1)
            temp1 = c_char_int[(int)cm[i]];
        else if (kind == 2)
            temp1 = l_char_int[(int)cm[i]];
        else if (kind == 3)
            temp1 = char_int[(int)cm[i]];
        else
            temp1 = 0;
        kind <<= 5;                 //种类号左移至最高三位
        kind ^= temp1;              //生成带控制信息的编码
        kind <<= sft_cnt;           //移动到相应的位置
        int_cm[count] ^= kind;
    }
}
void init_table()    //初始化映射表
{
    int start =65;
    for (int i = 0;i < 26;i++,start++)
    {
        c_char_int.insert(make_pair(start, i));
        int_c_char.insert(make_pair(i, start));
    }
    start = 97;
    for (int i = 0;i < 26;i++,start++)
    {
        l_char_int.insert(make_pair(start, i));
        int_l_char.insert(make_pair(i, start));
    }
    start = 48;
    for (int i = 0;i < 10;i++,start++)
    {
        char_int.insert(make_pair(start, i));
        int_char.insert(make_pair(i, start));
    }
}
void init_counter()    //初始化counter
{
    for (int i = 0;i < 16;i++)
        ct[i] = rand()%256;
}
void Encrypt(u8 a[],u32 b[])    //加解密函数,第一个参数为aes加密后的counter,第二个用于保存加密后的密文或者解密后的明文
//每次从counter中取5位出来与明文相异或,控制位保持不变
{
    unsigned int temp=0,temp1=0, temp2=0;
    unsigned int xr[4]={0,0,0,0};
    //xor用于保存将u8 counter换成4个int值,便于后面的异或作
    unsigned int sft_cnt_cm,sft_cnt_sct, count_cm = 0,count_sct=0;
    for (int i = 0;i < 16;i++)  //将u8 counter换成4个int值,便于后面的异或操作
    {
        temp=(int)a[i];
        xr[i / 4] = xr[i / 4] ^ (temp << ((i % 4) * 8));
    }
    for (int i = 0;i < 16;i++)
    {
        count_cm = i * 8 / 32;
        count_sct = i * 5/ 32;
        sft_cnt_cm = i * 8 - (i * 8 / 32) * 32;  //用于定位int所保存的4个值哪一个值
        sft_cnt_sct=i*5- (i *5 / 32) * 32;          //用于定位本次所需取出的5位组的位置
        if (i*5== 30) //跨int操作特殊处理
        {
            temp1 = 0x03;
            temp1 &= (xr[0] >>30);
            temp2 = 0x07;
            temp2 &= xr[1];
            temp2<<=2;
            temp2 ^= temp1;
            temp2 <<= sft_cnt_cm;
            b[count_cm]^=temp2;
            continue;
        }
        if (i*5 == 60)
        {
            temp1 = 0x0f;
            temp1 &= (xr[1] >> 28);
            temp2 = 0x01;
            temp2 &= xr[2];
            temp2<<=4;
            temp2 ^= temp1;
            temp2 <<= sft_cnt_cm;
            b[count_cm]^=temp2;
            temp1 = 0x1f;
            continue;
        }
        temp1 = 0x1f;      //每次取5位
        temp1 <<= sft_cnt_sct;    //移动到相应的位置
        temp2 = temp1&xr[count_sct];   //与xor相与获取6位组的密文
        temp2>>=sft_cnt_sct;
        temp2 <<= sft_cnt_cm;//移动到相应的位置
        b[count_cm]^= temp2;       //更新数据
    }
}
void Show(u32 a[])  //将加解密后的编码以字符串的方式显示出来
//每次取出8位出来,根据控制信息与数值输出字符
{
    unsigned int temp1,temp2,temp3;
    int sft_cnt=0,count=0;
    for(int i=0;;i++)
    {
        count=i*8/32;
        sft_cnt=i*8-((i*8)/32)*32;
        temp1=0xff;
        temp2=0x1f;
        temp3=0xe0;
        temp1<<=sft_cnt;
        temp2<<=sft_cnt;
        temp3<<=sft_cnt;
        temp1&=a[count];
        temp2&=temp1;
        temp3&=temp1;
        temp2>>=sft_cnt;
        temp3>>=(5+sft_cnt);
        if(temp3==1)
            cout<<(char)int_c_char[temp2%26];
        else if(temp3==2)
            cout<<(char)int_l_char[temp2%26];
        else if(temp3==3)
            cout<<temp2%10;
        else if(temp3==4)
            cout<<"-";
        else if(temp3==5)
            cout<<"*";
        else
            break;
    }
    cout<<endl;
}
void Decrypt(u8 a[],u32 b[])
{
    Encrypt(a,b);    //解密就是再加密一次
}
int main()
{
    srand((unsigned int)time(NULL));
    int Nr;  //用于保存轮加密的轮数
    cin >> cm;    //输入的明文
    init_table();     //初始化字符集的映射表
    change_to_bigint();       //将输入的明文字符串映射为0,1编码
    init_counter();              //用counter模式来实现aes加密,初始化随机数
    Nr = rijndaelKeySetupEnc(rk, cipherKey, 128);   //密钥扩展
    rijndaelEncrypt(rk, Nr, ct, sct);             //加密counter
    for(int i=0;i<4;i++)
    sm[i]=int_cm[i];
    Encrypt(sct,sm);     //与明文异或生成密文并显示(保持格式加密)
    Show(sm);
    Decrypt(sct,sm);      //解密
    Show(sm);
    getchar();
    getchar();
    return 0;
}

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值