mirror of
https://github.com/vzakharchenko/huawei-hilink
synced 2024-11-17 15:25:32 +00:00
309 lines
9.2 KiB
JavaScript
309 lines
9.2 KiB
JavaScript
/* eslint-disable */
|
|
|
|
const {restCalls} = require("../src/utils/DefaultRestCalls");
|
|
const parser = require('xml2js');
|
|
const CryptoJS = require('crypto-js');
|
|
const {RSAKey} = require('./rsa');
|
|
const publicKey = {
|
|
publicKey:null,
|
|
};
|
|
const publicSession = {
|
|
login:'0',
|
|
session:'',
|
|
token1:'',
|
|
token2:''
|
|
};
|
|
|
|
var C = CryptoJS;
|
|
var C_lib = C.lib;
|
|
var WordArray = C_lib.WordArray;
|
|
var C_algo = C.algo;
|
|
|
|
var SHA2 = C_algo.SHA256;
|
|
var HmacSHA2 = C.HmacSHA256;
|
|
var Base = C_lib.Base;
|
|
|
|
var SCRAM = C_algo.SCRAM = Base.extend({
|
|
cfg: Base.extend({
|
|
keySize: 8,
|
|
hasher: SHA2,
|
|
hmac: HmacSHA2
|
|
}),
|
|
|
|
init: function (cfg) {
|
|
this.cfg = this.cfg.extend(cfg);
|
|
},
|
|
/**
|
|
* return client nonce
|
|
*/
|
|
nonce: function () {
|
|
lastNonce = WordArray.random(this.cfg.keySize * 4);
|
|
return lastNonce;
|
|
},
|
|
/**
|
|
* pbkdf2
|
|
*/
|
|
saltedPassword: function (password, salt, iterations) {
|
|
return CryptoJS.PBKDF2(password, salt, {
|
|
keySize: this.cfg.keySize,
|
|
iterations: iterations,
|
|
hasher: this.cfg.hasher
|
|
});
|
|
},
|
|
/**
|
|
* ClientKey = HMAC(saltPwd, "Client Key")
|
|
*/
|
|
clientKey: function (saltPwd) {
|
|
return this.cfg.hmac(saltPwd, "Client Key");
|
|
},
|
|
/**
|
|
* ServerKey = HMAC(saltPwd, "Server Key")
|
|
*/
|
|
serverKey: function (saltPwd) {
|
|
return this.cfg.hmac(saltPwd, "Server Key");
|
|
},
|
|
/**
|
|
* StoredKey = HASH(ClientKey)
|
|
*/
|
|
storedKey: function (clientKey) {
|
|
var hasher = this.cfg.hasher.create();
|
|
hasher.update(clientKey);
|
|
|
|
return hasher.finalize();
|
|
},
|
|
/**
|
|
* Signature = HMAC(StoredKey, AuthMessage)
|
|
*/
|
|
signature: function (storedKey, authMessage) {
|
|
return this.cfg.hmac(storedKey, authMessage);
|
|
},
|
|
/**
|
|
* ClientProof = ClientKey ^ ClientSignature
|
|
*/
|
|
clientProof: function (password, salt, iterations, authMessage) {
|
|
var spwd = this.saltedPassword(password, salt, iterations);
|
|
var ckey = this.clientKey(spwd);
|
|
var skey = this.storedKey(ckey);
|
|
var csig = this.signature(skey, authMessage);
|
|
|
|
for (var i = 0; i < ckey.sigBytes / 4; i += 1) {
|
|
ckey.words[i] = ckey.words[i] ^ csig.words[i]
|
|
}
|
|
return ckey.toString();
|
|
},
|
|
/**
|
|
* ServerProof = HMAC(ServerKey, AuthMessage)
|
|
*/
|
|
serverProof: function (password, salt, iterations, authMessage) {
|
|
var spwd = this.saltedPassword(password, salt, iterations);
|
|
var skey = this.serverKey(spwd);
|
|
var sig = this.signature(skey, authMessage);
|
|
return sig.toString();
|
|
}
|
|
});
|
|
|
|
/**
|
|
* var scram = CryptoJS.SCRAM();
|
|
*/
|
|
C.SCRAM = function (cfg) {
|
|
return SCRAM.create(cfg);
|
|
};
|
|
|
|
|
|
async function getPublicKey(session){
|
|
if (!publicKey.publicKey){
|
|
const resp = await restCalls.fetchData(`http://${session.url}/api/webserver/publickey`,'GET', {
|
|
'cookie': `sessionId=${session.SesInfo}`,
|
|
__RequestVerificationToken: session.TokInfo
|
|
});
|
|
const message = await parser.parseStringPromise(resp);
|
|
publicKey.publicKey= message.response;
|
|
}
|
|
return publicKey.publicKey
|
|
}
|
|
|
|
function utf8Encode(string) {
|
|
var stringTemp = string.replace(/\r\n/g, '\n');
|
|
var utftext = '';
|
|
for (var n = 0; n < stringTemp.length; n++) {
|
|
var charStr = stringTemp.charCodeAt(n);
|
|
if (charStr < 128) {
|
|
utftext += String.fromCharCode(charStr);
|
|
} else if ((charStr > 127) && (charStr < 2048)) {
|
|
utftext += String.fromCharCode((charStr >> 6) | 192);
|
|
utftext += String.fromCharCode((charStr & 63) | 128);
|
|
} else {
|
|
utftext += String.fromCharCode((charStr >> 12) | 224);
|
|
utftext += String.fromCharCode(((charStr >> 6) & 63) | 128);
|
|
utftext += String.fromCharCode((charStr & 63) | 128);
|
|
}
|
|
}
|
|
return utftext;
|
|
}
|
|
|
|
function base64encode(str) {
|
|
var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
var outputStr = '';
|
|
var char1;
|
|
var char2;
|
|
var char3;
|
|
var encry1;
|
|
var encry2;
|
|
var encry3;
|
|
var encry4;
|
|
var i = 0;
|
|
var input = utf8Encode(str);
|
|
while (i < input.length) {
|
|
char1 = input.charCodeAt(i++);
|
|
char2 = input.charCodeAt(i++);
|
|
char3 = input.charCodeAt(i++);
|
|
encry1 = char1 >> 2;
|
|
encry2 = ((char1 & 3) << 4) | (char2 >> 4);
|
|
encry3 = ((char2 & 15) << 2) | (char3 >> 6);
|
|
encry4 = char3 & 63;
|
|
if (isNaN(char2)) {
|
|
encry3 = encry4 = 64;
|
|
} else if (isNaN(char3)) {
|
|
encry4 = 64;
|
|
}
|
|
outputStr += keyStr.charAt(encry1) + keyStr.charAt(encry2) + keyStr.charAt(encry3) + keyStr.charAt(encry4);
|
|
}
|
|
return outputStr;
|
|
}
|
|
|
|
async function doRSAEncrypt(session,encstring) {
|
|
if (encstring === '') {
|
|
return '';
|
|
}
|
|
let res;
|
|
const gEncPublickey = { e: '', n: '' };
|
|
const pubkeyKeyInfo = await getPublicKey(session);
|
|
// eslint-disable-next-line prefer-destructuring
|
|
gEncPublickey.n = pubkeyKeyInfo.encpubkeyn[0];
|
|
// eslint-disable-next-line prefer-destructuring
|
|
gEncPublickey.e = pubkeyKeyInfo.encpubkeye[0];
|
|
var rsa = new RSAKey();
|
|
rsa.setPublic(gEncPublickey.n, gEncPublickey.e);
|
|
var encStr = base64encode(encstring);
|
|
var num = encStr.length / 245;
|
|
// if (EMUI.LoginStateController.rsapadingtype === '1') {
|
|
num = encStr.length / 214;
|
|
// }
|
|
var restotal = '';
|
|
var rsan = gEncPublickey.n;
|
|
for (var i = 0; i < num; i++) {
|
|
// if (EMUI.LoginStateController.rsapadingtype === '1') {
|
|
var encdata = encStr.substr(i * 214, 214);
|
|
res = rsa.encryptOAEP(encdata);
|
|
// } else {
|
|
// var encdata = encStr.substr(i * 245, 245);
|
|
// res = rsa.encrypt(encdata);
|
|
// }
|
|
if (res.length !== rsan.length) {
|
|
i--;
|
|
continue;
|
|
}
|
|
restotal += res;
|
|
}
|
|
return restotal;
|
|
}
|
|
|
|
const scram = CryptoJS.SCRAM();
|
|
const smsNonce = scram.nonce().toString();
|
|
const smsSalt = scram.nonce().toString();
|
|
const nonceStr = smsNonce + smsSalt;
|
|
|
|
|
|
function getDAesString(encrypted, keystr, ivstr) {
|
|
var key = CryptoJS.enc.Hex.parse(keystr);
|
|
var iv = CryptoJS.enc.Hex.parse(ivstr);
|
|
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
|
|
iv: iv,
|
|
mode: CryptoJS.mode.CBC,
|
|
padding: CryptoJS.pad.Pkcs7
|
|
});
|
|
return decrypted.toString(CryptoJS.enc.Latin1);
|
|
}
|
|
|
|
function utf8to16(str) {
|
|
var output, i, leng, unic;
|
|
var char1, char2;
|
|
output = "";
|
|
leng = str.length;
|
|
i = 0;
|
|
while (i < leng) {
|
|
unic = str.charCodeAt(i++);
|
|
switch (unic >> 4) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
output += str.charAt(i - 1);
|
|
break;
|
|
case 12:
|
|
case 13:
|
|
char1 = str.charCodeAt(i++);
|
|
output += String.fromCharCode(((unic & 0x1F) << 6) | (char1 & 0x3F));
|
|
break;
|
|
case 14:
|
|
char1 = str.charCodeAt(i++);
|
|
char2 = str.charCodeAt(i++);
|
|
output += String.fromCharCode(((unic & 0x0F) << 12) |
|
|
((char1 & 0x3F) << 6) |
|
|
((char2 & 0x3F) << 0));
|
|
break;
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
function dataDecrypt(scram,smsNonce,smsSalt,nonceStr,encryptedData) {
|
|
if (!encryptedData.response
|
|
|| !encryptedData.response.pwd
|
|
|| !encryptedData.response.hash
|
|
|| !encryptedData.response.iter) {
|
|
throw new Error('Request error: '+JSON.stringify(encryptedData))
|
|
}
|
|
if (!encryptedData.response
|
|
|| encryptedData.response.pwd.length===0
|
|
|| encryptedData.response.hash.length === 0
|
|
|| encryptedData.response.iter.length === 0) {
|
|
throw new Error('Request error: '+JSON.stringify(encryptedData))
|
|
}
|
|
const pwdret = {
|
|
response:{
|
|
pwd:encryptedData.response.pwd[0],
|
|
hash:encryptedData.response.hash[0],
|
|
iter:encryptedData.response.iter[0],
|
|
}
|
|
}
|
|
var smsEncrypted = pwdret.response.pwd;
|
|
var salt = CryptoJS.enc.Hex.parse(smsSalt);
|
|
var iter = pwdret.response.iter;
|
|
var saltedStr = scram.saltedPassword(smsNonce, salt, iter);
|
|
saltedStr = saltedStr.toString();
|
|
var aesKey = saltedStr.substring(0, 32);
|
|
var aesIV = saltedStr.substring(32, 48);
|
|
var hmacKey = saltedStr.substring(48, 64);
|
|
var hashData = scram.signature(CryptoJS.enc.Hex.parse(smsEncrypted), CryptoJS.enc.Hex.parse(hmacKey));
|
|
hashData = hashData.toString();
|
|
if (pwdret.response.hash !== hashData) {
|
|
throw new Error('UserPwd hash error');
|
|
}
|
|
var encrypted = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(smsEncrypted));
|
|
var decryptedData = getDAesString(encrypted, aesKey, aesIV);
|
|
decryptedData = utf8to16(decryptedData);
|
|
decryptedData = decryptedData.substring(decryptedData.indexOf('<response>'));
|
|
return decryptedData ;
|
|
}
|
|
|
|
module.exports.dataDecrypt = dataDecrypt;
|
|
module.exports.CryptoJS = CryptoJS;
|
|
module.exports.doRSAEncrypt = doRSAEncrypt;
|
|
module.exports.publicKey = publicKey;
|
|
module.exports.publicSession = publicSession;
|