2024-源鲁杯-crypto

记录几道题

breakbox

题目:

#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
#define ROUND 16
// 0<sBox[i]<15
int sBox[16] ={
        3, 10, 15, 12,
        9, 2, 1, 7,
        x, x, x, x,
        x, x, x, x
};

void derive_round_key(unsigned int key, unsigned char *round_key, int length) {

    unsigned int tmp = key;
    int i;
    for(i = 0; i < length / 16; i++)
    {
        memcpy(round_key + i * 16,      &tmp, 4);   tmp++;
        memcpy(round_key + i * 16 + 4,  &tmp, 4);   tmp++;
        memcpy(round_key + i * 16 + 8,  &tmp, 4);   tmp++;
        memcpy(round_key + i * 16 + 12, &tmp, 4);   tmp++;
    }
}

void reverseBits(unsigned char* state) {
    unsigned char temp[16];
    int i,j;
    for ( i = 0; i < 16; i++) {
        unsigned char byte = 0;
        for ( j = 0; j < 8; j++) {
            byte |= ((state[i] >> j) & 1) << (7 - j);
        }
        temp[15 - i] = byte;
    }
    for ( i = 0; i < 16; i++) {
        state[i] = temp[i];
    }
}

void sBoxTransform(unsigned char* state) {
        int i;
    for ( i = 0; i < 16; i++) {
        int lo = sBox[state[i] & 0xF];
        int hi = sBox[state[i] >> 4];
        state[i] = (hi << 4) | lo;
    }
    
}

void leftShiftBytes(unsigned char* state) {
        int i;
    unsigned char temp[16];
    for ( i = 0; i < 16; i += 4) {
        temp[i + 0] = state[i + 2] >> 3 | (state[i + 1] << 5);
        temp[i + 1] = state[i + 3] >> 3 | (state[i + 2] << 5);
        temp[i + 2] = state[i + 0] >> 3 | (state[i + 3] << 5);
        temp[i + 3] = state[i + 1] >> 3 | (state[i + 0] << 5);
    }
    for ( i = 0; i < 16; i++)
    {
        state[i] = temp[i];
    }
}
void addRoundKey(unsigned char* state, unsigned char* roundKey, unsigned int round) {
        int i,j;
    for ( i = 0; i < 16; i++) {
        for ( j = 0; j < 8; j++) {
            state[i] ^= ((roundKey[i + round * 16] >> j) & 1) << j;
            
        }
    }
}


void encrypt(unsigned char* password, unsigned int key, unsigned char* ciphertext) {
    unsigned char roundKeys[16 * ROUND] = {}; 
    derive_round_key(key, roundKeys, 16 * ROUND);

    unsigned char state[16];
    memcpy(state, password, 16); 
        int round;
    for ( round = 0; round < ROUND; round++)
    {   
        reverseBits(state);
        sBoxTransform(state);
        leftShiftBytes(state);
        addRoundKey(state, roundKeys, round); 
    }

    memcpy(ciphertext, state, 16);
}

void main() {
    unsigned char password[] = "";
        unsigned int key = 0xFFFF00EE; 
    unsigned char ciphertext[16]; 
    encrypt(password, key, ciphertext);
    int i;
    printf("Encrypted password:");
    for (i = 0; i < 16; i++) {
        printf("%02X", ciphertext[i]);
    }
}



/* password_len = 16,and give you key,but we can not know sbox[:-8],please guess it! */

encry password:087BB2594D0BCE4CBE82620AB5BC7A96
input your password to get flag!

先把sbox已知的数逆出来得到,未知数就拿100来代替了

#逆向过程:
#s[0]=3 -> r[3] = 0
int rBox[16] = { 100, 6, 5, 0,
                 100, 100, 100, 7,
                 100, 4, 1,100 ,
                 3, 100, 100, 2 };

剩下几位靠爆破得到,我写的代码就是依托答辩,但是我觉得还挺好理解的

for (int i = 8; i < 16; i++)
{
    rBox[0] = i;
    for (int j = 8; j < 16; j++)
    {
        if (j == i) {
            continue;
        }
        rBox[4] = j;
        for (int k = 8; k < 16; k++) {
            if (j == k || k == i) {
                continue;
            }
            rBox[5] = k;
            for (int i1 = 8; i1 < 16; i1++) {
                if (k == i1 || i1 == j || i1 == i) {
                    continue;
                }
                rBox[6] = i1;
                for (int j1 = 8; j1 < 16; j1++) {
                    if (i1 == j1 || j1 == i || j1 == j || j1 == k) {
                        continue;
                    }
                    rBox[8] = j1;
                    for (int k1 = 8; k1 < 16; k1++) {
                        if (j1 == k1 || k1 == i || k1 == j || k1 == i1 || k1 == k) {
                            continue;
                        }
                        rBox[11] = k1;
                        for (int i2 = 8; i2 < 16; i2++) {
                            if (k1 == i2 || i2 == i || i2 == j || i2 == k || i2 == i1 || i2 == j1) {
                                continue;
                            }
                            rBox[13] = i2;
                            for (int j2 = 8; j2 < 16; j2++) {
                                if (j2 == i2 || j2 == k || j2 == i || j2 == j || j2 == i1 || j2 == j1 || j2 == k1) {
                                    continue;
                                }
                                rBox[14] = j2;

最后注意一下inv_leftShiftBytes就行了
exp:

#include <openssl/sha.h>
#include "stdlib.h"
#include <stdio.h>
#include <string.h>
#pragma warning(disable:4996)
#define ROUND 16
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")
#include <stdbool.h>
#include <ctype.h>
void print(unsigned char* m) {
    for (int i = 0; i < 16; i++) {
        printf("%02X", m[i]);
    }
    printf("\n");
}

int is_all_visible(unsigned char* str) {
    while (*str) { // 循环直到字符串的结尾(NULL字符)
        if (!isprint((unsigned char)*str)) { // 如果字符不是可见的
            return 0; // 返回假
        }
        str++; // 移动到下一个字符
    }
    return 1; // 所有字符都是可见的,返回真
}

// 判断字符串是否全部由可见字符组成
int visible_char_length(unsigned char* str) {
    int count = 0;
    while (*str) {
        if (isprint((unsigned char)*str)) {
            count++;
        }
        str++;
    }
    return count;
}
//S-Box 16x16


int rBox[16] = { 100, 6, 5, 0,
                 100, 100, 100, 7,
                 100, 4, 1,100 ,
                 3, 100, 100, 2 };
// 将十六进制字符串转换为 unsigned char 数组
void hex_to_bytes(const char* hex_str, unsigned char* bytes, size_t bytes_len) {
    size_t hex_len = strlen(hex_str);
    if (hex_len % 2 != 0 || hex_len / 2 > bytes_len) {
        fprintf(stderr, "Invalid hex string length.n");
        return;
    }

    for (size_t i = 0; i < hex_len / 2; i++) {
        sscanf(hex_str + 2 * i, "%2hhx", &bytes[i]);
    }
}


// 派生轮密钥
void derive_round_key(unsigned int key, unsigned char* round_key, int length) {

    unsigned int tmp = key;
    for (int i = 0; i < length / 16; i++)
    {
        memcpy(round_key + i * 16, &tmp, 4);   tmp++;
        memcpy(round_key + i * 16 + 4, &tmp, 4);   tmp++;
        memcpy(round_key + i * 16 + 8, &tmp, 4);   tmp++;
        memcpy(round_key + i * 16 + 12, &tmp, 4);   tmp++;
    }
}


// 比特逆序
void reverseBits(unsigned char* state) {
    unsigned char temp[16];
    for (int i = 0; i < 16; i++) {
        unsigned char byte = 0;
        for (int j = 0; j < 8; j++) {
            byte |= ((state[i] >> j) & 1) << (7 - j);
        }
        temp[15 - i] = byte;
    }
    for (int i = 0; i < 16; i++) {
        state[i] = temp[i];
    }
}


/*void sBoxTransform(unsigned char* state) {
    for (int i = 0; i < 16; i++) {
        int lo = sBox[state[i] & 0xF];
        int hi = sBox[state[i] >> 4];
        state[i] = (hi << 4) | lo;
    }
}*/

void inv_sBoxTransform(unsigned char* state) {
    //for (int i = 0; i < 16; i++) {
    //    printf("%d ", rBox[i]);
   // }
     //  printf("\n");

    for (int i = 0; i < 16; i++) {
        int lo = rBox[state[i] & 0xF];
        int hi = rBox[state[i] >> 4];
        state[i] = (hi << 4) | lo;
    }

}


/*void leftShiftBytes(unsigned char* state) {
    unsigned char temp[16];
    for (int i = 0; i < 16; i += 4) {
        temp[i + 0] = state[i + 2] >> 3 | (state[i + 1] << 5);
        temp[i + 1] = state[i + 3] >> 3 | (state[i + 2] << 5);
        temp[i + 2] = state[i + 0] >> 3 | (state[i + 3] << 5);
        temp[i + 3] = state[i + 1] >> 3 | (state[i + 0] << 5);

    }
    for (int i = 0; i < 16; i++)
    {
        state[i] = temp[i];
    }
}*/

void inv_leftShiftBytes(unsigned char* state) {
    unsigned char temp[16];
    for (int i = 0; i < 16; i += 4) {
        // temp[i + 0] = state[i + 2] >> 3 | (state[i + 1] << 5);
         //temp[i + 1] = state[i + 3] >> 3 | (state[i + 2] << 5);
         //temp[i + 2] = state[i + 0] >> 3 | (state[i + 3] << 5);
         //temp[i + 3] = state[i + 1] >> 3 | (state[i + 0] << 5);

        temp[i + 0] = state[i + 2] << 3 | (state[i + 3] >> 5);
        temp[i + 1] = state[i + 3] << 3 | (state[i + 0] >> 5);
        temp[i + 2] = state[i + 0] << 3 | (state[i + 1] >> 5);
        temp[i + 3] = state[i + 1] << 3 | (state[i + 2] >> 5);
    }
    for (int i = 0; i < 16; i++)
    {
        state[i] = temp[i];
    }
}


// 轮密钥加
void addRoundKey(unsigned char* state, unsigned char* roundKey, unsigned int round) {
    for (int i = 0; i < 16; i++) {
        for (int j = 0; j < 8; j++) {
            state[i] ^= ((roundKey[i + round * 16] >> j) & 1) << j;
        }
    }
}

// 加密函数
/*void encrypt(unsigned char* password, unsigned int key, unsigned char* ciphertext) {
    unsigned char roundKeys[16 * ROUND] = {}; //

    // 生成轮密钥
    derive_round_key(key, roundKeys, 16 * ROUND);

    // 初始状态为16字节的口令
    unsigned char state[16]; // 初始状态为16字节的密码
    memcpy(state, password, 16); // 初始状态为密码的初始值

    // 迭代加密过程
    for (int round = 0; round < ROUND; round++)
    {
        reverseBits(state);
        sBoxTransform(state);
        leftShiftBytes(state);
        addRoundKey(state, roundKeys, round);
    }

    memcpy(ciphertext, state, 16);
}*/

void decrypt(unsigned char* ciphertext, unsigned int key, unsigned char* plaintext) {
    unsigned char roundKeys[16 * ROUND] = {}; //
    for (int i = 8; i < 16; i++)
    {
        rBox[0] = i;
        for (int j = 8; j < 16; j++)
        {
            if (j == i) {
                continue;
            }
            rBox[4] = j;
            for (int k = 8; k < 16; k++) {
                if (j == k || k == i) {
                    continue;
                }
                rBox[5] = k;
                for (int i1 = 8; i1 < 16; i1++) {
                    if (k == i1 || i1 == j || i1 == i) {
                        continue;
                    }
                    rBox[6] = i1;
                    for (int j1 = 8; j1 < 16; j1++) {
                        if (i1 == j1 || j1 == i || j1 == j || j1 == k) {
                            continue;
                        }
                        rBox[8] = j1;
                        for (int k1 = 8; k1 < 16; k1++) {
                            if (j1 == k1 || k1 == i || k1 == j || k1 == i1 || k1 == k) {
                                continue;
                            }
                            rBox[11] = k1;
                            for (int i2 = 8; i2 < 16; i2++) {
                                if (k1 == i2 || i2 == i || i2 == j || i2 == k || i2 == i1 || i2 == j1) {
                                    continue;
                                }
                                rBox[13] = i2;
                                for (int j2 = 8; j2 < 16; j2++) {
                                    if (j2 == i2 || j2 == k || j2 == i || j2 == j || j2 == i1 || j2 == j1 || j2 == k1) {
                                        continue;
                                    }
                                    rBox[14] = j2;
                                    // 生成轮密钥
                                    derive_round_key(key, roundKeys, 16 * ROUND);

                                    // 初始状态为16字节的口令
                                    unsigned char state[16]; // 初始状态为16字节的密码
                                    memcpy(state, ciphertext, 16); // 初始状态为密码的初始值

                                    // 迭代加密过程
                                    for (int round = ROUND - 1; round >= 0; round--)
                                    {
                                        addRoundKey(state, roundKeys, round);
                                        inv_leftShiftBytes(state);
                                        inv_sBoxTransform(state);
                                        reverseBits(state);
                                    }

                                    memcpy(plaintext, state, 16);
                                    if (plaintext[0] > 31 && plaintext[0] < 127 && plaintext[1] > 31 && plaintext[1] < 127 && plaintext[2] > 31 && plaintext[2] < 127 && plaintext[3] > 31 && plaintext[3] < 127 && plaintext[4] > 31 && plaintext[4] < 127 && plaintext[5] > 31 && plaintext[5] < 127 && plaintext[6] > 31 && plaintext[6] < 127) {
                                        printf("%s", plaintext);
                                        printf("\n");
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

bool isPrintable(unsigned char* data, int length) {
    for (int i = 0; i < length; i++) {
        if (data[i] < 32 || data[i] > 126) {
            return false;
        }
    }
    return true;
}

int main() {
    unsigned char ciphertext[16]; // 16字节的状态
    long long int cnt111 = 0;
    unsigned char plaintext[16]; // 16字节的状态
    const char hex_ct[] = "087BB2594D0BCE4CBE82620AB5BC7A96";
    unsigned int k = 0xFFFF00EE;
    hex_to_bytes(hex_ct, ciphertext, 16);
    long long cnt = 0;

    decrypt(ciphertext, k, plaintext);


    return 0;

}

ancat

猫脸变换,记录一下脚本
exp:

import matplotlib.pyplot as plt
import cv2
import numpy as np
from PIL import Image
def de_arnold(img,shuffle_time,a,b):
    r, c, d = img.shape
    dp = np.zeros(img.shape, np.uint8)

    for s in range(shuffle_time):
        for i in range(r):
            for j in range(c):
                x = ((a * b + 1) * i - b * j) % r
                y = (-a * i + j) % c
                dp[x, y, :] = img[i, j, :]
        img = np.copy(dp)
    cv2.imwrite(f"flag.png",img)

img_en = cv2.imread('en_flag.png')
de_arnold(img_en, 3,6, 9)

EandR

题目:

import random
from Crypto.Util.number import *
from password import password
password1 = bytes_to_long(password[0:10])
password2 = bytes_to_long(password[10:15])
password3 = bytes_to_long(password[15:])
q1 = getPrime(80)
a,b,c = [random.randrange(1,q1-1) for _ in "_yi_gei_woli_giaogiao"][:3]
def add(P,Q):
        if P[0] != Q[0] and P[1] != Q[1]:
                t = ((Q[1]-P[1]) * inverse(Q[0]-P[0],q1)) %q1
        else:
                t = ((3*c*P[0]*P[0]+a) * inverse(2*b*P[1],q1))%q1

        x3 = b*inverse(c,q1)*t*t - P[0] - Q[0]
        y3 = t*(P[0] - x3) - P[1]
        return (x3%q1, y3%q1)

def mul(t, A, B=0):
        if not t: return B
        return mul(t//2, add(A,A), B if not t&1 else add(B,A) if B else A)

G = (543964449142803087188784, 288605946000947449279542)
Ps = []
ms = [random.randrange(1,q1-1) for _ in "giaoli_wo_ki_gay_giao"[:4]] + [password1]
for m in ms:
        P = mul(m,G)
        Ps.append(P)
print(f'Ps = {Ps}')
#Ps = [(260275824641779979588305, 726300335217221063663551), (263184922060743661751480, 611614193933496916037740), (582822220331206509336492, 481246655450613023120881), (372364178450359878096924, 693486907224438901452705), (227415654827717701646056, 348607835248429842358207)]

def get_good_prime(bit_length):
        while True:
                a = random.getrandbits(bit_length//2)
                b = random.getrandbits(bit_length//2)

                if b % 3 == 0:
                        continue

                p = a ** 2 + 3 * b ** 2
                if p.bit_length() == bit_length and p % 3 == 1 and isPrime(p):
                        return p

def addtion(P, Q, mod):
        m, n = P
        p, q = Q

        if p is None:
                return P
        if m is None:
                return Q

        if n is None and q is None:
                x = m * p % mod
                y = (m + p) % mod
                return (x, y)

        if n is None and q is not None:
                m, n, p, q = p, q, m, n

        if q is None:
                if (n + p) % mod != 0:
                        x = (m * p + 2) * inverse(n + p, mod) % mod
                        y = (m + n * p) * inverse(n + p, mod) % mod
                        return (x, y)
                elif (m - n ** 2) % mod != 0:
                        x = (m * p + 2) * inverse(m - n ** 2, mod) % mod
                        return (x, None)
                else:
                        return (None, None)
        else:
                if (m + p + n * q) % mod != 0:
                        x = (m * p + (n + q) * 2) * inverse(m + p + n * q, mod) % mod
                        y = (n * p + m * q + 2) * inverse(m + p + n * q, mod) % mod
                        return (x, y)
                elif (n * p + m * q + 2) % mod != 0:
                        x = (m * p + (n + q) * 2) * inverse(n * p + m * q + r, mod) % mod
                        return (x, None)
                else:
                        return (None, None)

def good_power(P, a, mod):
        res = (None, None)
        t = P
        while a > 0:
                if a & 1:
                        res = addtion(res, t, mod)
                t = addtion(t, t, mod)
                a >>= 1
        return res

p = get_good_prime(512)
q = get_good_prime(512)
n = p * q


phi =(p**2 + p + 1) * (q **2 + q + 1)

d = getPrime(250)
e = inverse(d, phi)
m = (password2,password3)
c = good_power(m, e, n)

print(f"c = {c}")
print(f"n = {n}")
print(f"e = {e}")
#c = (85422492752594163973525590153185181637578599526748527548916818661479717263661942043798519054634085790883203742143922909753155434484575316617409323425452920098106836753343255561397020191055166143284978002585043504528894342913998542611098251874319443218091798571063752406953498370967948413185742430124774364502, 76360473484928457783902531276059575220337561977824728338226901050505962483334908329971039234703811585714576796248193194224345311394246955572476959264834718452867915059519112273971322043676881006521735191342236986562040370170197311513561834788296920114495955011761008433746711656717672295490499621868087698727)
#n = 132719529494169666440015361510648436961564899266678472070578908438683877891624167098238871100680873610907493030493888543311583489467977492321159269370993104122316666862684984291699054526052448281045072084505401048771540969410719257800557252293084614152823911423359393963461618267528202871491263273689330662483
#e = 11129124355754297663162018546827275323752484161275828202691755264373860584802812666274619573801591775394317054892274391559877638968525372552912822620960106630890646377568381371715175233391190130896052686700941699773696737503798559366444705210907918989156659958714227911553806284829827584317491856812837076773878027948902531976851782851828778907966453369256525240545004196650478844079204128934633946462554325449608508882698599949761290061856624339283077816678434588316049724978427174141375678236660470842166757271021085154473717712706728832602385344078603418705101145889874790221291898011811923959932221790456898299847

先看第一部分:
是一个ECC,我们可以通过题目中的

t = ((3*c*P[0]*P[0]+a) * inverse(2*b*P[1],q1))%q1

t是曲线的斜率,就是原式求导后的结果,得到原式是

by2cx3+ax+dmodqb*y^{2} \equiv c*x^{3}+a*x+d \mod q

我们知道6组数据求四个未知量,那么我们可以使用groebner来求解其中的未知数
为了方便运算我们可以把原式看成

y2ax3+bx+cmodqy^{2} \equiv a*x^{3}+b*x+c \mod q

from Crypto.Util.number import *

G = (543964449142803087188784, 288605946000947449279542)

Ps = [(260275824641779979588305, 726300335217221063663551), (263184922060743661751480, 611614193933496916037740), (582822220331206509336492, 481246655450613023120881), (372364178450359878096924, 693486907224438901452705), (227415654827717701646056, 348607835248429842358207)]
R.<a,b,c>=ZZ[]
F = [a * G[0] ^ 3 + b * G[0] + c - G[1] ^ 2]
for _ in range(5):
    f = a * Ps[_][0] ^ 3 + b * Ps[_][0] + c -Ps[_][1] ^ 2
    F.append(f)

L = Ideal(F).groebner_basis()
print(L)
#[a + 226820338772807027243218, b + 773167489336543856487958, c + 758871032836012559341025, 813190268037982043592049]

#求解出a,b,c,q

得到完整的曲线后,进行映射成椭圆曲线y02=x03+a0x0+b0y_0^{2} = x_0^{3} +a_0*x_0 +b_0其中(x0=a3x)(x_0 = \sqrt[3]{a}x)
映射完之后,进行 discrete_log(Q, P, operation='+') 求解k即可
exp:

from Crypto.Util.number import *

G = (543964449142803087188784, 288605946000947449279542)

Ps = [(260275824641779979588305, 726300335217221063663551), (263184922060743661751480, 611614193933496916037740), (582822220331206509336492, 481246655450613023120881), (372364178450359878096924, 693486907224438901452705), (227415654827717701646056, 348607835248429842358207)]
print(long_to_bytes(G[0]))
#s0_3@5y_c0

R.<a,b,c>=ZZ[]
F = [a * G[0] ^ 3 + b * G[0] + c - G[1] ^ 2]
for _ in range(5):
    f = a * Ps[_][0] ^ 3 + b * Ps[_][0] + c -Ps[_][1] ^ 2
    F.append(f)

L = Ideal(F).groebner_basis()
print(L)

G = (543964449142803087188784, 288605946000947449279542)
q=813190268037982043592049
a = -226820338772807027243218 % q
b = -773167489336543856487958 % q
c = -758871032836012559341025 % q


P.<k> = PolynomialRing(GF(q))  
f = k^3 - a 
k = f.roots()
print(k)
k = 232592821046908396945406
gx = G[0] * k % q
gy = G[1]
tx = Ps[-1][0] * k % q
ty = Ps[-1][1]

A = b * inverse_mod(k,q) 
B = c
E=EllipticCurve(Zmod(q),[A,B])
G=E(gx,gy)
print(G.order())
T=E(tx,ty)
dlp = discrete_log(T,G,operation='+')
print(long_to_bytes(dlp))
#ylcTf_e_or'

第二部分参考 :糖醋小鸡块的博客

ed=1+k(p2+p+1)(q2+q+1)ed = 1 + k(p^2+p+1)(q^2+q+1)

化为

ed=1+k[n2n+1+(n+1)(p+q)+(p+q)2]ed = 1 + k[n^2 - n + 1 + (n+1)(p+q) + (p+q)^2]

令x=k,y=p+q

f=1+x[n2n+1+(n+1)y+y2](mod  e)f = 1 + x[n^2 - n + 1 + (n+1)y + y^2] \quad(mod\;e)

在进行二元copper求解x,y
exp:

from Crypto.Util.number import *
from gmpy2 import *
import itertools


def small_roots(f, bounds, m=1, d=None):
    if not d:
        d = f.degree()

    R = f.base_ring()
    N = R.cardinality()

    f /= f.coefficients().pop(0)
    f = f.change_ring(ZZ)

    G = Sequence([], f.parent())
    for i in range(m + 1):
        base = N ^ (m - i) * f ^ i
        for shifts in itertools.product(range(d), repeat=f.nvariables()):
            g = base * prod(map(power, f.variables(), shifts))
            G.append(g)

    B, monomials = G.coefficient_matrix()
    monomials = vector(monomials)

    factors = [monomial(*bounds) for monomial in monomials]
    for i, factor in enumerate(factors):
        B.rescale_col(i, factor)

    B = B.dense_matrix().LLL()

    B = B.change_ring(QQ)
    for i, factor in enumerate(factors):
        B.rescale_col(i, 1 / factor)

    H = Sequence([], f.parent().change_ring(QQ))
    for h in filter(None, B * monomials):
        H.append(h)
        I = H.ideal()
        if I.dimension() == -1:
            H.pop()
        elif I.dimension() == 0:
            roots = []
            for root in I.variety(ring=ZZ):
                root = tuple(R(root[var]) for var in f.variables())
                roots.append(root)
            return roots

    return []


n = 132719529494169666440015361510648436961564899266678472070578908438683877891624167098238871100680873610907493030493888543311583489467977492321159269370993104122316666862684984291699054526052448281045072084505401048771540969410719257800557252293084614152823911423359393963461618267528202871491263273689330662483
e = 11129124355754297663162018546827275323752484161275828202691755264373860584802812666274619573801591775394317054892274391559877638968525372552912822620960106630890646377568381371715175233391190130896052686700941699773696737503798559366444705210907918989156659958714227911553806284829827584317491856812837076773878027948902531976851782851828778907966453369256525240545004196650478844079204128934633946462554325449608508882698599949761290061856624339283077816678434588316049724978427174141375678236660470842166757271021085154473717712706728832602385344078603418705101145889874790221291898011811923959932221790456898299847

PR.<x,y>= PolynomialRing(Zmod(e))
f = 1 + x * (n ^ 2 - n + 1 + (n + 1) * y + y ^ 2)
res = small_roots(f, (2 ^ 256, 2 ^ 512), m=2, d=3)

pplusq = int(res[0][1])
pminusq = iroot(pplusq ^ 2 - 4 * n, 2)[0]
p = (pplusq + pminusq) // 2
q = n // p
print(p)
print(q)
#p =11535800156719048931347276045879377428643243582810776040089157673637898260385736466169737110946935313493516144396403906845807153884435472856105926366322231
#q = 11505012889536485414879400690227492114674311121404688222379266667261973620824161923078590149522686297199691051054957568059021196948596303095778287403345093
from Crypto.Util.number import *
from gmpy2 import *
import itertools


def addtion(P, Q, mod):
        m, n = P
        p, q = Q

        if p is None:
                return P
        if m is None:
                return Q

        if n is None and q is None:
                x = m * p % mod
                y = (m + p) % mod
                return (x, y)

        if n is None and q is not None:
                m, n, p, q = p, q, m, n

        if q is None:
                if (n + p) % mod != 0:
                        x = (m * p + 2) * inverse(n + p, mod) % mod
                        y = (m + n * p) * inverse(n + p, mod) % mod
                        return (x, y)
                elif (m - n ** 2) % mod != 0:
                        x = (m * p + 2) * inverse(m - n ** 2, mod) % mod
                        return (x, None)
                else:
                        return (None, None)
        else:
                if (m + p + n * q) % mod != 0:
                        x = (m * p + (n + q) * 2) * inverse(m + p + n * q, mod) % mod
                        y = (n * p + m * q + 2) * inverse(m + p + n * q, mod) % mod
                        return (x, y)
                elif (n * p + m * q + 2) % mod != 0:
                        x = (m * p + (n + q) * 2) * inverse(n * p + m * q + r, mod) % mod
                        return (x, None)
                else:
                        return (None, None)
def good_power(P, a, mod):
        res = (None, None)
        t = P
        while a > 0:
                if a & 1:
                        res = addtion(res, t, mod)
                t = addtion(t, t, mod)
                a >>= 1
        return res
c = (85422492752594163973525590153185181637578599526748527548916818661479717263661942043798519054634085790883203742143922909753155434484575316617409323425452920098106836753343255561397020191055166143284978002585043504528894342913998542611098251874319443218091798571063752406953498370967948413185742430124774364502, 76360473484928457783902531276059575220337561977824728338226901050505962483334908329971039234703811585714576796248193194224345311394246955572476959264834718452867915059519112273971322043676881006521735191342236986562040370170197311513561834788296920114495955011761008433746711656717672295490499621868087698727)
p =11535800156719048931347276045879377428643243582810776040089157673637898260385736466169737110946935313493516144396403906845807153884435472856105926366322231
q = 11505012889536485414879400690227492114674311121404688222379266667261973620824161923078590149522686297199691051054957568059021196948596303095778287403345093
e = 11129124355754297663162018546827275323752484161275828202691755264373860584802812666274619573801591775394317054892274391559877638968525372552912822620960106630890646377568381371715175233391190130896052686700941699773696737503798559366444705210907918989156659958714227911553806284829827584317491856812837076773878027948902531976851782851828778907966453369256525240545004196650478844079204128934633946462554325449608508882698599949761290061856624339283077816678434588316049724978427174141375678236660470842166757271021085154473717712706728832602385344078603418705101145889874790221291898011811923959932221790456898299847
N = p*q
phi = (p**2 + p + 1)*(q**2 + q + 1)
d = invert(e,phi)
m = good_power(c,d,N)

m = (409403877231, 10673380708147344593726104065762264760478541144788135806)
print(long_to_bytes((m[0])))
print(long_to_bytes(m[1]))
# b'_R_go'
# b'oooood_game_114514giao~'

butterfly_love

题目:

from Crypto.Util.number import getPrime, bytes_to_long
from gmpy2 import *
import os
import sys
from hashlib import sha256,sha512
flag =os.getenv("GZCTF_FLAG").encode()
class LIANGZHU:
    def __init__(self):
        p, q = getPrime(512), getPrime(512)
        self.e = 65537
        self.d = invert(self.e,(p-1)*(q-1))
        self.n = p * q
    def listen(self, m): return pow(m, self.e, self.n)
    def say(self, c): return pow(c, self.d, self.n)

def my_print(message):
    sys.stdout.write(f'{message}\n')
    sys.stdout.flush()
    sys.stderr.flush()

def read_str():
    return sys.stdin.readline().strip()

def proof_of_work():
    s = hex(bytes_to_long(os.urandom(10)))[2:]
    digest = sha256(s.encode()).hexdigest()
    print(f"sha256(XXXXXX + {s[6:]})=={digest}")
    my_print("Give me XXXXXX: ")
    #print(s,s[:6])
    x = read_str()
    if len(x) != 6 or x != s[:6]:
        print("Wrong!")
        return False
    return True

def PoW():
    if not proof_of_work():
        exit(-1)

PoW()
Liangshanbo, Zhuyingtai = LIANGZHU(), LIANGZHU()
temp = os.urandom(32)
print('the flag and some noise:', Liangshanbo.listen(bytes_to_long(temp[:16] + flag + temp[16:])))

for _ in temp:
    print('Zhuyingtai listen:', Zhuyingtai.listen(Liangshanbo.say(int(input('Liangshanbo say: '))))) 
    print('Liangshanbo listen:', Liangshanbo.listen(Zhuyingtai.say(int(input('Zhuyingtai say: ')))))


首先想办法求 n1,n2,先输入c= -1给oracle 1,得到

x(n11)emodn2x \equiv(n1 - 1)^{e} \mod n2

x填入 oracle 2,oracle2会将

((n11)modn2)modn1((n1-1) \mod n2)\mod n1

输出,假设 n1< n2 ,最后的值就是 n1- 1,从而求出 n1
已知n1的情况下,可以送temodn1t^{e} \mod n1到 oracle 1,只要t< n1 则输出值为

xtemodn2x \equiv t^{e} \mod n2

因此n2(xte)n2|(x - t^{e}),所以用多组t 操作后再 gcd 就能求出 n2,将

c1memodn1c1\equiv m^{e} \mod n1

带入到oracle1中,得到

cmemodn2c \equiv m^{e}\mod n2

此时将-c代入oracle 2 得到

c2(n2m)emod(n1)c2 \equiv (n2-m)^e \mod (n1)

再通过明文线性相关攻击和HGCD解密
exp:

from pwn import *
from Crypto.Util.number import long_to_bytes

#with process(['python', 'main.py']) as sh:

def proof_of_work():
    rev = r.recvuntil("sha256(XXXXXX+")
    suffix = r.recv(14).decode()
    rev = r.recvuntil(b" == ")
    tar = r.recv(64).decode()

    def f(x):
        hashresult = hashlib.sha256(x.encode()+suffix.encode()).hexdigest()
        return hashresult == tar
    prefix = util.iters.mbruteforce(f, string.digits + string.ascii_letters, 6, 'upto')
    r.recvuntil('XXXXXX: ')
    r.sendline(prefix.encode())


with remote('challenge.yuanloo.com', 42376) as sh:
    proof_of_work()
    sh.readuntil(b'noise: ')
    flag1 = int(sh.readline())
    def get(n):
        sh.sendline(str(n).encode())
        sh.readuntil(b'hears: ')
        return int(sh.readline())

    a = get(-1)
    m = get(a) + 1
    assert get(m) == 0, "Fails about 50% of the time, try again"
    n = get(get(-a)) + a
    assert get(n) == 0, "Fails about 4% of the time (if the above succeeds), try again"
    flag2 = get(-get(flag1))

def GCD(a, b):

    def HGCD(a, b):
        if 2 * b.degree() <= a.degree() or a.degree() == 1:
            return 1, 0, 0, 1
        m = a.degree() // 2
        a_top, a_bot = a.quo_rem(x**m)
        b_top, b_bot = b.quo_rem(x**m)
        R00, R01, R10, R11 = HGCD(a_top, b_top)
        c = R00 * a + R01 * b
        d = R10 * a + R11 * b
        q, e = c.quo_rem(d)
        d_top, d_bot = d.quo_rem(x**(m // 2))
        e_top, e_bot = e.quo_rem(x**(m // 2))
        S00, S01, S10, S11 = HGCD(d_top, e_top)
        RET00 = S01 * R00 + (S00 - q * S01) * R10
        RET01 = S01 * R01 + (S00 - q * S01) * R11
        RET10 = S11 * R00 + (S10 - q * S11) * R10
        RET11 = S11 * R01 + (S10 - q * S11) * R11
        return RET00, RET01, RET10, RET11

    q, r = a.quo_rem(b)
    if r == 0:
        return b
    R00, R01, R10, R11 = HGCD(a, b)
    c = R00 * a + R01 * b
    d = R10 * a + R11 * b
    if d == 0:
        return c.monic()
    q, r = c.quo_rem(d)
    if r == 0:
        return d
    return GCD(d, r)

print('Calculating...')

x = Zmod(m)['x'].gen()
f, g = x**65537-flag1, (n-x)**65537-flag2
print(long_to_bytes(int(x-GCD(f,g).monic())))

⭕️

题目:

from sage.all import ZZ, randint
from Crypto.Util.number import *
p = None

def generate_distortion_map(E):
    if E.a_invariants() != (0,6,0,1,0):
        raise NotImplementedError
    return E.isogeny(E.lift_x(ZZ(1)), codomain=E)

def generate_torsion_points(E, a, b):
    def get_l_torsion_basis(E, l):
        n = (p+1) // l
        return (n*G for G in E.gens())

    P2, Q2 = get_l_torsion_basis(E, 2**a)
    P3, Q3 = get_l_torsion_basis(E, 3**b)

    return P2, Q2, P3, Q3

from flag import flag
flag = bytes_to_long(flag)
def generate_key(E_start, b, P2, Q2, P3, Q3):
    bobs_key = flag
    K = P3 + bobs_key*Q3
    phi = E_start.isogeny(K, algorithm="factored")
    EB = phi.codomain()
    EB.set_order((p+1)**2, num_checks=0)
    PB, QB = phi(P2), phi(Q2)
    return bobs_key, EB, PB, QB


a = 305
b = 192
p = 2^a*3^b - 1
Fp2.<i> = GF(p^2, modulus=x^2+1)
R.<x> = PolynomialRing(Fp2)

E_start = EllipticCurve(Fp2, [0,6,0,1,0])
E_start.set_order((p+1)^2)

two_i = generate_distortion_map(E_start)

P2, Q2, P3, Q3 = generate_torsion_points(E_start, a, b)

flag_key, EB, PB, QB = generate_key(E_start, b, P2, Q2, P3, Q3)

print(EB)
print(PB)
print(QB)

"""
Elliptic Curve defined by y^2 = x^3 + 6*x^2 + (1109655386602666580941477264844188509870568726343453010771770543665511250648180561681677488303290640863245633469198578301207900328491716466654470349910400724631139969542193124833051079*i+2116239248619087101677214169270633679594454755906693836568034229947351325062332338053907457802709748610111020509037164276717020111001082512633925347579357851693517057782645336434230575)*x + (783233241190388171387544682511032475647421068250023300290363249038620119995420899574317207343308349718411589404085433006020673690798356551667106568546291827001684869794402242067695854*i+1972744566958070881282131795626840370625118459932253321456562523309337576438614381897961997884583203821363249684189786452976563714388989414218292121069137192174721660268448964759287049) over Finite Field in i of size 2638940411073262671963620699288286770183560231187222316750407556465639836010558150163225530335162533481049256757217964651333810422125728537407397155806079217346919294449255613110157311^2
(1792805099210360888864761590321391235025824991548234912676247217808406536821234881384389175924130468280991088357660252370848305634037983159579204419296531735459329230669983096853856246*i + 171253309786548245036128932419221024429140017061733162803654587078736014845338272553757000723916403099300493601067652633948439740076865619503812837361164299530464912490228468097800783 : 354858932953470647164407208876248915819655125217303333206005726572045601374950018701435041440177841288062762055220650414072032960690957944114792835539535784706989279413982852603736575*i + 652241231208054817913369235175691302162155547428861981772486556413182925887029191547328926720048813218596706336154397071250972427384520853013935344373831652140490902941929446372831718 : 1)
(2186267301001259402114997355550578512125192708867710349339620240110565042023451739162302255305174185314466942521888744412961910909391429250064295777978302914701578195376147036042606489*i + 1113400569081370973415138408967328130898700595223023714237127216136706721906751381588571638690905466982759185164650150666678077272021890081392532363649111691002821924551541633624805969 : 475011489753746240024500178367364859418901588829939924748705578009262827369222834659815495729670558797454143390912073311509838111085236909370323483802926909195458815683174215323355088*i + 925039345882842856209794407096335244092780460386698951051338086161413597699668891541282650447520394073160493795142052782764553543711321165686302397695781016000953589530090195707014184 : 1)
"""

后量子密码,具体原理还不是很清楚,先记个脚本吧
exp:

import time
from itertools import product
from helpers import possibly_parallel, supersingular_gens, fast_log3
from richelot_aux import AuxiliaryIsogeny, Does22ChainSplit, Pushing3Chain
from uvtable import uvtable
from Crypto.Util.number import *

def _do_speedup():

    proof.all(False)

    from sage.misc.banner import require_version
    if not require_version(9,7):

        p = 2^127 - 1
        to_patch = [GF(3), GF(3^2), GF(p), GF(p^2)]
        for x in to_patch:
            type(x).vector_space = sage.misc.cachefunc.cached_method(type(x).vector_space)

        from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective
        AlgebraicScheme_subscheme_projective.dimension = lambda self: 1


_do_speedup()


def CastryckDecruAttack(E_start, P2, Q2, EB, PB, QB, two_i, num_cores=1):
    tim = time.time()
    skB = []
    expdata = [[0, 0, 0] for _ in range(b-3)]
    for i in range(b%2, b-3, 2):
        index = (b-i) // 2
        row = uvtable[index-1]
        if row[1] <= a:
            expdata[i] = row[1:4]
    bet1 = 0
    while not expdata[bet1][0]:
        bet1 += 1
    bet1 += 1

    ai,u,v = expdata[bet1-1]
    bi = b - bet1
    alp = a - ai
    @possibly_parallel(num_cores)
    def CheckGuess(first_digits):
        scalar = sum(3^k*d for k,d in enumerate(first_digits))
        tauhatkernel = 3^bi * (P3 + scalar*Q3)
        tauhatkernel_distort = u*tauhatkernel + v*two_i(tauhatkernel)
        C, P_c, Q_c, chainC = AuxiliaryIsogeny(bet1, u, v, E_start, P2, Q2, tauhatkernel, two_i)
        split = Does22ChainSplit(C, EB, 2^alp*P_c, 2^alp*Q_c, 2^alp*PB, 2^alp*QB, ai)
        if split:
            Eguess, _ = Pushing3Chain(E_start, tauhatkernel, bet1)
            chain, (E1, E2) = split
            P3c = chainC(P3)
            Q3c = chainC(Q3)
            if E2.j_invariant() == Eguess.j_invariant():
                CB, index = E1, 0
            else:
                CB, index = E2, 1
            def apply_chain(c, X):
                X = (X, None)
                for f in c:
                    X = f(X)
                return X[index]
            P3c_CB = apply_chain(chain, P3c)
            Q3c_CB = apply_chain(chain, Q3c)
            Z3 = Zmod(3^b)
            CB.set_order((p+1)^2, num_checks=1)
            P_CB, Q_CB = supersingular_gens(CB)
            P3_CB = ((p+1) / 3^b) * P_CB
            Q3_CB = ((p+1) / 3^b) * Q_CB
            w = P3_CB.weil_pairing(Q3_CB, 3^b)
            for G in (P3_CB, Q3_CB):
                xP = fast_log3(P3c_CB.weil_pairing(G, 3^b), w)
                xQ = fast_log3(Q3c_CB.weil_pairing(G, 3^b), w)
                if xQ % 3 != 0:
                    sk = int(-Z3(xP) / Z3(xQ))
                    return sk

            return True

    guesses = [ZZ(i).digits(3, padto=bet1) for i in range(3^bet1)]

    for result in CheckGuess(guesses):
        ((first_digits,), _), sk = result
        if sk is not None:
            bobskey = sk
            break

    bobscurve, _ = Pushing3Chain(E_start, P3 + bobskey*Q3, b)
    flag = bobscurve.j_invariant() == EB.j_invariant()
    if flag:
        print(long_to_bytes(bobskey))

def generate_distortion_map(E):
    if E.a_invariants() != (0,6,0,1,0):
        raise NotImplementedError
    return E.isogeny(E.lift_x(ZZ(1)), codomain=E)

def generate_torsion_points(E, a, b):
    def get_l_torsion_basis(E, l):
        n = (p+1) // l
        return (n*G for G in E.gens())

    P2, Q2 = get_l_torsion_basis(E, 2**a)
    P3, Q3 = get_l_torsion_basis(E, 3**b)

    return P2, Q2, P3, Q3

a = 305
b = 192
p = 2^a*3^b - 1
Fp2.<i> = GF(p^2, modulus=x^2+1)
R.<x> = PolynomialRing(Fp2)

E_start = EllipticCurve(Fp2, [0,6,0,1,0])
E_start.set_order((p+1)^2)

two_i = generate_distortion_map(E_start)

P2, Q2, P3, Q3 = generate_torsion_points(E_start, a, b)



# 定义系数 A, B, C,这里需要将你提供的大整数转换为有限域 Fp2 中的元素
A = Fp2(1109655386602666580941477264844188509870568726343453010771770543665511250648180561681677488303290640863245633469198578301207900328491716466654470349910400724631139969542193124833051079*i+2116239248619087101677214169270633679594454755906693836568034229947351325062332338053907457802709748610111020509037164276717020111001082512633925347579357851693517057782645336434230575)

C = Fp2(783233241190388171387544682511032475647421068250023300290363249038620119995420899574317207343308349718411589404085433006020673690798356551667106568546291827001684869794402242067695854*i+1972744566958070881282131795626840370625118459932253321456562523309337576438614381897961997884583203821363249684189786452976563714388989414218292121069137192174721660268448964759287049)

# 定义椭圆曲线 E_B
EB = EllipticCurve(Fp2, [0, 6, 0, A, C])
EB.set_order((p + 1)^2, num_checks=0)

PB_x = Fp2(1792805099210360888864761590321391235025824991548234912676247217808406536821234881384389175924130468280991088357660252370848305634037983159579204419296531735459329230669983096853856246*i + 171253309786548245036128932419221024429140017061733162803654587078736014845338272553757000723916403099300493601067652633948439740076865619503812837361164299530464912490228468097800783)
PB_y = Fp2(354858932953470647164407208876248915819655125217303333206005726572045601374950018701435041440177841288062762055220650414072032960690957944114792835539535784706989279413982852603736575*i + 652241231208054817913369235175691302162155547428861981772486556413182925887029191547328926720048813218596706336154397071250972427384520853013935344373831652140490902941929446372831718)
PB_z = Fp2(1)

QB_x = Fp2(2186267301001259402114997355550578512125192708867710349339620240110565042023451739162302255305174185314466942521888744412961910909391429250064295777978302914701578195376147036042606489*i + 1113400569081370973415138408967328130898700595223023714237127216136706721906751381588571638690905466982759185164650150666678077272021890081392532363649111691002821924551541633624805969)
QB_y = Fp2(475011489753746240024500178367364859418901588829939924748705578009262827369222834659815495729670558797454143390912073311509838111085236909370323483802926909195458815683174215323355088*i + 925039345882842856209794407096335244092780460386698951051338086161413597699668891541282650447520394073160493795142052782764553543711321165686302397695781016000953589530090195707014184)
QB_z = Fp2(1)


PB = EB(PB_x, PB_y, PB_z)
QB = EB(QB_x, QB_y, QB_z)

CastryckDecruAttack(E_start, P2, Q2, EB, PB, QB, two_i, num_cores=24)