diff --git a/Source/Core/Common/Crypto/bn.cpp b/Source/Core/Common/Crypto/bn.cpp index 78ea444384..339b269d39 100644 --- a/Source/Core/Common/Crypto/bn.cpp +++ b/Source/Core/Common/Crypto/bn.cpp @@ -3,61 +3,43 @@ // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt #include -#include +#include #include "Common/CommonTypes.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]) - 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; + u32 dig = N[i] + c; c = (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; - u32 dig; - u8 c; - - c = 0; - for (i = n - 1; i < n; i--) + u8 c = 0; + for (int i = n - 1; i >= 0; --i) { - dig = a[i] + b[i] + c; + u32 dig = a[i] + b[i] + c; c = (dig >= 0x100); 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); } -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); - for (i = 0; i < n; i++) - for (mask = 0x80; mask != 0; mask >>= 1) + for (int i = 0; i < n; i++) + { + for (u8 mask = 0x80; mask != 0; mask >>= 1) { bn_add(d, d, d, N, n); if ((a[i] & mask) != 0) 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]; - u32 i; - u8 mask; bn_zero(d, n); d[n - 1] = 1; - for (i = 0; i < en; i++) - for (mask = 0x80; mask != 0; mask >>= 1) + for (int i = 0; i < en; i++) + { + for (u8 mask = 0x80; mask != 0; mask >>= 1) { bn_mul(t, d, d, N, n); 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 bn_copy(d, t, n); } + } } // 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]; diff --git a/Source/Core/Common/Crypto/bn.h b/Source/Core/Common/Crypto/bn.h index 5c0c85b157..7ab2ab3fb1 100644 --- a/Source/Core/Common/Crypto/bn.h +++ b/Source/Core/Common/Crypto/bn.h @@ -8,9 +8,9 @@ // bignum arithmetic -int bn_compare(const u8* a, const u8* b, u32 n); -void bn_sub_modulus(u8* a, const u8* N, u32 n); -void bn_add(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, u32 n); -void bn_inv(u8* d, const u8* a, const u8* N, u32 n); // only for prime N -void bn_exp(u8* d, const u8* a, const u8* N, u32 n, const u8* e, u32 en); +int bn_compare(const u8* a, const u8* b, int 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, int 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, int n); // only for prime N +void bn_exp(u8* d, const u8* a, const u8* N, int n, const u8* e, int en); diff --git a/Source/Core/Common/Crypto/ec.cpp b/Source/Core/Common/Crypto/ec.cpp index 5fe7e9bb2b..9906ccd5e9 100644 --- a/Source/Core/Common/Crypto/ec.cpp +++ b/Source/Core/Common/Crypto/ec.cpp @@ -6,6 +6,7 @@ // Licensed under the terms of the GNU GPL, version 2 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +#include #include #include #include @@ -20,6 +21,158 @@ #pragma warning(disable : 4505) #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 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 data{}; +}; + +static Elt operator+(const Elt& a, const Elt& b) +{ + Elt d; + for (std::size_t i = 0; i < std::tuple_size{}; 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 m_data{}; + static_assert(sizeof(decltype(m_data)) == 60, "Wrong size for m_data"); +}; + // 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, 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}; // base point -static const u8 ec_G[60] = {0x00, 0xfa, 0xc9, 0xdf, 0xcb, 0xac, 0x83, 0x13, 0xbb, 0x21, 0x39, 0xf1, - 0xbb, 0x75, 0x5f, 0xef, 0x65, 0xbc, 0x39, 0x1f, 0x8b, 0x36, 0xf8, 0xf8, - 0xeb, 0x73, 0x71, 0xfd, 0x55, 0x8b, 0x01, 0x00, 0x6a, 0x08, 0xa4, 0x19, - 0x03, 0x35, 0x06, 0x78, 0xe5, 0x85, 0x28, 0xbe, 0xbf, 0x8a, 0x0b, 0xef, - 0xf8, 0x67, 0xa7, 0xca, 0x36, 0x71, 0x6f, 0x7e, 0x01, 0xf8, 0x10, 0x52}; +constexpr Point ec_G{ + {{{0x00, 0xfa, 0xc9, 0xdf, 0xcb, 0xac, 0x83, 0x13, 0xbb, 0x21, 0x39, 0xf1, 0xbb, 0x75, 0x5f, + 0xef, 0x65, 0xbc, 0x39, 0x1f, 0x8b, 0x36, 0xf8, 0xf8, 0xeb, 0x73, 0x71, 0xfd, 0x55, 0x8b}}}, + {{{0x01, 0x00, 0x6a, 0x08, 0xa4, 0x19, 0x03, 0x35, 0x06, 0x78, 0xe5, 0x85, 0x28, 0xbe, 0xbf, + 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) -{ - 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++) + Elt u = a.X() + b.X(); + if (u.IsZero()) { - y = a[i + 1]; - d[i] = x ^ (y >> 7); - x = y << 1; + u = a.Y() + b.Y(); + if (u.IsZero()) + 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; - u8 mask; - - elt_zero(d); - - i = 0; - mask = 1; - for (n = 0; n < 233; n++) + Point d; + for (std::size_t i = 0; i < 30; i++) { - elt_mul_x(d, d); - - if ((a[i] & mask) != 0) - elt_add(d, d, b); - - mask >>= 1; - if (mask == 0) + for (u8 mask = 0x80; mask != 0; mask >>= 1) { - mask = 0x80; - i++; - } - } -} - -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); + d = d.Double(); if ((a[i] & mask) != 0) - point_add(d, d, b); + d = d + b; } + } + return d; } 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 Sign(const u8* key, const u8* hash) { - u8 e[30]; - u8 kk[30]; - u8 m[30]; - u8 minv[30]; - u8 mG[60]; - // FILE *fp; - - elt_zero(e); + u8 e[30]{}; memcpy(e + 10, hash, 20); // Changing random number generator to a lame one... + u8 m[30]; silly_random(m, sizeof(m)); // fp = fopen("/dev/random", "rb"); // 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); m[0] = 0; - // R = (mG).x - - point_mul(mG, m, ec_G); - elt_copy(R, mG); - if (bn_compare(R, ec_N, 30) >= 0) - bn_sub_modulus(R, ec_N, 30); + Elt r = (m * ec_G).X(); + if (bn_compare(r.data.data(), ec_N, 30) >= 0) + bn_sub_modulus(r.data.data(), ec_N, 30); // S = m**-1*(e + Rk) (mod N) - elt_copy(kk, k); - if (bn_compare(kk, ec_N, 30) >= 0) - bn_sub_modulus(kk, ec_N, 30); - bn_mul(S, R, kk, ec_N, 30); - bn_add(kk, S, e, ec_N, 30); - bn_inv(minv, m, ec_N, 30); - bn_mul(S, minv, kk, ec_N, 30); + u8 kk[30]; + std::copy_n(key, sizeof(kk), kk); + if (bn_compare(kk, ec_N, sizeof(kk)) >= 0) + bn_sub_modulus(kk, ec_N, sizeof(kk)); + Elt s; + bn_mul(s.data.data(), r.data.data(), 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 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) { u8 Sinv[30]; - u8 e[30]; - u8 w1[30], w2[30]; - u8 r1[60], r2[60]; bn_inv(Sinv, S, ec_N, 30); - - elt_zero(e); + u8 e[30]{}; memcpy(e + 10, hash, 20); + u8 w1[30], w2[30]; bn_mul(w1, e, Sinv, ec_N, 30); bn_mul(w2, R, Sinv, ec_N, 30); - point_mul(r1, w1, ec_G); - point_mul(r2, w2, Q); + Point r1 = w1 * ec_G + w2 * Point{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); - - if (bn_compare(r1, ec_N, 30) >= 0) - bn_sub_modulus(r1, ec_N, 30); - - return (bn_compare(r1, R, 30) == 0); + return (bn_compare(rx.data(), R, 30) == 0); } -void ec_priv_to_pub(const u8* k, u8* Q) +std::array PrivToPub(const u8* key) { - point_mul(Q, k, ec_G); + const Point data = key * ec_G; + std::array result; + std::copy_n(data.Data(), result.size(), result.begin()); + return result; } +std::array ComputeSharedSecret(const u8* private_key, const u8* public_key) +{ + std::array 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 #pragma warning(pop) #endif +} // namespace Common::ec diff --git a/Source/Core/Common/Crypto/ec.h b/Source/Core/Common/Crypto/ec.h index 3bf8b9904f..18b0d48d98 100644 --- a/Source/Core/Common/Crypto/ec.h +++ b/Source/Core/Common/Crypto/ec.h @@ -4,10 +4,18 @@ #pragma once +#include + #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 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 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 PrivToPub(const u8* key); +} // namespace Common::ec diff --git a/Source/Core/Core/IOS/IOSC.cpp b/Source/Core/Core/IOS/IOSC.cpp index 7f47421ca8..569568395d 100644 --- a/Source/Core/Core/IOS/IOSC.cpp +++ b/Source/Core/Core/IOS/IOSC.cpp @@ -250,8 +250,8 @@ ReturnCode IOSC::ComputeSharedKey(Handle dest_handle, Handle private_handle, Han } // Calculate the ECC shared secret. - std::array shared_secret; - point_mul(shared_secret.data(), private_entry->data.data(), public_entry->data.data()); + const std::array shared_secret = + Common::ec::ComputeSharedSecret(private_entry->data.data(), public_entry->data.data()); std::array sha1; 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(cert_out.data()) + 0xc4, name, 0x40); const u32 swapped_key_id = Common::swap32(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 public_key = Common::ec::PrivToPub(private_key); + std::copy(public_key.cbegin(), public_key.cend(), cert_out.begin() + 0x108); 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); 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(), - hash.data()); + auto signature = Common::ec::Sign(m_key_entries[HANDLE_CONSOLE_KEY].data.data(), hash.data()); + std::copy(signature.cbegin(), signature.cend(), ap_cert_out + 4); 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 ROOT_PUBLIC_KEY = { diff --git a/Source/UnitTests/Common/CMakeLists.txt b/Source/UnitTests/Common/CMakeLists.txt index 8b94438c30..ecd8ca0f29 100644 --- a/Source/UnitTests/Common/CMakeLists.txt +++ b/Source/UnitTests/Common/CMakeLists.txt @@ -4,6 +4,7 @@ add_dolphin_test(BitUtilsTest BitUtilsTest.cpp) add_dolphin_test(BlockingLoopTest BlockingLoopTest.cpp) add_dolphin_test(BusyLoopTest BusyLoopTest.cpp) add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp) +add_dolphin_test(CryptoEcTest Crypto/EcTest.cpp) add_dolphin_test(EventTest EventTest.cpp) add_dolphin_test(FixedSizeQueueTest FixedSizeQueueTest.cpp) add_dolphin_test(FlagTest FlagTest.cpp) diff --git a/Source/UnitTests/Common/Crypto/EcTest.cpp b/Source/UnitTests/Common/Crypto/EcTest.cpp new file mode 100644 index 0000000000..3fc955da89 --- /dev/null +++ b/Source/UnitTests/Common/Crypto/EcTest.cpp @@ -0,0 +1,45 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Common/Crypto/ec.h" + +constexpr std::array 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 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 HASH{{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}}; + const std::array 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 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); +}