Reputation: 946
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;
}
Upvotes: 1
Views: 515
Reputation: 1
import crypto from "crypto";
import { toBigIntLE, toBufferLE } from "bigint-buffer";
import sha1 from "sha1";
import { modPow } from 'bigint-crypto-utils';
// 常量
const _g: bigint = BigInt(7);
const _N: bigint = BigInt('0x894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7');
/**
* 计算SRP6验证器
* @param username string 用户名
* @param password string 密码
* @param salt Buffer 盐
* @returns Buffer 验证器
*/
function calculateSRP6Verifier(username: string, password: string, salt: Buffer): Buffer {
const h1: Buffer = Buffer.from(sha1((username + ':' + password).toUpperCase()), 'hex') ;
const h2: bigint = toBigIntLE(Buffer.from(sha1(Buffer.concat([salt, h1])), 'hex'))
let verifier: Buffer = toBufferLE(modPow(_g, h2, _N), 32)
verifier = Buffer.concat([verifier, Buffer.alloc(32 - verifier.length, '\0')]);
return verifier;
}
/**
* 获取注册数据
* @param username string 用户名
* @param password string 密码
* @returns [Buffer, Buffer] 注册数据
*/
function getRegistrationData(username:string, password:string): [Buffer, Buffer] {
const salt: Buffer = crypto.randomBytes(32);
const verifier: Buffer = calculateSRP6Verifier(username, password, salt);
return [salt, verifier];
}
/**
* 验证SRP6
* @param user string 用户名
* @param pass string 密码
* @param salt Buffer 盐
* @param verifier Buffer 验证器
* @returns boolean 是否验证成功
*/
function verifySRP6(user: string, pass: string, salt: Buffer, verifier: Buffer): boolean {
const paddedVerifier: Buffer = calculateSRP6Verifier(user, pass, salt)
return verifier.equals(paddedVerifier);
}
Upvotes: 0
Reputation: 946
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
Upvotes: 1