From 017f6a2e7a7553fd37fd7820b80a58a4f8ddd74d Mon Sep 17 00:00:00 2001
From: ergo720 <45463469+ergo720@users.noreply.github.com>
Date: Mon, 11 Mar 2019 18:39:22 +0100
Subject: [PATCH] Use libtommath to do rsa
---
build/win32/libtomcrypt_VS2008.vcxproj | 4 +-
build/win32/libtommath_VS2008.vcxproj | 4 +-
src/common/crypto/EmuRsa.cpp | 1612 +-----------------------
src/common/crypto/EmuRsa.h | 35 +-
src/common/util/CxbxUtil.cpp | 45 +-
src/common/util/CxbxUtil.h | 2 +
src/common/xbe/Xbe.cpp | 25 +-
src/core/kernel/exports/EmuKrnlXc.cpp | 13 +-
8 files changed, 154 insertions(+), 1586 deletions(-)
diff --git a/build/win32/libtomcrypt_VS2008.vcxproj b/build/win32/libtomcrypt_VS2008.vcxproj
index 85b6478a6..52335d433 100644
--- a/build/win32/libtomcrypt_VS2008.vcxproj
+++ b/build/win32/libtomcrypt_VS2008.vcxproj
@@ -70,14 +70,14 @@
$(SolutionDir)$(Configuration)\
- $(Configuration)\
+ $(Configuration)\$(ProjectName)
MinimumRecommendedRules.ruleset
$(SolutionDir)$(Configuration)\
- $(Configuration)\
+ $(Configuration)\$(ProjectName)
MinimumRecommendedRules.ruleset
diff --git a/build/win32/libtommath_VS2008.vcxproj b/build/win32/libtommath_VS2008.vcxproj
index d335e68f0..8964ff8bd 100644
--- a/build/win32/libtommath_VS2008.vcxproj
+++ b/build/win32/libtommath_VS2008.vcxproj
@@ -70,7 +70,7 @@
$(SolutionDir)$(Configuration)\
- $(Configuration)\
+ $(Configuration)\$(ProjectName)
MinimumRecommendedRules.ruleset
@@ -84,7 +84,7 @@
$(SolutionDir)$(Configuration)\
- $(Configuration)\
+ $(Configuration)\$(ProjectName)
MinimumRecommendedRules.ruleset
diff --git a/src/common/crypto/EmuRsa.cpp b/src/common/crypto/EmuRsa.cpp
index 38616e123..331660a45 100644
--- a/src/common/crypto/EmuRsa.cpp
+++ b/src/common/crypto/EmuRsa.cpp
@@ -25,59 +25,29 @@
// ******************************************************************
// Acknowledgment:
-// This rsa implementation is directly borrowed from the xbedump tool of XQEMU (GPLv2 license)
-// https://github.com/xqemu/xbedump
+// verify_hash, RSApkcs1paddingtable and RSA_PUBLIC_KEY are from the
+// file xboxlib.c of the xbedump tool (and that file only, GPLv2).
+// https://github.com/XboxDev/xbedump/blob/master/xboxlib.c
+
+// xboxlib.c license
+/***************************************************************************
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+***************************************************************************/
#define LOG_PREFIX CXBXR_MODULE::RSA
#include "EmuRsa.h"
#include "core\kernel\support\Emu.h" // For EmuLog
-#include
-#include
+#include "tomcrypt.h"
+#include "tommath.h"
+#define CHK_MP_RET(x) do { int ret = (x); if (ret != MP_OKAY) return false; } while(0)
-/* 2^(16*MAX_SHORTS)-1 will fit into a giant, but take care:
-* one usually has squares, etc. of giants involved, and
-* every intermediate giant in a calculation must fit into
-* this many shorts. Thus, if you want systematically to effect
-* arithmetic on B-bit operands, you need MAX_SHORTS > B/8,
-* preferably a tad larger than this; e.g. MAX_SHORTS > B/7.
-*/
-#define MAX_SHORTS (1<<19)
-#define GIANT_INFINITY (-1)
-#define FA 0
-#define TR 1
-#define TWOPI (double)(2*3.1415926535897932384626433)
-#define TWO16 (double)(65536.0)
-#define TWOM16 (double)(0.0000152587890625)
-#define SQRTHALF (double)(0.707106781186547524400844362104)
-
-#define newmin(a,b) ((a)<(b)? (a) : (b))
-/* Size by which to increment the stack used in pushg() and popg(). */
-#define STACK_GROW 16
-/* Error codes */
-#define DIVIDEBYZERO 1
-#define OVFLOW 2
-#define SIGN 3
-#define OVERRANGE 4
-#define AUTO_MUL 0
-#define GRAMMAR_MUL 1
-#define FFT_MUL 2
-#define KARAT_MUL 3
-/* Next, mumber of shorts per operand at which Karatsuba breaks over. */
-#define KARAT_BREAK 40
-/* Next, mumber of shorts per operand at which FFT breaks over. */
-#define FFT_BREAK 200
-
-
-/* Structure definitions */
-typedef struct
-{
- int sign;
- unsigned short n[1]; /* number of shorts = abs(sign) */
-} giantstruct;
-
-typedef giantstruct* giant;
const unsigned char RSApkcs1paddingtable[3][16] = {
{ 0x0F, 0x14,0x04,0x00,0x05,0x1A,0x02,0x03,0x0E,0x2B,0x05,0x06,0x09,0x30,0x21,0x30 },
@@ -85,94 +55,62 @@ const unsigned char RSApkcs1paddingtable[3][16] = {
{ 0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
};
-
-/* Global variables. */
-int current_max_size = 0, cur_run = 0;
-static int stack_glen = 0;
-static int cur_stack_elem = 0;
-static int cur_stack_size = 0;
-static giant* stack;
-giant cur_den = NULL, cur_recip = NULL;
-int error = 0;
-int mulmode = AUTO_MUL;
-static double* z = NULL, *z2 = NULL;
-int checkFFTerror = 0;
-double maxFFTerror;
-double* sinCos = NULL;
-
-
-/* Global function declarations */
-giant newgiant(int numshorts);
-void gigimport(giant g, const unsigned char* buff, int len);
-void auxmulg(giant a, giant b);
-void normal_subg(giant a, giant b);
-void reverse_subg(giant a, giant b);
-void normal_addg(giant a, giant b);
-void FFTmulg(giant y, giant x);
-void FFTsquareg(giant x);
-void grammarmulg(giant a, giant b);
-void grammarsquareg(giant b);
-void karatmulg(giant a, giant b);
-void karatsquareg(giant b);
-void justg(giant x);
-void addsignal(giant x, double* z, int n);
-void fftinv_hermitian_to_real(double* z, int n);
-void mul_hermitian(double* a, double* b, int n);
-void square_hermitian(double* b, int n);
-void fft_real_to_hermitian(double* z, int n);
-void giant_to_double(giant x, int sizex, double* z, int L);
-int lpt(int, int *);
-double gfloor(double);
-void init_sinCos(int);
-double s_sin(int);
-double s_cos(int);
-void scramble_real(double* x, int n);
-// Stack functions
-static giant popg();
-static void pushg(int a);
-// Math Functions
-void powermodg(giant x, giant n, giant z); /* x := x^n (mod z). */
-void modg(giant d, giant n); /* num := num % den, any positive den. */
-void squareg(giant g); /* g *= g. */
-void mulg(giant a, giant b); /* b *= a. */
-int bitval(giant n, int pos); /* Returns the value of the pos bit of n. */
-int bitlen(giant n); /* Returns the bit-length n; e.g. n=7 returns 3. */
-void itog(int n, giant g); /* Integer <-> giant. */
-void gtog(giant src, giant dest); /* Copies one giant to another. */
-void make_recip(giant d, giant r); /* r becomes the steady-state reciprocal 2^(2b)/d, where * b = bit-length of d-1. */
-void modg_via_recip(giant d, giant r, giant n); /* n := n % d, d positive, using stored reciprocal directly. */
-int gcompg(giant a, giant b); /* Returns 1, 0, -1 as a>b, a=b, an, d_len);
+ // NOTE: init_LTM has been deprecated in favor to crypt_mp_init("L"). However, in the latest master branch crypt_mp_init
+ // is still undefined.
+ static bool need_init = true;
+ if (need_init) {
+ init_LTM();
+ need_init = false;
+ }
}
-void RSAdecrypt(const unsigned char* c_number, unsigned char* cryptbuffer, RSA_PUBLIC_KEY key)
+bool xbox_exp_mod(unsigned char* pA, const unsigned char* pB, const unsigned char* pC, const unsigned char* pD,
+ size_t b_size, size_t c_size, size_t d_size)
{
- ModExp(cryptbuffer, c_number, 256, key.KeyData.Exponent, 4, key.KeyData.Modulus, 256);
+ mp_int a, b, c, d;
+ CHK_MP_RET(mp_init(&a));
+ CHK_MP_RET(mp_init(&b));
+ CHK_MP_RET(mp_init(&c));
+ CHK_MP_RET(mp_init(&d));
+ CHK_MP_RET(mp_import(&b, 1, -1, b_size, 0, 0, pB));
+ CHK_MP_RET(mp_import(&c, 1, -1, c_size, 0, 0, pC));
+ CHK_MP_RET(mp_import(&d, 1, -1, d_size, 0, 0, pD));
+
+ CHK_MP_RET(mp_exptmod(&b, &c, &d, &a));
+
+ CHK_MP_RET(mp_export(pA, NULL, -1, 4, -1, 0, &a));
+
+ return true;
}
-bool Verifyhash(const unsigned char* hash, const unsigned char* decryptBuffer, RSA_PUBLIC_KEY key)
+bool xbox_rsa_public(const unsigned char* in_buf, unsigned char* out_buf, RSA_PUBLIC_KEY key)
+{
+ rsa_key tom_key;
+ unsigned char in_buf_be[256] = { 0 };
+ unsigned char out_buf_be[256] = { 0 };
+ unsigned long out_len = 256;
+ unsigned char modulus_be[256] = { 0 };
+ unsigned char exp_be[4] = { 0 };
+
+ // We must swap the data since libtom expects the data to be in big endian
+ swap_endianess(key.KeyData.Modulus, modulus_be, 256);
+ swap_endianess(key.KeyData.Exponent, exp_be, 4);
+ swap_endianess(in_buf, in_buf_be, 256);
+ if (rsa_set_key(modulus_be, 256, exp_be, 4, NULL, 0, &tom_key) != CRYPT_OK) {
+ EmuLog(LOG_LEVEL::WARNING, "Failed to load rsa key");
+ return false;
+ }
+ if (rsa_exptmod(in_buf_be, 256, out_buf_be, &out_len, PK_PUBLIC, &tom_key) != CRYPT_OK) {
+ EmuLog(LOG_LEVEL::WARNING, "rsa_exptmod failed");
+ return false;
+ }
+ swap_endianess(out_buf_be, out_buf, 256);
+ return true;
+}
+
+bool verify_hash(const unsigned char* hash, const unsigned char* decryptBuffer, RSA_PUBLIC_KEY key)
{
unsigned char cmphash[20];
int a;
@@ -212,1421 +150,3 @@ bool Verifyhash(const unsigned char* hash, const unsigned char* decryptBuffer, R
return true;
}
-
-giant newgiant(int numshorts)
-{
- int size;
- giant thegiant;
-
- if (numshorts > MAX_SHORTS) {
- EmuLog(LOG_LEVEL::WARNING, "Requested giant too big.");
- }
- if (numshorts <= 0)
- numshorts = MAX_SHORTS;
- size = numshorts * sizeof(short) + sizeof(int);
- thegiant = (giant)malloc(size);
- thegiant->sign = 0;
-
- if (newmin(2 * numshorts, MAX_SHORTS) > current_max_size)
- current_max_size = newmin(2 * numshorts, MAX_SHORTS);
-
- /* If newgiant() is being called for the first time, set the
- * size of the stack giants. */
- if (stack_glen == 0) stack_glen = current_max_size;
-
- return(thegiant);
-}
-
-void gigimport(giant g, const unsigned char *buff, int len) {
-
- // copy buffered 'number' into giant's number buffer
- memcpy(g->n, buff, len);
-
- assert((len % 2) == 0);
-
- // Get number of shorts
- g->sign = len / 2;
-
- // Only count used shorts
- while((g->sign >= 1) && (g->n[g->sign - 1] == 0)) {
- g->sign -= 1;
- }
-
- assert(g->sign != 0);
-}
-
-void powermodg(giant x, giant n, giant g)
-/* x becomes x^n (mod g). */
-{
- int len, pos;
- giant scratch2 = popg();
-
- gtog(x, scratch2);
- itog(1, x);
- len = bitlen(n);
- pos = 0;
- while (1)
- {
- if (bitval(n, pos++))
- {
- mulg(scratch2, x);
- modg(g, x);
- }
- if (pos >= len)
- break;
- squareg(scratch2);
- modg(g, scratch2);
- }
- pushg(1);
-}
-
-giant popg()
-{
- int i;
-
- if (current_max_size <= 0) current_max_size = MAX_SHORTS;
-
- if (cur_stack_size == 0) {
- /* Initialize the stack if we're just starting out.
- * Note that all stack giants will be whatever current_max_size is
- * when newgiant() is first called. */
- cur_stack_size = STACK_GROW;
- stack = (giant *)malloc(cur_stack_size * sizeof(giant));
- for (i = 0; i < STACK_GROW; i++)
- stack[i] = NULL;
- if (stack_glen == 0) stack_glen = current_max_size;
- }
- else if (cur_stack_elem >= cur_stack_size) {
- /* Expand the stack if we need to. */
- i = cur_stack_size;
- cur_stack_size += STACK_GROW;
- stack = (giant *)realloc(stack, cur_stack_size * sizeof(giant));
- for (; i < cur_stack_size; i++)
- stack[i] = NULL;
- }
- else if (cur_stack_elem < cur_stack_size - 2 * STACK_GROW) {
- /* Prune the stack if it's too big. Disabled, so the stack can only expand */
- /* cur_stack_size -= STACK_GROW;
- for (i = cur_stack_size - STACK_GROW; i < cur_stack_size; i++)
- free(stack[i]);
- stack = (giant *) realloc (stack,cur_stack_size * sizeof(giant)); */
- }
-
- /* Malloc our giant. */
- if (stack[cur_stack_elem] == NULL)
- stack[cur_stack_elem] = (giant)malloc(stack_glen * sizeof(short) + sizeof(int));
- stack[cur_stack_elem]->sign = 0;
-
- return(stack[cur_stack_elem++]);
-}
-
-void pushg(int a)
-{
- if (a < 0) return;
- cur_stack_elem -= a;
- if (cur_stack_elem < 0) cur_stack_elem = 0;
-}
-
-void modg(giant d, giant n)
-/* n becomes n%d. n is arbitrary, but the denominator d must be positive! */
-{
- if (cur_recip == NULL) {
- cur_recip = newgiant(current_max_size);
- cur_den = newgiant(current_max_size);
- gtog(d, cur_den);
- make_recip(d, cur_recip);
- }
- else if (gcompg(d, cur_den)) {
- gtog(d, cur_den);
- make_recip(d, cur_recip);
- }
- modg_via_recip(d, cur_recip, n);
-}
-
-void squareg(giant b)
-/* b becomes b^2. */
-{
- auxmulg(b, b);
-}
-
-void mulg(giant a, giant b)
-/* b becomes a*b. */
-{
- auxmulg(a, b);
-}
-
-void auxmulg(giant a, giant b)
-/* Optimized general multiply, b becomes a*b. Modes are:
-* AUTO_MUL: switch according to empirical speed criteria.
-* GRAMMAR_MUL: force grammar-school algorithm.
-* KARAT_MUL: force Karatsuba divide-conquer method.
-* FFT_MUL: force floating point FFT method. */
-{
- float grammartime;
- int square = (a == b);
- int sizea, sizeb;
-
- switch (mulmode)
- {
- case GRAMMAR_MUL:
- if (square) grammarsquareg(b);
- else grammarmulg(a, b);
- break;
- case FFT_MUL:
- if (square)
- FFTsquareg(b);
- else
- FFTmulg(a, b);
- break;
- case KARAT_MUL:
- if (square) karatsquareg(b);
- else karatmulg(a, b);
- break;
- case AUTO_MUL:
- sizea = abs(a->sign);
- sizeb = abs(b->sign);
- if ((sizea > KARAT_BREAK) && (sizea <= FFT_BREAK) &&
- (sizeb > KARAT_BREAK) && (sizeb <= FFT_BREAK)) {
- if (square) karatsquareg(b);
- else karatmulg(a, b);
-
- }
- else {
- grammartime = (float)sizea;
- grammartime *= (float)sizeb;
- if (grammartime < FFT_BREAK * FFT_BREAK)
- {
- if (square) grammarsquareg(b);
- else grammarmulg(a, b);
- }
- else
- {
- if (square) FFTsquareg(b);
- else FFTmulg(a, b);
- }
- }
- break;
- }
-}
-
-int bitval(giant n, int pos)
-{
- int i = abs(pos) >> 4, c = 1 << (pos & 15);
-
- return (((n->n[i]) & c) != 0);
-}
-
-int bitlen(giant n)
-{
- int b = 16, c = 1 << 15, w;
-
- if (isZero(n))
- return(0);
- w = n->n[abs(n->sign) - 1];
- while ((w&c) == 0)
- {
- b--;
- c >>= 1;
- }
- return (16 * (abs(n->sign) - 1) + b);
-}
-
-void itog(int i, giant g)
-/* The giant g becomes set to the integer value i. */
-{
- unsigned int j = abs(i);
-
- if (i == 0)
- {
- g->sign = 0;
- g->n[0] = 0;
- return;
- }
- g->n[0] = (unsigned short)(j & 0xFFFF);
- j >>= 16;
- if (j)
- {
- g->n[1] = (unsigned short)j;
- g->sign = 2;
- }
- else
- {
- g->sign = 1;
- }
- if (i < 0)
- g->sign = -(g->sign);
-}
-
-void gtog(giant srcgiant, giant destgiant)
-/* destgiant becomes equal to srcgiant. */
-{
- int numbytes = sizeof(int) + abs(srcgiant->sign) * sizeof(short);
-
- memcpy((char *)destgiant, (char *)srcgiant, numbytes);
-}
-
-void make_recip(giant d, giant r)
-/* r becomes the steady-state reciprocal
-* 2^(2b)/d, where b = bit-length of d-1. */
-{
- int b;
- giant tmp, tmp2;
-
- if (isZero(d) || (d->sign < 0))
- {
- exit(SIGN);
- }
- tmp = popg();
- tmp2 = popg();
- itog(1, r);
- subg(r, d);
- b = bitlen(d);
- addg(r, d);
- gshiftleft(b, r);
- gtog(r, tmp2);
- while (1)
- {
- gtog(r, tmp);
- squareg(tmp);
- gshiftright(b, tmp);
- mulg(d, tmp);
- gshiftright(b, tmp);
- addg(r, r);
- subg(tmp, r);
- if (gcompg(r, tmp2) <= 0)
- break;
- gtog(r, tmp2);
- }
- itog(1, tmp);
- gshiftleft(2 * b, tmp);
- gtog(r, tmp2);
- mulg(d, tmp2);
- subg(tmp2, tmp);
- itog(1, tmp2);
- while (tmp->sign < 0)
- {
- subg(tmp2, r);
- addg(d, tmp);
- }
- pushg(2);
-}
-
-void modg_via_recip(giant d, giant r, giant n)
-/* This is the fastest mod of the present collection.
-* n := n % d, where r is the precalculated
-* steady-state reciprocal of d. */
-{
- int s = (bitlen(r) - 1), sign = n->sign;
- giant tmp, tmp2;
-
- if (isZero(d) || (d->sign < 0))
- {
- exit(SIGN);
- }
-
- tmp = popg();
- tmp2 = popg();
-
- n->sign = abs(n->sign);
- while (1)
- {
- gtog(n, tmp); gshiftright(s - 1, tmp);
- mulg(r, tmp);
- gshiftright(s + 1, tmp);
- mulg(d, tmp);
- subg(tmp, n);
- if (gcompg(n, d) >= 0)
- subg(d, n);
- if (gcompg(n, d) < 0)
- break;
- }
- if (sign >= 0)
- goto done;
- if (isZero(n))
- goto done;
- negg(n);
- addg(d, n);
-done:
- pushg(2);
- return;
-}
-
-int gcompg(giant a, giant b)
-/* Returns -1,0,1 if ab, respectively. */
-{
- int sa = a->sign, j, sb = b->sign, va, vb, sgn;
-
- if (sa > sb)
- return(1);
- if (sa < sb)
- return(-1);
- if (sa < 0)
- {
- sa = -sa; /* Take absolute value of sa. */
- sgn = -1;
- }
- else
- {
- sgn = 1;
- }
- for (j = sa - 1; j >= 0; j--)
- {
- va = a->n[j];
- vb = b->n[j];
- if (va > vb)
- return(sgn);
- if (va < vb)
- return(-sgn);
- }
- return(0);
-}
-
-void subg(giant a, giant b)
-/* b := b - a, any signs, any result. */
-{
- int asgn = a->sign, bsgn = b->sign;
-
- if (asgn == 0)
- return;
- if (bsgn == 0)
- {
- gtog(a, b);
- negg(b);
- return;
- }
- if ((asgn < 0) != (bsgn < 0))
- {
- if (bsgn > 0)
- {
- negg(a);
- normal_addg(a, b);
- negg(a);
- return;
- }
- negg(b);
- normal_addg(a, b);
- negg(b);
- return;
- }
- if (bsgn > 0)
- {
- if (gcompg(b, a) >= 0)
- {
- normal_subg(a, b);
- return;
- }
- reverse_subg(a, b);
- negg(b);
- return;
- }
- negg(a);
- negg(b);
- if (gcompg(b, a) >= 0)
- {
- normal_subg(a, b);
- negg(a);
- negg(b);
- return;
- }
- reverse_subg(a, b);
- negg(a);
- return;
-}
-
-void gshiftright(int bits, giant g)
-/* shift g right bits bits. Equivalent to g = g/2^bits. */
-{
- register int j, size = abs(g->sign);
- register unsigned int carry;
- int words = bits >> 4;
- int remain = bits & 15, cremain = (16 - remain);
-
- if (bits == 0)
- return;
- if (isZero(g))
- return;
- if (bits < 0) {
- gshiftleft(-bits, g);
- return;
- }
- if (words >= size) {
- g->sign = 0;
- return;
- }
- if (remain == 0) {
- memmove(g->n, g->n + words, (size - words) * sizeof(short));
- g->sign += (g->sign < 0) ? (words) : (-words);
- }
- else {
- size -= words;
-
- if (size)
- {
- for (j = 0;j < size - 1;++j)
- {
- carry = g->n[j + words + 1] << cremain;
- g->n[j] = (unsigned short)((g->n[j + words] >> remain) | carry);
- }
- g->n[size - 1] = (unsigned short)(g->n[size - 1 + words] >> remain);
- }
-
- if (g->n[size - 1] == 0)
- --size;
-
- if (g->sign > 0)
- g->sign = size;
- else
- g->sign = -size;
- }
-}
-
-void gshiftleft(int bits, giant g)
-/* shift g left bits bits. Equivalent to g = g*2^bits. */
-{
- int rem = bits & 15, crem = 16 - rem, words = bits >> 4;
- int size = abs(g->sign), j, k, sign = gsign(g);
- unsigned short carry, dat;
-
- if (!bits)
- return;
- if (!size)
- return;
- if (bits < 0) {
- gshiftright(-bits, g);
- return;
- }
- if (size + words + 1 > current_max_size) {
- error = OVFLOW;
- exit(error);
- }
- if (rem == 0) {
- memmove(g->n + words, g->n, size * sizeof(short));
- for (j = 0; j < words; j++) g->n[j] = 0;
- g->sign += (g->sign < 0) ? (-words) : (words);
- }
- else {
- k = size + words;
- carry = 0;
- for (j = size - 1; j >= 0; j--) {
- dat = g->n[j];
- g->n[k--] = (unsigned short)((dat >> crem) | carry);
- carry = (unsigned short)(dat << rem);
- }
- do {
- g->n[k--] = carry;
- carry = 0;
- } while (k >= 0);
-
- k = size + words;
- if (g->n[k] == 0)
- --k;
- g->sign = sign * (k + 1);
- }
-}
-
-void addg(giant a, giant b)
-/* b := b + a, any signs any result. */
-{
- int asgn = a->sign, bsgn = b->sign;
-
- if (asgn == 0)
- return;
- if (bsgn == 0)
- {
- gtog(a, b);
- return;
- }
- if ((asgn < 0) == (bsgn < 0))
- {
- if (bsgn > 0)
- {
- normal_addg(a, b);
- return;
- }
- absg(b);
- if (a != b) absg(a);
- normal_addg(a, b);
- negg(b);
- if (a != b) negg(a);
- return;
- }
- if (bsgn > 0)
- {
- negg(a);
- if (gcompg(b, a) >= 0)
- {
- normal_subg(a, b);
- negg(a);
- return;
- }
- reverse_subg(a, b);
- negg(a);
- negg(b);
- return;
- }
- negg(b);
- if (gcompg(b, a) < 0)
- {
- reverse_subg(a, b);
- return;
- }
- normal_subg(a, b);
- negg(b);
- return;
-}
-
-int isZero(giant thegiant)
-/* Returns TR if thegiant == 0. */
-{
- register int count;
- int length = abs(thegiant->sign);
- register unsigned short * numpointer = thegiant->n;
-
- if (length)
- {
- for (count = 0; count < length; ++count, ++numpointer)
- {
- if (*numpointer != 0)
- return(FA);
- }
- }
- return(TR);
-}
-
-void negg(giant g)
-/* g becomes -g. */
-{
- g->sign = -g->sign;
-}
-
-void normal_subg(giant a, giant b)
-/* b := b - a; requires b, a non-negative and b >= a. */
-{
- int j, size = b->sign;
- unsigned int k;
-
- if (a->sign == 0)
- return;
-
- k = 0;
- for (j = 0; j < a->sign; ++j)
- {
- k += 0xffff - a->n[j] + b->n[j];
- b->n[j] = (unsigned short)(k & 0xffff);
- k >>= 16;
- }
- for (j = a->sign; j < size; ++j)
- {
- k += 0xffff + b->n[j];
- b->n[j] = (unsigned short)(k & 0xffff);
- k >>= 16;
- }
-
- if (b->n[0] == 0xffff)
- iaddg(1, b);
- else
- ++b->n[0];
-
- while ((size-- > 0) && (b->n[size] == 0));
-
- b->sign = (b->n[size] == 0) ? 0 : size + 1;
-}
-
-void reverse_subg(giant a, giant b)
-/* b := a - b; requires b, a non-negative and a >= b. */
-{
- int j, size = a->sign;
- unsigned int k;
-
- k = 0;
- for (j = 0; j < b->sign; ++j)
- {
- k += 0xffff - b->n[j] + a->n[j];
- b->n[j] = (unsigned short)(k & 0xffff);
- k >>= 16;
- }
- for (j = b->sign; j < size; ++j)
- {
- k += 0xffff + a->n[j];
- b->n[j] = (unsigned short)(k & 0xffff);
- k >>= 16;
- }
-
- b->sign = size; /* REC, 21 Apr 1996. */
- if (b->n[0] == 0xffff)
- iaddg(1, b);
- else
- ++b->n[0];
-
- while (!b->n[--size]);
-
- b->sign = size + 1;
-}
-
-void iaddg(int i, giant g)
-/* Giant g becomes g + (int)i. */
-{
- int w, j = 0, carry = 0, size = abs(g->sign);
- giant tmp;
-
- if (isZero(g))
- {
- itog(i, g);
- }
- else if (g->sign < 0) {
- tmp = popg();
- itog(i, tmp);
- addg(tmp, g);
- pushg(1);
- return;
- }
- else
- {
- w = g->n[0] + i;
- do
- {
- g->n[j] = (unsigned short)(w & 65535L);
- carry = w >> 16;
- w = g->n[++j] + carry;
- } while ((carry != 0) && (j < size));
- }
- if (carry)
- {
- ++g->sign;
- g->n[size] = (unsigned short)carry;
- }
-}
-
-int gsign(giant g)
-/* Returns the sign of g. */
-{
- if (isZero(g))
- return(0);
- if (g->sign > 0)
- return(1);
- return(-1);
-}
-
-void absg(giant g)
-{
- /* g becomes the absolute value of g. */
- if (g->sign < 0)
- g->sign = -g->sign;
-}
-
-void FFTmulg(giant y, giant x)
-{
- /* x becomes y*x. */
- int lambda, sizex = abs(x->sign), sizey = abs(y->sign);
- int finalsign = gsign(x)*gsign(y);
- register int L;
-
- if ((sizex <= 4) || (sizey <= 4))
- {
- grammarmulg(y, x);
- return;
- }
- L = lpt(sizex + sizey, &lambda);
- if (!z) z = (double *)malloc(MAX_SHORTS * sizeof(double));
- if (!z2) z2 = (double *)malloc(MAX_SHORTS * sizeof(double));
-
- giant_to_double(x, sizex, z, L);
- giant_to_double(y, sizey, z2, L);
- fft_real_to_hermitian(z, L);
- fft_real_to_hermitian(z2, L);
- mul_hermitian(z2, z, L);
- fftinv_hermitian_to_real(z, L);
- addsignal(x, z, L);
- x->sign = finalsign * abs(x->sign);
-}
-
-void FFTsquareg(giant x)
-{
- int j, size = abs(x->sign);
- register int L;
-
- if (size < 4)
- {
- grammarmulg(x, x);
- return;
- }
- L = lpt(size + size, &j);
- if (!z) z = (double *)malloc(MAX_SHORTS * sizeof(double));
- giant_to_double(x, size, z, L);
- fft_real_to_hermitian(z, L);
- square_hermitian(z, L);
- fftinv_hermitian_to_real(z, L);
- addsignal(x, z, L);
- x->sign = abs(x->sign);
-}
-
-void grammarmulg(giant a, giant b)
-/* b becomes a*b. */
-{
- int i, j;
- unsigned int prod, carry = 0;
- int asize = abs(a->sign), bsize = abs(b->sign);
- unsigned short *aptr, *bptr, *destptr;
- unsigned short mult;
- giant scratch = popg();
-
- for (i = 0; i < asize + bsize; ++i)
- {
- scratch->n[i] = 0;
- }
-
- bptr = &(b->n[0]);
- for (i = 0; i < bsize; ++i)
- {
- mult = *(bptr++);
- if (mult)
- {
- carry = 0;
- aptr = &(a->n[0]);
- destptr = &(scratch->n[i]);
- for (j = 0; j < asize; ++j)
- {
- prod = *(aptr++) * mult + *destptr + carry;
- *(destptr++) = (unsigned short)(prod & 0xffff);
- carry = prod >> 16;
- }
- *destptr = (unsigned short)carry;
- }
- }
- bsize += asize;
- if (!carry)
- --bsize;
- scratch->sign = gsign(a)*gsign(b)*bsize;
- gtog(scratch, b);
- pushg(1);
-}
-
-void grammarsquareg(giant a)
-/* a := a^2. */
-{
- unsigned int cur_term;
- unsigned int prod, carry = 0, temp;
- unsigned int asize = abs(a->sign), max = asize * 2 - 1;
- unsigned short *ptr = a->n, *ptr1, *ptr2;
- giant scratch;
-
- if (asize == 0) {
- itog(0, a);
- return;
- }
-
- scratch = popg();
-
- asize--;
-
- temp = *ptr;
- temp *= temp;
- scratch->n[0] = temp;
- carry = temp >> 16;
-
- for (cur_term = 1; cur_term < max; cur_term++) {
- ptr1 = ptr2 = ptr;
- if (cur_term <= asize) {
- ptr2 += cur_term;
- }
- else {
- ptr1 += cur_term - asize;
- ptr2 += asize;
- }
- prod = carry & 0xFFFF;
- carry >>= 16;
- while (ptr1 < ptr2) {
- temp = *ptr1++ * *ptr2--;
- prod += (temp << 1) & 0xFFFF;
- carry += (temp >> 15);
- }
- if (ptr1 == ptr2) {
- temp = *ptr1;
- temp *= temp;
- prod += temp & 0xFFFF;
- carry += (temp >> 16);
- }
- carry += prod >> 16;
- scratch->n[cur_term] = (unsigned short)(prod);
- }
- if (carry) {
- scratch->n[cur_term] = carry;
- scratch->sign = cur_term + 1;
- }
- else scratch->sign = cur_term;
-
- gtog(scratch, a);
- pushg(1);
-}
-
-/* Improved Karatsuba routines from A. Powell, improvements by G. Woltman. */
-void karatmulg(giant x, giant y)
-/* y becomes x*y. */
-{
- int s = abs(x->sign), t = abs(y->sign), w, bits,
- sg = gsign(x)*gsign(y);
- giant a, b, c, d, e, f;
-
- if ((s <= KARAT_BREAK) || (t <= KARAT_BREAK)) {
- grammarmulg(x, y);
- return;
- }
- w = (s + t + 2) / 4; bits = 16 * w;
- a = popg(); b = popg(); c = popg();
- d = popg(); e = popg(); f = popg();
- gtog(x, a); absg(a); if (w <= s) { a->sign = w; justg(a); }
- gtog(x, b); absg(b);
- gshiftright(bits, b);
- gtog(y, c); absg(c); if (w <= t) { c->sign = w; justg(c); }
- gtog(y, d); absg(d);
- gshiftright(bits, d);
- gtog(a, e); normal_addg(b, e); /* e := (a + b) */
- gtog(c, f); normal_addg(d, f); /* f := (c + d) */
- karatmulg(e, f); /* f := (a + b)(c + d) */
- karatmulg(c, a); /* a := a c */
- karatmulg(d, b); /* b := b d */
- normal_subg(a, f);
- /* f := (a + b)(c + d) - a c */
- normal_subg(b, f);
- /* f := (a + b)(c + d) - a c - b d */
- gshiftleft(bits, b);
- normal_addg(f, b);
- gshiftleft(bits, b);
- normal_addg(a, b);
- gtog(b, y); y->sign *= sg;
- pushg(6);
-
- return;
-}
-
-void karatsquareg(giant x)
-/* x becomes x^2. */
-{
- int s = abs(x->sign), w, bits;
- giant a, b, c;
-
- if (s <= KARAT_BREAK) {
- grammarsquareg(x);
- return;
- }
- w = (s + 1) / 2; bits = 16 * w;
- a = popg(); b = popg(); c = popg();
- gtog(x, a); a->sign = w; justg(a);
- gtog(x, b); absg(b);
- gshiftright(bits, b);
- gtog(a, c); normal_addg(b, c);
- karatsquareg(c);
- karatsquareg(a);
- karatsquareg(b);
- normal_subg(b, c);
- normal_subg(a, c);
- gshiftleft(bits, b);
- normal_addg(c, b);
- gshiftleft(bits, b);
- normal_addg(a, b);
- gtog(b, x);
- pushg(3);
-
- return;
-}
-
-void justg(giant x)
-{
- int s = x->sign, sg = 1;
-
- if (s < 0) {
- sg = -1;
- s = -s;
- }
- --s;
- while (x->n[s] == 0) {
- --s;
- if (s < 0) break;
- }
- x->sign = sg * (s + 1);
-}
-
-void normal_addg(giant a, giant b)
-/* b := a + b, both a,b assumed non-negative. */
-{
- int carry = 0;
- int asize = a->sign, bsize = b->sign;
- long k;
- int j = 0;
- unsigned short *aptr = a->n, *bptr = b->n;
-
- if (asize < bsize)
- {
- for (j = 0; j < asize; j++)
- {
- k = *aptr++ + *bptr + carry;
- carry = 0;
- if (k >= 65536L)
- {
- k -= 65536L;
- ++carry;
- }
- *bptr++ = (unsigned short)k;
- }
- for (j = asize; j < bsize; j++)
- {
- k = *bptr + carry;
- carry = 0;
- if (k >= 65536L)
- {
- k -= 65536L;
- ++carry;
- }
- *bptr++ = (unsigned short)k;
- }
- }
- else
- {
- for (j = 0; j < bsize; j++)
- {
- k = *aptr++ + *bptr + carry;
- carry = 0;
- if (k >= 65536L)
- {
- k -= 65536L;
- ++carry;
- }
- *bptr++ = (unsigned short)k;
- }
- for (j = bsize; j < asize; j++)
- {
- k = *aptr++ + carry;
- carry = 0;
- if (k >= 65536L)
- {
- k -= 65536L;
- ++carry;
- }
- *bptr++ = (unsigned short)k;
- }
- }
- if (carry)
- {
- *bptr = 1; ++j;
- }
- b->sign = j;
-}
-
-void addsignal(giant x, double* z, int n)
-{
- register int j, k, m, car, last;
- register double f, g, err;
-
- maxFFTerror = 0;
- last = 0;
- for (j = 0;j < n;j++)
- {
- f = gfloor(z[j] + 0.5);
- if (f != 0.0) last = j;
- if (checkFFTerror)
- {
- err = fabs(f - z[j]);
- if (err > maxFFTerror)
- maxFFTerror = err;
- }
- z[j] = 0;
- k = 0;
- do
- {
- g = gfloor(f*TWOM16);
- z[j + k] += f - g * TWO16;
- ++k;
- f = g;
- } while (f != 0.0);
- }
- car = 0;
- for (j = 0;j < last + 1;j++)
- {
- m = (int)(z[j] + car);
- x->n[j] = (unsigned short)(m & 0xffff);
- car = (m >> 16);
- }
- if (car)
- x->n[j] = (unsigned short)car;
- else
- --j;
-
- while (!(x->n[j])) --j;
-
- x->sign = j + 1;
-}
-
-void fftinv_hermitian_to_real(double* z, int n)
-/* Input is {Re(z^[0]),...,Re(z^[n/2),Im(z^[n/2-1]),...,Im(z^[1]).
-* This is a decimation-in-frequency, split-radix algorithm.
-*/
-{
- register double cc1, ss1, cc3, ss3;
- register int is, id, i0, i1, i2, i3, i4, i5, i6, i7, i8,
- a, a3, b, b3, nminus = n - 1, dil, expand;
- register double *x, e;
- int nn = n >> 1;
- double t1, t2, t3, t4, t5;
- int n2, n4, n8, i, j;
-
- init_sinCos(n);
- expand = cur_run / n;
- x = z - 1;
- n2 = n << 1;
- while (nn >>= 1)
- {
- is = 0;
- id = n2;
- n2 >>= 1;
- n4 = n2 >> 2;
- n8 = n4 >> 1;
- do
- {
- for (i = is;i < n;i += id)
- {
- i1 = i + 1;
- i2 = i1 + n4;
- i3 = i2 + n4;
- i4 = i3 + n4;
- t1 = x[i1] - x[i3];
- x[i1] += x[i3];
- x[i2] += x[i2];
- x[i3] = t1 - 2.0*x[i4];
- x[i4] = t1 + 2.0*x[i4];
- if (n4 == 1)
- continue;
- i1 += n8;
- i2 += n8;
- i3 += n8;
- i4 += n8;
- t1 = (x[i2] - x[i1])*SQRTHALF;
- t2 = (x[i4] + x[i3])*SQRTHALF;
- x[i1] += x[i2];
- x[i2] = x[i4] - x[i3];
- x[i3] = -2.0*(t2 + t1);
- x[i4] = 2.0*(t1 - t2);
- }
- is = (id << 1) - n2;
- id <<= 2;
- } while (is < n - 1);
- dil = n / n2;
- a = dil;
- for (j = 2;j <= n8;j++)
- {
- a3 = (a + (a << 1))&nminus;
- b = a * expand;
- b3 = a3 * expand;
- cc1 = s_cos(b);
- ss1 = s_sin(b);
- cc3 = s_cos(b3);
- ss3 = s_sin(b3);
- a = (a + dil)&nminus;
- is = 0;
- id = n2 << 1;
- do
- {
- for (i = is;i < n;i += id)
- {
- i1 = i + j;
- i2 = i1 + n4;
- i3 = i2 + n4;
- i4 = i3 + n4;
- i5 = i + n4 - j + 2;
- i6 = i5 + n4;
- i7 = i6 + n4;
- i8 = i7 + n4;
- t1 = x[i1] - x[i6];
- x[i1] += x[i6];
- t2 = x[i5] - x[i2];
- x[i5] += x[i2];
- t3 = x[i8] + x[i3];
- x[i6] = x[i8] - x[i3];
- t4 = x[i4] + x[i7];
- x[i2] = x[i4] - x[i7];
- t5 = t1 - t4;
- t1 += t4;
- t4 = t2 - t3;
- t2 += t3;
- x[i3] = t5 * cc1 + t4 * ss1;
- x[i7] = -t4 * cc1 + t5 * ss1;
- x[i4] = t1 * cc3 - t2 * ss3;
- x[i8] = t2 * cc3 + t1 * ss3;
- }
- is = (id << 1) - n2;
- id <<= 2;
- } while (is < n - 1);
- }
- }
- is = 1;
- id = 4;
- do
- {
- for (i0 = is;i0 <= n;i0 += id)
- {
- i1 = i0 + 1;
- e = x[i0];
- x[i0] = e + x[i1];
- x[i1] = e - x[i1];
- }
- is = (id << 1) - 1;
- id <<= 2;
- } while (is < n);
- scramble_real(z, n);
- e = 1 / (double)n;
- for (i = 0;i < n;i++)
- {
- z[i] *= e;
- }
-}
-
-void mul_hermitian(double* a, double* b, int n)
-{
- register int k, half = n >> 1;
- register double aa, bb, am, bm;
-
- b[0] *= a[0];
- b[half] *= a[half];
- for (k = 1;k < half;k++)
- {
- aa = a[k];
- bb = b[k];
- am = a[n - k];
- bm = b[n - k];
- b[k] = aa * bb - am * bm;
- b[n - k] = aa * bm + am * bb;
- }
-}
-
-void square_hermitian(double* b, int n)
-{
- register int k, half = n >> 1;
- register double c, d;
-
- b[0] *= b[0];
- b[half] *= b[half];
- for (k = 1;k < half;k++)
- {
- c = b[k];
- d = b[n - k];
- b[n - k] = 2.0*c*d;
- b[k] = (c + d)*(c - d);
- }
-}
-
-void fft_real_to_hermitian(double* z, int n)
-/* Output is {Re(z^[0]),...,Re(z^[n/2),Im(z^[n/2-1]),...,Im(z^[1]).
-* This is a decimation-in-time, split-radix algorithm.
-*/
-{
- register double cc1, ss1, cc3, ss3;
- register int is, id, i0, i1, i2, i3, i4, i5, i6, i7, i8,
- a, a3, b, b3, nminus = n - 1, dil, expand;
- register double *x, e;
- int nn = n >> 1;
- double t1, t2, t3, t4, t5, t6;
- register int n2, n4, n8, i, j;
-
- init_sinCos(n);
- expand = cur_run / n;
- scramble_real(z, n);
- x = z - 1; /* FORTRAN compatibility. */
- is = 1;
- id = 4;
- do
- {
- for (i0 = is;i0 <= n;i0 += id)
- {
- i1 = i0 + 1;
- e = x[i0];
- x[i0] = e + x[i1];
- x[i1] = e - x[i1];
- }
- is = (id << 1) - 1;
- id <<= 2;
- } while (is < n);
-
- n2 = 2;
- while (nn >>= 1)
- {
- n2 <<= 1;
- n4 = n2 >> 2;
- n8 = n2 >> 3;
- is = 0;
- id = n2 << 1;
- do
- {
- for (i = is;i < n;i += id)
- {
- i1 = i + 1;
- i2 = i1 + n4;
- i3 = i2 + n4;
- i4 = i3 + n4;
- t1 = x[i4] + x[i3];
- x[i4] -= x[i3];
- x[i3] = x[i1] - t1;
- x[i1] += t1;
- if (n4 == 1)
- continue;
- i1 += n8;
- i2 += n8;
- i3 += n8;
- i4 += n8;
- t1 = (x[i3] + x[i4])*SQRTHALF;
- t2 = (x[i3] - x[i4])*SQRTHALF;
- x[i4] = x[i2] - t1;
- x[i3] = -x[i2] - t1;
- x[i2] = x[i1] - t2;
- x[i1] += t2;
- }
- is = (id << 1) - n2;
- id <<= 2;
- } while (is < n);
- dil = n / n2;
- a = dil;
- for (j = 2;j <= n8;j++)
- {
- a3 = (a + (a << 1))&nminus;
- b = a * expand;
- b3 = a3 * expand;
- cc1 = s_cos(b);
- ss1 = s_sin(b);
- cc3 = s_cos(b3);
- ss3 = s_sin(b3);
- a = (a + dil)&nminus;
- is = 0;
- id = n2 << 1;
- do
- {
- for (i = is;i < n;i += id)
- {
- i1 = i + j;
- i2 = i1 + n4;
- i3 = i2 + n4;
- i4 = i3 + n4;
- i5 = i + n4 - j + 2;
- i6 = i5 + n4;
- i7 = i6 + n4;
- i8 = i7 + n4;
- t1 = x[i3] * cc1 + x[i7] * ss1;
- t2 = x[i7] * cc1 - x[i3] * ss1;
- t3 = x[i4] * cc3 + x[i8] * ss3;
- t4 = x[i8] * cc3 - x[i4] * ss3;
- t5 = t1 + t3;
- t6 = t2 + t4;
- t3 = t1 - t3;
- t4 = t2 - t4;
- t2 = x[i6] + t6;
- x[i3] = t6 - x[i6];
- x[i8] = t2;
- t2 = x[i2] - t3;
- x[i7] = -x[i2] - t3;
- x[i4] = t2;
- t1 = x[i1] + t5;
- x[i6] = x[i1] - t5;
- x[i1] = t1;
- t1 = x[i5] + t4;
- x[i5] -= t4;
- x[i2] = t1;
- }
- is = (id << 1) - n2;
- id <<= 2;
- } while (is < n);
- }
- }
-}
-
-void giant_to_double(giant x, int sizex, double* z, int L)
-{
- register int j;
-
- for (j = sizex;j < L;j++)
- {
- z[j] = 0.0;
- }
- for (j = 0;j < sizex;j++)
- {
- z[j] = x->n[j];
- }
-}
-
-int lpt(int n, int* lambda)
-/* Returns least power of two greater than n. */
-{
- register int i = 1;
-
- *lambda = 0;
- while (i < n)
- {
- i <<= 1;
- ++(*lambda);
- }
- return(i);
-}
-
-double gfloor(double f)
-{
- return floor(f);
-}
-
-void init_sinCos(int n)
-{
- int j;
- double e = TWOPI / n;
-
- if (n <= cur_run)
- return;
- cur_run = n;
- if (sinCos)
- free(sinCos);
- sinCos = (double *)malloc(sizeof(double)*(1 + (n >> 2)));
- for (j = 0;j <= (n >> 2);j++)
- {
- sinCos[j] = sin(e*j);
- }
-}
-
-double s_cos(int n)
-{
- int quart = (cur_run >> 2);
-
- if (n < quart)
- return(s_sin(n + quart));
- return(-s_sin(n - quart));
-}
-
-double s_sin(int n)
-{
- int seg = n / (cur_run >> 2);
-
- switch (seg)
- {
- case 0: return(sinCos[n]);
- case 1: return(sinCos[(cur_run >> 1) - n]);
- case 2: return(-sinCos[n - (cur_run >> 1)]);
- case 3: return(-sinCos[cur_run - n]);
- }
- return 0;
-}
-
-void scramble_real(double* x, int n)
-{
- register int i, j, k;
- register double tmp;
-
- for (i = 0, j = 0;i < n - 1;i++)
- {
- if (i < j)
- {
- tmp = x[j];
- x[j] = x[i];
- x[i] = tmp;
- }
- k = n / 2;
- while (k <= j)
- {
- j -= k;
- k >>= 1;
- }
- j += k;
- }
-}
diff --git a/src/common/crypto/EmuRsa.h b/src/common/crypto/EmuRsa.h
index 01204a3a7..5acd2b0a6 100644
--- a/src/common/crypto/EmuRsa.h
+++ b/src/common/crypto/EmuRsa.h
@@ -17,7 +17,7 @@
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
-// * (c) 2018 ergo720
+// * (c) 2018-2019 ergo720
// *
// * All rights reserved
// *
@@ -28,27 +28,26 @@
#pragma pack(4)
-typedef struct _RSA_PUBLIC_KEY
+typedef union _RSA_PUBLIC_KEY
{
- union
- {
- unsigned char Default[284];
- struct {
- char Magic[4]; // "RSA1"
- unsigned int Bloblen; // 264 (Modulus + Exponent + Modulussize)
- unsigned char Bitlen[4]; // 2048
- unsigned int ModulusSize; // 255 (bytes in the Modulus)
- unsigned char Exponent[4];
- unsigned char Modulus[256]; // Bit endian style
- unsigned char Unknown[8]; // ?
- }KeyData;
- };
+ unsigned char Default[284];
+ struct {
+ char Magic[4]; // "RSA1"
+ unsigned int Bloblen; // 264 (Modulus + Exponent + Modulussize)
+ unsigned char Bitlen[4]; // 2048
+ unsigned int ModulusSize; // 255 (bytes in the Modulus)
+ unsigned char Exponent[4]; // Public exponent
+ unsigned char Modulus[256]; // Bit endian style
+ unsigned char Unknown[8]; // ?
+ }KeyData;
} RSA_PUBLIC_KEY;
#pragma pack()
-void ModExp(unsigned char* a_number, const unsigned char* b_number, unsigned int b_len, const unsigned char* c_number, unsigned int c_len, const unsigned char* d_number, unsigned int d_len);
-void RSAdecrypt(const unsigned char* c_number, unsigned char* cryptbuffer, RSA_PUBLIC_KEY key);
-bool Verifyhash(const unsigned char* hash, const unsigned char* decryptBuffer, RSA_PUBLIC_KEY key);
+void init_tom_lib();
+bool xbox_exp_mod(unsigned char* pA, const unsigned char* pB, const unsigned char* pC, const unsigned char* pD,
+ size_t b_size, size_t c_size, size_t d_size);
+bool xbox_rsa_public(const unsigned char* in_buf, unsigned char* out_buf, RSA_PUBLIC_KEY key);
+bool verify_hash(const unsigned char* hash, const unsigned char* decryptBuffer, RSA_PUBLIC_KEY key);
#endif
diff --git a/src/common/util/CxbxUtil.cpp b/src/common/util/CxbxUtil.cpp
index a29a79af7..19b7ef8d2 100644
--- a/src/common/util/CxbxUtil.cpp
+++ b/src/common/util/CxbxUtil.cpp
@@ -26,7 +26,34 @@
// ******************************************************************
// Acknowledgment: some of the functions present are from XQEMU (GPLv2)
-// https://xqemu.com/
+// https://xqemu.com/
+
+// swap_endianess is extracted from mbedtls_mpi_read_binary used in the file bignum.h of ReactOS
+
+/**
+* \file bignum.h
+*
+* \brief Multi-precision integer library
+*
+* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+* SPDX-License-Identifier: GPL-2.0
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* This file is part of mbed TLS (https://tls.mbed.org)
+*/
// The intent of this file is to add general functions which are not kernel specific (for those CxbxKrnl.h should be used instead)
@@ -235,3 +262,19 @@ void unix2dos(std::string& string)
position += 2;
}
}
+
+void swap_endianess(const unsigned char* in_buf, unsigned char* out_buf, size_t size)
+{
+ size_t i, j, n;
+ uint32_t* out_buf_uint = (uint32_t*)out_buf;
+
+ memset(out_buf_uint, 0, size);
+
+ for (n = 0; n < size; n++)
+ if (in_buf[n] != 0)
+ break;
+
+ for (i = size, j = 0; i > n; i--, j++) {
+ out_buf_uint[j / 4] |= ((uint32_t)in_buf[i - 1]) << ((j % 4) << 3);
+ }
+}
diff --git a/src/common/util/CxbxUtil.h b/src/common/util/CxbxUtil.h
index b113cfa92..b4ec0875e 100644
--- a/src/common/util/CxbxUtil.h
+++ b/src/common/util/CxbxUtil.h
@@ -85,5 +85,7 @@ static uint32 RoundUp(uint32 dwValue, uint32 dwMult)
return dwValue + dwMult - remainder;
}
+
+void swap_endianess(const unsigned char* in_buf, unsigned char* out_buf, size_t size);
#endif
diff --git a/src/common/xbe/Xbe.cpp b/src/common/xbe/Xbe.cpp
index 6dd19bdf0..20d1f6e48 100644
--- a/src/common/xbe/Xbe.cpp
+++ b/src/common/xbe/Xbe.cpp
@@ -780,12 +780,14 @@ bool Xbe::CheckXbeSignature()
{
// Workaround for nxdk (and possibly oxdk?): xbe's built with nxdk have the digital signature set to all zeros, which will lead
// to a crash during its decryption in RSAdecrypt. Detect this condition and skip the check if true
- {
- UCHAR Dummy[256] = { 0 };
- if (memcmp(m_Header.pbDigitalSignature, Dummy, 256) == 0) {
- return false;
- }
- }
+ //{
+ // UCHAR Dummy[256] = { 0 };
+ // if (memcmp(m_Header.pbDigitalSignature, Dummy, 256) == 0) {
+ // return false;
+ // }
+ //}
+
+ init_tom_lib();
DWORD HeaderDigestSize = m_Header.dwSizeofHeaders - (sizeof(m_Header.dwMagic) + sizeof(m_Header.pbDigitalSignature));
UCHAR SHADigest[A_SHA_DIGEST_LEN];
@@ -800,11 +802,12 @@ bool Xbe::CheckXbeSignature()
// TODO: memcpy(keys[3].Default, (void*)xboxkrnl::XePublicKeyDataDebug, 284);
for (int i = 0; i < keys.size(); i++) {
- RSAdecrypt(m_Header.pbDigitalSignature, crypt_buffer, keys[i]);
- if (Verifyhash(SHADigest, crypt_buffer, keys[i])) {
- // Load the successful key into XboxKrnl::XePublicKeyData for application use
- memcpy(xboxkrnl::XePublicKeyData, keys[i].Default, 284);
- return true; // success
+ if (xbox_rsa_public(m_Header.pbDigitalSignature, crypt_buffer, keys[i])) {
+ if (verify_hash(SHADigest, crypt_buffer, keys[i])) {
+ // Load the successful key into XboxKrnl::XePublicKeyData for application use
+ memcpy(xboxkrnl::XePublicKeyData, keys[i].Default, 284);
+ return true; // success
+ }
}
}
diff --git a/src/core/kernel/exports/EmuKrnlXc.cpp b/src/core/kernel/exports/EmuKrnlXc.cpp
index 2d305ab61..fe2ff2ca0 100644
--- a/src/core/kernel/exports/EmuKrnlXc.cpp
+++ b/src/core/kernel/exports/EmuKrnlXc.cpp
@@ -21,7 +21,8 @@
// *
// * (c) 2002-2003 Aaron Robinson
// * (c) 2016 Patrick van Logchem
-// * (c) 2019 Jannik Vogel
+// * (c) 2019 Jannik Vogel
+// * (c) 2018-2019 ergo720
// *
// * All rights reserved
// *
@@ -213,13 +214,13 @@ xboxkrnl::ULONG NTAPI JumpedModExp
xboxkrnl::LPDWORD pD,
xboxkrnl::ULONG dwN
)
-{
- ULONG ret = 1;
-
+{
unsigned int len = dwN * 4;
- ModExp((unsigned char*)pA, (const unsigned char*)pB, len, (const unsigned char*)pC, len, (const unsigned char*)pD, len);
+ if (xbox_exp_mod((unsigned char*)pA, (const unsigned char*)pB, (const unsigned char*)pC, (const unsigned char*)pD, len, len, len)) {
+ return 1;
+ }
- return ret;
+ return 0;
}
xboxkrnl::VOID NTAPI JumpedDESKeyParity