基于C语言的UTF-8中英文替换密码设计
简要说明
本设计为湖南大学密码学的一次课程作业设计。非作业目的可随意引用。
由于本人初次接触密码学,本设计可能存在问题以及漏洞。若发现望指出。
GitHub : https://github.com/He11oLiu/SubstitutionCipher
中文utf-8 简单偏移替换密码
初次尝试
中文utf-8的读取
utf-8的格式
UTF-8编码规则:如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其余各字节均以10开头。
获取单个utf-8 编码的长度,注意当最高位为0情况。
int get_utf_8_len(char s){
int i = 0x80,len = 0;
while(s&i) {i=i>>1;len++;}
return len==0?1:len;
}
从byte数组中获取单个utf-8 字符
word_length = get_utf_8_len(word_byte[i]);
strncpy(word_utf_8,word_byte+i,word_length);
从3字节utf-8 字符中获取utf-8 编号
int get_utf_8_code(char *s){
return (*s & 0x0F)<<12 | (*(s+1)&0x3F)<<6 |(*(s+2)&0x3F);
}
获取中文字符
常用中文显示范围
U+4e00 - U+9fa5
故利用utf_8_is_cn来判断
#define max_cn_utf_8 0x9fa5
#define min_cn_utf_8 0x4e00
#define cn_utf_8_size (max_cn_utf_8-min_cn_utf_8)
#define utf_8_is_cn(code) (code>=min_cn_utf_8 && code <max_cn_utf_8)
偏移加密测试
/**
* Caesar_cipher_encrpt
* 简单凯撒加密测试,bias为偏移量
* 常用中文大小为cn_utf_8_size
*/
void Caesar_cipher_encrpt(int_32U *plain_code,int_32U *cipher_code,int_32U bias){
*cipher_code = ((*plain_code-min_cn_utf_8)+bias)%cn_utf_8_size + min_cn_utf_8;
}
/**
* Caesar_cipher_decrpt
* 简单凯撒解密测试,bias为偏移量
* 常用中文大小为cn_utf_8_size
*/
void Caesar_cipher_decrpt(int_32U *cipher_code,int_32U *plain_code,int_32U bias){
*plain_code = ((*cipher_code+cn_utf_8_size-min_cn_utf_8)-bias)%cn_utf_8_size + min_cn_utf_8;
}
主函数中测试:
if(utf_8_is_cn(utf_8_code)){
Caesar_cipher_encrpt(&utf_8_code,&cipher_code,100);
get_utf_8_word(cipher_code, word_utf_8);
printf("Encrpted: %s ",word_utf_8);
Caesar_cipher_decrpt(&cipher_code,&utf_8_code,100);
get_utf_8_word(utf_8_code, word_utf_8);
printf("Decrpted: %s\n",word_utf_8);
}
测试结果
Encrpted: 云 Decrpted: 中
Encrpted: 旫 Decrpted: 文
Encrpted: 匄 Decrpted: 加
Encrpted: 尪 Decrpted: 密
Encrpted: 涯 Decrpted: 测
Encrpted: 谹 Decrpted: 试
注意 第一部分代码中有部分错误
在进行下面改进的过程中发现,没有用unsigned的话,会导致%为有符号数。
故将原来的int重新定义如下
typedef unsigned int int_32U;
typedef unsigned long long int_64U;
加密解密程序框架设计
~ ./encryption test out
Encrption end!
~ ./decryption out test1
Decryption end!
初版简单偏移替换加密解密见Caesar_cipher中源代码。
替换加密加强
由于中文文字过多,使用完整的密码转换本不再合理。故分析针对每一个明文,可用的因素有以下几点:
- 类似秘钥的
seed - 明文所在位置:明文字符所在位置作为一个因素引入,可以防止相同的字替换到相同的字符,尽量避免统计概率的暴露。
搭建起支持变换seed的框架如下:
#define find_bias(seed1,seed2) generate_bias_simple(seed1,seed2)
typedef unsigned int int_32U;
typedef unsigned long long int_64U;
int generate_bias_simple(int_32U seed1,int_64U seed2);
在传入替换加密解密时,利用生成的bias
bias = find_bias(count,(int_64U)seed_high<<32|seed_low);
Caesar_cipher_decrpt(&utf_8_code,&plain_code,bias);
而最简单的,利用上述两个因素的bias计算如下:
int generate_bias_simple(int_32U seed1,int_64U seed2){
return (seed1*seed2)%cn_utf_8_size;
}
该算法加密主要部分代码
while(!feof(fp_in)){
if(fgets(word_byte,max_len,fp_in)==NULL) continue;
for(i = 0; word_byte[i]!='\0';i = i + word_length){
count ++;
//获取utf-8编码该字长度
word_length = get_utf_8_len(word_byte[i]);
//获取utf-8字,放入word_utf_8中
strncpy(word_utf_8,word_byte+i,word_length);
word_utf_8[word_length] = '\0';
// printf("%s",word_utf_8);
if(word_length == 3) {
//获取当前utf-8字符的utf-8码
utf_8_code = get_utf_8_code(word_byte+i);
//若utf-8为中文 进行加密
if(utf_8_is_cn(utf_8_code)){
bias = find_bias(count,(int_64U)seed_high<<32|seed_low);
//偏移替换加密
Caesar_cipher_encrpt(&utf_8_code,&cipher_code,bias);
//获取utf_8的字
get_utf_8_word(cipher_code, word_utf_8);
fprintf(fp_out,"%s",word_utf_8);
}
else{
fprintf(fp_out,"%s",word_utf_8);
}
}
else
fprintf(fp_out,"%s",word_utf_8);
}
}
该算法解密主要部分代码
while(!feof(fp_in)){
if(fgets(word_byte,max_len,fp_in)==NULL) continue;
for(i = 0; word_byte[i]!='\0' ;i = i + word_length){
count ++;
//获取utf-8编码该字长度
word_length = get_utf_8_len(word_byte[i]);
//获取utf-8字,放入word_utf_8中
strncpy(word_utf_8,word_byte+i,word_length);
word_utf_8[word_length] = '\0';
if(word_length == 3) {
//获取当前utf-8字符的utf-8码
utf_8_code = get_utf_8_code(word_byte+i);
//若utf-8为中文 进行解密
if(utf_8_is_cn(utf_8_code)){
//计算偏移量
bias = find_bias(count,(int_64U)seed_high<<32|seed_low);
//凯撒密码解密部分
Caesar_cipher_decrpt(&utf_8_code,&plain_code,bias);
get_utf_8_word(plain_code, word_utf_8);
fprintf(fp_out,"%s",word_utf_8);
}
else{
fprintf(fp_out,"%s",word_utf_8);
}
}
else
fprintf(fp_out,"%s",word_utf_8);
}
}
加密解密测试
test_txt内容
句子测试:
在密码学中,恺撒密码(英语:Caesar cipher),或称恺撒加密、恺撒变换、变换加密,是一种最简单且最广为人知的加密技术。
相同字符测试:
密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密。
输入命令加密
~ ./encryption test_txt out ab12idhs
Encrption end!
out内容
偮呢酊媸:
鮯禕鉙片迻,魚確汷懺(旼駥:Caesar cipher),嚐饗籪紋阆鮵、瘺盛鄎鴡、捨潻覦轕,澏叩簿鑟參嚅齲捂薮燲滻煮沖玟祎粑媈。
蹐柭騥擘历鳽:
郭赶暾捇忐誽蝆悎崗妠蒍脖綟囧印繝竦睯傷黥砭璶焿鰬颵锾溆欏闼銅輎桖擟慨豕裞。
输入命令解密
~ ./decryption out test_out ab12idhs
Decryption end!
test_out内容
句子测试:
在密码学中,恺撒密码(英语:Caesar cipher),或称恺撒加密、恺撒变换、变换加密,是一种最简单且最广为人知的加密技术。
相同字符测试:
密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密密。
若输入秘钥错误 (只错了一位)
~ ./decryption out test_out ab12idhr
Decryption end!
test_out内容
另孒济诙:
圯寎砊孰丸,悇撠寕砑(范谀:Caesar cipher),戺稕悠撹勈寯、悥撾吅掐、合掓勒对,晤丶稄朸箹厏乏朼庼乸仹砥盅勢尉拄杴。
着呕审筱涗谢:
尖尗尘尙尚尛尜尝尞尟尠尡尢尣尤尥尦尧尨尩尪尫尬尭尮尯尰就尲尳尴尵尶尷尸尹。
很明显,在秘钥在只错一位的情况下,已经在正确的明文周围了,下面就来想办法结局一下这个相关性
打乱秘钥与偏移的连续性
由于之前已经写好了整体的框架,这里只需要更改generate_bias_simple函数中的内容。
这次增强的主要原因是,当密钥只有少数几位差距时,乘法所具有的连续性不能够很好的被打乱,所以导致上面密文与原文过于接近。
所以希望能找到一种映射,从连续的秘钥,映射到非连续的秘钥。
经过思考,觉得希望每次所乘秘钥均不同。故设计以下改变seed2的办法。(可能有数学缺陷,先这么设计着,还不知道怎么证明)
- 右边32-bit等于与左32-bit异或
- 交换左右部分
- 循环左移
seed1&0x07位
测试函数如下:(见key_test.c文件)
int main(int argc, const char * argv[]) {
int_64u s_key = 0xf18283a18c4d5fb1;
int count;
printf("%llx\n",s_key);
for(count = 0; count <100;count ++){
s_key = s_key>>32 | ((int)s_key^(s_key>>32))<<32;
s_key = s_key>>(64-(count&0x7))|s_key << (count&0x7);
printf("%llx\n",s_key);
}
return 0;
}
截取部分如下
11ac4ddcb0ddcedb
42e3060e23589bb9
86ee76dd0b8c1839
6b1377243773b6ec
c60c1c86b1377245
e76dd878c18390ce
由于是移动是0 1 2 … 7 则每次是移动28 bit,且每次均有异或。其循环的周期还是比较大的。
修改产生bias 函数如下:
int generate_bias_advance(int_32U seed1,int_64U seed2){
seed2 = seed2>>32 | ((int)seed2^(seed2>>32))<<32;
seed2 = seed2>>(64-(seed1&0x7))|seed2 << (seed1&0x7);
return (seed2*seed1)%cn_utf_8_size;
}
修改后利用秘钥ab12idhr 解密ab12idhs加密的上面同一段文字,结果为
匧塘摣琕:
儼壎煓鸳缪,楤度爓爑(根厅:Caesar cipher),腅嫉少緥镭軽、萜呁磻门、鎭邩娍枨,緷旐秭券儲仢鏛髹棬鳹欓急韫鏲觍曹摁。
局澃郉酭鏩箌:
辻煍蕘婍勤过婣笥賃歝祸鐲甉艬酒非觋敭涘籲霮甑皜懲蛓彽憸撲枮架實縫菛妍嗘麗。
这次第二排没有明显与位置相关的痕迹了。
性能测试
测试环境
利用2k字的文件进行测试,并在代码中加入统计部分。
~ ./encryption test_2k out ab12idhr
Encrption finish! Count : 1843 Time : 0.000746seconds
Speed : 2469 k per socend
~ ./decryption out test_out ab12idhr
Decryption finish! Count : 1843 Time : 0.000720seconds
Speed : 2558 k per socend
存在的问题 & 改进方向
- 针对每个字均更改秘钥可能导致效率不够高,可以更改成每一轮更改秘钥。
- 没有验证数学上的严谨性,可能存在周期性问题,当获取大量明文密文对是可能会受到攻击。
- 可以在输入秘钥上提供更友好的16进制输入方式。
- 可以添加加密接口供其他程序使用。
英文 utf-8 替换密码
简要说明
英文utf-8替换密码的设计继承了前文中文的加密,用法与文件目录相同,不再展示说明。
设计内容
设计思路
由于已经完成了utf-8 的中文加密的内容,所有希望能够有足够的兼容性,能够同时加密中文以及英文。故继承了中文加密的算法,只做出了少数改变。
添加英文utf-8 相关宏
#define min_en_utf_8 0x61
#define max_en_utf_8 0x7a
#define en_utf_8_size (max_en_utf_8-min_en_utf_8)
#define utf_8_is_en(code) (code>=min_en_utf_8 && code < max_en_utf_8)
修改偏移量宏,使其能够兼容英文
#define find_bias_cn(seed1,seed2) generate_bias_advance(seed1,seed2,cn_utf_8_size)
#define find_bias_en(seed1,seed2) generate_bias_advance(seed1,seed2,en_utf_8_size)
增加英文加密解密替换模块
void Caesar_cipher_encrpt_en(int_8U *plain_code,int_8U *cipher_code,int_8U bias){
*cipher_code = ((*plain_code-min_en_utf_8)+bias)%en_utf_8_size + min_en_utf_8;
}
void Caesar_cipher_decrpt_en(int_8U *cipher_code,int_8U *plain_code,int_8U bias){
*plain_code = ((*cipher_code+en_utf_8_size-min_en_utf_8)-bias)%en_utf_8_size + min_en_utf_8;
}
增加英文处理模块
else if(word_length == 1){
utf_8_en_code = word_utf_8[0];
if(utf_8_is_en(utf_8_en_code)){
count_work++;
count_en++;
//这里是英语处理
bias = find_bias_en(count_en,(int_64U)seed_high<<32|seed_low);
Caesar_cipher_encrpt_en(&utf_8_en_code,&cipher_en_code,bias);
*word_utf_8 = cipher_en_code;
*(word_utf_8 + 1) = 0x00;
fprintf(fp_out,"%s",word_utf_8);
}
else{
fprintf(fp_out,"%s",word_utf_8);
}
}
测试功能
同中文相同的处理内容,处理结果如下(秘钥ab12idhs):
瓍赋忲躗:
締跁妕軂锻,牴譊崙詒(昉萘:Ceuqvm pfgssl),竨孵短餀藼釁、惫苨鈒郵、枊衭賡廹,巔醳捱嬈愷軷吉遞愴器撞窧鳰辣摽酢瓴。
娐賉馻蚟倌包:
烙莓鮋樁閰羫咯膄儯闤鳬泃鬴誻櫏尟忩蓴鹍澅伓闋胯衟釤靅三片咗伶霏拺爺處佪甉。
性能测试
同样找了一个大约为2k字的测试文档,保存在test_2k,测试环境同中文加密测试,测试结果如下:
~ ./encryption test_2k test_out ab12idhs
StartEncrption finish! Count : 8448 Time : 0.003290seconds
Speed : 2559 k per socend
~ ./decryption test_out test_2k ab12idhs
Decryption finish! Count : 8448 Time : 0.003720seconds
Speed : 2264 k per socend
这个结果可以说明,计算秘钥的函数严重影响了效率
存在的问题
- 由于英语的字母较少,很容易替换到相同的字母,大大减少了可替换的空间。
- 为了兼容中文加密,英语也采用中文的比较复杂的算法,导致其速度没有改善。
- 英文用替换加密实际证明不太靠谱,还是需要结合扩散形成更复杂的分组加密。
基于C语言的UTF-8中英文替换密码设计的更多相关文章
- selenium2自动化测试实战--基于Python语言
自动化测试基础 一. 软件测试分类 1.1 根据项目流程阶段划分软件测试 1.1.1 单元测试 单元测试(或模块测试)是对程序中的单个子程序或具有独立功能的代码段进行测试的过程. 1.1.2 集成测试 ...
- 《Selenium2自动化测试实战--基于Python语言》 --即将面市
发展历程: <selenium_webdriver(python)第一版> 将本博客中的这个系列整理为pdf文档,免费. <selenium_webdriver(python)第 ...
- 在云平台上基于Go语言+Google图表API提供二维码生成应用
二维码能够说已经深深的融入了我们的生活其中.到处可见它的身影:但通常我们都是去扫二维码, 曾经我们分享给朋友一个网址直接把Url发过去,如今我们能够把自己的信息生成二维码再分享给他人. 这里就分享一下 ...
- 关于《selenium2自动测试实战--基于Python语言》
关于本书的类型: 首先在我看来技术书分为两类,一类是“思想”,一类是“操作手册”. 对于思想类的书,一般作者有很多年经验积累,这类书需要细读与品位.高手读了会深有体会,豁然开朗.新手读了不止所云,甚至 ...
- Gogs - 基于 Go 语言的自助 Git 服务
Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务.Gogs 的目标是打造一个最简单.最快速和最轻松的方式搭建自助 Git 服务.使用 Go 语言开发使得 Gogs ...
- Ggoogle Protocol Buffer的使用 (基于C++语言)
首先说明的是Protocol Buffle是灵活高效的.它的一个很好的优点(很重要的,我认为)就是后向兼容性--当我们扩展了了.proto文件后,我们照样可以用它来读取之前生成的文件. 之前已经写了关 ...
- 基于C# 语言的两个html解析器
基于C# 语言的两个html解析器 1)Html Agility Pack http://nsoup.codeplex.com/ 代码段示例: HtmlDocument doc = new HtmlD ...
- springmvc国际化 基于浏览器语言的国际化配置
当前标签: springmvc springmvc国际化 基于浏览器语言的国际化配置 苏若年 2013-10-09 13:03 阅读:305 评论:0 SpringMVC中应用Ajax异步通讯 ...
- 基于JAVA语言的多线程技术
1.简介 多线程技术属于操作系统范围内的知识: 进程与线程 可以这么理解,一个应用程序就是一个进程,在一个进程中包含至少一个线程:进程就是线程的容器,真正工作.处理任务的是线程. 进程是操作系统分配资 ...
随机推荐
- 游走[HNOI2013]
[题目描述] 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这 ...
- 成为Java顶尖程序员 ,看这11本书就够了(转)
学习的最好途径就是看书",这是我自己学习并且小有了一定的积累之后的第一体会.个人认为看书有两点好处: 1.能出版出来的书一定是经过反复的思考.雕琢和审核的,因此从专业性的角度来说,一本好书的 ...
- redis单机安装以及简单redis集群搭建
安装环境: 两台虚拟机都是Centos 7.0 IP分别为:192.168.149.132 192.168.149.133 Redis采用的版本是redis-3.2.4 集群是采用两台虚拟机模拟8个 ...
- 136. Single Number【LeetCode】异或运算符,算法,java
Given an array of integers, every element appears twice except for one. Find that single one. Note:Y ...
- 175. Combine Two Tables【LeetCode】-LEFT JON 和RIGHT JOIN,两张表关联查询-java -sql入门
Table: Person +-------------+---------+ | Column Name | Type | +-------------+---------+ | PersonId ...
- DB2的日志理解难点
在DB2中最早的recovery时间点,是由minBuffLsn 和 lowTranLsn 的最小值决定的. minBuffLsn: represents the oldest change to a ...
- trycatch放在for循环的里面还是外面好
try放在for循环里面和外面的区别是什么呢?先看看下面的代码的区别:public class Test { public void test1(){ for (int count ...
- Qt 无边框拖拽实现
Qt 无边框拖拽实现 头文件定义: class TDragProxy:public QObject { Q_OBJECT public: TDragProxy(QWidget* parent); ~T ...
- 突然兴起复习一下Swift3.0
/// 参考Swift3.0.1文档 /// 摘录来自: Apple Inc. "The Swift Programming Language (Swift 3.0.1)". iB ...
- EF vs ADO.NET
EF有什么缺点,什么时候需要考虑用ADO.NET http://blog.sina.com.cn/s/blog_4aedf6370102wgxl.html