简要说明

本设计为湖南大学密码学的一次课程作业设计。非作业目的可随意引用。

由于本人初次接触密码学,本设计可能存在问题以及漏洞。若发现望指出。

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中英文替换密码设计的更多相关文章

  1. selenium2自动化测试实战--基于Python语言

    自动化测试基础 一. 软件测试分类 1.1 根据项目流程阶段划分软件测试 1.1.1 单元测试 单元测试(或模块测试)是对程序中的单个子程序或具有独立功能的代码段进行测试的过程. 1.1.2 集成测试 ...

  2. 《Selenium2自动化测试实战--基于Python语言》 --即将面市

    发展历程: <selenium_webdriver(python)第一版>   将本博客中的这个系列整理为pdf文档,免费. <selenium_webdriver(python)第 ...

  3. 在云平台上基于Go语言+Google图表API提供二维码生成应用

    二维码能够说已经深深的融入了我们的生活其中.到处可见它的身影:但通常我们都是去扫二维码, 曾经我们分享给朋友一个网址直接把Url发过去,如今我们能够把自己的信息生成二维码再分享给他人. 这里就分享一下 ...

  4. 关于《selenium2自动测试实战--基于Python语言》

    关于本书的类型: 首先在我看来技术书分为两类,一类是“思想”,一类是“操作手册”. 对于思想类的书,一般作者有很多年经验积累,这类书需要细读与品位.高手读了会深有体会,豁然开朗.新手读了不止所云,甚至 ...

  5. Gogs - 基于 Go 语言的自助 Git 服务

    Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务.Gogs 的目标是打造一个最简单.最快速和最轻松的方式搭建自助 Git 服务.使用 Go 语言开发使得 Gogs ...

  6. Ggoogle Protocol Buffer的使用 (基于C++语言)

    首先说明的是Protocol Buffle是灵活高效的.它的一个很好的优点(很重要的,我认为)就是后向兼容性--当我们扩展了了.proto文件后,我们照样可以用它来读取之前生成的文件. 之前已经写了关 ...

  7. 基于C# 语言的两个html解析器

    基于C# 语言的两个html解析器 1)Html Agility Pack http://nsoup.codeplex.com/ 代码段示例: HtmlDocument doc = new HtmlD ...

  8. springmvc国际化 基于浏览器语言的国际化配置

    当前标签: springmvc   springmvc国际化 基于浏览器语言的国际化配置 苏若年 2013-10-09 13:03 阅读:305 评论:0   SpringMVC中应用Ajax异步通讯 ...

  9. 基于JAVA语言的多线程技术

    1.简介 多线程技术属于操作系统范围内的知识: 进程与线程 可以这么理解,一个应用程序就是一个进程,在一个进程中包含至少一个线程:进程就是线程的容器,真正工作.处理任务的是线程. 进程是操作系统分配资 ...

随机推荐

  1. IMPEX

    1.Impex是基于java Model的一种面向对象的数据操作手段,因此写impex代码前需要理清java Model之间的依赖关系. 2.基本语法:mode type[modifier=value ...

  2. Python3常用网络编程模块介绍

    一.socket模块 网络服务都是建立在socket基础之上的,socket是网络连接端点,是网络的基础:每个socket都被绑定到指定的IP和端口上: 1.首先使用socket(family=AF_ ...

  3. java8之lambda表达式(1)-基本语法

    lambda表达式,即带有参数的表达式,为更清晰地理解lambda表达式,先看如下例子: (1) class Student{ private String name; private Double ...

  4. Git分支使用心得

    在去年的大约这个时候,我的领导让我研究一下git的使用方法,方便我们自己的代码管理,因为我们原先使用的是SVN,使用起来没那么方便,所以让我研究研究git的使用.我就简单的研究了两天,用我的IDE(v ...

  5. 使用 Node.js 搭建一个 API 网关

    原文地址:Building an API Gateway using Node.js 外部客户端访问微服务架构中的服务时,服务端会对认证和传输有一些常见的要求.API 网关提供共享层来处理服务协议之间 ...

  6. linux下scrapy环境搭建

    最近使用scrapy做数据挖掘,使用scrapy定时抓取数据并存入MongoDB,本文记录环境搭建过程以作备忘 OS:ubuntu 14.04  python:2.7.6 scrapy:1.0.5 D ...

  7. angular学习(五)-- Module

    1.5 模块:Module 模块定义了一个应用程序 模块是应用程序中不同部分的容器 模块是应用控制器的容器 控制器通常属于一个模块 ng 中模块的引入最重要的目的就是为了解决原来全局定义的控制器污染的 ...

  8. python学习===如何理解python中的return

    首先要了解,函数是什么?书上可能会说函数是完成功能的模块之类的话.其实说白了,函数就是个你招来的工人.你给他一些材料,告诉他怎么用这些材料拼装,然后他负责把拼装好的成品交给你.材料就是函数的参数,成品 ...

  9. $($('.className').html( )选择器的工作原理

    $($('.slot')[0]).html('<img src = "' + images[slotOne-1] + '">');

  10. 【复制】【编码】MySQL复制中的编码问题

    编码背景知识 Latin-1,全称ISO 8859-1 Latin 1 对ASCII的拉丁语扩展 向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x8 ...