Full solution of EZDSA challenge from MidnightSun CTF Quals 2019.
tl;dr retrieving key using Euler’s Criterion to break signature authentication
Solved by: s0rc3r3r & v3ct0r
In this challenge, we are given a script that signs any message given as an input:
1 | class PrivateSigningKey: |
We will use the notation below to represent the following variables:
1 | `m`: integer representation of message input given to the server for signing |
The signature is similar to ElGamal signature, but works as follows:
$ k = g^{u;*;m};%;q $
$ r = (g^{k};%;p);%;q $
$ s = ((k^{q-2};%;q)*(h+(key*r)));%;q $
Server returns (r, s) pair for any m given as input (with one exception that we will see later in the post)
Our motive is to recover the value of key, since it is the integer representation of the flag!
Setting a tentative target
If by giving some input, k becomes equal to 1, then recovering key becomes very easy:
$ s = ((k^{(q-2)};%;q)*(h+(key*r)));%;q $
$ s = ((1^{(q-2)};%;q)*(h+(key*r)));%;q $
$ s = (h+(key*r));%;q$
$ (s-h)*r^{-1}\equiv key \mod q $
We know the values of h, r and s, hence key can be calculated using the above formula,
on one condition that k becomes equal to 1
The question now is: how do we make the value of k equal to 1?
Finding input such that k=1
We now need to find an input message m such that
$ k = g^{u;*;m};%;q = 1 $
Trivial Approach
The easiest approach is to send q-1 as m. This is because
$ k = g^{u;*;m};%;q $
$ k = g^{u;*;(q-1)};%;q $
$ k = (g^{(q-1)};%;q)^{u};%;q $
$ k = 1^u;%;q $
$ k = 1 $
The above set of equations is a direct consequence of Fermat’s Little Theorem:
if GCD(a, p) == 1 then:
$ a^{(p-1)}\equiv 1 \mod p $
But there is a problem. If we look at an assert statement in the function that signs our message:
1 | assert(bytes_to_long(m) % (self.q - 1) != 0) |
The above statement means that our message cannot be a multiple of q-1, hence we cannot send q-1 as m.
Applying Euler’s Criterion
Case-1: u is an even number
In such a case, we can send m = (q-1)/2 and get the following:
$ k = g^{u;*;m};%;q $
$ k = g^{u’;*;2;*;m};%;q $
$ k = g^{u’;*;2;*;((q-1)/2)};%;q $
$ k = (g^{(q-1)};%;q)^{u’};%;q $
$ k = 1;%;q = 1 $
Case-2: u is an odd number, we send m = (q-1)/2 and get the following:
$ k = g^{u;*;m};%;q $
$ k = g^{u;*;((q-1)/2)};%;q $
$ k = (g^{((q-1)/2)};%;q)^{u};%;q $
From Euler’s Criterion, we have:
If GCD(a, p) == 1
$ a^{(p-1)/2}\equiv \begin{cases}
1;(mod;p),\exists x\mid x^2\equiv a\mod p\newline
-1;(mod;p), otherwise
\end{cases} $
There are equal number of quadratic residues and quadratic non-residues in a group over a prime number. A proof of this is illustrated in Wikipedia:
Source: Euler’s Criterion proof - Wikipedia
This basically means that no matter what, if m = (q-1)/2, value of k will be either 1 or -1. So, we sent m = (q-1)/2 to the server, and got r = g % q. This straightaway implies that k turned out to be equal to 1.
key can then be simply calculated as:
$ (s-h)*r^{-1}\equiv key \mod p $
1 | from Crypto.Util.number import * |
th4t_w4s_e4sy_eh?