// eslint-disable-next-line no-restricted-imports import { createCipheriv, createHash, createHmac, pbkdf2 } from 'crypto' import { deflateSync, gunzipSync } from 'zlib' import { ige256Decrypt, ige256Encrypt, initAsync, InitInput } from '@mtcute/wasm' import { MaybeAsync } from '../../types/index.js' import { BaseCryptoProvider, IAesCtr, ICryptoProvider, IEncryptionScheme } from './abstract.js' export abstract class BaseNodeCryptoProvider extends BaseCryptoProvider { createAesCtr(key: Uint8Array, iv: Uint8Array): IAesCtr { const cipher = createCipheriv(`aes-${key.length * 8}-ctr`, key, iv) const update = (data: Uint8Array) => cipher.update(data) return { process: update, } } pbkdf2( password: Uint8Array, salt: Uint8Array, iterations: number, keylen = 64, algo = 'sha512', ): MaybeAsync { return new Promise((resolve, reject) => pbkdf2(password, salt, iterations, keylen, algo, (err: Error | null, buf: Uint8Array) => err !== null ? reject(err) : resolve(buf), ), ) } sha1(data: Uint8Array): Uint8Array { return createHash('sha1').update(data).digest() } sha256(data: Uint8Array): Uint8Array { return createHash('sha256').update(data).digest() } hmacSha256(data: Uint8Array, key: Uint8Array): Uint8Array { return createHmac('sha256', key).update(data).digest() } gzip(data: Uint8Array, maxSize: number): Uint8Array | null { // todo: test if wasm impl is better fit here try { // telegram accepts both zlib and gzip, but zlib is faster and has less overhead, so we use it here return deflateSync(data, { maxOutputLength: maxSize, }) // hot path, avoid additional runtime checks // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (e: any) { if (e.code === 'ERR_BUFFER_TOO_LARGE') { return null } throw e } } gunzip(data: Uint8Array): Uint8Array { return gunzipSync(data) } } export class NodeCryptoProvider extends BaseNodeCryptoProvider implements ICryptoProvider { private wasmInput?: InitInput constructor(params?: { wasmInput?: InitInput }) { super() this.wasmInput = params?.wasmInput } initialize(): Promise { return initAsync(this.wasmInput) } createAesIge(key: Uint8Array, iv: Uint8Array): IEncryptionScheme { return { encrypt(data: Uint8Array): Uint8Array { return ige256Encrypt(data, key, iv) }, decrypt(data: Uint8Array): Uint8Array { return ige256Decrypt(data, key, iv) }, } } }