Browse Source

Use crypto.getRandomValues() everywhere

master
Eduard Kuzmenko 3 years ago
parent
commit
37da386b9c
  1. 14
      src/helpers/random.ts
  2. 4
      src/lib/appManagers/appStateManager.ts
  3. 6
      src/lib/crypto/crypto_utils.ts
  4. 4
      src/lib/mtproto/apiFileManager.ts
  5. 9
      src/lib/mtproto/bin_utils.ts
  6. 6
      src/lib/mtproto/networker.ts
  7. 4
      src/lib/mtproto/singleInstance.ts
  8. 4
      src/lib/mtproto/timeManager.ts
  9. 4
      src/lib/mtproto/transports/padded.ts
  10. 48
      src/vendor/leemon.ts

14
src/helpers/random.ts

@ -4,11 +4,17 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE * https://github.com/morethanwords/tweb/blob/master/LICENSE
*/ */
export function nextRandomInt(maxValue: number) { const arrays = {
return Math.floor(Math.random() * maxValue); 8: new Uint8Array(1),
16: new Uint16Array(1),
32: new Uint32Array(1),
};
export function nextRandomUint(bits: 8 | 16 | 32) {
const array = arrays[bits];
crypto.getRandomValues(array);
return array[0];
} }
export function randomLong() { export function randomLong() {
return '' + nextRandomInt(0xFFFFFFFF) + nextRandomInt(0xFFFFFF); return '' + nextRandomUint(32) + nextRandomUint(32);
//return '' + parseInt(nextRandomInt(0xFFFFFFFF).toString(16) + nextRandomInt(0xFFFFFFFF).toString(16), 16);
} }

4
src/lib/appManagers/appStateManager.ts

@ -22,7 +22,7 @@ import { Chat } from '../../layer';
import { isMobile } from '../../helpers/userAgent'; import { isMobile } from '../../helpers/userAgent';
import DATABASE_STATE from '../../config/databases/state'; import DATABASE_STATE from '../../config/databases/state';
import sessionStorage from '../sessionStorage'; import sessionStorage from '../sessionStorage';
import { nextRandomInt } from '../../helpers/random'; import { nextRandomUint } from '../../helpers/random';
const REFRESH_EVERY = 24 * 60 * 60 * 1000; // 1 day const REFRESH_EVERY = 24 * 60 * 60 * 1000; // 1 day
//const REFRESH_EVERY_WEEK = 24 * 60 * 60 * 1000 * 7; // 7 days //const REFRESH_EVERY_WEEK = 24 * 60 * 60 * 1000 * 7; // 7 days
@ -156,7 +156,7 @@ export const STATE_INIT: State = {
}, },
keepSigned: true, keepSigned: true,
chatContextMenuHintWasShown: false, chatContextMenuHintWasShown: false,
stateId: nextRandomInt(0xFFFFFFFF) stateId: nextRandomUint(32)
}; };
const ALL_KEYS = Object.keys(STATE_INIT) as any as Array<keyof State>; const ALL_KEYS = Object.keys(STATE_INIT) as any as Array<keyof State>;

6
src/lib/crypto/crypto_utils.ts

@ -22,7 +22,7 @@ import {str2bigInt, bpe, equalsInt, greater,
import { addPadding } from '../mtproto/bin_utils'; import { addPadding } from '../mtproto/bin_utils';
import { bytesToWordss, bytesFromWordss, bytesToHex, bytesFromHex, convertToUint8Array } from '../../helpers/bytes'; import { bytesToWordss, bytesFromWordss, bytesToHex, bytesFromHex, convertToUint8Array } from '../../helpers/bytes';
import { nextRandomInt } from '../../helpers/random'; import { nextRandomUint } from '../../helpers/random';
import type { RSAPublicKeyHex } from '../mtproto/rsaKeysManager'; import type { RSAPublicKeyHex } from '../mtproto/rsaKeysManager';
const subtle = typeof(window) !== 'undefined' && 'crypto' in window ? window.crypto.subtle : self.crypto.subtle; const subtle = typeof(window) !== 'undefined' && 'crypto' in window ? window.crypto.subtle : self.crypto.subtle;
@ -200,8 +200,8 @@ export function pqPrimeLeemon(what: number[]): [Uint8Array, Uint8Array, number]
var y = new Array(minLen); var y = new Array(minLen);
for(i = 0; i < 3; ++i) { for(i = 0; i < 3; ++i) {
q = (nextRandomInt(128) & 15) + 17; q = (nextRandomUint(8) & 15) + 17;
copyInt_(x, nextRandomInt(1000000000) + 1); copyInt_(x, nextRandomUint(32) + 1);
copy_(y, x); copy_(y, x);
lim = 1 << (i + 18); lim = 1 << (i + 18);

4
src/lib/mtproto/apiFileManager.ts

@ -16,7 +16,7 @@ import { readBlobAsArrayBuffer } from "../../helpers/blob";
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise"; import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
import { notifyAll, notifySomeone } from "../../helpers/context"; import { notifyAll, notifySomeone } from "../../helpers/context";
import { getFileNameByLocation } from "../../helpers/fileName"; import { getFileNameByLocation } from "../../helpers/fileName";
import { nextRandomInt } from "../../helpers/random"; import { randomLong } from "../../helpers/random";
import { InputFile, InputFileLocation, UploadFile } from "../../layer"; import { InputFile, InputFileLocation, UploadFile } from "../../layer";
import { DcId, WorkerTaskVoidTemplate } from "../../types"; import { DcId, WorkerTaskVoidTemplate } from "../../types";
import CacheStorageController from "../cacheStorage"; import CacheStorageController from "../cacheStorage";
@ -524,7 +524,7 @@ export class ApiFileManager {
const activeDelta = this.getDelta(partSize); const activeDelta = this.getDelta(partSize);
const totalParts = Math.ceil(fileSize / partSize); const totalParts = Math.ceil(fileSize / partSize);
const fileId: [number, number] = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]; const fileId = randomLong();
let _part = 0; let _part = 0;

9
src/lib/mtproto/bin_utils.ts

@ -11,7 +11,6 @@
import { bufferConcats } from '../../helpers/bytes'; import { bufferConcats } from '../../helpers/bytes';
import { add_, bigInt2str, cmp, leftShift_, str2bigInt } from '../../vendor/leemon'; import { add_, bigInt2str, cmp, leftShift_, str2bigInt } from '../../vendor/leemon';
import { nextRandomInt } from '../../helpers/random';
/// #if !MTPROTO_WORKER /// #if !MTPROTO_WORKER
// @ts-ignore // @ts-ignore
@ -141,15 +140,13 @@ export function addPadding<T extends number[] | ArrayBuffer | Uint8Array>(
const needPadding = blockSizeAsTotalLength ? blockSize - len : blockSize - (len % blockSize); const needPadding = blockSizeAsTotalLength ? blockSize - len : blockSize - (len % blockSize);
if(needPadding > 0 && needPadding < blockSize) { if(needPadding > 0 && needPadding < blockSize) {
////console.log('addPadding()', len, blockSize, needPadding); ////console.log('addPadding()', len, blockSize, needPadding);
const padding: number[] = new Array(needPadding); const padding = new Uint8Array(needPadding);
if(zeroes) { if(zeroes) {
for(let i = 0; i < needPadding; ++i) { for(let i = 0; i < needPadding; ++i) {
padding[i] = 0; padding[i] = 0;
} }
} else { } else {
for(let i = 0; i < needPadding; ++i) { padding.randomize();
padding[i] = nextRandomInt(255);
}
} }
if(bytes instanceof ArrayBuffer) { if(bytes instanceof ArrayBuffer) {
@ -158,7 +155,7 @@ export function addPadding<T extends number[] | ArrayBuffer | Uint8Array>(
return (prepend ? bufferConcats(padding, bytes) : bufferConcats(bytes, padding)) as T; return (prepend ? bufferConcats(padding, bytes) : bufferConcats(bytes, padding)) as T;
} else { } else {
// @ts-ignore // @ts-ignore
return (prepend ? padding.concat(bytes) : bytes.concat(padding)) as T; return (prepend ? [...padding].concat(bytes) : bytes.concat([...padding])) as T;
} }
} }

6
src/lib/mtproto/networker.ts

@ -21,7 +21,7 @@ import { InvokeApiOptions } from '../../types';
import { longToBytes } from '../crypto/crypto_utils'; import { longToBytes } from '../crypto/crypto_utils';
import MTTransport from './transports/transport'; import MTTransport from './transports/transport';
import { convertToUint8Array, bytesCmp, bytesToHex, bufferConcats } from '../../helpers/bytes'; import { convertToUint8Array, bytesCmp, bytesToHex, bufferConcats } from '../../helpers/bytes';
import { nextRandomInt } from '../../helpers/random'; import { nextRandomUint, randomLong } from '../../helpers/random';
import App from '../../config/app'; import App from '../../config/app';
import DEBUG from '../../config/debug'; import DEBUG from '../../config/debug';
import Modes from '../../config/modes'; import Modes from '../../config/modes';
@ -549,7 +549,7 @@ export default class MTPNetworker {
this.checkConnectionTimeout = 0; this.checkConnectionTimeout = 0;
const serializer = new TLSerialization({mtproto: true}); const serializer = new TLSerialization({mtproto: true});
const pingId = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]; const pingId = randomLong();
serializer.storeMethod('ping', { serializer.storeMethod('ping', {
ping_id: pingId ping_id: pingId
@ -1103,7 +1103,7 @@ export default class MTPNetworker {
this.log.error('wrong length', dataBuffer, canBeLength, message.msg_id); this.log.error('wrong length', dataBuffer, canBeLength, message.msg_id);
} */ } */
const paddingLength = (16 - (data.getOffset() % 16)) + 16 * (1 + nextRandomInt(5)); const paddingLength = (16 - (data.getOffset() % 16)) + 16 * (1 + nextRandomUint(8) % 5);
const padding = /* (message as any).padding || */new Uint8Array(paddingLength).randomize()/* .fill(0) */; const padding = /* (message as any).padding || */new Uint8Array(paddingLength).randomize()/* .fill(0) */;
/* const padding = [167, 148, 207, 226, 86, 192, 193, 57, 124, 153, 174, 145, 159, 1, 5, 70, 127, 157, /* const padding = [167, 148, 207, 226, 86, 192, 193, 57, 124, 153, 174, 145, 159, 1, 5, 70, 127, 157,
51, 241, 46, 85, 141, 212, 139, 234, 213, 164, 197, 116, 245, 70, 184, 40, 40, 201, 233, 211, 150, 51, 241, 46, 85, 141, 212, 139, 234, 213, 164, 197, 116, 245, 70, 184, 40, 40, 201, 233, 211, 150,

4
src/lib/mtproto/singleInstance.ts

@ -10,7 +10,7 @@
*/ */
import { MOUNT_CLASS_TO } from "../../config/debug"; import { MOUNT_CLASS_TO } from "../../config/debug";
import { nextRandomInt } from "../../helpers/random"; import { nextRandomUint } from "../../helpers/random";
import { logger } from "../logger"; import { logger } from "../logger";
import rootScope from "../rootScope"; import rootScope from "../rootScope";
import sessionStorage from "../sessionStorage"; import sessionStorage from "../sessionStorage";
@ -53,7 +53,7 @@ export class SingleInstance {
} }
public reset() { public reset() {
this.instanceID = nextRandomInt(0xFFFFFFFF); this.instanceID = nextRandomUint(32);
this.masterInstance = false; this.masterInstance = false;
if(this.deactivateTimeout) clearTimeout(this.deactivateTimeout); if(this.deactivateTimeout) clearTimeout(this.deactivateTimeout);
this.deactivateTimeout = 0; this.deactivateTimeout = 0;

4
src/lib/mtproto/timeManager.ts

@ -11,7 +11,7 @@
import sessionStorage from '../sessionStorage'; import sessionStorage from '../sessionStorage';
import { longFromInts } from './bin_utils'; import { longFromInts } from './bin_utils';
import { nextRandomInt } from '../../helpers/random'; import { nextRandomUint } from '../../helpers/random';
import { MOUNT_CLASS_TO } from '../../config/debug'; import { MOUNT_CLASS_TO } from '../../config/debug';
import { WorkerTaskVoidTemplate } from '../../types'; import { WorkerTaskVoidTemplate } from '../../types';
import { notifySomeone } from '../../helpers/context'; import { notifySomeone } from '../../helpers/context';
@ -44,7 +44,7 @@ export class TimeManager {
const timeTicks = Date.now(), const timeTicks = Date.now(),
timeSec = Math.floor(timeTicks / 1000) + this.timeOffset, timeSec = Math.floor(timeTicks / 1000) + this.timeOffset,
timeMSec = timeTicks % 1000, timeMSec = timeTicks % 1000,
random = nextRandomInt(0xFFFF); random = nextRandomUint(16);
let messageId: TimeManager['lastMessageId'] = [timeSec, (timeMSec << 21) | (random << 3) | 4]; let messageId: TimeManager['lastMessageId'] = [timeSec, (timeMSec << 21) | (random << 3) | 4];
if(this.lastMessageId[0] > messageId[0] || if(this.lastMessageId[0] > messageId[0] ||

4
src/lib/mtproto/transports/padded.ts

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE * https://github.com/morethanwords/tweb/blob/master/LICENSE
*/ */
import { nextRandomInt } from "../../../helpers/random"; import { nextRandomUint } from "../../../helpers/random";
import { IntermediatePacketCodec } from "./intermediate"; import { IntermediatePacketCodec } from "./intermediate";
/* Data packets are aligned to 4bytes. This codec adds random bytes of size /* Data packets are aligned to 4bytes. This codec adds random bytes of size
from 0 to 3 bytes, which are ignored by decoder. */ from 0 to 3 bytes, which are ignored by decoder. */
@ -13,7 +13,7 @@ class PaddedIntermediatePacketCodec extends IntermediatePacketCodec {
public obfuscateTag = new Uint8Array([this.tag, this.tag, this.tag, this.tag]); public obfuscateTag = new Uint8Array([this.tag, this.tag, this.tag, this.tag]);
public encodePacket(data: Uint8Array) { public encodePacket(data: Uint8Array) {
let padding = new Uint8Array(nextRandomInt(3)).randomize(); let padding = new Uint8Array(nextRandomUint(8) % 3).randomize();
let len = data.byteLength + padding.byteLength; let len = data.byteLength + padding.byteLength;
let header = new Uint8Array(new Uint32Array([len]).buffer); let header = new Uint8Array(new Uint32Array([len]).buffer);

48
src/vendor/leemon.ts vendored

@ -345,11 +345,11 @@ export function expand(x: number[], n: number): number[] {
* @param {number} k * @param {number} k
* @returns {number[]} * @returns {number[]}
*/ */
export function randTruePrime(k: number): number[] { /* export function randTruePrime(k: number): number[] {
var ans = int2bigInt(0, k, 0) var ans = int2bigInt(0, k, 0)
randTruePrime_(ans, k) randTruePrime_(ans, k)
return trim(ans, 1) return trim(ans, 1)
} } */
/** /**
* return a k-bit random probable prime with probability of error < 2^-80 * return a k-bit random probable prime with probability of error < 2^-80
@ -358,7 +358,7 @@ export function randTruePrime(k: number): number[] {
* @param {number} k * @param {number} k
* @returns {number[]} * @returns {number[]}
*/ */
export function randProbPrime(k: number): number[] { /* export function randProbPrime(k: number): number[] {
if (k >= 600) return randProbPrimeRounds(k, 2) //numbers from HAC table 4.3 if (k >= 600) return randProbPrimeRounds(k, 2) //numbers from HAC table 4.3
if (k >= 550) return randProbPrimeRounds(k, 4) if (k >= 550) return randProbPrimeRounds(k, 4)
if (k >= 500) return randProbPrimeRounds(k, 5) if (k >= 500) return randProbPrimeRounds(k, 5)
@ -370,7 +370,7 @@ export function randProbPrime(k: number): number[] {
if (k >= 150) return randProbPrimeRounds(k, 18) if (k >= 150) return randProbPrimeRounds(k, 18)
if (k >= 100) return randProbPrimeRounds(k, 27) if (k >= 100) return randProbPrimeRounds(k, 27)
return randProbPrimeRounds(k, 40) //number from HAC remark 4.26 (only an estimate) return randProbPrimeRounds(k, 40) //number from HAC remark 4.26 (only an estimate)
} } */
/** /**
* return a k-bit probable random prime using n rounds of Miller Rabin * return a k-bit probable random prime using n rounds of Miller Rabin
@ -381,7 +381,7 @@ export function randProbPrime(k: number): number[] {
* @param {number} n * @param {number} n
* @returns {number[]} * @returns {number[]}
*/ */
export function randProbPrimeRounds(k: number, n: number): number[] { /* export function randProbPrimeRounds(k: number, n: number): number[] {
var ans, i, divisible, B var ans, i, divisible, B
B = 30000 //B is largest prime to use in trial division B = 30000 //B is largest prime to use in trial division
ans = int2bigInt(0, k, 0) ans = int2bigInt(0, k, 0)
@ -423,11 +423,7 @@ export function randProbPrimeRounds(k: number, n: number): number[] {
if (!divisible) return ans if (!divisible) return ans
} }
/*:: } */
declare var never: empty
return never
*/
}
/** /**
* return a new bigInt equal to (x mod n) for bigInts x and n. * return a new bigInt equal to (x mod n) for bigInts x and n.
@ -450,11 +446,11 @@ export function mod(x: number[], n: number[]): number[] {
* @param {number} n * @param {number} n
* @returns {number[]} * @returns {number[]}
*/ */
export function addInt(x: number[], n: number): number[] { /* export function addInt(x: number[], n: number): number[] {
var ans = expand(x, x.length + 1) var ans = expand(x, x.length + 1)
addInt_(ans, n) addInt_(ans, n)
return trim(ans, 1) return trim(ans, 1)
} } */
/** /**
* return x*y for bigInts x and y. This is faster when y<x. * return x*y for bigInts x and y. This is faster when y<x.
@ -547,11 +543,11 @@ export function add(x: number[], y: number[]): number[] {
* @param {number[]} n * @param {number[]} n
* @returns {(number[] | null)} * @returns {(number[] | null)}
*/ */
export function inverseMod(x: number[], n: number[]): number[] | null { /* export function inverseMod(x: number[], n: number[]): number[] | null {
var ans = expand(x, n.length) var ans = expand(x, n.length)
var s = inverseMod_(ans, n) var s = inverseMod_(ans, n)
return s ? trim(ans, 1) : null return s ? trim(ans, 1) : null
} } */
/** /**
* return (x*y mod n) for bigInts x,y,n. * return (x*y mod n) for bigInts x,y,n.
@ -580,7 +576,7 @@ export function multMod(x: number[], y: number[], n: number[]): number[] {
* @param {number} k * @param {number} k
* @return {void} * @return {void}
*/ */
export function randTruePrime_(ans: number[], k: number): void { /* export function randTruePrime_(ans: number[], k: number): void {
var c, m, pm, dd, j, r, B, divisible, z, zz, recSize var c, m, pm, dd, j, r, B, divisible, z, zz, recSize
var w var w
if (primes.length == 0) primes = findPrimes(30000) //check for divisibility by primes <=30000 if (primes.length == 0) primes = findPrimes(30000) //check for divisibility by primes <=30000
@ -712,7 +708,7 @@ export function randTruePrime_(ans: number[], k: number): void {
} }
} }
} }
} } */
/** /**
* Return an n-bit random BigInt (n>=1). If s=1, then the most significant of those n bits is set to 1. * Return an n-bit random BigInt (n>=1). If s=1, then the most significant of those n bits is set to 1.
@ -722,13 +718,13 @@ export function randTruePrime_(ans: number[], k: number): void {
* @param {number} s * @param {number} s
* @returns {number[]} * @returns {number[]}
*/ */
export function randBigInt(n: number, s: number): number[] { /* export function randBigInt(n: number, s: number): number[] {
var a, b var a, b
a = Math.floor((n - 1) / bpe) + 2 //# array elements to hold the BigInt with a leading 0 element a = Math.floor((n - 1) / bpe) + 2 //# array elements to hold the BigInt with a leading 0 element
b = int2bigInt(0, 0, a) b = int2bigInt(0, 0, a)
randBigInt_(b, n, s) randBigInt_(b, n, s)
return b return b
} } */
/** /**
* Set b to an n-bit random BigInt. If s=1, then the most significant of those n bits is set to 1. * Set b to an n-bit random BigInt. If s=1, then the most significant of those n bits is set to 1.
@ -741,7 +737,7 @@ export function randBigInt(n: number, s: number): number[] {
* @param {number} s * @param {number} s
* @return {void} * @return {void}
*/ */
export function randBigInt_(b: number[], n: number, s: number): void { /* export function randBigInt_(b: number[], n: number, s: number): void {
var i, a var i, a
for (i = 0; i < b.length; i++) b[i] = 0 for (i = 0; i < b.length; i++) b[i] = 0
a = Math.floor((n - 1) / bpe) + 1 //# array elements to hold the BigInt a = Math.floor((n - 1) / bpe) + 1 //# array elements to hold the BigInt
@ -750,7 +746,7 @@ export function randBigInt_(b: number[], n: number, s: number): void {
} }
b[a - 1] &= (2 << ((n - 1) % bpe)) - 1 b[a - 1] &= (2 << ((n - 1) % bpe)) - 1
if (s == 1) b[a - 1] |= 1 << ((n - 1) % bpe) if (s == 1) b[a - 1] |= 1 << ((n - 1) % bpe)
} } */
/** /**
* Return the greatest common divisor of bigInts x and y (each with same number of elements). * Return the greatest common divisor of bigInts x and y (each with same number of elements).
@ -852,7 +848,7 @@ export function GCD_(x: number[], y: number[]): void {
* @param {number[]} n * @param {number[]} n
* @returns {(0 | 1)} * @returns {(0 | 1)}
*/ */
export function inverseMod_(x: number[], n: number[]): Bool { /* export function inverseMod_(x: number[], n: number[]): Bool {
var k = 1 + 2 * Math.max(x.length, n.length) var k = 1 + 2 * Math.max(x.length, n.length)
if (!(x[0] & 1) && !(n[0] & 1)) { if (!(x[0] & 1) && !(n[0] & 1)) {
@ -934,11 +930,7 @@ export function inverseMod_(x: number[], n: number[]): Bool {
return 1 return 1
} }
} }
/*:: } */
declare var never: empty
return never
*/
}
/** /**
* return x**(-1) mod n, for integers x and n. * return x**(-1) mod n, for integers x and n.
@ -973,9 +965,9 @@ export function inverseModInt(x: number, n: number): number {
} }
//this deprecated function is for backward compatibility only. //this deprecated function is for backward compatibility only.
function inverseModInt_(x: number, n: number) { /* function inverseModInt_(x: number, n: number) {
return inverseModInt(x, n) return inverseModInt(x, n)
} } */
/** /**
* Given positive bigInts x and y, change the bigints v, a, and b to positive bigInts such that: * Given positive bigInts x and y, change the bigints v, a, and b to positive bigInts such that:

Loading…
Cancel
Save