维吉尼亚表和列置换结合加密

维吉尼亚表和列置换结合加密

功能概述

  1. 该加密算法结合采用了维吉尼亚(Vigenere)表的一次密码本加密以及列置换加密方案。
  2. 密钥为一个随机密码本中的一个随机段落。

    加密算法

  3. 加密时,明文与密钥key由用户输入。密钥可以是任意的一个随机密码本中的一个随机段落。程序将明文与密钥存放于两个列表之中。一般来说密钥的长度小于明文的长度,程序将会把密钥重复,直至两个列表长度相等,以达到两个列表中的元素能够一一对应的目的。明文与密钥对应相加,再模26,得到密文对应的数字,再转换为对应字母。随后进行列置换再进行一次加密。

    #加密函数
    def Encrypt(P,key):
    P=list(P)
    for i in range(len(P)):
    P[i]=p[i].lower()
    P=[ord(x)-ord('a') for x in P]
    P=np.array(P)
    m=len(P)//len(key)
    n=len(P)%len(key)
    K=key*m+key[0:n]
    C=(P+K)%26
    C=[chr(x+ord('A')) for x in C]
    C=Encrypt_Transposition(C)
    C=''.join(C)
    return C
  4. 列置换加密即是将上述加密得到的密文横着读,但是以一定长度竖着写出来。(本程序中选择的长度为5.)然后再横着一行一行的写在一起得到一条完整的密文。

    #加密列置换
    def Encrypt_Transposition(B):
    B=list(B)
    A=[]
    D=[]
    a=len(B)
    for i in range(a):
    if (i%5==0 and i!=0):
    A.append(D)
    D=[]
    D.append(B[i])
    if(len(D)!=0):
    A.append(D)
    D=[]
    for i in range(5):
    for j in range(len(A)):
    if ((len(A[j])-1)>=i):
    D.append(A[j][i])
    return D

解密算法

  1. 解密的难度在于将列置换后的密文如何还原为最初只是进行维吉尼亚表加密后得到的密文。如上所述,我们加密之后得到的是一条很长的字符串,它是被横着读竖着写再横着读连成的一条,所以要想解密,我们便反过来将它先横着写,然后竖着读,再横着写成一条即可。
  2. 用户输入需要解密的密文之后,我们将这个字符串强制类型转换存进一个列表里,每5个是一列,那么我们最终只会有5行。那么每一行要写多少个呢?我们是不知道的,密文的长度不一定刚好是5的整数倍,这必然导致每一行的字符数不一定相等。我们用len()函数得到列表的长度之后,将该长度对5作取余运算,假设得到的余数为n。那么便是有n行会比剩余的5-n行多一个字符。此时只需在程序中加入一个计数器,当计数器大小等于n时,每行写的字符串开始比上面的行少一个即可。

    #解密列置换
    def Decrypt_Transposition(B):
    B=list(B)
    A=[]
    D=[]
    b=len(B)
    m=b//5
    n=b%5
    count=0
    for i in range(n):
    for j in range(m+1):
    D.append(B[count])
    count=count+1
    A.append(D)
    D=[]
    for i in range(5-n):
    for j in range(m):
    D.append(B[count])
    count=count+1
    A.append(D)
    D=[]
    D=[]
    for i in range(5):
    for j in range(len(A)):
    if ((len(A[j])-1)>=i):
    D.append(A[j][i])
    return D
  3. 对列置换解密之后,得到的便是最初的密文。我们反向使用维吉尼亚表加密的方法,便可得到明文。

    #解密函数
    def Decrypt(C,key):

    C=list(C)
    C=Decrypt_Transposition(C)
    C=[ord(x)-ord('A') for x in C]
    C=np.array(C)
    m=len(C)//len(key)
    n=len(C)%len(key)
    K=key*m+key[0:n]
    P=(C-K)%26
    P=[chr(x+ord('a')) for x in P]
    P=''.join(P)
    return P

功能实现的完整代码

import numpy as np
#加密列置换
def Encrypt_Transposition(B):
B=list(B)
A=[]
D=[]
a=len(B)
for i in range(a):
if (i%5==0 and i!=0):
A.append(D)
D=[]
D.append(B[i])
if(len(D)!=0):
A.append(D)
D=[]
for i in range(5):
for j in range(len(A)):
if ((len(A[j])-1)>=i):
D.append(A[j][i])
return D
#解密列置换
def Decrypt_Transposition(B):
B=list(B)
A=[]
D=[]
b=len(B)
m=b//5
n=b%5
count=0
for i in range(n):
for j in range(m+1):
D.append(B[count])
count=count+1
A.append(D)
D=[]
for i in range(5-n):
for j in range(m):
D.append(B[count])
count=count+1
A.append(D)
D=[]
D=[]
for i in range(5):
for j in range(len(A)):
if ((len(A[j])-1)>=i):
D.append(A[j][i])
return D


#加密函数
def Encrypt(P,key):
P=list(P)
for i in range(len(P)):
P[i]=p[i].lower()
P=[ord(x)-ord('a') for x in P]
P=np.array(P)
m=len(P)//len(key)
n=len(P)%len(key)
K=key*m+key[0:n]
C=(P+K)%26
C=[chr(x+ord('A')) for x in C]
C=Encrypt_Transposition(C)
C=''.join(C)
return C

#解密函数
def Decrypt(C,key):

C=list(C)
C=Decrypt_Transposition(C)
C=[ord(x)-ord('A') for x in C]
C=np.array(C)
m=len(C)//len(key)
n=len(C)%len(key)
K=key*m+key[0:n]
P=(C-K)%26
P=[chr(x+ord('a')) for x in P]
P=''.join(P)
return P


#主函数
#加密请按E,解密请按D
user_input=input('E or D:');
#输入合法性判断
while(user_input!='E' and user_input!='D'):
user_input=input('Input error, please reenter:')

key=input('Please enter the key:')
while(not key.isalpha()):#输入合法性判断
key=input('Input error,key is alpha, please reenter:')

key=list(key)
for i in range(len(key)):
if key[i].islower():
key[i]=ord(key[i])-ord('a')
else:
key[i]=ord(key[i])-ord('A')

if user_input=='E':
#加密过程
P=input('Please enter a clear text:')
C=Encrypt(P,key)
print ('Ciphertext:%s'% C)
else:
#解密过程
C=input('Please enter a Ciphertext:')
P=Decrypt(C,key)
print ('clear text:%s' % P)

运行环境

python3.6.6及其自带IDLE

测试

随机测试了密钥比明文短和密钥比明文长两种情况

打包

至此,这个程序基本上可以用来玩一玩了,我将它打包成了exe文件,哪怕没有python运行环境的电脑也能使用。


但是在执行exe文件的时候我发现密文输出的一瞬间文件就执行结束了,然后我才想起来我的主函数部分只是执行了一次。于是乎我将主函数部分改了一下,添加了一个while循环,在用户输入done的时候结束循环,表示执行结束,便解决了这个问题。

 
#主函数
while True:
#加密请按E,解密请按D
user_input=input('E or D or done:');
if user_input=='done':
break
#输入合法性判断
while(user_input!='E' and user_input!='D'):
user_input=input('Input error, please reenter:')

key=input('Please enter the key:')
while(not key.isalpha()):#输入合法性判断
key=input('Input error,key is alpha, please reenter:')

key=list(key)
for i in range(len(key)):
if key[i].islower():
key[i]=ord(key[i])-ord('a')
else:
key[i]=ord(key[i])-ord('A')

if user_input=='E':
#加密过程
P=input('Please enter a clear text:')
C=Encrypt(P,key)
print ('Ciphertext:%s'% C)
else:
#解密过程
C=input('Please enter a Ciphertext:')
P=Decrypt(C,key)
print ('clear text:%s' % P)

exe文件测试

等待它跳出输入提示之后再开始

测试样例

图形化界面

  1. 用PyQt5做了图形化界面
  2. 做了图形化界面之后,对原代码也进行了一些修改。加密解密算法没更改,添加了随机生成的密钥,而不是原来的人工输入密钥。
    # 随机生成密钥
    def get_random():
    return ''.join(random.choice(string.ascii_letters) for _ in range(15))

另外,本程序将所有除了字母以外的字符视为了不合法输入,原来的手动输入密钥进行了输入合法性的判断:

key=input('Please enter the key:')  
while(not key.isalpha()):#输入合法性判断
key=input('Input error,key is alpha, please reenter:')

故而随机生成的密钥中也只包含了字母(大小写随机)

  1. 同样,若用户需要在明文密文中使用数字,涉及到数字时可用其英文表示。加密时无论是大写还是小写,本程序在加密函数中将其统一转换为了小写字母,因为大小写不改变英文单词本身含义,且小写更便于人们阅读。故而最终解密得到的也是小写字母。

    #加密函数
    def Encrypt(P,key):
    P=list(P)
    for i in range(len(P)):
    P[i]=p[i].lower()
  2. 使用说明
    运行打包好的exe文件,些许时刻之后会出现以下界面:


第一步应该生成密钥,也可以先输入需要加密的文本再生成密钥。
第二步点击加密,加密后的结果会出现在左下角。
第三步不需要重新生成密钥,直接将左下角出现的密文填入解密框,点击解密即可。

代码

更改后的代码将加密部分和主函数部分分成了两个.py文件,加密解密部分存放于vigenere.py中,主函数部分实现图形化界面以及调用加密解密函数,存放于main.py中。这时候我用的就是PyCharm了而不是python自带的IDLE。

# vigenere.py
import numpy as np
import random, string

# 随机生成密钥
def get_random():
return ''.join(random.choice(string.ascii_letters) for _ in range(15))

# 加密列置换


def Encrypt_Transposition(B):
B = list(B)
A = []
D = []
a = len(B)
for i in range(a):
if (i % 5 == 0 and i != 0):
A.append(D)
D = []
D.append(B[i])
if (len(D) != 0):
A.append(D)
D = []
for i in range(5):
for j in range(len(A)):
if ((len(A[j]) - 1) >= i):
D.append(A[j][i])
return D


# 解密列置换
def Decrypt_Transposition(B):
B = list(B)
A = []
D = []
b = len(B)
m = b // 5
n = b % 5
count = 0
for i in range(n):
for j in range(m + 1):
D.append(B[count])
count = count + 1
A.append(D)
D = []
for i in range(5 - n):
for j in range(m):
D.append(B[count])
count = count + 1
A.append(D)
D = []
D = []
for i in range(5):
for j in range(len(A)):
if ((len(A[j]) - 1) >= i):
D.append(A[j][i])
return D


# 加密函数
def Encrypt(P, key):
P = list(P)
for i in range(len(P)):
P[i] = P[i].lower()
P = [ord(x) - ord('a') for x in P]
P = np.array(P)
m = len(P) // len(key)
n = len(P) % len(key)
K = key * m + key[0:n]
C = (P + K) % 26
C = [chr(x + ord('A')) for x in C]
C = Encrypt_Transposition(C)
C = ''.join(C)
return C


# 解密函数
def Decrypt(C, key):

C = list(C)
C = Decrypt_Transposition(C)
C = [ord(x) - ord('A') for x in C]
C = np.array(C)
m = len(C) // len(key)
n = len(C) % len(key)
K = key * m + key[0:n]
P = (C - K) % 26
P = [chr(x + ord('a')) for x in P]
P = ''.join(P)
return P


# # 主函数
# while True:
# # 加密请按E,解密请按D
# user_input = input('E or D or done:');
# if user_input == 'done':
# break
# # 输入合法性判断
# while (user_input != 'E' and user_input != 'D'):
# user_input = input('Input error, please reenter:')
#
# key = input('Please enter the key:')
# while (not key.isalpha()): # 输入合法性判断
# key = input('Input error,key is alpha, please reenter:')
#
# key = list(key)
# for i in range(len(key)):
# if key[i].islower():
# key[i] = ord(key[i]) - ord('a')
# else:
# key[i] = ord(key[i]) - ord('A')
#
# if user_input == 'E':
# # 加密过程
# P = input('Please enter a clear text:')
# C = Encrypt(P, key)
# print('Ciphertext:%s' % C)
# else:
# # 解密过程
# C = input('Please enter a Ciphertext:')
# P = Decrypt(C, key)
# print('clear text:%s' % P)

# main.py
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import sys
from vigenere import *
class Main(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("维吉尼亚表与列置换结合加密")

self.layout = QVBoxLayout(self)
self.enc_area = QTextEdit()
self.dec_area = QTextEdit()
self.enc_area.setPlaceholderText("加密框")
self.dec_area.setPlaceholderText("解密框")
self.row = QHBoxLayout()
self.row.addWidget(self.enc_area)
self.row.addWidget(self.dec_area)
self.layout.addLayout(self.row)

self.row2 = QHBoxLayout()
self.enc_btn = QPushButton("加密")
self.dec_btn = QPushButton("解密")
self.row2.addWidget(self.enc_btn)
self.row2.addWidget(self.dec_btn)
self.layout.addLayout(self.row2)

self.gen_btn = QPushButton("生成密钥")
self.layout.addWidget(self.gen_btn)

self.clear_btn = QPushButton("清空!")
self.layout.addWidget(self.clear_btn)
self.result = QLabel()
self.layout.addWidget(self.result)

self.bind_evt()


def bind_evt(self):
def set_key():
self.key = get_random()
QMessageBox.information(None, "生成密钥", "密钥为%s" % self.key)
self.key = list(self.key)
for i in range(len(self.key)):
if self.key[i].islower():
self.key[i] = ord(self.key[i]) - ord('a')
else:
self.key[i] = ord(self.key[i]) - ord('A')
self.gen_btn.clicked.connect(set_key)

def encode():
# print(self.enc_area.toPlainText(),self.key)
s = Encrypt(self.enc_area.toPlainText(),self.key)
self.result.setText(s)
self.enc_btn.clicked.connect(encode)

def decode():
s = Decrypt(self.dec_area.toPlainText(), self.key)
self.result.setText(s)
self.dec_btn.clicked.connect(decode)

def clear():
self.enc_area.clear()
self.dec_area.clear()
self.result.clear()
self.clear_btn.clicked.connect(clear)


if __name__ == '__main__':
app = QApplication(sys.argv)
m = Main()
m.show()
sys.exit(app.exec())

BHuman2017代码编译

今晚在帮助同学编译Bhuman的代码的时候发现了参考文档的一些问题,想起来好久没写博客了就当作是bug记录简单的写一小篇吧。

一、参考文档

按照这篇文档进行的编译:

解压压缩包的时候如果直接在文件安装的地方右键解压报错的话可以在终端使用 unzip filename.zip 这个命令。

如果是tar文件的解压的话可以用tar --help来查看相应的指令。

另外在输入这一行指令时我出现了文件名不匹配的错误。

报错时仔细看log,他会告诉不匹配的原因是因为它想要的文件名是什么,将改行命令做出相应的修改就可以了。

文档其余地方在这次测试中没有出现其他问题。


SCI in Xingyi

一、SCI family

  1. 最初看到志愿者招募推送的时候,我以为这个活动和和美国《科学引文索引》(Science Citation Index, 简称 SCI )有关,但是后来了解到,这里的SCI指的是Service Civil International,中文也就是“国际公民服务团”,Service Civil International, SCI是一个对不同年龄不同背景开放的志愿与文化交流平台。由瑞士工程师皮埃尔.施莱索尔先生于1920 年创建。施莱索尔先生于第一次世界大战结束后组织的和平人道活动为今天的Service Civil International,SCI奠定了基础。至今为止,SCI在全球已经拥有45个分部,96个合作伙伴,并且数量仍在持续增长。我这次参与的便是由国际公民服务团(中国)在兴义阳光书院举办的英语冬令营项目。

  2. 兴义市阳光书院的前身是兴义八中的初中部,本人作为兴义八中的毕业生对其也有一定的情谊。而且此次活动中校方的总负责人谢百军老师也是我初中时候的班主任,所以我便积极参与了此次活动。

  3. 我在兴义八中读七年级的时候,那年的暑假也作为学生参加了二十国英语夏令营。时过境迁,这次作为志愿者回到阳光书院,在整个活动过程中仿佛也看到了自己的当初的影子。

二、 冬令营简要回顾

  1. 此次活动中外国志愿者来自美国,保加利亚,波兰和巴基斯坦,本来还有一位哥伦比亚的志愿者,但是由于护照出了问题,没能参与到这次活动中来。中国志愿者则主要由兴义八中的校友组成,另外也有省内贵阳地区,遵义地区以及宁夏,四川,云南,北京等省份的伙伴儿。

  2. 志愿者一般三人一个小组,一名外国志愿者加上两名中国志愿者。轮番对不同班级介绍不同国家的文化,另有一组专门设计模拟联合国课程。在通过面试之后我和领队 Dadi Xu说起过我修过英美文化相关的课程,所以我便被分到了美国小组。我的两个partner分别是Becky和Rita. Becky是美国人,在纽约和加州都居住过,现居南京,来中国已经两年了。以前就读于纽约州立大学,现在是南京大学天文学博士。Rita是ECNU孟宪承书院英语师范班的大三学生。她们俩都非常的可爱。

  1. 在这次冬令营中,我们的主体课程是各国家文化的分享和模拟联合国。与此同时也通过保护鸡蛋和橘子游戏等向孩子们传递了感恩和平等理念。Dadi一直强调感恩和平等是SCI一直想要在全世界传达的理念。也正是这个原因,在冬令营结束的时候他拒绝了校方提出的评选优秀营员和优秀志愿者的提议。当然,学校也有自己的考虑,这里我不做更多评论。

  2. 冬令营有收获的不仅仅是学生,还有志愿者。我曾经就读于兴义八中,阳光书院与兴义八中一脉相承,所以我深知这个学校的一些教学制度和理念,也明白作为当地最优秀的学生他们所面对的学业等各方面的竞争压力。实不相瞒,离开八中之后我觉得自己少了很多斗志,以前的那种热情洋溢在我身上渐渐少了许多,或许也有自己长大了的原因。但是当我每天陪伴在这些学生身边和他们交流玩耍的时候,我是被他们感染的。我沉浸在他们的天真烂漫和斗志昂扬当中。They are very energetic. 当意识到以前的时光是多么美好的时候,时间它已经悄悄溜走了。另外,认识了活动中来自天南海北的志愿者伙伴,也大大开拓我的视野,了解了不同人的不同生活,不同经历。也让自己进一步知道了生活的更多种可能。这些都是孩子们和伙伴们带给我的,也是SCI带给我的。通过参与这样的志愿与文化交流活动,SCI带给了青年们独立之品格,国际之视野以及奉献之精神。这是弥足珍贵的。

三、Finally

  1. 其实冬令营已经结束好几天了,回忆起来我觉得还是蛮恍惚的。曾经互不相识的这么一群人能在这么短的时间内形成一个团队并且较为圆满地完成了这次冬令营活动,着实令人欣喜。这当中离不开大家的协作和认真负责,团队的小伙伴们真的很棒。最后结束那天刚好是我的二十一岁生日,我也收到了大家意外的惊喜,我会把这一切留在我的脑海里。分别的时候大家彼此都拥抱了,因为大家都知道这是一场萍水相逢,后会可能无期。但还是要说:see you somewhere and someday.




一些python学习的基本操作

一、python的安装及环境变量配置

1.python安装包下载:

  1. 网址:www.python.org
  2. 安装包选择:以Windows为例,64位的选择 Windows x86-64 execuable installer。32位的选择Windows x86 execuable installer
  3. 安装包储存路径:建议放在一个自己找得到的文件夹里(文件夹分类是个好习惯)

2.安装包运行

  1. 建议选择 Customize installation,自定义路径,自己选择一个能找得到的安装路径,比如 D:\python (Repeat:文件夹分类是个好习惯)
  2. 记得勾选Add Python to PATH.(其余未特殊说明的,均按照其默认勾选)
  3. Optional Features建议全部勾选,尤其是pip一定要勾选。
  4. Advanced Options勾选Install for all users,其余按照默认勾选。储存路径还是那句话:找一个自己能找的到的。
  5. install完成之后会提示你安装成功,有时候会出现:Disable path length limit. 出现的话点击一下,禁用掉系统Path长度自动限制。至此python安装完毕
  6. 检查是否安装成功并且将python配置到了环境变量中:win+r,输入cmd打开命令行提示符,输入python,如果出现下载的python版本号,说明ok了,如果提示你python不是外部命令之类的,可能是前面忘记:Add Python to PATH。则需要配置一下python的环境变量。

3.环境变量的配置

  1. 控制面板→系统和安全→系统→高级系统设置→环境变量→编辑→新建→(将python的储存路径复制粘贴过来这儿)→一步步确定。
  2. 环境变量配置好之后,重复“安装包运行-6”中的操作。

二、一些库的安装

1. pygame的安装

  1. 上述准备工作都完成之后,我们以pygame的安装来简单举例:win+r,然后输入cmd打开命令行提示符
  2. 输入这行代码:pip install pygame 如果报错说明前面的pip没弄好。如果输入该行代码后出现:Collecting pygame,则稍等一会儿就会自动把pygame安装好。

2. requests 的安装

  1. 同理:pip install requests

三、将python脚本打包成exe可执行文件

  1. 安装pyinstaller:在命令行中输入如下命令:pip install pyinstaller

  2. 然后将目录切换到要打包的py文件的所在路径,输入指令: pyinstaller -F yourfile.py (注意,文件的命名不要有中文以及空格,否则的话打包的时候会出错)

  3. 介绍一下一些参数的含义:

  4. 看到参数含义,我们可以留意到 -F 是指定打包后只生成一个exe格式的文件,也就是说假设程序是需要导入外部文件的,打包的时候就不会自动导入,需要自己手动添加。

  5. 上述第二步完成后,会发现你原来的文件夹里会生成一些其他文件,exe文件就在dist文件夹下,双击运行即可。假设出现闪退,可以在代码中加入

    import os

    os.system('pause') #这句放在最后

  6. 详情可查看官方文档:
    pyinstaller (链接打不开的话可以手动输入https://pyinstaller.readthedocs.io)

四、PyCharm

(瞌睡来了,未完待续)


Monte Carlo 方法求解π的近似值

首先可以了解一下Monte Carlo 方法,这里是链接https://en.wikipedia.org/wiki/Monte_Carlo_method。

根据圆的面积公式S=πR^2,当R=1时,S=π。
我们在一个边长为1的正方形中划定一个半径为1的1/4圆区域。我们向这个正方形区域内随机投点,根据几何概型(高中数学知识,我在此不再赘述),点落到1/4圆区域内的概率为P=π/4. 这个概率的四倍便可以视为π的近似值。
根据这个思路,我们要想用程序模拟出π的近似值,就可以转换为模拟这样一个几何概型求它的概率的问题。以下是用c语言实现这个过程的代码:

/这个精度有点看概率,一开始我宏定义N为2000,得到了3.16,
改成10000得到了3.19,
改成20000得到了3.17,
改成200000,得到了3.14,
之后又用200000测试了4次,得到了三次3.14,一次3.13
/

最后再简单介绍一下程序中用到的几个函数。如果是像我一样的c语言刚入门学习的小白可能会不太熟悉,详细的用法可以自行翻书查阅。

rand()函数可以产生伪随机数,之所以说是伪随机数是因为rand()函数的内部实现是通过线性同余法实现的,由于其周期较长所以,所以在一定范围内可以看作是随机的。rand()返回的是0-RAND_MAX之间的随机数。调用rand()函数时需要设置随机数种子,如果不设置的话,它自动设置为1,随机数种子相同,产生的随机数也是相同的,这样的达不到我们要用产生随机数模拟投点来求π的近似值的目的了。设置随机数种子需要srand()函数,它是随机数产生器的初始化函数,再利用time函数来返回系统时间作为随机数种子,就可以达到每次随机数种子都不同的目的了。因为每次运行程序的时间肯定是不同的。可以像我上面的程序中那样写为srand(time(0)); ,另一种的常见的用法是直接在time函数中放一个空指针:srand((unsigned)time(NULL))。
rand()和srand()所需的头文件是stdlib.h,time()函数所需的头文件是time.h。
以上全部是我一些粗浅的理解,难免有错误之处,欢迎指正。随着自己学习的深入回过头再看的时候应该会有更好的理解吧。


Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

$ hexo new "My New Post"

More info: Writing

Run server

$ hexo server

More info: Server

Generate static files

$ hexo generate

More info: Generating

Deploy to remote sites

$ hexo deploy

More info: Deployment