1.仿射密码
仿射密码为单表加密的一种,字母系统中所有字母都用一个简单数学方程加密,对应至数值,或转回字母。其仍有所有替代密码之弱处。所有字母皆借由方程加密,b为移动大小。
仿射密码是一种替换密码。它是一个字母对一个字母的。它的加密函数是
取余m为字母系统大小且a和b为密码关键值。a之值必须使得a与m互质。解密方程为
此处满足等式
举例说明
在以下一加密一解密的例子中,字母为从A至Z,且在表格中都有对应值。
明文为 "AFFINE CIPHER" ,a对应5,b对应 8,而m对应26 (因共使用26字母),a的所有可能值有 1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 与 25。 若a不等于 1,b之值可随机选定。加密函数为y=E(x)=(5x+8)(mod 26)
解密方程为D(y)=21(y-8) mod 26 ,a的逆元为21
通过编程实现代换密码算法——仿射密码和简单置换密码算法
# -*- coding: UTF-8 -*-
import math
"""
仿射密码加密解密模块
@author WQ
@time 2020/11/18
"""
class Affine():
"""
仿射密码
Encrypt:加密方法
Decrypt:解密方法
letters:字母数字对应字典
"""
def __init__(self):
self.ciphertext='' #加密后的密文
self.plaintext='' #解密后的明文
self.reverse=0 #秘钥a的逆元
self.list_keya=[3,5,7,9,11,15,17,19,21,23,25] #秘钥a可能取值
self.letters = {
'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 'g':6, 'h': 7,
'i': 8, 'j': 9, 'k': 10, 'l': 11, 'm': 12, 'n': 13, 'o': 14,
'p': 15, 'q': 16, 'r': 17, 's': 18, 't': 19, 'u': 20,
'v': 21, 'w': 22, 'x': 23, 'y': 24, 'z': 25}
def gcd(self,a,b=26):
if(a<b):
return self.gcd(b,a)
while(a%b!=0):
temp = b
b = a%b
a = temp
return b
def Encrypt(self,a=0,b=0,input=""):
"""
对输入的字符串进行加密
加密算法:c=Ea,b(m)=am+b(mod26) m是单个明文字母
args={
a,b:秘钥
input:用于加密的明文
}
"""
if(self.gcd(a)!=1):
print("秘钥a错误,应与26互质,请重输!")
exit(0)
if(b>=26):
print("秘钥b错误[0~26],请重输!")
exit(0)
input=input.lower()
digitals=[]
#加密转化成密文对应数字
for i in input:
for j in self.letters:
if(i==j):
d=(a*self.letters[i]+b)%26
digitals.append(d)
#将对应数字转化对应密文字母
for i in digitals:
for j in self.letters:
if(i==self.letters[j]):
self.ciphertext=self.ciphertext+j
def Decrypt(self, a, b, input=""):
"""
对输入的字符串进行解密
解密算法:m=Da,b(m)=a(-1)(c-b)(mod26) c是单个密文字母
args={
a(-1):秘钥a的逆元
b:秘钥
input:用于解密的秘文
}
"""
if(self.gcd(a)!=1):
print("秘钥a错误,应与26互质,请重输!")
exit(0)
if(b>=26):
print("秘钥b错误[0~26],请重输!")
exit(0)
digitals=[]
self.reverse=self.Inverse(a) #求逆元
for i in input:#解密 密文转化成对应数字
for j in self.letters:
if(i==j):
digitals.append(self.letters[j])
#解密
for i in digitals:
t=(self.reverse*(i-b))%26
for j in self.letters:
if(t==self.letters[j]):
self.plaintext=self.plaintext+j
def BruteForce(self, input=''):
#暴力破解仿射密码
digitals=[]
plaintext=''
for i in input: #解密 密文转化成对应数字
for j in self.letters:
if(i==j):
digitals.append(self.letters[j])
for keya in self.list_keya:
a=self.Inverse(keya)
for keyb in range(0,26):
for i in digitals:
t=(keya*(i-keyb))%26
for j in self.letters:
if(t==self.letters[j]):
plaintext=plaintext+j
break
print(plaintext)
plaintext=''
def Inverse(self, a,mod=26):
#求秘钥a的逆元 欧几里得算法
x1,x2,x3 = 1,0,mod
y1,y2,y3 = 0,1,a
while(1):
if(y3==0):
g=x3
break
if(y3==1):
g=y3
break
q=math.floor(x3/y3)#向下取整
t1,t2,t3=x1-q*y1,x2-q*y2,x3-q*y3
x1,x2,x3=y1,y2,y3
y1,y2,y3=t1,t2,t3
return y2 #逆元求得为y2,y3为gcd(a,26),最大公因数
if __name__ == "__main__":
test=Affine()
#a=test.Inverse(615647919867658945209035999713482421889581801898774401730949,691310408299283134015133178155232316338199895735303344369216)
#print(a)
inputs=input("请输入待加密明文:")
a=int(input("请输入秘钥[a]:"))
b=int(input("请输入秘钥[b]:"))
test.Encrypt(a,b,inputs)
test.Decrypt(a,b,test.ciphertext)
s1 = "加密为:" + test.ciphertext
s2 ="解密为:" + test.plaintext
s3 = str(a) + "的逆元为: " + str(test.reverse)
print(s1)
print(s2)
print(s3)
#test.BruteForce(test.ciphertext)
2.Hill密码
希尔密码(Hill cipher)是一种经典的多字母替换密码,使用线性代数的概念,通过矩阵运算来加密和解密消息。
加密过程:
- 首先,选择一个密钥矩阵 K。该矩阵必须是可逆的,通常是一个方阵。
- 将明文消息分成等长的块,每个块包含密钥矩阵的列数个字符。
- 将每个明文块表示为一个列向量 X。
- 对于每个明文块 X,计算密文块 Y = K * X,其中 * 表示矩阵乘法。
- 将每个密文块表示为一个列向量 Y。
解密过程:
- 使用密钥矩阵 K 的逆矩阵 K^-1。
- 对于每个密文块 Y,计算明文块 X = K^-1 * Y。
- 将每个明文块表示为一个列向量 X。
- 将每个明文块连接起来,得到解密后的明文消息。
我们通过一个示例来说明希尔密码的加密和解密过程。
3.Playfair密码(格列佛密码)
Playfair密码使用一个5x5的方形矩阵(称为Playfair方阵)来加密和解密消息。这种密码的特点是在加密和解密过程中使用了一些规则来处理特殊情况,例如重复字母和字母对在同一行或同一列的情况。
加密:
- 首先,根据规则,将明文中的字母映射到Playfair方阵中的对应字母。
- 如果明文中有重复的字母,将它们之间插入一个额外的字母(通常是一个不常用的字母,如X)。
- 将每对字母在方阵中的位置确定,并应用特定的规则将它们替换为另一对字母。
- 将替换后的字母对组合在一起,形成密文。
解密:
- 根据规则,将密文中的字母映射回Playfair方阵中的对应字母。
- 将每对字母在方阵中的位置确定,并应用特定的规则将它们替换为另一对字母。
- 将替换后的字母对组合在一起,形成明文。
Playfair密码的关键是Playfair方阵的构建和字母对的替换规则。方阵中的字母顺序可以根据密钥来确定,通常将密钥中的字母按顺序填充到方阵中,然后将剩余的字母按照某种规则填充。替换规则通常涉及字母对在方阵中的位置关系,例如将字母对替换为同一行的另一对字母或同一列的另一对字母。
在Playfair密码中,字母的映射规则如下:
-
首先,构建一个5x5的方阵,其中包含了字母A到Z(通常将字母J排除,因为它与字母I相似)。
-
将明文中的字母分成一对一对进行加密。如果明文中有奇数个字母,可以在最后一个字母后面添加一个虚拟字母(通常是X)。
-
对于每一对字母,根据它们在方阵中的位置应用以下规则进行映射:
a. 如果两个字母在方阵中的行相同,将它们分别替换为同一行中的下一个字母。如果一个字母在该行的最右侧,则将其替换为该行的最左侧字母。
b. 如果两个字母在方阵中的列相同,将它们分别替换为同一列中的下一个字母。如果一个字母在该列的最底部,则将其替换为该列的最顶部字母。
c. 如果两个字母既不在同一行也不在同一列,将它们替换为形成一个矩形的对角线上的另外两个字母。矩形的顶点由这两个字母在方阵中的位置确定。
-
将替换后的字母对组合在一起,形成密文。
举个例子
假设我们有以下Playfair方阵:
A B C D E
A F G H I J
B K L M N O
C P Q R S T
D U V W X Y
E Z
现在我们要加密的明文是:"HELLO"。下面是正确的加密步骤:
-
将明文中的字母映射到Playfair方阵中的对应字母:
"H" 映射为 "G"
"E" 映射为 "L"
"L" 映射为 "M"
"L" 映射为 "M"
"O" 映射为 "N" -
处理重复字母,将它们之间插入一个额外的字母(通常是X):
"LL" 变为 "LXLX" -
将每对字母在方阵中的位置确定,并应用特定的规则将它们替换为另一对字母:
"LX" 替换为 "LM"
"LX" 替换为 "LM" -
将替换后的字母对组合在一起,形成密文:
密文为:"LMLM"
现在,我们对密文进行解密的步骤:
-
将密文中的字母映射回Playfair方阵中的对应字母:
"LM" 映射为 "LX"
"LM" 映射为 "LX" -
将替换后的字母对组合在一起,形成明文:
明文为:"LXLX"
通过以上步骤,我们成功地将明文 "HELLO" 加密为密文 "LMLM",并且可以将密文 "LMLM" 解密回明文 "HELLO"。
4.列移位密码
通过对明文中的字母进行重新排列来进行加密。它基于将明文按照特定规则填充到矩阵中,然后按照列的顺序读取密文。
加密过程如下:
- 首先,选择一个密钥,这个密钥是一个由数字组成的序列,例如"3124"。
- 将明文按照密钥中的数字顺序填充到一个矩阵中。如果明文长度不能完全填充矩阵,则在末尾添加填充字符。
- 按照列的顺序读取矩阵中的字符,得到密文。
解密过程与加密过程相反:
- 使用相同的密钥,将密文按照密钥中的数字顺序填充到一个矩阵中。
- 按照矩阵中的列顺序读取字符,得到原始的明文。
举个例子
假设我们有一个明文消息为:"HELLO WORLD",密钥为"3124"。
加密过程:
- 将明文按照密钥中的数字顺序填充到矩阵中:
3 1 2 4 H E L L O W O R L D
- 按照列的顺序读取矩阵中的字符,得到密文:
密文为:"HORLLDEWLO"
解密过程:
- 使用相同的密钥,将密文按照密钥中的数字顺序填充到一个矩阵中:
3 1 2 4 H O R L L D E W L O
- 按照矩阵中的列顺序读取字符,得到原始的明文:
原始的明文为:"HELLO WORLD"
刷题记录
1.easysa1
这是RSA加密算法,可以通过分解n得到p和q,可以用在线网址factordb.com
然后使用欧拉函数计算(p-1)*(q-1),接着使用gmpy2库中的invert函数(即e*d mod n=1)和powmod函数(即m =c^d mod N)
import gmpy2 import binascii e = 65537 N = 1455925529734358105461406532259911790807347616464991065301847 c = 69380371057914246192606760686152233225659503366319332065009 p = 1201147059438530786835365194567 q = 1212112637077862917192191913841 n = (p-1)*(q-1) d = gmpy2.invert(e,n)#即e*d mod n = 1 m = gmpy2.powmod(c,d,N)#即m = c^d mod N print(binascii.unhexlify(hex(m)[2:]))
解析代码
print(binascii.unhexlify(hex(m)[2:]))
hex(m):hex()
函数将其转换为十六进制字符串表示
hex(m)[2:]
:这里使用切片操作[2:]
,从十六进制字符串中去除前缀'0x'
,只保留有效的十六进制部分
binascii.unhexlify(hex(m)[2:])
:unhexlify()
函数将十六进制字符串转换为对应的二进制数据。在这里,它接收hex(m)[2:]
作为参数,将其转换为二进制数据
2.easyrsa2
题目
题解:给了两组e、n、c,e都相同,可通过欧几里得算法求最大公因数p,q=N1//p,下面的计算和上题一样,代码如下:
import gmpy2
import binascii
e = 65537
N1 = 23686563925537577753047229040754282953352221724154495390687358877775380147605152455537988563490716943872517593212858326146811511103311865753018329109314623702207073882884251372553225986112006827111351501044972239272200616871716325265416115038890805114829315111950319183189591283821793237999044427887934536835813526748759612963103377803089900662509399569819785571492828112437312659229879806168758843603248823629821851053775458651933952183988482163950039248487270453888288427540305542824179951734412044985364866532124803746008139763081886781361488304666575456680411806505094963425401175510416864929601220556158569443747
c1 = 1627484142237897613944607828268981193911417408064824540711945192035649088104133038147400224070588410335190662682231189997580084680424209495303078061205122848904648319219646588720994019249279863462981015329483724747823991513714172478886306703290044871781158393304147301058706003793357846922086994952763485999282741595204008663847963539422096343391464527068599046946279309037212859931303335507455146001390326550668531665493245293839009832468668390820282664984066399051403227990068032226382222173478078505888238749583237980643698405005689247922901342204142833875409505180847943212126302482358445768662608278731750064815
N2 = 22257605320525584078180889073523223973924192984353847137164605186956629675938929585386392327672065524338176402496414014083816446508860530887742583338880317478862512306633061601510404960095143941320847160562050524072860211772522478494742213643890027443992183362678970426046765630946644339093149139143388752794932806956589884503569175226850419271095336798456238899009883100793515744579945854481430194879360765346236418019384644095257242811629393164402498261066077339304875212250897918420427814000142751282805980632089867108525335488018940091698609890995252413007073725850396076272027183422297684667565712022199054289711
c2 = 2742600695441836559469553702831098375948641915409106976157840377978123912007398753623461112659796209918866985480471911393362797753624479537646802510420415039461832118018849030580675249817576926858363541683135777239322002741820145944286109172066259843766755795255913189902403644721138554935991439893850589677849639263080528599197595705927535430942463184891689410078059090474682694886420022230657661157993875931600932763824618773420077273617106297660195179922018875399174346863404710420166497017196424586116535915712965147141775026549870636328195690774259990189286665844641289108474834973710730426105047318959307995062
p = gmpy2.gcd(N1,N2)
q = N1//p
n = (p-1)*(q-1)
d = gmpy2.invert(e,n)#即e*d mod n = 1
m = gmpy2.powmod(c1,d,N1)#即m = c^d mod N
print(binascii.unhexlify(hex(m)[2:]))
3. easyrsa3
题目
题解:和easyrsa2类似,同样是两组数,这次是n相同,看了题解知道是共模攻击
原理
共模攻击即用两个及以上的公钥(n,e)来加密同一条信息m
已知有密文:
c1 = pow(m, e1, n)
c2 = pow(m, e2, n)
条件:
当e1,e2互质,则有gcd(e1,e2)=1
根据扩展欧几里德算法,对于不完全为 0 的整数 a,b,gcd(a,b)表示 a,b 的最大公约数。那么一定存在整数 x,y 使得 gcd(a,b)=ax+by
所以得到:
e1*s1+e2*s2 = 1
因为e1和e2为正整数,所以s1、s2皆为整数,但是一正一负,此时假设s1为正数,s2为负数
原文链接:https://blog.csdn.net/Luiino/article/details/124623375
import gmpy2
import binascii
n = 15944475431088053285580229796309956066521520107276817969079550919586650535459242543036143360865780730044733026945488511390818947440767542658956272380389388112372084760689777141392370253850735307578445988289714647332867935525010482197724228457592150184979819463711753058569520651205113690397003146105972408452854948512223702957303406577348717348753106868356995616116867724764276234391678899662774272419841876652126127684683752880568407605083606688884120054963974930757275913447908185712204577194274834368323239143008887554264746068337709465319106886618643849961551092377843184067217615903229068010117272834602469293571
e1 = 797
c1 = 11157593264920825445770016357141996124368529899750745256684450189070288181107423044846165593218013465053839661401595417236657920874113839974471883493099846397002721270590059414981101686668721548330630468951353910564696445509556956955232059386625725883038103399028010566732074011325543650672982884236951904410141077728929261477083689095161596979213961494716637502980358298944316636829309169794324394742285175377601826473276006795072518510850734941703194417926566446980262512429590253643561098275852970461913026108090608491507300365391639081555316166526932233787566053827355349022396563769697278239577184503627244170930
e2 = 521
c2 = 6699274351853330023117840396450375948797682409595670560999898826038378040157859939888021861338431350172193961054314487476965030228381372659733197551597730394275360811462401853988404006922710039053586471244376282019487691307865741621991977539073601368892834227191286663809236586729196876277005838495318639365575638989137572792843310915220039476722684554553337116930323671829220528562573169295901496437858327730504992799753724465760161805820723578087668737581704682158991028502143744445435775458296907671407184921683317371216729214056381292474141668027801600327187443375858394577015394108813273774641427184411887546849
s = gmpy2.gcdext(e1,e2)#扩展欧几里得算法,得到x,y,即ax+by=gcd(a,b)
m1 = gmpy2.powmod(c1,s[1],n)
m2 = gmpy2.powmod(c2,s[2],n)
m = (m1*m2)%n
print(binascii.unhexlify(hex(m)[2:]))
使用gmpy2.gcdext()
函数进行扩展欧几里得算法,计算e1
和e2
的最大公约数以及对应的系数x
和y
m = (m1*m2)%n将解密得到的两部分明文m1
和m2
相乘并取模n
,得到最终的明文m
4.easyrsa4
题目
由题目条件可知e非常小,为低加密指数攻击
原理:
e为3,对n和c来说非常小。
当m^3<n,可以推出m^3=c;
当m^3>n,可以推出(m^3+i·n)mod n=c(i为系数,只要找到i,然后c+i n能开三次方就能得到m)
import gmpy2
import binascii
e = 3
n = 18970053728616609366458286067731288749022264959158403758357985915393383117963693827568809925770679353765624810804904382278845526498981422346319417938434861558291366738542079165169736232558687821709937346503480756281489775859439254614472425017554051177725143068122185961552670646275229009531528678548251873421076691650827507829859299300272683223959267661288601619845954466365134077547699819734465321345758416957265682175864227273506250707311775797983409090702086309946790711995796789417222274776215167450093735639202974148778183667502150202265175471213833685988445568819612085268917780718945472573765365588163945754761
c = 150409620528139732054476072280993764527079006992643377862720337847060335153837950368208902491767027770946661
i = 0
while True:
if gmpy2.iroot((c+i*n),3)[1] == 1:
m = gmpy2.iroot((c+i*n),3)[0]
break
i += 1
print(binascii.unhexlify(hex(m)[2:]))
解析代码
解密过程使用一个循环来尝试不同的偏移量i
,直到找到满足条件的明文。在循环中,使用gmpy2.iroot()
函数计算(c+i*n)
的立方根,并检查是否存在整数解。如果存在整数解,将其作为明文m
。