Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding react-native environment #187

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

happymaskterriblefate
Copy link

This adds a working react-native environment to mtproto-core. I was unable to get things working with the canonical expo-crypto because it does not accept Uint8Arrays as inputs to it's hashing methods, so I grabbed some off-the-shelf modules to polyfill all the required methods and built-ins.

@happymaskterriblefate
Copy link
Author

Switched this PR to use text-encoding instead of web-encoding because web-encoding broke after ejecting my expo app.

@happymaskterriblefate
Copy link
Author

Friendly bump on this :)

Copy link
Owner

@alik0211 alik0211 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use single quotes for strings. In general, the PR is very cool, I'm ready to smear it after corrections

Comment on lines +59 to 65
"peerDependencies": {
"react-native": "*",
"fast-sha256": "^1.3.0",
"jssha": "^3.2.0",
"react-native-get-random-values": "^1.7.0",
"text-encoding": "^0.7.0"
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package file.json is used for all environments, so I think it's better to remove peerDependencies for react-native from here. Instead, I will add instructions for installing these dependencies to the documentation

@VityaSchel
Copy link

Hello, any updates? :) By the way, can I somehow extract this PR into my own local copy of repository and merge it? Maybe make a patch file from this PR for patch-package? I really want to use it in my project! (expo)

@VityaSchel
Copy link

I was able to use this but I ran into some problems:

  1. You have to replace deprecated asyncstorage from react-native with community package
  2. Some methods are sooooooo slow. Like crypto.getSRPParams takes 2 minutes just to generate parameters. Maybe I'm doing something wrong but I tried running it in isolation with timer and it takes too much time and this method is required for 2fa. Imagine wasting 5 minutes on trying different passwords in order to log in while official clients and nodejs allows you to make requests almost immediately :(

@VityaSchel
Copy link

VityaSchel commented Oct 3, 2022

It seems to be problem with TextEncoder

Benchmark:

class Crypto {
  constructor({ SHA1, SHA256, PBKDF2, getRandomBytes }) {
    this.SHA1 = SHA1;
    this.SHA256 = SHA256;
    this.PBKDF2 = PBKDF2;
    this.getRandomBytes = getRandomBytes;

    this.rsa = new RSA({ SHA1 });
  }

  async getSRPParams({ g, p, salt1, salt2, gB, password }) {
    const H = this.SHA256;
    const SH = (data, salt) => {
      return this.SHA256(concatBytes(salt, data, salt));
    };
    const PH1 = async (password, salt1, salt2) => {
      return await SH(await SH(password, salt1), salt2);
    };
    const PH2 = async (password, salt1, salt2) => {
      return await SH(
        await this.PBKDF2(await PH1(password, salt1, salt2), salt1, 100000),
        salt2
      );
    };

    const encoder = new TextEncoder();

    // == SECTION 1 == //
    const gBigInt = bigInt(g);
    const gBytes = bigIntToBytes(gBigInt, 256);
    const pBigInt = bytesToBigInt(p);
    const aBigInt = bytesToBigInt(this.getRandomBytes(256));
    const gABigInt = gBigInt.modPow(aBigInt, pBigInt);
    const gABytes = bigIntToBytes(gABigInt);
    const gBBytes = bytesToBigInt(gB);
    // == SECTION 2 == //
    const [k, u, x] = await Promise.all([
      H(concatBytes(p, gBytes)),
      H(concatBytes(gABytes, gB)),
      PH2(encoder.encode(password), salt1, salt2),
    ]);
    // == SECTION 3 == //
    const kBigInt = bytesToBigInt(k);
    const uBigInt = bytesToBigInt(u);
    const xBigInt = bytesToBigInt(x);
    const vBigInt = gBigInt.modPow(xBigInt, pBigInt);
    const kVBigInt = kBigInt.multiply(vBigInt).mod(pBigInt);
    let tBigInt = gBBytes.subtract(kVBigInt).mod(pBigInt);
    if (tBigInt.isNegative()) {
      tBigInt = tBigInt.add(pBigInt);
    }
    const sABigInt = tBigInt.modPow(
      aBigInt.add(uBigInt.multiply(xBigInt)),
      pBigInt
    );
    const sABytes = bigIntToBytes(sABigInt);
    // == SECTION 4 == //
    const kA = await H(sABytes);
    // == SECTION 5 == //
    const M1 = await H(
      concatBytes(
        xorBytes(await H(p), await H(gBytes)),
        await H(salt1),
        await H(salt2),
        gABytes,
        gB,
        kA
      )
    );
    // == SECTION 6 == //

    return { A: gABytes, M1 };
  }
}
Section Timer
1-2 20.97 seconds
2-3 136.16 seconds
3-4 23.15 seconds
4-5 0.01 seconds
5-6 0.00 seconds

Result: 180.29 seconds (3 minutes)

@VityaSchel
Copy link

VityaSchel commented Oct 3, 2022

I ran additional test to find execution time for this line: PH2(encoder.encode(password), salt1, salt2),:

TextEncoder.encode() function takes 0.01 seconds to complete, and PH2 is 135.61 seconds, so it's a problem with crypto module.

I noticed PBKDF2 takes iterations number as argument in function, which is hardcoded to 100000. Is there any way to optimize it?

Also account.getPassword method takes about 30 seconds to complete. Maybe it's because I'm running it twice? First time I execute it with new socket, it responds immediately.

Update: I think PBKDF2 doesn't work at all. It always gives me incorrect 2fa password error.

const sha256 = require("fast-sha256");

async function PBKDF2(password, salt, iterations) {
return sha256.pbkdf2(password, salt, iterations, 512);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May return incorrect string. Also sometimes getting SRP_ID_INVALID error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants