Try   HackMD

OK - zer0pts CTF 2022

tags: zer0pts CTF 2022

Writeups: https://hackmd.io/@ptr-yudai/rJgjygUM9

overview

The program implements Oblivisous Transfer by RSA. We can get either

K or
C
. Our purpose is to get
KC
.

solution

step1

By sending

v such that
vx1(vx2)modn
, the
k1k2modn
stands.

Because

k1(vx1)dmodn and
k2(vx2)d((vx1))d(vx1)dmodn
. (
d
is odd value)

Thus,

c1+c2K+Cmodn where
c1k1+Kmodn
,
c2k2+Cmodn
stands.

Additionaly, the LSB of

c1+c2 is always fixed because
KC
is consistent. Hence we can assume the parity of
c1+c2
and find
K+C
without modulo under the assumption. If the parity of
K+Cmodn
is different from our assumption, we can get
K+C
by adding
n
to
|K+Cmodn|
. Otherwise
|K+Cmodn|=K+C
. Because
n
is odd value.

Now we have

K+Cmodn. Can we determine
KC
uniquely?

Appearently no. But for now, we know

K and
C
are different in every connection while
KC
is consistent. So considering about collecting some cases of
(K,C)
pair.

For now, the problem is turned into to find

X=KiCi from some
Yi=Ki+Ci
.

step2

Therefore, if the following problem is solved, secret has been recovered.

Statement:
Generate an integer sequence

Bi=Ai+(mAi) from a random integer
m
of
N
bits and an integer sequence
A
of random
N
bits. Recover
m
from the integer sequence
B
.
Constraints:

  • N=1024
  • |A|=20

First, let us make an observation about the generated number

Ai+(mAi). From the facts about addition, the following formula transformation holds.

Ai+(mAi)=(AimAi)+2(Ai&(mAi))(1)=m+2(Ai&(mAi))

Here, the XOR in the

Ai&(mAi) part can be taken as inverting the bit extracted by &. So it should be the same if all the bits are inverted first and then extracted. Let us denote the bit inversion of
x
as
x
, then the following holds.

(1)=m+2(Ai&m)=m+m+(Ai&m)+((Ai&m)m)=0+(Ai&m)+((Ai&m)((Ai&m)+(Ai&m)))(2)=0+(Ai&m)(Ai&m)

The equation transformation regarding bit inversion is a bit cumbersome, but it is no problem to think of it as the one's complement in a sufficiently large finite number of bits. In this case, since

N=1024 bits, we can write the following using
C=2N+11
.

(2)=C+(Ai&(Cm))(Ai&(Cm))

This equation can be interpreted as a script like the following.

C = 2 ** (N + 1) - 1
B_i = C
for i in range(N):
  if not (C-m & (1 << i)): continue
  res += (1 << i) * choice([-1, 1])

Now consider the probability that the most significant bit of

|BiC| is equal to the most significant bit of
Cm
. It turns out that this is 1 if
Cm
and the most significant bit are equal, and 1/2 if they are not ((symmetry makes it clear)). Since the most significant bit is always smaller when they are not equal, we can find the most significant bit of
Cm
from the sequence
B
with probability more than
12|B|
by taking the largest most significant bit. Next, subtract the most significant bit from
|BiC|
and take its absolute value. Then we have the same problem for the second bit from the top.

Thus, we found that by repeating this process, we can find

m with probability greater than
(12|B|)N
. The script will be as follows.

def solve(bs):
    BIT = 1024
    C = 2 ** (BIT + 1) - 1
    bs = [abs(b - C) for b in bs]

    res = C
    while not all([b == 0 for b in bs]):
        msb = 1 << (max(bs).bit_length() - 1)
        res -= msb
        bs = [abs(b - msb) for b in bs]
    if any([b != 0 for b in bs]): return None
    return res