1. 程式人生 > 實用技巧 >仿射密碼-fanfie--affine

仿射密碼-fanfie--affine

⭐仿射密碼


仿射密碼 是一種專情密碼,一對一替換 ~~


  • 加密函式是 e(x) = ax + b (mod m) 其中a和m 互質,m是字母的數目。

  • 解碼函式是 d(x) = a^-1(x - b) (mod m) (打不出來湊合一下 a^-1 乘法逆元)


⭐仿射例題


【攻防世界】 - - fanfie

先上題,該題來源於 BITSCTF 。 【題目連結】


下載附件,得到如下的字串。 長度不長,大寫字母和數字組成。 很容易讓人想到 Base64/32 解密。


MZYVMIWLGBL7CIJOGJQVOA3IN5BLYC3NHI

先簡單提一下 詳細介紹可以看一下網上大佬的這篇

關於base系列的加密解密

  • Base64 : 由 0-9、a-z、A-Z、+、/ 及字尾 “=” 組成 將任意位元組序列資料編碼成ASCII字串
  • Base32 : 用32個可列印字元 A-Z、2-7 對任意位元組資料進行編碼

然而通過Base64解碼並沒有發現什麼。(這題腦洞是真的大!!怪不得叫“ fanfie”-幻想)

通過百度大佬 題解 才知:


  • [ ] 將BITSCTF 進行Base32加密 附 Base32加密網站

    IJEVIU2DKRDA====
    
  • [ ] 得到的這串密文與題目給出的字串進行比對

    MZYVMIWLGBL7CIJOGJQVOA3IN5BLYC3NHI
    IJEVIU2DKRDA====
    

發現上面相同的字母對應的下面的字母也一致。(如 M - I 、L - D)既然如此,那便有跡可循。

因為是Base32編碼。那麼對A-Z、2-7 進行編碼:

A B C D E F G H
0 1 2 3 4 5 6 7
I J K L M N O P
8 9 10 11 12 13 14 15
Q R S T U V W X
16 17 18 19 20 21 22 23
Y Z 2 3 4 5 6 7
24 25 26 27 28 29 30 31

由此更直觀可見,字母對應關係

3 ->11 4 ->24 8 ->12 20 ->8 21->21 25->9 26->22


這種一個字母替換一個字母的替換密碼就是 仿射密碼

  • 加密函式是 e(x) = ax + b (mod m) 其中a和m 互質,m是字母的數目。

  • 解碼函式是 d(x) = a^-1(x - b) (mod m) (打不出來湊合一下 a^-1 乘法逆元)


如何進行仿射解密呢? 我們有倆種方法:

  1. 進行肉眼勘測和手動計算
  2. python指令碼自動跑

先來看第一種: 由上述所有條件,我們可以自豪的斷定: 仿射密碼的 a = 13 b = 4

經過仿射解密 可得 :

MZYVMIWLGBL7CIJOGJQVOA3IN5BLYC3NHI --> IJEVIU2DKRDHWUZSKZ4VSMTUN5RDEWTNPU

第二種,上指令碼:借鑑大佬 仿射加密解密指令碼 歐幾里得演算法求解乘法逆元


已知 加密仿射的 a:13 b:4 模:32 第一步先求解 13關於模32的逆元


# 歐幾里德演算法求最大公約數
def get_gcd(a, b):
    k = a // b
    remainder = a % b
    while remainder != 0:
        a = b
        b = remainder
        k = a // b
        remainder = a % b
    return b
# 改進歐幾里得演算法求線性方程的x與y
def get_(a, b):
    if b == 0:
        return 1, 0
    else:
        k = a // b
        remainder = a % b
        x1, y1 = get_(b, remainder)
        x, y = y1, x1 - k * y1
    return x, y
a = input('a:')
b = input('b:')
a, b = int(a), int(b)

# 將初始b的絕對值進行儲存
if b < 0:
    m = abs(b)
else:
    m = b
flag = get_gcd(a, b)
# 判斷最大公約數是否為1,若不是則沒有逆元
if flag == 1:
    x, y = get_(a, b)
    x0 = x % m  # 對於Python '%'就是求模運算,因此不需要'+m'
    print("所求的逆元:", x0)  # x0就是所求的逆元
else:
    print("Do not have!")


k1:仿射加密函式中的a

k2:仿射加密函式中的b

k3:13關於 模32 的逆元


輸入到下面java程式碼中

import java.util.Scanner;
public class Main{
    public static void main(String[] args) {
        char[] form = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
                'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7'};
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入待加密的明文:");
        String MingWen = sc.nextLine();
        MingWen=MingWen.toUpperCase();
        final int K1 = 13;  //仿射加密函式中的a
        final int K2 = 4;  //仿射加密函式中的b
        final int K3 = 5;  // 13關於 模32 的逆元
        int [] cipherNum=new int[MingWen.length()];//用來儲存數字化的密文
        encryption(MingWen,form,K1,K2,K3,cipherNum);
    }
    public static void encryption(String MingWen,char[] form,int K1,int K2,int k3,int[] cipherNum){
        char[] pla=new char[MingWen.length()];
        for (int i = 0; i <MingWen.length() ; i++) {
            pla[i]=MingWen.charAt(i);
        }

        int[] MingWenNumber=new int[pla.length];
        for (int i = 0; i <pla.length ; i++) {
            for (int j = 0; j <form.length ; j++) {
                if (form[j]==pla[i]) {
                    MingWenNumber[i] = j;
                }
            }
        }
        //通過腳標將明文全部轉化為數字
        char[] cipher = new char[MingWen.length()];
        char[] JieMI = new char[MingWen.length()];
        int len = MingWen.length();//cipher密碼陣列 用來儲存密文
        for (int i = 0; i <MingWen.length() ; i++) {
            int a= Math.floorMod((K1*MingWenNumber[i]+K2),32);
            cipherNum[i]=a;
            cipher[i]=form[a];
            //計算密文並存入陣列中
        }
        System.out.println("加密結果是:");
        System.out.println(cipher);
        
        for (int i =0;i<len;i++){
            JieMI[i]=form[Math.floorMod(k3*(MingWenNumber[i]-K2),32)];
        }
        System.out.println("解密結果是:");
        System.out.println(JieMI);
    }
}


IJEVIU2DKRDHWUZSKZ4VSMTUN5RDEWTNPU

最後一步啦~ 對指令碼跑出的程式碼進行 Base32 解碼 。網站同上。


BITSCTF{S2VyY2tob2Zm}


再來一簡單題!

【bugkuCtf】 -- affine

題目連結 請戳這裡


u1s1,該題目就非常實誠。直接給出 a / b 以及 密文 並且 affine 直接明示 這是 仿射解密 。


  • E(x) = (ax + b) (mod m) a=17 b = -8
  • szzyfimhyzd

話不多說,我們可以繼續使用上面的指令碼 也可以使用下面一種更快的指令碼 搬自這位大佬


def get(a, b):
    if b == 0:
        return 1, 0
    else:
        k = a //b
        remainder = a % b
        x1, y1 = get(b, remainder)
        x, y =y1, x1 - k * y1
    return x, y

s = input("請輸入解密字元:").upper()
a = int(input("請輸入a:"))
b = int(input("請輸入b:"))

#求a關於26的乘法逆元
x, y = get(a, 26)
a1 = x % 26

l= len(s)
for i in range(l):
    cipher = a1 * (ord(s[i])- 65 - b) % 26
    res=chr(cipher + 65)
    print(res, end='')


因為題目已經明確給出 ,所以直接進行解析就好。


preflag = "szzyfimhyzd"
flags = []
for i in preflag:
    flags.append(ord(i)-97)
flag = ""
for i in flags:
    for j in range(0,26):
        a = (17 * j - 8) % 26
        if(a == i): 
            flag += chr(j+97)
print(flag)

那最後的flag就是:

affineshift

⭐結語

最後:其實我蠻驚奇的。 fanfie && affine 取名上十分巧妙。

( 前一題是不是有暗示的意味在呢~~手動狗頭 )


寶藏軟體推薦

【強烈安利】 無意間知道了這個神仙軟體 captfencoder (點選下載哦~)

裡面聚合編碼轉換古典密碼密碼學其他編碼實用工具!!


還是老規矩 :關於以上鍊接引用【侵權刪】

若有錯誤之處,還請多多指正~~

【轉載請放連結】 https://www.cnblogs.com/Jlay/p/RSA_Environment.html