[buuctf.reverse] 168_GAesDecode

这是一个apk的题,没用jni都是java的代码

输入flag后然后按下按钮就直接加密比对,这里一个参数是输入的flag另一个是加密用的key(很长),后边是比对的值,也就是密文。很明显是base64编码过的。

        ((Button) findViewById(R.id.verifyButton)).setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                try {
                    CharSequence message;
                    if (MainActivity.encrypt(plainTextView.getText().toString(), "This is a AES-like encryption algorithm. However, we do some change. Therefore, you cannot directly use security class to decrypt the message. Our challenge is to find the plain text of this encrypt message with th fixed key. ").equals("kNk3Qz+l/kLpGuKxf5iGE9cOoTmmn9Ac+UdF4b2CHqU=")) {
                        message = "Congratulation! Correct Flag!";
                    } else {
                        message = "Incorrect Flag!";
                    }
                    new Builder(MainActivity.this).setMessage(message).setPositiveButton((CharSequence) "OK", null).show();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

再看加密函数encrypt,题目说了是类AES加密,流程是AES的流程。

先把明文分成16字节的段,每断单独处理。

  1. 对明文初始化放入4*4的state里顺序是[0,4,8,12],[1,5,9,13]...先列后行
  2. 然后进行11轮加密,每轮取密钥的第n*16个字节作为密钥
  3. 第0轮只对明文addRoundKey
  4. 1-9轮进行substitute,shiftRows,mixCloumns,再作addRoundKey
  5. 第10轮只作substitute,shiftRows,再作addRoundKey
  6. 最后按顺序取出作为密文
    public static String encrypt(String plainText, String key) throws Exception {
        byte[] keyBytes = key.getBytes("UTF-8");
        byte[] plainTextBytes = plainText.getBytes("UTF-8");
        byte[] resultBytes = new byte[(((plainTextBytes.length + 15) / 16) * 16)];
        int i = 0;
        while (i < plainTextBytes.length) {
            byte[] inputBytes = new byte[16];
            int j = 0;
            while (j < 16 && i + j < plainTextBytes.length) {
                inputBytes[j] = plainTextBytes[i + j];
                j++;
            }
            LightState state = new LightState(inputBytes);
            for (int round = 0; round <= 10; round++) {
                byte[] roundKey = new byte[16];
                for (j = 0; j < 16; j++) {
                    roundKey[j] = keyBytes[(round * 16) + j];
                }
                if (round == 0) {
                    state.addRoundKey(roundKey);
                } else if (round < 10) {
                    state.substitute();
                    state.shiftRows();
                    state.mixCloumns();
                    state.addRoundKey(roundKey);
                } else {
                    state.substitute();
                    state.shiftRows();
                    state.addRoundKey(roundKey);
                }
            }
            for (int row = 0; row < 4; row++) {
                for (int column = 0; column < 4; column++) {
                    resultBytes[((row * 4) + i) + column] = state.value(row, column);
                }
            }
            i += 16;
        }
        return Base64.encodeToString(resultBytes, 2);
    }

然后看每个加密过程

1,addRoundKey,将明文块与密钥进行异或,取密钥的顺序也是先列后行

    public void addRoundKey(byte[] key) {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                byte[] bArr = this._states[i];
                bArr[j] = (byte) (bArr[j] ^ key[(j * 4) + i]);
            }
        }
    }

2,substitute 取明文sbox后的结果,这是个转换表而且是1对1的

   public void substitute() {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                this._states[i][j] = sbox(this._states[i][j]);
            }
        }
    }

3,sbox先求inverse再分成位(低位在前)然后再求出结果

    public static byte sbox(byte a) {
        int inverse = inverse(a);
        if (inverse < 0) {
            inverse += 256;
        }
        int[] c = new int[8];
        for (int i = 0; i < 8; i++) {
            c[i] = inverse % 2;
            inverse /= 2;
        }
        int[] s = new int[]{((((c[7] + c[6]) + c[5]) + c[4]) + c[3]) % 2, (((((c[6] + c[5]) + c[4]) + c[3]) + c[2]) + 1) % 2, (((((c[5] + c[4]) + c[3]) + c[2]) + c[1]) + 1) % 2, ((((c[4] + c[3]) + c[2]) + c[1]) + c[0]) % 2, ((((c[7] + c[3]) + c[2]) + c[1]) + c[0]) % 2, ((((c[7] + c[6]) + c[2]) + c[1]) + c[0]) % 2, (((((c[7] + c[6]) + c[5]) + c[1]) + c[0]) + 1) % 2, (((((c[7] + c[6]) + c[5]) + c[4]) + c[0]) + 1) % 2};
        return (byte) ((((((((s[7] * 128) + (s[6] * 64)) + (s[5] * 32)) + (s[4] * 16)) + (s[3] * 8)) + (s[2] * 4)) + (s[1] * 2)) + s[0]);
    }

4,inverse调用multiply进行254轮加密

    public static byte inverse(byte a) {
        byte result = (byte) 1;
        for (int i = 0; i < 254; i++) {
            result = multiply(result, a);
        }
        return result;
    }

5,multiply这个函数非常复杂,自己对照写了python的居然不对

    public static byte multiply(int a, int b) {
        int i;
        if (a < 0) {
            a += 256;
        }
        if (b < 0) {
            b += 256;
        }
        int[] avalues = new int[8];
        int[] bvalues = new int[8];
        for (i = 0; i < 8; i++) {
            avalues[i] = a % 2;
            a /= 2;
        }
        for (i = 0; i < 8; i++) {
            bvalues[i] = b % 2;
            b /= 2;
        }
        int[] results = new int[16];
        for (int j = 7; j >= 0; j--) {
            if (bvalues[j] > 0) {
                for (i = 0; i < 8; i++) {
                    if (avalues[i] > 0) {
                        results[i + j] = (results[i + j] + 1) % 2;
                    }
                }
            }
        }
        if (results[15] > 0) {
            results[5] = (results[5] + 1) % 2;
            results[3] = (results[3] + 1) % 2;
            results[2] = (results[2] + 1) % 2;
            results[1] = (results[1] + 1) % 2;
            results[0] = (results[0] + 1) % 2;
        }
        if (results[14] > 0) {
            results[7] = (results[7] + 1) % 2;
            results[4] = (results[4] + 1) % 2;
            results[3] = (results[3] + 1) % 2;
            results[1] = (results[1] + 1) % 2;
        }
        if (results[13] > 0) {
            results[6] = (results[6] + 1) % 2;
            results[3] = (results[3] + 1) % 2;
            results[2] = (results[2] + 1) % 2;
            results[0] = (results[0] + 1) % 2;
        }
        if (results[12] > 0) {
            results[7] = (results[7] + 1) % 2;
            results[5] = (results[5] + 1) % 2;
            results[3] = (results[3] + 1) % 2;
            results[1] = (results[1] + 1) % 2;
            results[0] = (results[0] + 1) % 2;
        }
        if (results[11] > 0) {
            results[7] = (results[7] + 1) % 2;
            results[6] = (results[6] + 1) % 2;
            results[4] = (results[4] + 1) % 2;
            results[3] = (results[3] + 1) % 2;
        }
        if (results[10] > 0) {
            results[6] = (results[6] + 1) % 2;
            results[5] = (results[5] + 1) % 2;
            results[3] = (results[3] + 1) % 2;
            results[2] = (results[2] + 1) % 2;
        }
        if (results[9] > 0) {
            results[5] = (results[5] + 1) % 2;
            results[4] = (results[4] + 1) % 2;
            results[2] = (results[2] + 1) % 2;
            results[1] = (results[1] + 1) % 2;
        }
        if (results[8] > 0) {
            results[4] = (results[4] + 1) % 2;
            results[3] = (results[3] + 1) % 2;
            results[1] = (results[1] + 1) % 2;
            results[0] = (results[0] + 1) % 2;
        }
        return (byte) ((((((((results[7] * 128) + (results[6] * 64)) + (results[5] * 32)) + (results[4] * 16)) + (results[3] * 8)) + (results[2] * 4)) + (results[1] * 2)) + results[0]);
    }

6,再往上发现它居然给了sbox逆向的数据,有了这个其实也就是用前面的逆向sbox了

    public static byte inverseSbox(byte a) {
        return (byte) new int[]{82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125}[(a + 256) % 256];
    }

7,shiftRows对4行进行移位,0行不动,1行先循环右移1位,2行2位,3行3位

  public void shiftRows() {
        for (int i = 0; i < 4; i++) {
            int j;
            byte[] temp = new byte[4];
            for (j = 0; j < 4; j++) {
                temp[j] = this._states[i][j];
            }
            for (j = 0; j < 4; j++) {
                this._states[i][j] = temp[(j + i) % 4];
            }
        }
    }

8,mixCloumns 这里是个小难点,每次取出一行的4个值,然后再通过multiply2和multiply3生成新值再进行异或得到4个新值。这里multiply3(a) = a^multiply2(a) 

而multiply2是个可逆运算,如果首位为0直接左移1位,如果首位为1左移1位再与29异或。这样如果密文尾位为1则是负数的情况先异或29再右移1位即可复原,如果尾位为0则直接右移1位。

    public static byte add(byte a, byte b) {
        return (byte) (a ^ b);
    }

    public static byte add(byte a, byte b, byte c, byte d) {
        return (byte) (((a ^ b) ^ c) ^ d);
    }

    public static byte multiply2(byte a) {
        if (a >= (byte) 0) {
            return (byte) (a << 1);
        }
        return (byte) ((a << 1) ^ 29);
    }

    public static byte multiply3(byte a) {
        return add(a, multiply2(a));
    }

    public void mixCloumns() {
        for (int j = 0; j < 4; j++) {
            byte[] temp = new byte[4];
            for (int i = 0; i < 4; i++) {
                temp[i] = this._states[i][j];
            }
            this._states[0][j] = add(multiply2(temp[0]), multiply3(temp[1]), temp[2], temp[3]);
            this._states[1][j] = add(temp[0], multiply2(temp[1]), multiply3(temp[2]), temp[3]);
            this._states[2][j] = add(temp[0], temp[1], multiply2(temp[2]), multiply3(temp[3]));
            this._states[3][j] = add(multiply3(temp[0]), temp[1], temp[2], multiply2(temp[3]));
        }
    }

流程和函数都弄明白就可以写逆向程序了

1,sbox函数改为数组,直接取值

r_sbox = [82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125]

2,完成substitute

def r_substitute(states):
    for i in range(4):
        for j in range(4):
            states[i][j] = r_sbox[states[i][j]]
    return states 

3,shiftRows

def r_shiftRows(states):
    for i in range(4):
        temp = [states[i][j] for j in range(4)]
        states[i] = [temp[(j-i)%4] for j in range(4)]
    return states 

4,mixColumns这块需要一个小的爆破

先把4个式子异或到一起就能得到temp[0]^temp[1]^temp[2]^temp[3]的值,然后爆破0,从而求出1再由1求2,由2求3,再由3求新的0,新旧0相同时得到原值。

def r_m2(a):
    if a&1 == 1:
        return ((a^29)>>1)|0x80 
    else:
        return a>>1 

def r_mix(states):
    for j in range(4):
        temp = [states[i][j] for i in range(4)]
        a0123 = temp[0]^temp[1]^temp[2]^temp[3]
        t = [temp[0]^a0123, temp[1]^a0123, temp[2]^a0123, temp[3]^a0123]
        for ma0 in range(0x100):
            ma1 = t[0]^ma0^r_m2(ma0)
            ma2 = t[1]^ma1^r_m2(ma1) 
            ma3 = t[2]^ma2^r_m2(ma2)
            mat = t[3]^ma3^r_m2(ma3) 
            if mat == ma0:
                states[0][j] = r_m2(ma0)
                states[1][j] = r_m2(ma1)
                states[2][j] = r_m2(ma2)
                states[3][j] = r_m2(ma3)
                break 
    return states 

5,addRoundKeys这个原样复制过来

def andRoundKey(states, rkey):
    return [[states[i][j]^rkey[j*4+i]  for j in range(4)] for i in range(4)]

6,然后是对应的输入输出函数

def state_in(cipher):
    return [[cipher[i*4+j]  for j in range(4)] for i in range(4)]

def state_out(states):
    s = b''
    for i in range(4):
        for j in range(4):
            s += bytes([states[j][i]])
    return s 

7,最后是整体的解密过程

def decrypt(cipher):
    for i in range(0, len(cipher),16):
        c = cipher[i: i+16]
        states = state_in(c)
        #print(list(c), states)
        for j in range(10,-1,-1):   #11轮每轮先异或key
            roundKey = key[j*16: j*16+16]
            #print(roundKey)
            if j == 0:
                states = andRoundKey(states, roundKey)
            elif j < 10:
                states = andRoundKey(states, roundKey)
                states = r_mix(states)
                states = r_shiftRows(states)
                states = r_substitute(states)
            else:
                states = andRoundKey(states, roundKey)
                states = r_shiftRows(states)
                states = r_substitute(states)
        flag = state_out(states)
        print(flag.decode(), end='')

            

from base64 import *

cipher = "kNk3Qz+l/kLpGuKxf5iGE9cOoTmmn9Ac+UdF4b2CHqU="
key =  b"This is a AES-like encryption algorithm. However, we do some change. Therefore, you cannot directly use security class to decrypt the message. Our challenge is to find the plain text of this encrypt message with th fixed key. "
cipher = b64decode(cipher)                    
#print(cipher)
        
decrypt(cipher)
#flag{aes_is_the_best_encryption}

虽然看上去没多大难点但是没有五六的钟头完不成。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值