• 《CTF特训营》——古典密码学


    目录

    一、移位密码

    1.简单移位密码

    (1)介绍

    (2)例子

    (3)加密解密的实现

    2.曲路密码

    3.云影密码

    4.栅栏密码

    二、代替密码

    1.单表代替密码

    (1)凯撒密码

    ①加密解密的实现

    ②例子

    (2)ROT13

    ①加密解密的实现

    (3)埃特巴什码

    ①加密解密的实现

    (4)经典单表代替密码

    ①加密解密的实现

    (5)培根密码

    (6)仿射密码

    ①加密解密的实现

    ②已知明文的攻击

    2.单表代替密码

    (1)棋盘类密码

    ①Playfari加密解密的实现

    ②Polybuis加密解密的实现(Nihilist原理相同)

    3.维吉尼亚密码

    4.希尔密码


    一、移位密码

    1.简单移位密码

    (1)介绍

    移位密码是密码学中最基础、最简单的一种密码形式,可以理解为明文根据密钥进行了位置的变换的得到的密文。

    (2)例子

    m = flag{easy_easy_crypto}

    k='3124'

    当明文为m,密钥为k时,移位密码首先以k的长度切分m,具体如下:

    flag  {eas    y_ea   sy_c   rypt   o}

    可以看到总共分成了6部分,按照密钥规则3124的顺序对每一部分进行密钥变化,所以密文为:

    lafgea{s_eyay_scyprt}o

    (3)加密解密的实现

    1. #利用Python实现
    2. #加密
    3. def shift_encrypt(m,k):
    4. l = len(k)
    5. c = ""
    6. for i in range(0,len(m),1):
    7. tmp_c = [""] * 1
    8. if i + 1 > len(m):
    9. tmp_n = m[i:]
    10. else:
    11. tmp_m = m[i:i+1]
    12. for kindex in range(len(tmp_m)):
    13. tmp_c [int(k[kindex]) - 1] = tmp_m[kindex]
    14. c += "".join(tmp_c)
    15. return c
    16. m = "flag{easy_easy_crypto}"
    17. k = '3124'
    18. print shift_encrypt(m,k)
    19. #解密
    20. def shift_encrypt(m,k):
    21. l = len(k)
    22. m = ""
    23. for i in range(0,len(c),1):
    24. tmp_m = [""] * 1
    25. if i + 1 > len(c):
    26. tmp_c = c[i:]
    27. use = []
    28. for kindex in range(len(tmp_c)):
    29. use,append(int(k[kindex]) - 1)
    30. use,sort()
    31. for kindex in range(len(tmp_c)):
    32. tmp_m[kindex] = tmp_c [use,index(int(k[kindex]) -1 )]
    33. else:
    34. tmp_c = c[i:i+1]
    35. for kindex in range(len(tmp_c)):
    36. tmp_m [kindex] = tmp_c[int(k[kindex]) - 1]
    37. m += "".join(tmp_m)
    38. return m
    39. m = "flag{easy_easy_crypto}"
    40. k = '3124'
    41. print shift_encrypt(c,k)

    2.曲路密码

    曲路密码也是移位密码的一种,加密原理如下:

     图中的密文就是从g到T,反过来就是解密

    3.云影密码

    云影密码又称01248密码,仅仅包含01248几个数字,其中0用于分割,其与数字用于加和操作之后转换为明文,解密方式如下:

    1. def c01248_decode(c):
    2. l = c.split("0")
    3. origin = "abcdefghijklmnopqrstuvwxyz"
    4. r = ""
    5. for i in 1:
    6. tmp = 0
    7. for num in i:
    8. tmp += int(num)
    9. r += origin [tmp-1]
    10. return r
    11. print c01248_decode("884210122048022440414224202480122")

    4.栅栏密码

    栅栏密码是一种比较特殊的移位密码,密钥只有一个数字k,表示栅栏的长度,所谓的栅栏密码,就是将加密的明文分成k个组,然后取每组的第一个字符依次连接,拼接而成的字符串就是密文

    (1)加密解密的实现

    1. #加密
    2. def zhalan_encrypt(m,k):
    3. chip = []
    4. for i in range(0,len(m),k):
    5. if i + k >= len(m):
    6. tmp_m = m[i]
    7. else:
    8. tmp_m = m[i:i+k]
    9. chip.append(tmp_m)
    10. c = ""
    11. for i in range(k):
    12. for tmp_m in chip:
    13. if i < len(tmp_m):
    14. c += tmp_m [i]
    15. return c
    16. m = "flag{zhalan_mima_hahaha}"
    17. k =4
    18. print zhalan_encrypt(m,k)
    19. #解密
    20. def zhanlan_decrypt(c,k):
    21. l = len(c)
    22. partnum = 1 / k
    23. if 1 % k != 0:
    24. partnum += 1
    25. m = [""] * 1
    26. for i in range(0,1,partnum):
    27. if i + partnum >= len(c):
    28. tmp_c = c[i:]
    29. else:
    30. tmp_c = c[i:i + partnum]
    31. for j in range(len(tmp_c)):
    32. m[j * k + i / partnum] = tmp_c[j]
    33. return "".join(m)
    34. c = "f{lm_alzaihhahnmaaga_ah}"
    35. k = 4
    36. print zhanlan_decrypt(c,k)

    二、代替密码

    1.单表代替密码

    (1)凯撒密码

    凯撒密码是非常著名密码,原理也非常简单,就是通过字母的位移数来实现加密界面,明文中的所有字母都在字母表上向后或镶嵌按照一个固定的数目进行偏移后被替代成密文。

    ①加密解密的实现

    1. #加密
    2. def kaisa_encrypt(m,k):
    3. r = ""
    4. for i in m:
    5. r += chr((ord(i) + k) % 128)
    6. return r
    7. m = "flag{kaisamima}"
    8. k = 3
    9. print kaisa_encrypt(m,k)
    10. #解密
    11. def kaisa_decrypt(c,k):
    12. r = ""
    13. for i in c:
    14. r += chr((ord(i) - k) % 128)
    15. return r
    16. c = "iodj-ndlvdplpd\x00"
    17. k = 3
    18. print kaisa_decrypt(c,k)

    针对单表替代密码的攻击方法本来是词频分析,但是凯撒密码的密钥取值空间太小,直接爆破也是很简单的办法,所以针对凯撒密码的攻击方法就是爆破密钥k。

    ②例子

    c="39.4H/?BA2,0.2@.?J

    上述所示密文c,在没有密钥k的情况下,我们爆破密钥k,并判断结果中是否包含flag格式的字符串,以爆破出明文m,代码如下:

    1. def kaisa_decrypt(c,k):
    2. r = ""
    3. for i in c:
    4. r += chr((ord(i) - k) % 128)
    5. return r
    6. def kaisai_brute(c,match_str):
    7. result = []
    8. for k in range(128):
    9. tmp = kaisa_decrypt(c,k)
    10. if match_str in tmp:
    11. result,append(tmp)
    12. return result
    13. c = "39.4H/?BA2,0.2@.?J"
    14. print kaisai_brute(c,"flag")

    (2)ROT13

    ROT13是凯撒的一种特例,当k=13,且只作用于大小写时,称之为ROT13,准确来讲他不能算是密码,而是编码,它没有密钥。

    ROT13通常作用于MD5、flag等字符串上,而我们通常知道MD5的字符只有ABCDEF,其对应的ROT13就是“NOPQRS”,flag对应的就是“SYNT”。

    ①加密解密的实现

    1. #加密解密都是一样的
    2. def rot13(m):
    3. r =""
    4. for i in m:
    5. if ord(i) in range(ord('A'),ord('Z') + 1):
    6. r += chr((ord(i) + 13 - ord('A')) % 26 + ord('A'))
    7. elif ord(i) in range(ord('a'),ord('z') + 1):
    8. r += chr((ord(i) + 13 - ord('a')) % 26 + ord('a'))
    9. else:
    10. r += i
    11. return r
    12. c = ""
    13. print rot13(c)
    14. print rot13(rot13(c))

    (3)埃特巴什码

    与凯撒密码不同的是,埃特巴什码(Atbash Cipher)的替代表不是通过位移获得的,而是通过对称获得的,其通过将字母表的位置完全镜面对称后获得字母的替代表,然后进行加密。

    ABCDEFGHIJKLMNOPQRSTUVWXYZ

    ZYXWVUTSRQPONMLKJIHGFEDCBA

    ①加密解密的实现

    1. #加密
    2. def bash_encode(m):
    3. alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    4. origin = alphabet + alphabet.lower()
    5. TH_A = alphabet[::-1]
    6. TH_a = alphabet.lower() [::-1]
    7. TH = TH_A + TH_a
    8. r = ""
    9. for i in m:
    10. tmp = origin.find(i)
    11. if tmp != -1:
    12. r += TH[tmp]
    13. else:
    14. r += i
    15. return r
    16. print bash_encode("")
    17. #解密
    18. def bash_encode(m):
    19. alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    20. origin = alphabet + alphabet.lower()
    21. TH_A = alphabet[::-1]
    22. TH_a = alphabet.lower() [::-1]
    23. TH = TH_A + TH_a
    24. r = ""
    25. for i in m:
    26. tmp = origin.find(i)
    27. if tmp != -1:
    28. r += TH[tmp]
    29. else:
    30. r += i
    31. return r
    32. print bash_encode(bash_encode(""))

    (4)经典单表代替密码

    经典单表代替密码就是一个代替表对每一个位置的字符进行查表替换,假设替换表内容如下:

    ABCDEFGHIJKLMNOPQRSTUVWXYZ

    ZYXWVUTSRQPONMLKJIHGFEDCBA

    ①加密解密的实现

    1. #加密
    2. def danbiao_eccrypt(m,k,origin="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    3. r = ""
    4. for i in m:
    5. if origin.find(i) != -1:
    6. r += k[origin.find(i)]
    7. else:
    8. r += i
    9. return r
    10. print danbiao_eccrypt("")
    11. #解密
    12. def dainbiao_decode(c,k,origin="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    13. r = ""
    14. for i in c:
    15. if k.find(i) != -1:
    16. r += origin[k.find(i)]
    17. else:
    18. r += 1
    19. return r
    20. print dainbiao_decode("")

    (5)培根密码

    培根密码一般使用两种不同字体标识密文,密文内容不是关键所在,关键是字体,使用AB代表两种字体,五个一组,表示密文,明文对应如下:

     网上有在线解密,可以自行搜索。

    (6)仿射密码

    仿射密码的替代表的生成方式依据:c=am+b mod n,其中,m为明文对应字母得到的数字,n为字符数量,c为密文,a和b为密钥。

    ①加密解密的实现

    1. #加密
    2. def fangshe_encode(m,a,b,origin="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    3. r = ""
    4. for i in m:
    5. if origin.find(i) != -1:
    6. r += origin[(a * origin.index(i) + b) % len(origin)]
    7. else:
    8. r += i
    9. return r
    10. print fangshe_encode("")
    11. #解密
    12. def fangshe_dencode(c,a,b,origin="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    13. r = ""
    14. n = len(origin)
    15. ai = primefac.modinv(a,n) %n
    16. for i in c:
    17. if origin.find(i) != -1:
    18. r += origin[(ai * (origin.index(i) - b)) % len(origin)]
    19. else:
    20. r += i
    21. return r
    22. print fangshe_dencode("")

    ②已知明文的攻击

    如果我们知道了任意两个字符的明文密文对,那么我们可以推理出密钥ab:

    1. def fangshe_guessab(c,a,b,origin="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    2. x1 = origin.index(m1)
    3. x2 = origin.index(m2)
    4. y1 = origin.index(c1)
    5. y2 = origin.index(c2)
    6. n = len(origin)
    7. dxi = primefac.modinv(x1 - x2,n) %n
    8. a = dxi * (y1 - y2) % n
    9. b = (y1 - a * x1) % n
    10. return (a,b)
    11. print fangshe_guessab("")

    2.单表代替密码

    (1)棋盘类密码

    Playfair、Polybius、Nihilist均属于棋盘类密码。此类密码的密钥为5x5的棋盘,棋盘的生成符合条件:顺序随意,不得出现重复的字母,i和j可视为同一个字(也有将q去除的,以保证总数为25个)生成棋盘后,不同的加密方式使用了不同的转换方式,生成棋盘的代码如下:

    1. def gen_cheese_map(k,use_Q=True,upper=True):
    2. k = k.upper()
    3. k0 = ""
    4. origin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    5. for i in k:
    6. if i not in k0:
    7. k0 += i
    8. for i in origin:
    9. if i not in k0:
    10. k0 += 1
    11. if use_Q == True:
    12. k0 = k0[0:k0.index("J")] + k0[k0.index("J") + 1:]
    13. else:
    14. k0 = k0[0:k0.index("Q")] + k0[k0.index("Q") + 1:]
    15. if upper == False:
    16. k0 = k0.lower()
    17. assert len(k0) == 25
    18. r =[]
    19. for i in range(5):
    20. r.append(k0[i * 5:i * 5 + 5])
    21. return r
    22. print gen_cheese_map("")

    ①Playfari加密解密的实现

    1. #加密
    2. def playfari_enchode(m,k = "",chesse_map = []):
    3. m = m.upper()
    4. origin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    5. tmp = ""
    6. for i in m:
    7. if i in origin:
    8. tmp += i
    9. m = tmp
    10. assert k! = "" or chesse_map != []
    11. if chesse_map = []
    12. map = gen_cheese_map(k)
    13. else:
    14. map = chesse_map
    15. m0 = []
    16. idx = 0
    17. while idx < len(m):
    18. tmp = m[idx:idx + 2]
    19. if tmp[0] != tmp[1]:
    20. m0.append(tmp)
    21. idx += 2
    22. elif tmp [0] != "X":
    23. m0.append(tmp[0] + 'X')
    24. idx += 1
    25. else:
    26. m0.append(tmp[0] + 'Q')
    27. idx += 1
    28. if idx == len(m) - 1:
    29. if tmp[0] != "X":
    30. m0.append(tmp[0] + 'X')
    31. idx += 1
    32. r = []
    33. for i in m0:
    34. r.append(_playfari_2char(i,map))
    35. return r
    36. print playfari_enchode("")
    37. #解密
    38. def _playfari_2char_decode(tmp,map):
    39. for i in range(5):
    40. for j in range(5):
    41. if map[i][j] == tmp[0]:
    42. ai=i
    43. aj=j
    44. if map[i][j] == tmp[1]:
    45. bi = i
    46. bj = j
    47. if ai = bi:
    48. axi = ai
    49. bxi = bi
    50. axj = (aj - 1) % 5
    51. bxj = (bj - 1) % 5
    52. elif aj == bj:
    53. axj = aj
    54. bxj = bj
    55. axi = (ai - i) % 5
    56. bxi = (bi - i) % 5
    57. else:
    58. axi = ai
    59. axj = bj
    60. bxi = bi
    61. bxj = aj
    62. return map[axi] [axi] + map[bxi][bxj]
    63. def playfair_decore[c,k = "",cheese_map = []]:
    64. assert k != "" or cheese_map != []
    65. if cheese_map == []:
    66. map = gen_cheese_map(k)
    67. else:
    68. map = cheese_map
    69. r = []
    70. for i in c:
    71. r.append(_playfari_2char_decode(i,map))
    72. return "".join(r)
    73. print playfair_decore("")

    ②Polybuis加密解密的实现(Nihilist原理相同)

    1. #加密
    2. def Polybuis_encode(m,k="",name = "ADFGX",cheese_map=[]):
    3. m = m.upper()
    4. assert k != "" or cheese_map != []
    5. if chesse_map == []:
    6. map = gen_cheese_map(k)
    7. else:
    8. map = cheese_map
    9. r =[]
    10. for x in m:
    11. for i in range(5):
    12. for j in range(5):
    13. if map [i][j] == x:
    14. r.append(name[i] + name[j])
    15. return r
    16. print Polybuis_encode("")
    17. #解密
    18. def Polybuis_decode(c,k = "",name = "ADFGX",cheese_map):
    19. assert k != "" or cheese_map != []
    20. if cheese_map == []:
    21. map = gen_cheese_map(k)
    22. else:
    23. map = cheese_map
    24. r = ""
    25. for x in c:
    26. i = name.index(x[0])
    27. j = name.index(x[1])
    28. r += map[i][j]
    29. return r
    30. print Polybuis_decode("")

    3.维吉尼亚密码

    维吉尼亚密码是标准的多表代替密码,多表代替密码的密钥不再是固定不变的,而是随着位置发生改变的,在维吉尼亚密码中,根据密钥的字母来选择。维吉尼亚密码爆破必须依赖爆破+词频来进行,网上有在线破解的方法。

    4.希尔密码

    希尔密码是运用基本矩阵论的原理替换密码,将每个字母当做26进制数字:A=0,B=1,C=2以此类推,将一串字母当成n维向量,与一个n x n的矩阵相乘,在将得出的结果mod26。

              

  • 相关阅读:
    【生日快乐】搜索技术【深度优先搜索】 - 回溯法
    34.0、C语言——C语言预处理(2) - 预编译指令
    python:基础知识
    SOLIDWORKS 专业显卡要求
    C#设计原则
    Java实现Csv文件导入导出
    Fabric.js 图形标注
    Design a TinyURL
    冒泡排序、选择排序、直接插入排序、二分法查找
    【算法修炼】二分查找最接近元素(最接近下标)
  • 原文地址:https://blog.csdn.net/qq_60503432/article/details/127588439