Search code examples
phpnode.jsgmpsrp-protocoltrinitycore

Is there a way to use GMP libraries in node.js to credentials with SRP6


I search a way to use the equivalent of the following PHP functions in Node.js after searching a while I found nothing working in my case:

gmp_init gmp_import gmp_powm gmp_export

The idea is to rewrite this php code in js:

function CalculateSRP6Verifier($username, $password, $salt)
    {
        // algorithm constants
        $g = gmp_init(7);
        $N = gmp_init('894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7', 16);
        
        // calculate first hash
        $h1 = sha1(strtoupper($username . ':' . $password), TRUE);
        
        // calculate second hash
        $h2 = sha1($salt.$h1, TRUE);
        
        // convert to integer (little-endian)
        $h2 = gmp_import($h2, 1, GMP_LSW_FIRST);
        
        // g^h2 mod N
        $verifier = gmp_powm($g, $h2, $N);
        
        // convert back to a byte array (little-endian)
        $verifier = gmp_export($verifier, 1, GMP_LSW_FIRST);
        
        // pad to 32 bytes, remember that zeros go on the end in little-endian!
        $verifier = str_pad($verifier, 32, chr(0), STR_PAD_RIGHT);
        
        // done!
        return $verifier;
    }

Solution

  • I found the answer to my question a while ago. This can be done in Node.js using the Buffer and the following libs bigint-buffer, big-integer as I did it below.

    const bigintBuffer = require(`bigint-buffer`)
    const BigInteger = require(`big-integer`)
    const crypto = require(`crypto`)
    
    /**
     *
     * @param {Buffer} salt
     * @param {string} identity
     * @param {string} password
     * @return {Buffer}
     */
    function computeVerifier (salt, identity, password) {
        const hashIP = crypto.createHash(`sha1`)
            .update(identity + `:` + password)
            .digest()
        const hashX = crypto.createHash(`sha1`)
            .update(salt)
            .update(hashIP)
            .digest()
        const x = bigintBuffer.toBigIntLE(hashX)
        const g = BigInt(`0x7`)
        const N = BigInt(`0x894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7`)
        const verifier = BigInteger(g).modPow(x, N)
        const lEVerifier = verifier.value.toString(16).match(/.{2}/g).reverse().join(``)
        return Buffer.from(lEVerifier, `hex`)
    }
    
    // Test
    crypto.randomBytes(32, (err, buf) => {
        if (err) throw err;
        computeVerifier(buf, `foo`, `bar`);
    });
    

    If you want to use directly a library I created one which works for TrinityCore and AzerothCore: https://www.npmjs.com/package/trinitycore-srp6