diff options
Diffstat (limited to 'libs/tgl/src/mtproto-utils.c')
-rw-r--r-- | libs/tgl/src/mtproto-utils.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/libs/tgl/src/mtproto-utils.c b/libs/tgl/src/mtproto-utils.c new file mode 100644 index 0000000000..481bff6371 --- /dev/null +++ b/libs/tgl/src/mtproto-utils.c @@ -0,0 +1,178 @@ +#include "config.h" +#include <openssl/bn.h> +#include "tgl.h" +#include "tools.h" + +#if !defined(HAVE___BUILTIN_BSWAP32) && !defined(__FreeBSD__) && !defined(__OpenBSD__) +static inline unsigned __builtin_bswap32(unsigned x) { + return ((x << 24) & 0xff000000) | + ((x << 8) & 0x00ff0000) | + ((x >> 8) & 0x0000ff00) | + ((x >> 24) & 0x000000ff); +} +#endif + +static unsigned long long gcd (unsigned long long a, unsigned long long b) { + return b ? gcd (b, a % b) : a; +} + +static int check_prime (struct tgl_state *TLS, BIGNUM *p) { + int r = BN_is_prime (p, BN_prime_checks, 0, TLS->BN_ctx, 0); + ensure (r >= 0); + return r; +} + + +// Complete set of checks see at https://core.telegram.org/mtproto/security_guidelines + + +// Checks that (p,g) is acceptable pair for DH +int tglmp_check_DH_params (struct tgl_state *TLS, BIGNUM *p, int g) { + if (g < 2 || g > 7) { return -1; } + if (BN_num_bits (p) != 2048) { return -1; } + + BIGNUM *t = BN_new (); + + BIGNUM *dh_g = BN_new (); + + ensure (BN_set_word (dh_g, 4 * g)); + ensure (BN_mod (t, p, dh_g, TLS->BN_ctx)); + int x = BN_get_word (t); + assert (x >= 0 && x < 4 * g); + + BN_free (dh_g); + + int res = 0; + switch (g) { + case 2: + if (x != 7) { res = -1; } + break; + case 3: + if (x % 3 != 2) { res = -1; } + break; + case 4: + break; + case 5: + if (x % 5 != 1 && x % 5 != 4) { res = -1; } + break; + case 6: + if (x != 19 && x != 23) { res = -1; } + break; + case 7: + if (x % 7 != 3 && x % 7 != 5 && x % 7 != 6) { res = -1; } + break; + } + + if (res < 0 || !check_prime (TLS, p)) { + BN_free (t); + return -1; + } + + BIGNUM *b = BN_new (); + ensure (BN_set_word (b, 2)); + ensure (BN_div (t, 0, p, b, TLS->BN_ctx)); + if (!check_prime (TLS, t)) { + res = -1; + } + BN_free (b); + BN_free (t); + return res; +} + +// checks that g_a is acceptable for DH +int tglmp_check_g_a (struct tgl_state *TLS, BIGNUM *p, BIGNUM *g_a) { + if (BN_num_bytes (g_a) > 256) { + return -1; + } + if (BN_num_bits (g_a) < 2048 - 64) { + return -1; + } + if (BN_cmp (p, g_a) <= 0) { + return -1; + } + + BIGNUM *dif = BN_new (); + BN_sub (dif, p, g_a); + if (BN_num_bits (dif) < 2048 - 64) { + BN_free (dif); + return -1; + } + BN_free (dif); + return 0; +} + +static unsigned long long BN2ull (BIGNUM *b) { + if (sizeof (BN_ULONG) == 8) { + return BN_get_word (b); + } else { + unsigned int tmp[2]; + memset (tmp, 0, 8); + BN_bn2bin (b, (void *)tmp); + return __builtin_bswap32 (tmp[0]) * (1ll << 32) | __builtin_bswap32 (tmp[1]); + } +} + +static void ull2BN (BIGNUM *b, unsigned long long val) { + if (sizeof (BN_ULONG) == 8 || val < (1ll << 32)) { + BN_set_word (b, val); + } else { + unsigned int tmp[2]; + tmp[0] = __builtin_bswap32 (val >> 32); + tmp[1] = __builtin_bswap32 ((unsigned)val); + BN_bin2bn ((void *)tmp, 8, b); + } +} + +int bn_factorize (BIGNUM *pq, BIGNUM *p, BIGNUM *q) { + // Should work in any case + // Rewrite this code + unsigned long long what = BN2ull (pq); + + int it = 0; + + unsigned long long g = 0; + int i; + for (i = 0; i < 3 || it < 1000; i++) { + int q = ((lrand48() & 15) + 17) % what; + unsigned long long x = (long long)lrand48 () % (what - 1) + 1, y = x; + int lim = 1 << (i + 18); + int j; + for (j = 1; j < lim; j++) { + ++it; + unsigned long long a = x, b = x, c = q; + while (b) { + if (b & 1) { + c += a; + if (c >= what) { + c -= what; + } + } + a += a; + if (a >= what) { + a -= what; + } + b >>= 1; + } + x = c; + unsigned long long z = x < y ? what + x - y : x - y; + g = gcd (z, what); + if (g != 1) { + break; + } + if (!(j & (j - 1))) { + y = x; + } + } + if (g > 1 && g < what) break; + } + + assert (g > 1 && g < what); + unsigned long long p1 = g; + unsigned long long p2 = what / g; + if (p1 > p2) { + unsigned long long t = p1; p1 = p2; p2 = t; + } + ull2BN (p, p1); + ull2BN (q, p2); + return 0; +} |