Merge pull request #6866 from leoetlino/ec-cleanup

ec: General cleanup
This commit is contained in:
Léo Lam 2018-05-20 20:04:19 +02:00 committed by GitHub
commit a974c69058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 324 additions and 383 deletions

View File

@ -3,61 +3,43 @@
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include <cstdio> #include <cstdio>
#include <string.h> #include <cstring>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Crypto/bn.h" #include "Common/Crypto/bn.h"
static void bn_zero(u8* d, u32 n) static void bn_zero(u8* d, int n)
{ {
memset(d, 0, n); std::memset(d, 0, n);
} }
static void bn_copy(u8* d, const u8* a, u32 n) static void bn_copy(u8* d, const u8* a, int n)
{ {
memcpy(d, a, n); std::memcpy(d, a, n);
} }
int bn_compare(const u8* a, const u8* b, u32 n) int bn_compare(const u8* a, const u8* b, int n)
{ {
u32 i; return std::memcmp(a, b, n);
}
for (i = 0; i < n; i++) void bn_sub_modulus(u8* a, const u8* N, int n)
{
u8 c = 0;
for (int i = n - 1; i >= 0; --i)
{ {
if (a[i] < b[i]) u32 dig = N[i] + c;
return -1;
if (a[i] > b[i])
return 1;
}
return 0;
}
void bn_sub_modulus(u8* a, const u8* N, u32 n)
{
u32 i;
u32 dig;
u8 c;
c = 0;
for (i = n - 1; i < n; i--)
{
dig = N[i] + c;
c = (a[i] < dig); c = (a[i] < dig);
a[i] -= dig; a[i] -= dig;
} }
} }
void bn_add(u8* d, const u8* a, const u8* b, const u8* N, u32 n) void bn_add(u8* d, const u8* a, const u8* b, const u8* N, int n)
{ {
u32 i; u8 c = 0;
u32 dig; for (int i = n - 1; i >= 0; --i)
u8 c;
c = 0;
for (i = n - 1; i < n; i--)
{ {
dig = a[i] + b[i] + c; u32 dig = a[i] + b[i] + c;
c = (dig >= 0x100); c = (dig >= 0x100);
d[i] = dig; d[i] = dig;
} }
@ -69,32 +51,30 @@ void bn_add(u8* d, const u8* a, const u8* b, const u8* N, u32 n)
bn_sub_modulus(d, N, n); bn_sub_modulus(d, N, n);
} }
void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, u32 n) void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, int n)
{ {
u32 i;
u8 mask;
bn_zero(d, n); bn_zero(d, n);
for (i = 0; i < n; i++) for (int i = 0; i < n; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
for (u8 mask = 0x80; mask != 0; mask >>= 1)
{ {
bn_add(d, d, d, N, n); bn_add(d, d, d, N, n);
if ((a[i] & mask) != 0) if ((a[i] & mask) != 0)
bn_add(d, d, b, N, n); bn_add(d, d, b, N, n);
} }
}
} }
void bn_exp(u8* d, const u8* a, const u8* N, u32 n, const u8* e, u32 en) void bn_exp(u8* d, const u8* a, const u8* N, int n, const u8* e, int en)
{ {
u8 t[512]; u8 t[512];
u32 i;
u8 mask;
bn_zero(d, n); bn_zero(d, n);
d[n - 1] = 1; d[n - 1] = 1;
for (i = 0; i < en; i++) for (int i = 0; i < en; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
for (u8 mask = 0x80; mask != 0; mask >>= 1)
{ {
bn_mul(t, d, d, N, n); bn_mul(t, d, d, N, n);
if ((e[i] & mask) != 0) if ((e[i] & mask) != 0)
@ -102,10 +82,11 @@ void bn_exp(u8* d, const u8* a, const u8* N, u32 n, const u8* e, u32 en)
else else
bn_copy(d, t, n); bn_copy(d, t, n);
} }
}
} }
// only for prime N -- stupid but lazy, see if I care // only for prime N -- stupid but lazy, see if I care
void bn_inv(u8* d, const u8* a, const u8* N, u32 n) void bn_inv(u8* d, const u8* a, const u8* N, int n)
{ {
u8 t[512], s[512]; u8 t[512], s[512];

View File

@ -8,9 +8,9 @@
// bignum arithmetic // bignum arithmetic
int bn_compare(const u8* a, const u8* b, u32 n); int bn_compare(const u8* a, const u8* b, int n);
void bn_sub_modulus(u8* a, const u8* N, u32 n); void bn_sub_modulus(u8* a, const u8* N, int n);
void bn_add(u8* d, const u8* a, const u8* b, const u8* N, u32 n); void bn_add(u8* d, const u8* a, const u8* b, const u8* N, int n);
void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, u32 n); void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, int n);
void bn_inv(u8* d, const u8* a, const u8* N, u32 n); // only for prime N void bn_inv(u8* d, const u8* a, const u8* N, int n); // only for prime N
void bn_exp(u8* d, const u8* a, const u8* N, u32 n, const u8* e, u32 en); void bn_exp(u8* d, const u8* a, const u8* N, int n, const u8* e, int en);

View File

@ -6,6 +6,7 @@
// Licensed under the terms of the GNU GPL, version 2 // Licensed under the terms of the GNU GPL, version 2
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include <algorithm>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
@ -20,6 +21,158 @@
#pragma warning(disable : 4505) #pragma warning(disable : 4505)
#endif #endif
namespace Common::ec
{
static const u8 square[16] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55};
struct Elt;
static Elt operator*(const Elt& a, const Elt& b);
struct Elt
{
bool IsZero() const
{
return std::all_of(data.begin(), data.end(), [](u8 b) { return b == 0; });
}
void MulX()
{
u8 carry = data[0] & 1;
u8 x = 0;
for (std::size_t i = 0; i < data.size() - 1; i++)
{
u8 y = data[i + 1];
data[i] = x ^ (y >> 7);
x = y << 1;
}
data[29] = x ^ carry;
data[20] ^= carry << 2;
}
Elt Square() const
{
std::array<u8, 60> wide;
for (std::size_t i = 0; i < data.size(); i++)
{
wide[2 * i] = square[data[i] >> 4];
wide[2 * i + 1] = square[data[i] & 15];
}
for (std::size_t i = 0; i < data.size(); i++)
{
u8 x = wide[i];
wide[i + 19] ^= x >> 7;
wide[i + 20] ^= x << 1;
wide[i + 29] ^= x >> 1;
wide[i + 30] ^= x << 7;
}
u8 x = wide[30] & ~1;
wide[49] ^= x >> 7;
wide[50] ^= x << 1;
wide[59] ^= x >> 1;
wide[30] &= 1;
Elt result;
std::copy(wide.cbegin() + 30, wide.cend(), result.data.begin());
return result;
}
Elt ItohTsujii(const Elt& b, std::size_t j) const
{
Elt t = *this;
while (j--)
t = t.Square();
return t * b;
}
Elt Inv() const
{
Elt t = ItohTsujii(*this, 1);
Elt s = t.ItohTsujii(*this, 1);
t = s.ItohTsujii(s, 3);
s = t.ItohTsujii(*this, 1);
t = s.ItohTsujii(s, 7);
s = t.ItohTsujii(t, 14);
t = s.ItohTsujii(*this, 1);
s = t.ItohTsujii(t, 29);
t = s.ItohTsujii(s, 58);
s = t.ItohTsujii(t, 116);
return s.Square();
}
std::array<u8, 30> data{};
};
static Elt operator+(const Elt& a, const Elt& b)
{
Elt d;
for (std::size_t i = 0; i < std::tuple_size<decltype(Elt::data)>{}; i++)
d.data[i] = a.data[i] ^ b.data[i];
return d;
}
static Elt operator*(const Elt& a, const Elt& b)
{
Elt d;
std::size_t i = 0;
u8 mask = 1;
for (std::size_t n = 0; n < 233; n++)
{
d.MulX();
if ((a.data[i] & mask) != 0)
d = d + b;
mask >>= 1;
if (mask == 0)
{
mask = 0x80;
i++;
}
}
return d;
}
static Elt operator/(const Elt& dividend, const Elt& divisor)
{
return dividend * divisor.Inv();
}
struct Point
{
Point() = default;
constexpr explicit Point(Elt x, Elt y) : m_data{{std::move(x), std::move(y)}} {}
explicit Point(const u8* data) { std::copy_n(data, sizeof(m_data), Data()); }
bool IsZero() const { return X().IsZero() && Y().IsZero(); }
Elt& X() { return m_data[0]; }
Elt& Y() { return m_data[1]; }
u8* Data() { return m_data[0].data.data(); }
const Elt& X() const { return m_data[0]; }
const Elt& Y() const { return m_data[1]; }
const u8* Data() const { return m_data[0].data.data(); }
Point Double() const
{
Point r;
if (X().IsZero())
return r;
const auto s = Y() / X() + X();
r.X() = s.Square() + s;
r.X().data[29] ^= 1;
r.Y() = s * r.X() + r.X() + X().Square();
return r;
}
private:
std::array<Elt, 2> m_data{};
static_assert(sizeof(decltype(m_data)) == 60, "Wrong size for m_data");
};
// y**2 + x*y = x**3 + x + b // y**2 + x*y = x**3 + x + b
UNUSED static const u8 ec_b[30] = {0x00, 0x66, 0x64, 0x7e, 0xde, 0x6c, 0x33, 0x2c, 0x7f, 0x8c, UNUSED static const u8 ec_b[30] = {0x00, 0x66, 0x64, 0x7e, 0xde, 0x6c, 0x33, 0x2c, 0x7f, 0x8c,
0x09, 0x23, 0xbb, 0x58, 0x21, 0x3b, 0x33, 0x3b, 0x20, 0xe9, 0x09, 0x23, 0xbb, 0x58, 0x21, 0x3b, 0x33, 0x3b, 0x20, 0xe9,
@ -31,303 +184,50 @@ static const u8 ec_N[30] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0x8a, 0x69, 0x22, 0x03, 0x1d, 0x26, 0x03, 0xcf, 0xe0, 0xd7}; 0x8a, 0x69, 0x22, 0x03, 0x1d, 0x26, 0x03, 0xcf, 0xe0, 0xd7};
// base point // base point
static const u8 ec_G[60] = {0x00, 0xfa, 0xc9, 0xdf, 0xcb, 0xac, 0x83, 0x13, 0xbb, 0x21, 0x39, 0xf1, constexpr Point ec_G{
0xbb, 0x75, 0x5f, 0xef, 0x65, 0xbc, 0x39, 0x1f, 0x8b, 0x36, 0xf8, 0xf8, {{{0x00, 0xfa, 0xc9, 0xdf, 0xcb, 0xac, 0x83, 0x13, 0xbb, 0x21, 0x39, 0xf1, 0xbb, 0x75, 0x5f,
0xeb, 0x73, 0x71, 0xfd, 0x55, 0x8b, 0x01, 0x00, 0x6a, 0x08, 0xa4, 0x19, 0xef, 0x65, 0xbc, 0x39, 0x1f, 0x8b, 0x36, 0xf8, 0xf8, 0xeb, 0x73, 0x71, 0xfd, 0x55, 0x8b}}},
0x03, 0x35, 0x06, 0x78, 0xe5, 0x85, 0x28, 0xbe, 0xbf, 0x8a, 0x0b, 0xef, {{{0x01, 0x00, 0x6a, 0x08, 0xa4, 0x19, 0x03, 0x35, 0x06, 0x78, 0xe5, 0x85, 0x28, 0xbe, 0xbf,
0xf8, 0x67, 0xa7, 0xca, 0x36, 0x71, 0x6f, 0x7e, 0x01, 0xf8, 0x10, 0x52}; 0x8a, 0x0b, 0xef, 0xf8, 0x67, 0xa7, 0xca, 0x36, 0x71, 0x6f, 0x7e, 0x01, 0xf8, 0x10, 0x52}}}};
static void elt_copy(u8* d, const u8* a) static Point operator+(const Point& a, const Point& b)
{ {
memcpy(d, a, 30); if (a.IsZero())
} return b;
if (b.IsZero())
return a;
static void elt_zero(u8* d) Elt u = a.X() + b.X();
{ if (u.IsZero())
memset(d, 0, 30);
}
static int elt_is_zero(const u8* d)
{
u32 i;
for (i = 0; i < 30; i++)
if (d[i] != 0)
return 0;
return 1;
}
static void elt_add(u8* d, const u8* a, const u8* b)
{
u32 i;
for (i = 0; i < 30; i++)
d[i] = a[i] ^ b[i];
}
static void elt_mul_x(u8* d, const u8* a)
{
u8 carry, x, y;
u32 i;
carry = a[0] & 1;
x = 0;
for (i = 0; i < 29; i++)
{ {
y = a[i + 1]; u = a.Y() + b.Y();
d[i] = x ^ (y >> 7); if (u.IsZero())
x = y << 1; return a.Double();
return Point{};
} }
d[29] = x ^ carry;
d[20] ^= carry << 2; const Elt s = (a.Y() + b.Y()) / u;
Elt t = s.Square() + s + b.X();
t.data[29] ^= 1;
const Elt rx = t + a.X();
const Elt ry = s * t + a.Y() + rx;
return Point{rx, ry};
} }
static void elt_mul(u8* d, const u8* a, const u8* b) static Point operator*(const u8* a, const Point& b)
{ {
u32 i, n; Point d;
u8 mask; for (std::size_t i = 0; i < 30; i++)
elt_zero(d);
i = 0;
mask = 1;
for (n = 0; n < 233; n++)
{ {
elt_mul_x(d, d); for (u8 mask = 0x80; mask != 0; mask >>= 1)
{
d = d.Double();
if ((a[i] & mask) != 0) if ((a[i] & mask) != 0)
elt_add(d, d, b); d = d + b;
mask >>= 1;
if (mask == 0)
{
mask = 0x80;
i++;
} }
} }
} return d;
static const u8 square[16] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55};
static void elt_square_to_wide(u8* d, const u8* a)
{
u32 i;
for (i = 0; i < 30; i++)
{
d[2 * i] = square[a[i] >> 4];
d[2 * i + 1] = square[a[i] & 15];
}
}
static void wide_reduce(u8* d)
{
u32 i;
u8 x;
for (i = 0; i < 30; i++)
{
x = d[i];
d[i + 19] ^= x >> 7;
d[i + 20] ^= x << 1;
d[i + 29] ^= x >> 1;
d[i + 30] ^= x << 7;
}
x = d[30] & ~1;
d[49] ^= x >> 7;
d[50] ^= x << 1;
d[59] ^= x >> 1;
d[30] &= 1;
}
static void elt_square(u8* d, const u8* a)
{
u8 wide[60];
elt_square_to_wide(wide, a);
wide_reduce(wide);
elt_copy(d, wide + 30);
}
static void itoh_tsujii(u8* d, const u8* a, const u8* b, u32 j)
{
u8 t[30];
elt_copy(t, a);
while (j--)
{
elt_square(d, t);
elt_copy(t, d);
}
elt_mul(d, t, b);
}
static void elt_inv(u8* d, const u8* a)
{
u8 t[30];
u8 s[30];
itoh_tsujii(t, a, a, 1);
itoh_tsujii(s, t, a, 1);
itoh_tsujii(t, s, s, 3);
itoh_tsujii(s, t, a, 1);
itoh_tsujii(t, s, s, 7);
itoh_tsujii(s, t, t, 14);
itoh_tsujii(t, s, a, 1);
itoh_tsujii(s, t, t, 29);
itoh_tsujii(t, s, s, 58);
itoh_tsujii(s, t, t, 116);
elt_square(d, s);
}
UNUSED static int point_is_on_curve(u8* p)
{
u8 s[30], t[30];
u8 *x, *y;
x = p;
y = p + 30;
elt_square(t, x);
elt_mul(s, t, x);
elt_add(s, s, t);
elt_square(t, y);
elt_add(s, s, t);
elt_mul(t, x, y);
elt_add(s, s, t);
elt_add(s, s, ec_b);
return elt_is_zero(s);
}
static int point_is_zero(const u8* p)
{
return elt_is_zero(p) && elt_is_zero(p + 30);
}
static void point_double(u8* r, const u8* p)
{
u8 s[30], t[30];
const u8 *px, *py;
u8 *rx, *ry;
px = p;
py = p + 30;
rx = r;
ry = r + 30;
if (elt_is_zero(px))
{
elt_zero(rx);
elt_zero(ry);
return;
}
elt_inv(t, px);
elt_mul(s, py, t);
elt_add(s, s, px);
elt_square(t, px);
elt_square(rx, s);
elt_add(rx, rx, s);
rx[29] ^= 1;
elt_mul(ry, s, rx);
elt_add(ry, ry, rx);
elt_add(ry, ry, t);
}
static void point_add(u8* r, const u8* p, const u8* q)
{
u8 s[30], t[30], u[30];
const u8 *px, *py, *qx, *qy;
u8 *rx, *ry;
px = p;
py = p + 30;
qx = q;
qy = q + 30;
rx = r;
ry = r + 30;
if (point_is_zero(p))
{
elt_copy(rx, qx);
elt_copy(ry, qy);
return;
}
if (point_is_zero(q))
{
elt_copy(rx, px);
elt_copy(ry, py);
return;
}
elt_add(u, px, qx);
if (elt_is_zero(u))
{
elt_add(u, py, qy);
if (elt_is_zero(u))
point_double(r, p);
else
{
elt_zero(rx);
elt_zero(ry);
}
return;
}
elt_inv(t, u);
elt_add(u, py, qy);
elt_mul(s, t, u);
elt_square(t, s);
elt_add(t, t, s);
elt_add(t, t, qx);
t[29] ^= 1;
elt_mul(u, s, t);
elt_add(s, u, py);
elt_add(rx, t, px);
elt_add(ry, s, rx);
}
void point_mul(u8* d, const u8* a, const u8* b) // a is bignum
{
u32 i;
u8 mask;
elt_zero(d);
elt_zero(d + 30);
for (i = 0; i < 30; i++)
for (mask = 0x80; mask != 0; mask >>= 1)
{
point_double(d, d);
if ((a[i] & mask) != 0)
point_add(d, d, b);
}
} }
static void silly_random(u8* rndArea, u8 count) static void silly_random(u8* rndArea, u8 count)
@ -341,19 +241,13 @@ static void silly_random(u8* rndArea, u8 count)
} }
} }
void generate_ecdsa(u8* R, u8* S, const u8* k, const u8* hash) std::array<u8, 60> Sign(const u8* key, const u8* hash)
{ {
u8 e[30]; u8 e[30]{};
u8 kk[30];
u8 m[30];
u8 minv[30];
u8 mG[60];
// FILE *fp;
elt_zero(e);
memcpy(e + 10, hash, 20); memcpy(e + 10, hash, 20);
// Changing random number generator to a lame one... // Changing random number generator to a lame one...
u8 m[30];
silly_random(m, sizeof(m)); silly_random(m, sizeof(m));
// fp = fopen("/dev/random", "rb"); // fp = fopen("/dev/random", "rb");
// if (fread(m, sizeof m, 1, fp) != 1) // if (fread(m, sizeof m, 1, fp) != 1)
@ -361,55 +255,65 @@ void generate_ecdsa(u8* R, u8* S, const u8* k, const u8* hash)
// fclose(fp); // fclose(fp);
m[0] = 0; m[0] = 0;
// R = (mG).x Elt r = (m * ec_G).X();
if (bn_compare(r.data.data(), ec_N, 30) >= 0)
point_mul(mG, m, ec_G); bn_sub_modulus(r.data.data(), ec_N, 30);
elt_copy(R, mG);
if (bn_compare(R, ec_N, 30) >= 0)
bn_sub_modulus(R, ec_N, 30);
// S = m**-1*(e + Rk) (mod N) // S = m**-1*(e + Rk) (mod N)
elt_copy(kk, k); u8 kk[30];
if (bn_compare(kk, ec_N, 30) >= 0) std::copy_n(key, sizeof(kk), kk);
bn_sub_modulus(kk, ec_N, 30); if (bn_compare(kk, ec_N, sizeof(kk)) >= 0)
bn_mul(S, R, kk, ec_N, 30); bn_sub_modulus(kk, ec_N, sizeof(kk));
bn_add(kk, S, e, ec_N, 30); Elt s;
bn_inv(minv, m, ec_N, 30); bn_mul(s.data.data(), r.data.data(), kk, ec_N, 30);
bn_mul(S, minv, kk, ec_N, 30); bn_add(kk, s.data.data(), e, ec_N, sizeof(kk));
u8 minv[30];
bn_inv(minv, m, ec_N, sizeof(minv));
bn_mul(s.data.data(), minv, kk, ec_N, 30);
std::array<u8, 60> signature;
std::copy(r.data.cbegin(), r.data.cend(), signature.begin());
std::copy(s.data.cbegin(), s.data.cend(), signature.begin() + 30);
return signature;
} }
UNUSED static int check_ecdsa(u8* Q, u8* R, u8* S, const u8* hash) UNUSED static int check_ecdsa(u8* Q, u8* R, u8* S, const u8* hash)
{ {
u8 Sinv[30]; u8 Sinv[30];
u8 e[30];
u8 w1[30], w2[30];
u8 r1[60], r2[60];
bn_inv(Sinv, S, ec_N, 30); bn_inv(Sinv, S, ec_N, 30);
u8 e[30]{};
elt_zero(e);
memcpy(e + 10, hash, 20); memcpy(e + 10, hash, 20);
u8 w1[30], w2[30];
bn_mul(w1, e, Sinv, ec_N, 30); bn_mul(w1, e, Sinv, ec_N, 30);
bn_mul(w2, R, Sinv, ec_N, 30); bn_mul(w2, R, Sinv, ec_N, 30);
point_mul(r1, w1, ec_G); Point r1 = w1 * ec_G + w2 * Point{Q};
point_mul(r2, w2, Q); auto& rx = r1.X().data;
if (bn_compare(rx.data(), ec_N, 30) >= 0)
bn_sub_modulus(rx.data(), ec_N, 30);
point_add(r1, r1, r2); return (bn_compare(rx.data(), R, 30) == 0);
if (bn_compare(r1, ec_N, 30) >= 0)
bn_sub_modulus(r1, ec_N, 30);
return (bn_compare(r1, R, 30) == 0);
} }
void ec_priv_to_pub(const u8* k, u8* Q) std::array<u8, 60> PrivToPub(const u8* key)
{ {
point_mul(Q, k, ec_G); const Point data = key * ec_G;
std::array<u8, 60> result;
std::copy_n(data.Data(), result.size(), result.begin());
return result;
} }
std::array<u8, 60> ComputeSharedSecret(const u8* private_key, const u8* public_key)
{
std::array<u8, 60> shared_secret;
const Point data = private_key * Point{public_key};
std::copy_n(data.Data(), shared_secret.size(), shared_secret.begin());
return shared_secret;
}
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif #endif
} // namespace Common::ec

View File

@ -4,10 +4,18 @@
#pragma once #pragma once
#include <array>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
void generate_ecdsa(u8* R, u8* S, const u8* k, const u8* hash); namespace Common::ec
{
/// Generate a signature using ECDSA.
std::array<u8, 60> Sign(const u8* key, const u8* hash);
void ec_priv_to_pub(const u8* k, u8* Q); /// Compute a shared secret from a private key (30 bytes) and public key (60 bytes).
std::array<u8, 60> ComputeSharedSecret(const u8* private_key, const u8* public_key);
void point_mul(u8* d, const u8* a, const u8* b); /// Convert a ECC private key (30 bytes) to a public key (60 bytes).
std::array<u8, 60> PrivToPub(const u8* key);
} // namespace Common::ec

View File

@ -250,8 +250,8 @@ ReturnCode IOSC::ComputeSharedKey(Handle dest_handle, Handle private_handle, Han
} }
// Calculate the ECC shared secret. // Calculate the ECC shared secret.
std::array<u8, 0x3c> shared_secret; const std::array<u8, 0x3c> shared_secret =
point_mul(shared_secret.data(), private_entry->data.data(), public_entry->data.data()); Common::ec::ComputeSharedSecret(private_entry->data.data(), public_entry->data.data());
std::array<u8, 20> sha1; std::array<u8, 20> sha1;
mbedtls_sha1(shared_secret.data(), shared_secret.size() / 2, sha1.data()); mbedtls_sha1(shared_secret.data(), shared_secret.size() / 2, sha1.data());
@ -425,7 +425,8 @@ static Certificate MakeBlankSigECCert(const char* signer, const char* name, cons
std::strncpy(reinterpret_cast<char*>(cert_out.data()) + 0xc4, name, 0x40); std::strncpy(reinterpret_cast<char*>(cert_out.data()) + 0xc4, name, 0x40);
const u32 swapped_key_id = Common::swap32(key_id); const u32 swapped_key_id = Common::swap32(key_id);
std::memcpy(cert_out.data() + 0x104, &swapped_key_id, sizeof(swapped_key_id)); std::memcpy(cert_out.data() + 0x104, &swapped_key_id, sizeof(swapped_key_id));
ec_priv_to_pub(private_key, cert_out.data() + 0x108); const std::array<u8, 60> public_key = Common::ec::PrivToPub(private_key);
std::copy(public_key.cbegin(), public_key.cend(), cert_out.begin() + 0x108);
return cert_out; return cert_out;
} }
@ -454,11 +455,12 @@ void IOSC::Sign(u8* sig_out, u8* ap_cert_out, u64 title_id, const u8* data, u32
std::copy(cert.begin(), cert.end(), ap_cert_out); std::copy(cert.begin(), cert.end(), ap_cert_out);
mbedtls_sha1(ap_cert_out + 0x80, 0x100, hash.data()); mbedtls_sha1(ap_cert_out + 0x80, 0x100, hash.data());
generate_ecdsa(ap_cert_out + 4, ap_cert_out + 34, m_key_entries[HANDLE_CONSOLE_KEY].data.data(), auto signature = Common::ec::Sign(m_key_entries[HANDLE_CONSOLE_KEY].data.data(), hash.data());
hash.data()); std::copy(signature.cbegin(), signature.cend(), ap_cert_out + 4);
mbedtls_sha1(data, data_size, hash.data()); mbedtls_sha1(data, data_size, hash.data());
generate_ecdsa(sig_out, sig_out + 30, ap_priv.data(), hash.data()); signature = Common::ec::Sign(ap_priv.data(), hash.data());
std::copy(signature.cbegin(), signature.cend(), sig_out);
} }
constexpr std::array<u8, 512> ROOT_PUBLIC_KEY = { constexpr std::array<u8, 512> ROOT_PUBLIC_KEY = {

View File

@ -4,6 +4,7 @@ add_dolphin_test(BitUtilsTest BitUtilsTest.cpp)
add_dolphin_test(BlockingLoopTest BlockingLoopTest.cpp) add_dolphin_test(BlockingLoopTest BlockingLoopTest.cpp)
add_dolphin_test(BusyLoopTest BusyLoopTest.cpp) add_dolphin_test(BusyLoopTest BusyLoopTest.cpp)
add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp) add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp)
add_dolphin_test(CryptoEcTest Crypto/EcTest.cpp)
add_dolphin_test(EventTest EventTest.cpp) add_dolphin_test(EventTest EventTest.cpp)
add_dolphin_test(FixedSizeQueueTest FixedSizeQueueTest.cpp) add_dolphin_test(FixedSizeQueueTest FixedSizeQueueTest.cpp)
add_dolphin_test(FlagTest FlagTest.cpp) add_dolphin_test(FlagTest FlagTest.cpp)

View File

@ -0,0 +1,45 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <gtest/gtest.h>
#include "Common/Crypto/ec.h"
constexpr std::array<u8, 30> PRIVATE_KEY{{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}};
constexpr std::array<u8, 60> PUBLIC_KEY{
{0x00, 0x21, 0x5b, 0xf7, 0x48, 0x2a, 0x64, 0x4b, 0xda, 0x9e, 0x02, 0x87, 0xaa, 0x37, 0x7d,
0x0c, 0x5d, 0x27, 0x48, 0x72, 0xf1, 0x19, 0x45, 0x44, 0xdf, 0x74, 0x57, 0x67, 0x60, 0xcd,
0x00, 0xa8, 0x6c, 0xe8, 0x55, 0xdd, 0x52, 0x98, 0x95, 0xc5, 0xc3, 0x3f, 0x7b, 0x0f, 0xc6,
0x9f, 0x95, 0x8b, 0x3e, 0xe3, 0x33, 0x84, 0x2f, 0x32, 0xe9, 0x03, 0xe6, 0xfb, 0xc8, 0x51}};
TEST(ec, Sign)
{
static constexpr std::array<u8, 20> HASH{{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}};
const std::array<u8, 60> sig = Common::ec::Sign(PRIVATE_KEY.data(), HASH.data());
// r and s must be non-null.
EXPECT_FALSE(std::all_of(sig.cbegin(), sig.cbegin() + 30, [](u8 b) { return b == 0; }));
EXPECT_FALSE(std::all_of(sig.cbegin() + 30, sig.cend(), [](u8 b) { return b == 0; }));
}
TEST(ec, PrivToPub)
{
EXPECT_EQ(Common::ec::PrivToPub(PRIVATE_KEY.data()), PUBLIC_KEY);
}
TEST(ec, GenerateSharedSecret)
{
static constexpr std::array<u8, 60> SECRET = {
{0x01, 0x20, 0x2b, 0x3b, 0x63, 0x18, 0x5b, 0x2f, 0x05, 0x4f, 0xb5, 0x2c, 0xe5, 0x46, 0xc2,
0x2d, 0x4e, 0x73, 0xf4, 0x15, 0xcb, 0xd2, 0x56, 0x7f, 0xff, 0x3f, 0x02, 0x23, 0xbe, 0xda,
0x01, 0xf3, 0x0c, 0x34, 0xb6, 0x37, 0xbf, 0x55, 0x5b, 0x04, 0x49, 0x5a, 0x07, 0xee, 0x78,
0xd2, 0x9a, 0x31, 0xce, 0x10, 0x42, 0xbf, 0x79, 0xc3, 0xcb, 0x22, 0x40, 0xe5, 0x94, 0x7f}};
EXPECT_EQ(Common::ec::ComputeSharedSecret(PRIVATE_KEY.data(), PUBLIC_KEY.data()), SECRET);
}