Helpers.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. const { isBrowser, isNode } = require('browser-or-node' )
  2. const BigInt = require('big-integer')
  3. const IS_NODE = isNode
  4. const crypto = require(IS_NODE ? 'crypto' : './crypto/crypto')
  5. /**
  6. * converts a buffer to big int
  7. * @param buffer
  8. * @param little
  9. * @param signed
  10. * @returns {bigInt.BigInteger}
  11. */
  12. function readBigIntFromBuffer(buffer, little = true, signed = false) {
  13. let randBuffer = Buffer.from(buffer)
  14. const bytesNumber = randBuffer.length
  15. if (little) {
  16. randBuffer = randBuffer.reverse()
  17. }
  18. let bigInt = BigInt(randBuffer.toString('hex'), 16)
  19. if (signed && Math.floor(bigInt.toString('2').length / 8) >= bytesNumber) {
  20. bigInt = bigInt.subtract(BigInt(2)
  21. .pow(BigInt(bytesNumber * 8)))
  22. }
  23. return bigInt
  24. }
  25. /**
  26. * Special case signed little ints
  27. * @param big
  28. * @param number
  29. * @returns {Buffer}
  30. */
  31. function toSignedLittleBuffer(big, number = 8) {
  32. const bigNumber = BigInt(big)
  33. const byteArray = []
  34. for (let i = 0; i < number; i++) {
  35. byteArray[i] = bigNumber.shiftRight(8 * i).and(255)
  36. }
  37. return Buffer.from(byteArray)
  38. }
  39. /**
  40. * converts a big int to a buffer
  41. * @param bigInt {BigInteger}
  42. * @param bytesNumber
  43. * @param little
  44. * @param signed
  45. * @returns {Buffer}
  46. */
  47. function readBufferFromBigInt(bigInt, bytesNumber, little = true, signed = false) {
  48. bigInt = BigInt(bigInt)
  49. const bitLength = bigInt.bitLength()
  50. const bytes = Math.ceil(bitLength / 8)
  51. if (bytesNumber < bytes) {
  52. throw new Error('OverflowError: int too big to convert')
  53. }
  54. if (!signed && bigInt.lesser(BigInt(0))) {
  55. throw new Error('Cannot convert to unsigned')
  56. }
  57. let below = false
  58. if (bigInt.lesser(BigInt(0))) {
  59. below = true
  60. bigInt = bigInt.abs()
  61. }
  62. const hex = bigInt.toString('16')
  63. .padStart(bytesNumber * 2, '0')
  64. let l = Buffer.from(hex, 'hex')
  65. if (little) {
  66. l = l.reverse()
  67. }
  68. if (signed && below) {
  69. if (little) {
  70. let reminder = false
  71. if (l[0] !== 0) {
  72. l[0] -= 1
  73. }
  74. for (let i = 0; i < l.length; i++) {
  75. if (l[i] === 0) {
  76. reminder = true
  77. continue
  78. }
  79. if (reminder) {
  80. l[i] -= 1
  81. reminder = false
  82. }
  83. l[i] = 255 - l[i]
  84. }
  85. } else {
  86. l[l.length - 1] = 256 - l[l.length - 1]
  87. for (let i = 0; i < l.length - 1; i++) {
  88. l[i] = 255 - l[i]
  89. }
  90. }
  91. }
  92. return l
  93. }
  94. /**
  95. * Generates a random long integer (8 bytes), which is optionally signed
  96. * @returns {BigInteger}
  97. */
  98. function generateRandomLong(signed = true) {
  99. return readBigIntFromBuffer(generateRandomBytes(8), true, signed)
  100. }
  101. /**
  102. * .... really javascript
  103. * @param n {number}
  104. * @param m {number}
  105. * @returns {number}
  106. */
  107. function mod(n, m) {
  108. return ((n % m) + m) % m
  109. }
  110. /**
  111. * returns a positive bigInt
  112. * @param n {BigInt}
  113. * @param m {BigInt}
  114. * @returns {BigInt}
  115. */
  116. function bigIntMod(n, m) {
  117. return ((n.remainder(m)).add(m)).remainder(m)
  118. }
  119. /**
  120. * Generates a random bytes array
  121. * @param count
  122. * @returns {Buffer}
  123. */
  124. function generateRandomBytes(count) {
  125. return Buffer.from(crypto.randomBytes(count))
  126. }
  127. /**
  128. * Calculate the key based on Telegram guidelines, specifying whether it's the client or not
  129. * @param sharedKey
  130. * @param msgKey
  131. * @param client
  132. * @returns {{iv: Buffer, key: Buffer}}
  133. */
  134. /*CONTEST
  135. this is mtproto 1 (mostly used for secret chats)
  136. async function calcKey(sharedKey, msgKey, client) {
  137. const x = client === true ? 0 : 8
  138. const [sha1a, sha1b, sha1c, sha1d] = await Promise.all([
  139. sha1(Buffer.concat([msgKey, sharedKey.slice(x, x + 32)])),
  140. sha1(Buffer.concat([sharedKey.slice(x + 32, x + 48), msgKey, sharedKey.slice(x + 48, x + 64)])),
  141. sha1(Buffer.concat([sharedKey.slice(x + 64, x + 96), msgKey])),
  142. sha1(Buffer.concat([msgKey, sharedKey.slice(x + 96, x + 128)]))
  143. ])
  144. const key = Buffer.concat([sha1a.slice(0, 8), sha1b.slice(8, 20), sha1c.slice(4, 16)])
  145. const iv = Buffer.concat([sha1a.slice(8, 20), sha1b.slice(0, 8), sha1c.slice(16, 20), sha1d.slice(0, 8)])
  146. return {
  147. key,
  148. iv
  149. }
  150. }
  151. */
  152. /**
  153. * Generates the key data corresponding to the given nonces
  154. * @param serverNonce
  155. * @param newNonce
  156. * @returns {{key: Buffer, iv: Buffer}}
  157. */
  158. async function generateKeyDataFromNonce(serverNonce, newNonce) {
  159. serverNonce = toSignedLittleBuffer(serverNonce, 16)
  160. newNonce = toSignedLittleBuffer(newNonce, 32)
  161. const [hash1, hash2, hash3] = await Promise.all([
  162. sha1(Buffer.concat([newNonce, serverNonce])),
  163. sha1(Buffer.concat([serverNonce, newNonce])),
  164. sha1(Buffer.concat([newNonce, newNonce])),
  165. ])
  166. const keyBuffer = Buffer.concat([hash1, hash2.slice(0, 12)])
  167. const ivBuffer = Buffer.concat([hash2.slice(12, 20), hash3, newNonce.slice(0, 4)])
  168. return {
  169. key: keyBuffer,
  170. iv: ivBuffer,
  171. }
  172. }
  173. function convertToLittle(buf) {
  174. const correct = Buffer.alloc(buf.length * 4)
  175. for (let i = 0; i < buf.length; i++) {
  176. correct.writeUInt32BE(buf[i], i * 4)
  177. }
  178. return correct
  179. }
  180. /**
  181. * Calculates the SHA1 digest for the given data
  182. * @param data
  183. * @returns {Promise}
  184. */
  185. function sha1(data) {
  186. const shaSum = crypto.createHash('sha1')
  187. shaSum.update(data)
  188. return shaSum.digest()
  189. }
  190. /**
  191. * Calculates the SHA256 digest for the given data
  192. * @param data
  193. * @returns {Promise}
  194. */
  195. function sha256(data) {
  196. const shaSum = crypto.createHash('sha256')
  197. shaSum.update(data)
  198. return shaSum.digest()
  199. }
  200. /**
  201. * Fast mod pow for RSA calculation. a^b % n
  202. * @param a
  203. * @param b
  204. * @param n
  205. * @returns {bigInt.BigInteger}
  206. */
  207. function modExp(a, b, n) {
  208. a = a.remainder(n)
  209. let result = BigInt.one
  210. let x = a
  211. while (b.greater(BigInt.zero)) {
  212. const leastSignificantBit = b.remainder(BigInt(2))
  213. b = b.divide(BigInt(2))
  214. if (leastSignificantBit.eq(BigInt.one)) {
  215. result = result.multiply(x)
  216. result = result.remainder(n)
  217. }
  218. x = x.multiply(x)
  219. x = x.remainder(n)
  220. }
  221. return result
  222. }
  223. /**
  224. * Gets the arbitrary-length byte array corresponding to the given integer
  225. * @param integer {number,BigInteger}
  226. * @param signed {boolean}
  227. * @returns {Buffer}
  228. */
  229. function getByteArray(integer, signed = false) {
  230. const bits = integer.toString(2).length
  231. const byteLength = Math.floor((bits + 8 - 1) / 8)
  232. return readBufferFromBigInt(BigInt(integer), byteLength, false, signed)
  233. }
  234. /**
  235. * returns a random int from min (inclusive) and max (inclusive)
  236. * @param min
  237. * @param max
  238. * @returns {number}
  239. */
  240. function getRandomInt(min, max) {
  241. min = Math.ceil(min)
  242. max = Math.floor(max)
  243. return Math.floor(Math.random() * (max - min + 1)) + min
  244. }
  245. /**
  246. * Sleeps a specified amount of time
  247. * @param ms time in milliseconds
  248. * @returns {Promise}
  249. */
  250. const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
  251. /**
  252. * Checks if the obj is an array
  253. * @param obj
  254. * @returns {boolean}
  255. */
  256. /*
  257. CONTEST
  258. we do'nt support array requests anyway
  259. function isArrayLike(obj) {
  260. if (!obj) return false
  261. const l = obj.length
  262. if (typeof l != 'number' || l < 0) return false
  263. if (Math.floor(l) !== l) return false
  264. // fast check
  265. if (l > 0 && !(l - 1 in obj)) return false
  266. // more complete check (optional)
  267. for (let i = 0; i < l; ++i) {
  268. if (!(i in obj)) return false
  269. }
  270. return true
  271. }
  272. */
  273. // Taken from https://stackoverflow.com/questions/18638900/javascript-crc32/18639999#18639999
  274. function makeCRCTable() {
  275. let c
  276. const crcTable = []
  277. for (let n = 0; n < 256; n++) {
  278. c = n
  279. for (let k = 0; k < 8; k++) {
  280. c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1))
  281. }
  282. crcTable[n] = c
  283. }
  284. return crcTable
  285. }
  286. let crcTable = null
  287. function crc32(buf) {
  288. if (!crcTable) {
  289. crcTable = makeCRCTable()
  290. }
  291. if (!Buffer.isBuffer(buf)) {
  292. buf = Buffer.from(buf)
  293. }
  294. let crc = -1
  295. for (let index = 0; index < buf.length; index++) {
  296. const byte = buf[index]
  297. crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8)
  298. }
  299. return (crc ^ (-1)) >>> 0
  300. }
  301. module.exports = {
  302. readBigIntFromBuffer,
  303. readBufferFromBigInt,
  304. generateRandomLong,
  305. mod,
  306. crc32,
  307. generateRandomBytes,
  308. //calcKey,
  309. generateKeyDataFromNonce,
  310. sha1,
  311. sha256,
  312. bigIntMod,
  313. modExp,
  314. getRandomInt,
  315. sleep,
  316. getByteArray,
  317. //isArrayLike,
  318. toSignedLittleBuffer,
  319. convertToLittle,
  320. IS_NODE,
  321. }