LoadRunner 12 模拟 RSA加密 登录的实现(JS)
LR 12 中 web_js_run API 非常坑,只能调用一个 JS 文件;更坑的是,不能通用 一个JS调用另外一个JS;(可能有,但在网上找了N个国家,都没有找到!如有,还请朋友告之,谢谢。)
现大部分的前端登录都有使用到RSA加密,以保障用户在登录的时候,账号密码不直接以明文方式传输,经过加密的账号密码即使被截取,也难以破解出真实的账号密码;
RSA 相关信息请自行搜索了解或下载, RSA加密算法在网上有N多开源的现成库可用(前、后端库);
经RSA加密的登录流程大致为:
1、前端在登录时会向服务端请求 RSA 四个关键值: PublicKey , Exponent ,rKey , Modulus;
2、前端使用获取到的 Exponent , Modulus ( 通过 RSA 库在前端执行)计算出私钥,然后使用获得的公钥以及私钥 对 用户的账号密码 进行加密,并生成加密后的字符串;
3、最后前端将完成加密的字符串发送给服务端,服务端解密成功后,返回登录成功的状态;
以下将以RSA加密登录为例,演示在Loadrunner 中的如何实现;
1 Action() 2 { 3 //char cliEncrypt[1000]; //用于保存需要加密的拼接好的字符串 4 int rc=0; 5 lr_save_string("19000000026","mobileNumberSet");//参数化的正确姿势 lr_save_string(lr_eval_string("{user_mobile}"),"mobileNumberSet"); 6 lr_save_string("123456","pwdSet"); 7 lr_save_string("","imgVerifyCodeSet"); 8 9 web_reg_save_param("SerJsonData", "LB=", "RB=", "Search=Body", LAST); 10 11 web_submit_data("encryptKey.action", 12 "Action=http://192.168.1.16/surperman/login/encryptKey.action", 13 "Method=GET", 14 "RecContentType=text/html", 15 "Referer=", 16 "Snapshot=t19.inf", 17 "Mode=HTML", 18 ITEMDATA, 19 LAST); 20 21 lr_output_message("# 获取密钥响应内容体:\n%s", lr_eval_string("{SerJsonData}")); 22 23 web_js_run( 24 "Code=getPublicKey(LR.getParam('SerJsonData'));", 25 "ResultParam=getDataPublicKey", 26 SOURCES, 27 "File=getkey.js",ENDITEM, 28 LAST); 29 30 web_js_run( 31 "Code=getExponent(LR.getParam('SerJsonData'));", 32 "ResultParam=getDataExponent", 33 SOURCES, 34 "File=getkey.js",ENDITEM, 35 LAST); 36 37 web_js_run( 38 "Code=getrKey(LR.getParam('SerJsonData'));", 39 "ResultParam=getDatarKey", 40 SOURCES, 41 "File=getkey.js",ENDITEM, 42 LAST); 43 44 web_js_run( 45 "Code=getModulus(LR.getParam('SerJsonData'));", 46 "ResultParam=getDataModulus", 47 SOURCES, 48 "File=getkey.js",ENDITEM, 49 LAST); 50 51 lr_output_message("# getDataPublicKey 的值为:\n%s", lr_eval_string("{getDataPublicKey}")); 52 lr_output_message("# getDataExponent 的值为:\n%s", lr_eval_string("{getDataExponent}")); 53 lr_output_message("# getDatarKey 的值为:\n%s", lr_eval_string("{getDatarKey}")); 54 lr_output_message("# getDataModulus 的值为:\n%s", lr_eval_string("{getDataModulus}")); 55 56 /* 57 lr_output_message("# mobileNumberSet 的值为:\n%s", lr_eval_string("{mobileNumberSet}")); 58 lr_output_message("# pwdSet 的值为:\n%s", lr_eval_string("{pwdSet}")); 59 lr_output_message("# imgVerifyCodeSet 的值为:\n%s", lr_eval_string("{imgVerifyCodeSet}")); 60 */ 61 //拼接 输入的手机号、密码等 需要加密字符串 62 //sprintf(cliEncrypt,"mobileNumber=%s&pwd=%s&imgVerifyCode=%s",lr_eval_string("{mobileNumberSet}"),lr_eval_string("{pwdSet}"),lr_eval_string("{imgVerifyCodeSet}")); 63 64 //将拼接好的字符串赋值给参数 parCliEncrypt 65 //lr_save_string(cliEncrypt,"parCliEncrypt"); 66 //lr_output_message(lr_eval_string("{parCliEncrypt}")); 67 68 web_js_run( 69 "Code=createEncrypt();", 70 "ResultParam=NewkeyEncrypt", 71 SOURCES, 72 "File=loginEncryptStr.js", 73 ENDITEM, 74 LAST); 75 76 lr_output_message("# NewkeyEncrypt 的值为:\n%s", lr_eval_string("{NewkeyEncrypt}")); 77 78 /*输入账号密码后,点击登录*/ 79 80 web_reg_save_param("newTokenJson", "LB=", "RB=", "Search=Body", LAST); 81 82 rc=web_custom_request("userPwdLogin.action", 83 "URL=http://192.168.1.16/surperman/login/userPwdLogin.action", 84 "Method=POST", 85 "Resource=0", 86 "RecContentType=text/html", 87 "Referer=", 88 "Snapshot=t21.inf", 89 "Mode=HTML", 90 "Body=encrypt={NewkeyEncrypt}&rKey={getDatarKey}", 91 LAST); 92 93 // 返回的字符串需要做编码转换处理,否则中文会显示为乱码 94 lr_convert_string_encoding(lr_eval_string("{newTokenJson}"),"utf-8",NULL,"newTokenJsonUTF"); 95 96 lr_output_message("# newTokenJson 的值为:\n%s", lr_eval_string("{newTokenJson}")); 97 lr_output_message("# newTokenJsonUTF 的值为:\n%s\nJS执行结果:%d", lr_eval_string("{newTokenJsonUTF}"), rc); 98 99 return 0; 100 }
LR 中 web_js_run 所调用的 getkey.js 长这样:
1 function getPublicKey(stringData) 2 { 3 var data = JSON.parse(stringData); 4 return data.publicKey; 5 } 6 7 function getExponent(stringData) 8 { 9 var data = JSON.parse(stringData); 10 return data.exponent; 11 } 12 13 function getrKey(stringData) 14 { 15 var data = JSON.parse(stringData); 16 return data.rKey; 17 } 18 19 function getModulus(stringData) 20 { 21 var data = JSON.parse(stringData); 22 return data.modulus; 23 }
LR 中 web_js_run 所调用的 loginEncryptStr.js 长这样(RSA 库前端开源部分代码可以直接跳过):
1 // RSA 库前端开源部分 - 开始 2 var RSAUtils = {}; 3 4 var biRadixBase = 2; 5 var biRadixBits = 16; 6 var bitsPerDigit = biRadixBits; 7 var biRadix = 1 << 16; // = 2^16 = 65536 8 var biHalfRadix = biRadix >>> 1; 9 var biRadixSquared = biRadix * biRadix; 10 var maxDigitVal = biRadix - 1; 11 var maxInteger = 9999999999999998; 12 13 //maxDigits: 14 //Change this to accommodate your largest number size. Use setMaxDigits() 15 //to change it! 16 // 17 //In general, if you're working with numbers of size N bits, you'll need 2*N 18 //bits of storage. Each digit holds 16 bits. So, a 1024-bit key will need 19 // 20 //1024 * 2 / 16 = 128 digits of storage. 21 // 22 var maxDigits; 23 var ZERO_ARRAY; 24 var bigZero, 25 bigOne; 26 27 var BigInt = window.BigInt = function (flag) { 28 if (typeof flag == "boolean" && flag == true) { 29 this.digits = null; 30 } else { 31 this.digits = ZERO_ARRAY.slice(0); 32 } 33 this.isNeg = false; 34 }; 35 36 RSAUtils.setMaxDigits = function (value) { 37 maxDigits = value; 38 ZERO_ARRAY = new Array(maxDigits); 39 for (var iza = 0; iza < ZERO_ARRAY.length; iza++) 40 ZERO_ARRAY[iza] = 0; 41 bigZero = new BigInt(); 42 bigOne = new BigInt(); 43 bigOne.digits[0] = 1; 44 }; 45 RSAUtils.setMaxDigits(20); 46 47 //The maximum number of digits in base 10 you can convert to an 48 //integer without JavaScript throwing up on you. 49 var dpl10 = 15; 50 51 RSAUtils.biFromNumber = function (i) { 52 var result = new BigInt(); 53 result.isNeg = i < 0; 54 i = Math.abs(i); 55 var j = 0; 56 while (i > 0) { 57 result.digits[j++] = i & maxDigitVal; 58 i = Math.floor(i / biRadix); 59 } 60 return result; 61 }; 62 63 //lr10 = 10 ^ dpl10 64 var lr10 = RSAUtils.biFromNumber(1000000000000000); 65 66 RSAUtils.biFromDecimal = function (s) { 67 var isNeg = s.charAt(0) == '-'; 68 var i = isNeg ? 1 : 0; 69 var result; 70 // Skip leading zeros. 71 while (i < s.length && s.charAt(i) == '0') 72 ++i; 73 if (i == s.length) { 74 result = new BigInt(); 75 } else { 76 var digitCount = s.length - i; 77 var fgl = digitCount % dpl10; 78 if (fgl == 0) 79 fgl = dpl10; 80 result = RSAUtils.biFromNumber(Number(s.substr(i, fgl))); 81 i += fgl; 82 while (i < s.length) { 83 result = RSAUtils.biAdd(RSAUtils.biMultiply(result, lr10), 84 RSAUtils.biFromNumber(Number(s.substr(i, dpl10)))); 85 i += dpl10; 86 } 87 result.isNeg = isNeg; 88 } 89 return result; 90 }; 91 92 RSAUtils.biCopy = function (bi) { 93 var result = new BigInt(true); 94 result.digits = bi.digits.slice(0); 95 result.isNeg = bi.isNeg; 96 return result; 97 }; 98 99 RSAUtils.reverseStr = function (s) { 100 var result = ""; 101 for (var i = s.length - 1; i > -1; --i) { 102 result += s.charAt(i); 103 } 104 return result; 105 }; 106 107 var hexatrigesimalToChar = [ 108 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 109 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 110 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 111 'u', 'v', 'w', 'x', 'y', 'z' 112 ]; 113 114 RSAUtils.biToString = function (x, radix) { // 2 <= radix <= 36 115 var b = new BigInt(); 116 b.digits[0] = radix; 117 var qr = RSAUtils.biDivideModulo(x, b); 118 var result = hexatrigesimalToChar[qr[1].digits[0]]; 119 while (RSAUtils.biCompare(qr[0], bigZero) == 1) { 120 qr = RSAUtils.biDivideModulo(qr[0], b); 121 digit = qr[1].digits[0]; 122 result += hexatrigesimalToChar[qr[1].digits[0]]; 123 } 124 return (x.isNeg ? "-" : "") + RSAUtils.reverseStr(result); 125 }; 126 127 RSAUtils.biToDecimal = function (x) { 128 var b = new BigInt(); 129 b.digits[0] = 10; 130 var qr = RSAUtils.biDivideModulo(x, b); 131 var result = String(qr[1].digits[0]); 132 while (RSAUtils.biCompare(qr[0], bigZero) == 1) { 133 qr = RSAUtils.biDivideModulo(qr[0], b); 134 result += String(qr[1].digits[0]); 135 } 136 return (x.isNeg ? "-" : "") + RSAUtils.reverseStr(result); 137 }; 138 139 var hexToChar = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 140 'a', 'b', 'c', 'd', 'e', 'f']; 141 142 RSAUtils.digitToHex = function (n) { 143 var mask = 0xf; 144 var result = ""; 145 for (i = 0; i < 4; ++i) { 146 result += hexToChar[n & mask]; 147 n >>>= 4; 148 } 149 return RSAUtils.reverseStr(result); 150 }; 151 152 RSAUtils.biToHex = function (x) { 153 var result = ""; 154 var n = RSAUtils.biHighIndex(x); 155 for (var i = RSAUtils.biHighIndex(x); i > -1; --i) { 156 result += RSAUtils.digitToHex(x.digits[i]); 157 } 158 return result; 159 }; 160 161 RSAUtils.charToHex = function (c) { 162 var ZERO = 48; 163 var NINE = ZERO + 9; 164 var littleA = 97; 165 var littleZ = littleA + 25; 166 var bigA = 65; 167 var bigZ = 65 + 25; 168 var result; 169 170 if (c >= ZERO && c <= NINE) { 171 result = c - ZERO; 172 } else if (c >= bigA && c <= bigZ) { 173 result = 10 + c - bigA; 174 } else if (c >= littleA && c <= littleZ) { 175 result = 10 + c - littleA; 176 } else { 177 result = 0; 178 } 179 return result; 180 }; 181 182 RSAUtils.hexToDigit = function (s) { 183 var result = 0; 184 var sl = Math.min(s.length, 4); 185 for (var i = 0; i < sl; ++i) { 186 result <<= 4; 187 result |= RSAUtils.charToHex(s.charCodeAt(i)); 188 } 189 return result; 190 }; 191 192 RSAUtils.biFromHex = function (s) { 193 var result = new BigInt(); 194 var sl = s.length; 195 for (var i = sl, j = 0; i > 0; i -= 4, ++j) { 196 result.digits[j] = RSAUtils.hexToDigit(s.substr(Math.max(i - 4, 0), Math.min(i, 4))); 197 } 198 return result; 199 }; 200 201 RSAUtils.biFromString = function (s, radix) { 202 var isNeg = s.charAt(0) == '-'; 203 var istop = isNeg ? 1 : 0; 204 var result = new BigInt(); 205 var place = new BigInt(); 206 place.digits[0] = 1; // radix^0 207 for (var i = s.length - 1; i >= istop; i--) { 208 var c = s.charCodeAt(i); 209 var digit = RSAUtils.charToHex(c); 210 var biDigit = RSAUtils.biMultiplyDigit(place, digit); 211 result = RSAUtils.biAdd(result, biDigit); 212 place = RSAUtils.biMultiplyDigit(place, radix); 213 } 214 result.isNeg = isNeg; 215 return result; 216 }; 217 218 RSAUtils.biDump = function (b) { 219 return (b.isNeg ? "-" : "") + b.digits.join(" "); 220 }; 221 222 RSAUtils.biAdd = function (x, y) { 223 var result; 224 225 if (x.isNeg != y.isNeg) { 226 y.isNeg = !y.isNeg; 227 result = RSAUtils.biSubtract(x, y); 228 y.isNeg = !y.isNeg; 229 } else { 230 result = new BigInt(); 231 var c = 0; 232 var n; 233 for (var i = 0; i < x.digits.length; ++i) { 234 n = x.digits[i] + y.digits[i] + c; 235 result.digits[i] = n % biRadix; 236 c = Number(n >= biRadix); 237 } 238 result.isNeg = x.isNeg; 239 } 240 return result; 241 }; 242 243 RSAUtils.biSubtract = function (x, y) { 244 var result; 245 if (x.isNeg != y.isNeg) { 246 y.isNeg = !y.isNeg; 247 result = RSAUtils.biAdd(x, y); 248 y.isNeg = !y.isNeg; 249 } else { 250 result = new BigInt(); 251 var n, 252 c; 253 c = 0; 254 for (var i = 0; i < x.digits.length; ++i) { 255 n = x.digits[i] - y.digits[i] + c; 256 result.digits[i] = n % biRadix; 257 // Stupid non-conforming modulus operation. 258 if (result.digits[i] < 0) 259 result.digits[i] += biRadix; 260 c = 0 - Number(n < 0); 261 } 262 // Fix up the negative sign, if any. 263 if (c == -1) { 264 c = 0; 265 for (var i = 0; i < x.digits.length; ++i) { 266 n = 0 - result.digits[i] + c; 267 result.digits[i] = n % biRadix; 268 // Stupid non-conforming modulus operation. 269 if (result.digits[i] < 0) 270 result.digits[i] += biRadix; 271 c = 0 - Number(n < 0); 272 } 273 // Result is opposite sign of arguments. 274 result.isNeg = !x.isNeg; 275 } else { 276 // Result is same sign. 277 result.isNeg = x.isNeg; 278 } 279 } 280 return result; 281 }; 282 283 RSAUtils.biHighIndex = function (x) { 284 var result = x.digits.length - 1; 285 while (result > 0 && x.digits[result] == 0) 286 --result; 287 return result; 288 }; 289 290 RSAUtils.biNumBits = function (x) { 291 var n = RSAUtils.biHighIndex(x); 292 var d = x.digits[n]; 293 var m = (n + 1) * bitsPerDigit; 294 var result; 295 for (result = m; result > m - bitsPerDigit; --result) { 296 if ((d & 0x8000) != 0) 297 break; 298 d <<= 1; 299 } 300 return result; 301 }; 302 303 RSAUtils.biMultiply = function (x, y) { 304 var result = new BigInt(); 305 var c; 306 var n = RSAUtils.biHighIndex(x); 307 var t = RSAUtils.biHighIndex(y); 308 var u, 309 uv, 310 k; 311 312 for (var i = 0; i <= t; ++i) { 313 c = 0; 314 k = i; 315 for (j = 0; j <= n; ++j, ++k) { 316 uv = result.digits[k] + x.digits[j] * y.digits[i] + c; 317 result.digits[k] = uv & maxDigitVal; 318 c = uv >>> biRadixBits; 319 //c = Math.floor(uv / biRadix); 320 } 321 result.digits[i + n + 1] = c; 322 } 323 // Someone give me a logical xor, please. 324 result.isNeg = x.isNeg != y.isNeg; 325 return result; 326 }; 327 328 RSAUtils.biMultiplyDigit = function (x, y) { 329 var n, 330 c, 331 uv; 332 333 result = new BigInt(); 334 n = RSAUtils.biHighIndex(x); 335 c = 0; 336 for (var j = 0; j <= n; ++j) { 337 uv = result.digits[j] + x.digits[j] * y + c; 338 result.digits[j] = uv & maxDigitVal; 339 c = uv >>> biRadixBits; 340 //c = Math.floor(uv / biRadix); 341 } 342 result.digits[1 + n] = c; 343 return result; 344 }; 345 346 RSAUtils.arrayCopy = function (src, srcStart, dest, destStart, n) { 347 var m = Math.min(srcStart + n, src.length); 348 for (var i = srcStart, j = destStart; i < m; ++i, ++j) { 349 dest[j] = src[i]; 350 } 351 }; 352 353 var highBitMasks = [0x0000, 0x8000, 0xC000, 0xE000, 0xF000, 0xF800, 354 0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0, 355 0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF]; 356 357 RSAUtils.biShiftLeft = function (x, n) { 358 var digitCount = Math.floor(n / bitsPerDigit); 359 var result = new BigInt(); 360 RSAUtils.arrayCopy(x.digits, 0, result.digits, digitCount, 361 result.digits.length - digitCount); 362 var bits = n % bitsPerDigit; 363 var rightBits = bitsPerDigit - bits; 364 for (var i = result.digits.length - 1, i1 = i - 1; i > 0; --i, --i1) { 365 result.digits[i] = ((result.digits[i] << bits) & maxDigitVal) | 366 ((result.digits[i1] & highBitMasks[bits]) >>> 367 (rightBits)); 368 } 369 result.digits[0] = ((result.digits[i] << bits) & maxDigitVal); 370 result.isNeg = x.isNeg; 371 return result; 372 }; 373 374 var lowBitMasks = [0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 375 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 376 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF]; 377 378 RSAUtils.biShiftRight = function (x, n) { 379 var digitCount = Math.floor(n / bitsPerDigit); 380 var result = new BigInt(); 381 RSAUtils.arrayCopy(x.digits, digitCount, result.digits, 0, 382 x.digits.length - digitCount); 383 var bits = n % bitsPerDigit; 384 var leftBits = bitsPerDigit - bits; 385 for (var i = 0, i1 = i + 1; i < result.digits.length - 1; ++i, ++i1) { 386 result.digits[i] = (result.digits[i] >>> bits) | 387 ((result.digits[i1] & lowBitMasks[bits]) << leftBits); 388 } 389 result.digits[result.digits.length - 1] >>>= bits; 390 result.isNeg = x.isNeg; 391 return result; 392 }; 393 394 RSAUtils.biMultiplyByRadixPower = function (x, n) { 395 var result = new BigInt(); 396 RSAUtils.arrayCopy(x.digits, 0, result.digits, n, result.digits.length - n); 397 return result; 398 }; 399 400 RSAUtils.biDivideByRadixPower = function (x, n) { 401 var result = new BigInt(); 402 RSAUtils.arrayCopy(x.digits, n, result.digits, 0, result.digits.length - n); 403 return result; 404 }; 405 406 RSAUtils.biModuloByRadixPower = function (x, n) { 407 var result = new BigInt(); 408 RSAUtils.arrayCopy(x.digits, 0, result.digits, 0, n); 409 return result; 410 }; 411 412 RSAUtils.biCompare = function (x, y) { 413 if (x.isNeg != y.isNeg) { 414 return 1 - 2 * Number(x.isNeg); 415 } 416 for (var i = x.digits.length - 1; i >= 0; --i) { 417 if (x.digits[i] != y.digits[i]) { 418 if (x.isNeg) { 419 return 1 - 2 * Number(x.digits[i] > y.digits[i]); 420 } else { 421 return 1 - 2 * Number(x.digits[i] < y.digits[i]); 422 } 423 } 424 } 425 return 0; 426 }; 427 428 RSAUtils.biDivideModulo = function (x, y) { 429 var nb = RSAUtils.biNumBits(x); 430 var tb = RSAUtils.biNumBits(y); 431 var origYIsNeg = y.isNeg; 432 var q, 433 r; 434 if (nb < tb) { 435 // |x| < |y| 436 if (x.isNeg) { 437 q = RSAUtils.biCopy(bigOne); 438 q.isNeg = !y.isNeg; 439 x.isNeg = false; 440 y.isNeg = false; 441 r = biSubtract(y, x); 442 // Restore signs, 'cause they're references. 443 x.isNeg = true; 444 y.isNeg = origYIsNeg; 445 } else { 446 q = new BigInt(); 447 r = RSAUtils.biCopy(x); 448 } 449 return [q, r]; 450 } 451 452 q = new BigInt(); 453 r = x; 454 455 // Normalize Y. 456 var t = Math.ceil(tb / bitsPerDigit) - 1; 457 var lambda = 0; 458 while (y.digits[t] < biHalfRadix) { 459 y = RSAUtils.biShiftLeft(y, 1); 460 ++lambda; 461 ++tb; 462 t = Math.ceil(tb / bitsPerDigit) - 1; 463 } 464 // Shift r over to keep the quotient constant. We'll shift the 465 // remainder back at the end. 466 r = RSAUtils.biShiftLeft(r, lambda); 467 nb += lambda; // Update the bit count for x. 468 var n = Math.ceil(nb / bitsPerDigit) - 1; 469 470 var b = RSAUtils.biMultiplyByRadixPower(y, n - t); 471 while (RSAUtils.biCompare(r, b) != -1) { 472 ++q.digits[n - t]; 473 r = RSAUtils.biSubtract(r, b); 474 } 475 for (var i = n; i > t; --i) { 476 var ri = (i >= r.digits.length) ? 0 : r.digits[i]; 477 var ri1 = (i - 1 >= r.digits.length) ? 0 : r.digits[i - 1]; 478 var ri2 = (i - 2 >= r.digits.length) ? 0 : r.digits[i - 2]; 479 var yt = (t >= y.digits.length) ? 0 : y.digits[t]; 480 var yt1 = (t - 1 >= y.digits.length) ? 0 : y.digits[t - 1]; 481 if (ri == yt) { 482 q.digits[i - t - 1] = maxDigitVal; 483 } else { 484 q.digits[i - t - 1] = Math.floor((ri * biRadix + ri1) / yt); 485 } 486 487 var c1 = q.digits[i - t - 1] * ((yt * biRadix) + yt1); 488 var c2 = (ri * biRadixSquared) + ((ri1 * biRadix) + ri2); 489 while (c1 > c2) { 490 --q.digits[i - t - 1]; 491 c1 = q.digits[i - t - 1] * ((yt * biRadix) | yt1); 492 c2 = (ri * biRadix * biRadix) + ((ri1 * biRadix) + ri2); 493 } 494 495 b = RSAUtils.biMultiplyByRadixPower(y, i - t - 1); 496 r = RSAUtils.biSubtract(r, RSAUtils.biMultiplyDigit(b, q.digits[i - t - 1])); 497 if (r.isNeg) { 498 r = RSAUtils.biAdd(r, b); 499 --q.digits[i - t - 1]; 500 } 501 } 502 r = RSAUtils.biShiftRight(r, lambda); 503 // Fiddle with the signs and stuff to make sure that 0 <= r < y. 504 q.isNeg = x.isNeg != origYIsNeg; 505 if (x.isNeg) { 506 if (origYIsNeg) { 507 q = RSAUtils.biAdd(q, bigOne); 508 } else { 509 q = RSAUtils.biSubtract(q, bigOne); 510 } 511 y = RSAUtils.biShiftRight(y, lambda); 512 r = RSAUtils.biSubtract(y, r); 513 } 514 // Check for the unbelievably stupid degenerate case of r == -0. 515 if (r.digits[0] == 0 && RSAUtils.biHighIndex(r) == 0) 516 r.isNeg = false; 517 518 return [q, r]; 519 }; 520 521 RSAUtils.biDivide = function (x, y) { 522 return RSAUtils.biDivideModulo(x, y)[0]; 523 }; 524 525 RSAUtils.biModulo = function (x, y) { 526 return RSAUtils.biDivideModulo(x, y)[1]; 527 }; 528 529 RSAUtils.biMultiplyMod = function (x, y, m) { 530 return RSAUtils.biModulo(RSAUtils.biMultiply(x, y), m); 531 }; 532 533 RSAUtils.biPow = function (x, y) { 534 var result = bigOne; 535 var a = x; 536 while (true) { 537 if ((y & 1) != 0) 538 result = RSAUtils.biMultiply(result, a); 539 y >>= 1; 540 if (y == 0) 541 break; 542 a = RSAUtils.biMultiply(a, a); 543 } 544 return result; 545 }; 546 547 RSAUtils.biPowMod = function (x, y, m) { 548 var result = bigOne; 549 var a = x; 550 var k = y; 551 while (true) { 552 if ((k.digits[0] & 1) != 0) 553 result = RSAUtils.biMultiplyMod(result, a, m); 554 k = RSAUtils.biShiftRight(k, 1); 555 if (k.digits[0] == 0 && RSAUtils.biHighIndex(k) == 0) 556 break; 557 a = RSAUtils.biMultiplyMod(a, a, m); 558 } 559 return result; 560 }; 561 562 window.BarrettMu = function (m) { 563 this.modulus = RSAUtils.biCopy(m); 564 this.k = RSAUtils.biHighIndex(this.modulus) + 1; 565 var b2k = new BigInt(); 566 b2k.digits[2 * this.k] = 1; // b2k = b^(2k) 567 this.mu = RSAUtils.biDivide(b2k, this.modulus); 568 this.bkplus1 = new BigInt(); 569 this.bkplus1.digits[this.k + 1] = 1; // bkplus1 = b^(k+1) 570 this.modulo = BarrettMu_modulo; 571 this.multiplyMod = BarrettMu_multiplyMod; 572 this.powMod = BarrettMu_powMod; 573 }; 574 575 function BarrettMu_modulo(x) { 576 var $dmath = RSAUtils; 577 var q1 = $dmath.biDivideByRadixPower(x, this.k - 1); 578 var q2 = $dmath.biMultiply(q1, this.mu); 579 var q3 = $dmath.biDivideByRadixPower(q2, this.k + 1); 580 var r1 = $dmath.biModuloByRadixPower(x, this.k + 1); 581 var r2term = $dmath.biMultiply(q3, this.modulus); 582 var r2 = $dmath.biModuloByRadixPower(r2term, this.k + 1); 583 var r = $dmath.biSubtract(r1, r2); 584 if (r.isNeg) { 585 r = $dmath.biAdd(r, this.bkplus1); 586 } 587 var rgtem = $dmath.biCompare(r, this.modulus) >= 0; 588 while (rgtem) { 589 r = $dmath.biSubtract(r, this.modulus); 590 rgtem = $dmath.biCompare(r, this.modulus) >= 0; 591 } 592 return r; 593 } 594 595 function BarrettMu_multiplyMod(x, y) { 596 /* 597 x = this.modulo(x); 598 y = this.modulo(y); 599 */ 600 var xy = RSAUtils.biMultiply(x, y); 601 return this.modulo(xy); 602 } 603 604 function BarrettMu_powMod(x, y) { 605 var result = new BigInt(); 606 result.digits[0] = 1; 607 var a = x; 608 var k = y; 609 while (true) { 610 if ((k.digits[0] & 1) != 0) 611 result = this.multiplyMod(result, a); 612 k = RSAUtils.biShiftRight(k, 1); 613 if (k.digits[0] == 0 && RSAUtils.biHighIndex(k) == 0) 614 break; 615 a = this.multiplyMod(a, a); 616 } 617 return result; 618 } 619 620 var RSAKeyPair = function (encryptionExponent, decryptionExponent, modulus) { 621 alert(1); 622 var $dmath = RSAUtils; 623 this.e = $dmath.biFromHex(encryptionExponent); 624 this.d = $dmath.biFromHex(decryptionExponent); 625 this.m = $dmath.biFromHex(modulus); 626 // We can do two bytes per digit, so 627 // chunkSize = 2 * (number of digits in modulus - 1). 628 // Since biHighIndex returns the high index, not the number of digits, 1 has 629 // already been subtracted. 630 this.chunkSize = 2 * $dmath.biHighIndex(this.m); 631 this.radix = 16; 632 this.barrett = new window.BarrettMu(this.m); 633 }; 634 635 RSAUtils.getKeyPair = function (encryptionExponent, decryptionExponent, modulus) { 636 return new RSAKeyPair(encryptionExponent, decryptionExponent, modulus); 637 }; 638 639 if (typeof window.twoDigit === 'undefined') { 640 window.twoDigit = function (n) { 641 return (n < 10 ? "0" : "") + String(n); 642 }; 643 } 644 645 // Altered by Rob Saunders (rob@robsaunders.net). New routine pads the 646 // string after it has been converted to an array. This fixes an 647 // incompatibility with Flash MX's ActionScript. 648 RSAUtils.encryptedString = function (key, s) { 649 var a = []; 650 var sl = s.length; 651 var i = 0; 652 while (i < sl) { 653 a[i] = s.charCodeAt(i); 654 i++; 655 } 656 while (a.length % key.chunkSize != 0) { 657 a[i++] = 0; 658 } 659 660 var al = a.length; 661 var result = ""; 662 var j, 663 k, 664 block; 665 for (i = 0; i < al; i += key.chunkSize) { 666 block = new BigInt(); 667 j = 0; 668 for (k = i; k < i + key.chunkSize; ++j) { 669 block.digits[j] = a[k++]; 670 block.digits[j] += a[k++] << 8; 671 } 672 var crypt = key.barrett.powMod(block, key.e); 673 var text = key.radix == 16 ? RSAUtils.biToHex(crypt) : RSAUtils.biToString(crypt, key.radix); 674 result += text + " "; 675 } 676 return result.substring(0, result.length - 1); // Remove last space. 677 }; 678 679 RSAUtils.decryptedString = function (key, s) { 680 var blocks = s.split(" "); 681 var result = ""; 682 var i, 683 j, 684 block; 685 for (i = 0; i < blocks.length; ++i) { 686 var bi; 687 if (key.radix == 16) { 688 bi = RSAUtils.biFromHex(blocks[i]); 689 } else { 690 bi = RSAUtils.biFromString(blocks[i], key.radix); 691 } 692 block = key.barrett.powMod(bi, key.d); 693 for (j = 0; j <= RSAUtils.biHighIndex(block); ++j) { 694 result += String.fromCharCode(block.digits[j] & 255, 695 block.digits[j] >> 8); 696 } 697 } 698 // Remove trailing null, if any. 699 if (result.charCodeAt(result.length - 1) == 0) { 700 result = result.substring(0, result.length - 1); 701 } 702 return result; 703 }; 704 705 RSAUtils.setMaxDigits(130); 706 // RSA 库前端开源部分 - 结束 707 708 // 以下为LR调用RSA加密实现的关键代码 709 function createEncrypt() { 710 //LR.loadLibrary('rsaiutil.js'); 711 //mobileNumberSet;//输入的手机号 712 //pwdSet;//输入的密码 713 //imgVerifyCodeSet;//输入的图形验证码 714 715 // 通过 LR.getParam('mobileNumberSet') 可以在 JS 脚本中直接获取 LR 脚本的参数 716 var cliPublicKey = new RSAUtils.getKeyPair(LR.getParam('getDataExponent'), "", LR.getParam('getDataModulus')); 717 var encrypt = "mobileNumber=" + LR.getParam('mobileNumberSet') + "&pwd=" + LR.getParam('pwdSet') + "&imgVerifyCode=" + LR.getParam('imgVerifyCodeSet');// 718 encrypt = encrypt.split("").reverse().join("");//将需要加密的字符串反序排列 719 encrypt = RSAUtils.encryptedString(cliPublicKey, encrypt); //获得加密后的字符串 720 return encrypt; 721 }
运行 Action 的结果:
1 虚拟用户脚本已于 : 2018/2/24 Saturday PM 4:05:06 启动 2 正在开始操作 vuser_init。 3 LoadRunner 12.53.0 (Windows 7) 的 Web Turbo 回放;内部版本 1203 (二月 24 2018 19:13:20) [MsgId: MMSG-26983] 4 运行模式: HTML [MsgId: MMSG-26993] 5 回放用户代理: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0) [MsgId: MMSG-26988] 6 运行时设置文件: "C:\Users\VuGen\Scripts\WebHttpHtml6\\default.cfg" [MsgId: MMSG-27141] 7 正在结束操作 vuser_init。 8 正在运行 Vuser... 9 正在开始迭代 1。 10 每个服务器的最大并发连接数: 6 [MsgId: MMSG-26989] 11 正在开始操作 Action。 12 Action.c(24): web_reg_save_param 已启动 [MsgId: MMSG-26355] 13 Action.c(24): 注册 web_reg_save_param 成功 [MsgId: MMSG-26390] 14 Action.c(26): web_submit_data("encryptKey.action") 已启动 [MsgId: MMSG-26355] 15 Action.c(26): web_submit_data("encryptKey.action") 已成功,613 个正文字节,155 个标头字节 [MsgId: MMSG-26386] 16 Action.c(36): # 获取密钥响应内容体: 17 {"publicKey":"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBEZM4rLUDmybC9qFGLUwTFNsAbUFxyb\/SDTPr\nfVVgrkg1PL4yTOFyHgJe5oMcZyR0hqdz8fGpkesiN20dWwUem67tAszHgIHcVuswwyT2nV7pUNMj\nz53v5QWHsZ6\/oW1LXVnGYwvjVATHc1p2VOuATGw28XDEukWyGcKzTtcwzwIDAQAB\n","error_msg":"ok","error_code":0,"exponent":"010001","rKey":"5406701c505548beb3c1043bbcee5229","modulus":"00c1119338acb5039b26c2f6a1462d4c1314db006d4171c9bfd20d33eb7d5560ae48353cbe324ce1721e025ee6831c67247486a773f1f1a991eb22376d1d5b051e9baeed02ccc78081dc56eb30c324f69d5ee950d323cf9defe50587b19ebfa16d4b5d59c6630be35404c7735a7654eb804c6c36f170c4ba45b219c2b34ed730cf"} 18 Action.c(38): web_js_run 已启动 [MsgId: MMSG-26355] 19 Action.c(38): web_js_run 已成功 [MsgId: MMSG-26392] 20 Action.c(45): web_js_run 已启动 [MsgId: MMSG-26355] 21 Action.c(45): web_js_run 已成功 [MsgId: MMSG-26392] 22 Action.c(52): web_js_run 已启动 [MsgId: MMSG-26355] 23 Action.c(52): web_js_run 已成功 [MsgId: MMSG-26392] 24 Action.c(59): web_js_run 已启动 [MsgId: MMSG-26355] 25 Action.c(59): web_js_run 已成功 [MsgId: MMSG-26392] 26 Action.c(66): # getDataPublicKey 的值为: 27 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBEZM4rLUDmybC9qFGLUwTFNsAbUFxyb/SDTPr\nfVVgrkg1PL4yTOFyHgJe5oMcZyR0hqdz8fGpkesiN20dWwUem67tAszHgIHcVuswwyT2nV7pUNMj\nz53v5QWHsZ6/oW1LXVnGYwvjVATHc1p2VOuATGw28XDEukWyGcKzTtcwzwIDAQAB\n 28 Action.c(67): # getDataExponent 的值为: 29 010001 30 Action.c(68): # getDatarKey 的值为: 31 5406701c505548beb3c1043bbcee5229 32 Action.c(69): # getDataModulus 的值为: 33 00c1119338acb5039b26c2f6a1462d4c1314db006d4171c9bfd20d33eb7d5560ae48353cbe324ce1721e025ee6831c67247486a773f1f1a991eb22376d1d5b051e9baeed02ccc78081dc56eb30c324f69d5ee950d323cf9defe50587b19ebfa16d4b5d59c6630be35404c7735a7654eb804c6c36f170c4ba45b219c2b34ed730cf 34 Action.c(109): web_js_run 已启动 [MsgId: MMSG-26355] 35 Alert from JS (len=1): 1 36 Action.c(109): web_js_run 已成功 [MsgId: MMSG-26392] 37 Action.c(117): # NewkeyEncrypt 的值为: 38 4ea861aa44b8d90b08677e525ebd2607a992b87108308329fb01afd518bf4104344cb26e149ec43416a8181ad4cfc7e358e9ca2a2eab0a9072e5d86182e91f524376a3414b268244c62a2e149ac905679f66dd455ea386537136660508a3af71b479df9dc7beaf21ef5f2e70edfad8e88c64af35415e68258599c4b09791e43e 39 Action.c(121): web_reg_save_param 已启动 [MsgId: MMSG-26355] 40 Action.c(121): 注册 web_reg_save_param 成功 [MsgId: MMSG-26390] 41 Action.c(123): web_custom_request("userPwdLogin.action") 已启动 [MsgId: MMSG-26355] 42 Action.c(123): web_custom_request("userPwdLogin.action") 已成功,490 个正文字节,155 个标头字节 [MsgId: MMSG-26386] 43 Action.c(137): # newTokenJson 的值为: 44 {"portraitUrl":"http:\/\/test.666.com\/pt\/com\/img\/default-doctor-portrait.jpg","userGuideStat":null,"error_msg":"鐧诲綍鎴愬姛","nickname":"鍖昏€?6","alias":"dev473002","token":"cbc70505fccd4866aa88f3404a4ab8d1","error_code":0,"tag":"dev鍖荤敓","user_id":473002,"portraitUuid":"","type":"鍖荤敓","statistics":{"dtOnlinePrescOrdersPaid":0,"userId":473002,"role":"dt","dtOnlinePrescOrders":170,"lastLoginTime":"201802","registerTime":"2017-05-16 10:47:51","dtQualified":true}} 45 Action.c(138): # newTokenJsonUTF 的值为: 46 {"portraitUrl":"http:\/\/test.666.com\/pt\/com\/img\/default-doctor-portrait.jpg","userGuideStat":null,"error_msg":"登录成功","nickname":"医者26","alias":"dev473002","token":"cbc70505fccd4866aa88f3404a4ab8d1","error_code":0,"tag":"dev侵权者","user_id":473002,"portraitUuid":"","type":"侵权者","statistics":{"dtOnlinePrescOrdersPaid":0,"userId":473002,"role":"dt","dtOnlinePrescOrders":170,"lastLoginTime":"201802","registerTime":"2017-05-16 10:47:51","dtQualified":true}} 47 JS执行结果:0 48 正在结束操作 Action。 49 正在结束迭代 1。 50 正在结束 Vuser... 51 正在开始操作 vuser_end。 52 正在结束操作 vuser_end。 53 Vuser 已终止。
另:开源的 RSA库 在未修改时,是独立的一个 JS 文件;未修改前是长这样:
1 /* 2 * RSA, a suite of routines for performing RSA public-key computations in JavaScript. 3 * Copyright 1998-2005 David Shapiro. 4 * Dave Shapiro 5 * dave@ohdave.com 6 * changed by Fuchun, 2010-05-06 7 * fcrpg2005@gmail.com 8 */ 9 10 (function ($w) { 11 12 if (typeof $w.RSAUtils === 'undefined') 13 var RSAUtils = $w.RSAUtils = {}; 14 15 var biRadixBase = 2; 16 var biRadixBits = 16; 17 var bitsPerDigit = biRadixBits; 18 var biRadix = 1 << 16; // = 2^16 = 65536 19 var biHalfRadix = biRadix >>> 1; 20 var biRadixSquared = biRadix * biRadix; 21 var maxDigitVal = biRadix - 1; 22 var maxInteger = 9999999999999998; 23 24 //maxDigits: 25 //Change this to accommodate your largest number size. Use setMaxDigits() 26 //to change it! 27 // 28 //In general, if you're working with numbers of size N bits, you'll need 2*N 29 //bits of storage. Each digit holds 16 bits. So, a 1024-bit key will need 30 // 31 //1024 * 2 / 16 = 128 digits of storage. 32 // 33 var maxDigits; 34 var ZERO_ARRAY; 35 var bigZero, 36 bigOne; 37 38 var BigInt = $w.BigInt = function (flag) { 39 if (typeof flag == "boolean" && flag == true) { 40 this.digits = null; 41 } else { 42 this.digits = ZERO_ARRAY.slice(0); 43 } 44 this.isNeg = false; 45 }; 46 47 RSAUtils.setMaxDigits = function (value) { 48 maxDigits = value; 49 ZERO_ARRAY = new Array(maxDigits); 50 for (var iza = 0; iza < ZERO_ARRAY.length; iza++) 51 ZERO_ARRAY[iza] = 0; 52 bigZero = new BigInt(); 53 bigOne = new BigInt(); 54 bigOne.digits[0] = 1; 55 }; 56 RSAUtils.setMaxDigits(20); 57 58 //The maximum number of digits in base 10 you can convert to an 59 //integer without JavaScript throwing up on you. 60 var dpl10 = 15; 61 62 RSAUtils.biFromNumber = function (i) { 63 var result = new BigInt(); 64 result.isNeg = i < 0; 65 i = Math.abs(i); 66 var j = 0; 67 while (i > 0) { 68 result.digits[j++] = i & maxDigitVal; 69 i = Math.floor(i / biRadix); 70 } 71 return result; 72 }; 73 74 //lr10 = 10 ^ dpl10 75 var lr10 = RSAUtils.biFromNumber(1000000000000000); 76 77 RSAUtils.biFromDecimal = function (s) { 78 var isNeg = s.charAt(0) == '-'; 79 var i = isNeg ? 1 : 0; 80 var result; 81 // Skip leading zeros. 82 while (i < s.length && s.charAt(i) == '0') 83 ++i; 84 if (i == s.length) { 85 result = new BigInt(); 86 } else { 87 var digitCount = s.length - i; 88 var fgl = digitCount % dpl10; 89 if (fgl == 0) 90 fgl = dpl10; 91 result = RSAUtils.biFromNumber(Number(s.substr(i, fgl))); 92 i += fgl; 93 while (i < s.length) { 94 result = RSAUtils.biAdd(RSAUtils.biMultiply(result, lr10), 95 RSAUtils.biFromNumber(Number(s.substr(i, dpl10)))); 96 i += dpl10; 97 } 98 result.isNeg = isNeg; 99 } 100 return result; 101 }; 102 103 RSAUtils.biCopy = function (bi) { 104 var result = new BigInt(true); 105 result.digits = bi.digits.slice(0); 106 result.isNeg = bi.isNeg; 107 return result; 108 }; 109 110 RSAUtils.reverseStr = function (s) { 111 var result = ""; 112 for (var i = s.length - 1; i > -1; --i) { 113 result += s.charAt(i); 114 } 115 return result; 116 }; 117 118 var hexatrigesimalToChar = [ 119 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 120 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 121 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 122 'u', 'v', 'w', 'x', 'y', 'z' 123 ]; 124 125 RSAUtils.biToString = function (x, radix) { // 2 <= radix <= 36 126 var b = new BigInt(); 127 b.digits[0] = radix; 128 var qr = RSAUtils.biDivideModulo(x, b); 129 var result = hexatrigesimalToChar[qr[1].digits[0]]; 130 while (RSAUtils.biCompare(qr[0], bigZero) == 1) { 131 qr = RSAUtils.biDivideModulo(qr[0], b); 132 digit = qr[1].digits[0]; 133 result += hexatrigesimalToChar[qr[1].digits[0]]; 134 } 135 return (x.isNeg ? "-" : "") + RSAUtils.reverseStr(result); 136 }; 137 138 RSAUtils.biToDecimal = function (x) { 139 var b = new BigInt(); 140 b.digits[0] = 10; 141 var qr = RSAUtils.biDivideModulo(x, b); 142 var result = String(qr[1].digits[0]); 143 while (RSAUtils.biCompare(qr[0], bigZero) == 1) { 144 qr = RSAUtils.biDivideModulo(qr[0], b); 145 result += String(qr[1].digits[0]); 146 } 147 return (x.isNeg ? "-" : "") + RSAUtils.reverseStr(result); 148 }; 149 150 var hexToChar = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 151 'a', 'b', 'c', 'd', 'e', 'f']; 152 153 RSAUtils.digitToHex = function (n) { 154 var mask = 0xf; 155 var result = ""; 156 for (i = 0; i < 4; ++i) { 157 result += hexToChar[n & mask]; 158 n >>>= 4; 159 } 160 return RSAUtils.reverseStr(result); 161 }; 162 163 RSAUtils.biToHex = function (x) { 164 var result = ""; 165 var n = RSAUtils.biHighIndex(x); 166 for (var i = RSAUtils.biHighIndex(x); i > -1; --i) { 167 result += RSAUtils.digitToHex(x.digits[i]); 168 } 169 return result; 170 }; 171 172 RSAUtils.charToHex = function (c) { 173 var ZERO = 48; 174 var NINE = ZERO + 9; 175 var littleA = 97; 176 var littleZ = littleA + 25; 177 var bigA = 65; 178 var bigZ = 65 + 25; 179 var result; 180 181 if (c >= ZERO && c <= NINE) { 182 result = c - ZERO; 183 } else if (c >= bigA && c <= bigZ) { 184 result = 10 + c - bigA; 185 } else if (c >= littleA && c <= littleZ) { 186 result = 10 + c - littleA; 187 } else { 188 result = 0; 189 } 190 return result; 191 }; 192 193 RSAUtils.hexToDigit = function (s) { 194 var result = 0; 195 var sl = Math.min(s.length, 4); 196 for (var i = 0; i < sl; ++i) { 197 result <<= 4; 198 result |= RSAUtils.charToHex(s.charCodeAt(i)); 199 } 200 return result; 201 }; 202 203 RSAUtils.biFromHex = function (s) { 204 var result = new BigInt(); 205 var sl = s.length; 206 for (var i = sl, j = 0; i > 0; i -= 4, ++j) { 207 result.digits[j] = RSAUtils.hexToDigit(s.substr(Math.max(i - 4, 0), Math.min(i, 4))); 208 } 209 return result; 210 }; 211 212 RSAUtils.biFromString = function (s, radix) { 213 var isNeg = s.charAt(0) == '-'; 214 var istop = isNeg ? 1 : 0; 215 var result = new BigInt(); 216 var place = new BigInt(); 217 place.digits[0] = 1; // radix^0 218 for (var i = s.length - 1; i >= istop; i--) { 219 var c = s.charCodeAt(i); 220 var digit = RSAUtils.charToHex(c); 221 var biDigit = RSAUtils.biMultiplyDigit(place, digit); 222 result = RSAUtils.biAdd(result, biDigit); 223 place = RSAUtils.biMultiplyDigit(place, radix); 224 } 225 result.isNeg = isNeg; 226 return result; 227 }; 228 229 RSAUtils.biDump = function (b) { 230 return (b.isNeg ? "-" : "") + b.digits.join(" "); 231 }; 232 233 RSAUtils.biAdd = function (x, y) { 234 var result; 235 236 if (x.isNeg != y.isNeg) { 237 y.isNeg = !y.isNeg; 238 result = RSAUtils.biSubtract(x, y); 239 y.isNeg = !y.isNeg; 240 } else { 241 result = new BigInt(); 242 var c = 0; 243 var n; 244 for (var i = 0; i < x.digits.length; ++i) { 245 n = x.digits[i] + y.digits[i] + c; 246 result.digits[i] = n % biRadix; 247 c = Number(n >= biRadix); 248 } 249 result.isNeg = x.isNeg; 250 } 251 return result; 252 }; 253 254 RSAUtils.biSubtract = function (x, y) { 255 var result; 256 if (x.isNeg != y.isNeg) { 257 y.isNeg = !y.isNeg; 258 result = RSAUtils.biAdd(x, y); 259 y.isNeg = !y.isNeg; 260 } else { 261 result = new BigInt(); 262 var n, 263 c; 264 c = 0; 265 for (var i = 0; i < x.digits.length; ++i) { 266 n = x.digits[i] - y.digits[i] + c; 267 result.digits[i] = n % biRadix; 268 // Stupid non-conforming modulus operation. 269 if (result.digits[i] < 0) 270 result.digits[i] += biRadix; 271 c = 0 - Number(n < 0); 272 } 273 // Fix up the negative sign, if any. 274 if (c == -1) { 275 c = 0; 276 for (var i = 0; i < x.digits.length; ++i) { 277 n = 0 - result.digits[i] + c; 278 result.digits[i] = n % biRadix; 279 // Stupid non-conforming modulus operation. 280 if (result.digits[i] < 0) 281 result.digits[i] += biRadix; 282 c = 0 - Number(n < 0); 283 } 284 // Result is opposite sign of arguments. 285 result.isNeg = !x.isNeg; 286 } else { 287 // Result is same sign. 288 result.isNeg = x.isNeg; 289 } 290 } 291 return result; 292 }; 293 294 RSAUtils.biHighIndex = function (x) { 295 var result = x.digits.length - 1; 296 while (result > 0 && x.digits[result] == 0) 297 --result; 298 return result; 299 }; 300 301 RSAUtils.biNumBits = function (x) { 302 var n = RSAUtils.biHighIndex(x); 303 var d = x.digits[n]; 304 var m = (n + 1) * bitsPerDigit; 305 var result; 306 for (result = m; result > m - bitsPerDigit; --result) { 307 if ((d & 0x8000) != 0) 308 break; 309 d <<= 1; 310 } 311 return result; 312 }; 313 314 RSAUtils.biMultiply = function (x, y) { 315 var result = new BigInt(); 316 var c; 317 var n = RSAUtils.biHighIndex(x); 318 var t = RSAUtils.biHighIndex(y); 319 var u, 320 uv, 321 k; 322 323 for (var i = 0; i <= t; ++i) { 324 c = 0; 325 k = i; 326 for (j = 0; j <= n; ++j, ++k) { 327 uv = result.digits[k] + x.digits[j] * y.digits[i] + c; 328 result.digits[k] = uv & maxDigitVal; 329 c = uv >>> biRadixBits; 330 //c = Math.floor(uv / biRadix); 331 } 332 result.digits[i + n + 1] = c; 333 } 334 // Someone give me a logical xor, please. 335 result.isNeg = x.isNeg != y.isNeg; 336 return result; 337 }; 338 339 RSAUtils.biMultiplyDigit = function (x, y) { 340 var n, 341 c, 342 uv; 343 344 result = new BigInt(); 345 n = RSAUtils.biHighIndex(x); 346 c = 0; 347 for (var j = 0; j <= n; ++j) { 348 uv = result.digits[j] + x.digits[j] * y + c; 349 result.digits[j] = uv & maxDigitVal; 350 c = uv >>> biRadixBits; 351 //c = Math.floor(uv / biRadix); 352 } 353 result.digits[1 + n] = c; 354 return result; 355 }; 356 357 RSAUtils.arrayCopy = function (src, srcStart, dest, destStart, n) { 358 var m = Math.min(srcStart + n, src.length); 359 for (var i = srcStart, j = destStart; i < m; ++i, ++j) { 360 dest[j] = src[i]; 361 } 362 }; 363 364 var highBitMasks = [0x0000, 0x8000, 0xC000, 0xE000, 0xF000, 0xF800, 365 0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0, 366 0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF]; 367 368 RSAUtils.biShiftLeft = function (x, n) { 369 var digitCount = Math.floor(n / bitsPerDigit); 370 var result = new BigInt(); 371 RSAUtils.arrayCopy(x.digits, 0, result.digits, digitCount, 372 result.digits.length - digitCount); 373 var bits = n % bitsPerDigit; 374 var rightBits = bitsPerDigit - bits; 375 for (var i = result.digits.length - 1, i1 = i - 1; i > 0; --i, --i1) { 376 result.digits[i] = ((result.digits[i] << bits) & maxDigitVal) | 377 ((result.digits[i1] & highBitMasks[bits]) >>> 378 (rightBits)); 379 } 380 result.digits[0] = ((result.digits[i] << bits) & maxDigitVal); 381 result.isNeg = x.isNeg; 382 return result; 383 }; 384 385 var lowBitMasks = [0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 386 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 387 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF]; 388 389 RSAUtils.biShiftRight = function (x, n) { 390 var digitCount = Math.floor(n / bitsPerDigit); 391 var result = new BigInt(); 392 RSAUtils.arrayCopy(x.digits, digitCount, result.digits, 0, 393 x.digits.length - digitCount); 394 var bits = n % bitsPerDigit; 395 var leftBits = bitsPerDigit - bits; 396 for (var i = 0, i1 = i + 1; i < result.digits.length - 1; ++i, ++i1) { 397 result.digits[i] = (result.digits[i] >>> bits) | 398 ((result.digits[i1] & lowBitMasks[bits]) << leftBits); 399 } 400 result.digits[result.digits.length - 1] >>>= bits; 401 result.isNeg = x.isNeg; 402 return result; 403 }; 404 405 RSAUtils.biMultiplyByRadixPower = function (x, n) { 406 var result = new BigInt(); 407 RSAUtils.arrayCopy(x.digits, 0, result.digits, n, result.digits.length - n); 408 return result; 409 }; 410 411 RSAUtils.biDivideByRadixPower = function (x, n) { 412 var result = new BigInt(); 413 RSAUtils.arrayCopy(x.digits, n, result.digits, 0, result.digits.length - n); 414 return result; 415 }; 416 417 RSAUtils.biModuloByRadixPower = function (x, n) { 418 var result = new BigInt(); 419 RSAUtils.arrayCopy(x.digits, 0, result.digits, 0, n); 420 return result; 421 }; 422 423 RSAUtils.biCompare = function (x, y) { 424 if (x.isNeg != y.isNeg) { 425 return 1 - 2 * Number(x.isNeg); 426 } 427 for (var i = x.digits.length - 1; i >= 0; --i) { 428 if (x.digits[i] != y.digits[i]) { 429 if (x.isNeg) { 430 return 1 - 2 * Number(x.digits[i] > y.digits[i]); 431 } else { 432 return 1 - 2 * Number(x.digits[i] < y.digits[i]); 433 } 434 } 435 } 436 return 0; 437 }; 438 439 RSAUtils.biDivideModulo = function (x, y) { 440 var nb = RSAUtils.biNumBits(x); 441 var tb = RSAUtils.biNumBits(y); 442 var origYIsNeg = y.isNeg; 443 var q, 444 r; 445 if (nb < tb) { 446 // |x| < |y| 447 if (x.isNeg) { 448 q = RSAUtils.biCopy(bigOne); 449 q.isNeg = !y.isNeg; 450 x.isNeg = false; 451 y.isNeg = false; 452 r = biSubtract(y, x); 453 // Restore signs, 'cause they're references. 454 x.isNeg = true; 455 y.isNeg = origYIsNeg; 456 } else { 457 q = new BigInt(); 458 r = RSAUtils.biCopy(x); 459 } 460 return [q, r]; 461 } 462 463 q = new BigInt(); 464 r = x; 465 466 // Normalize Y. 467 var t = Math.ceil(tb / bitsPerDigit) - 1; 468 var lambda = 0; 469 while (y.digits[t] < biHalfRadix) { 470 y = RSAUtils.biShiftLeft(y, 1); 471 ++lambda; 472 ++tb; 473 t = Math.ceil(tb / bitsPerDigit) - 1; 474 } 475 // Shift r over to keep the quotient constant. We'll shift the 476 // remainder back at the end. 477 r = RSAUtils.biShiftLeft(r, lambda); 478 nb += lambda; // Update the bit count for x. 479 var n = Math.ceil(nb / bitsPerDigit) - 1; 480 481 var b = RSAUtils.biMultiplyByRadixPower(y, n - t); 482 while (RSAUtils.biCompare(r, b) != -1) { 483 ++q.digits[n - t]; 484 r = RSAUtils.biSubtract(r, b); 485 } 486 for (var i = n; i > t; --i) { 487 var ri = (i >= r.digits.length) ? 0 : r.digits[i]; 488 var ri1 = (i - 1 >= r.digits.length) ? 0 : r.digits[i - 1]; 489 var ri2 = (i - 2 >= r.digits.length) ? 0 : r.digits[i - 2]; 490 var yt = (t >= y.digits.length) ? 0 : y.digits[t]; 491 var yt1 = (t - 1 >= y.digits.length) ? 0 : y.digits[t - 1]; 492 if (ri == yt) { 493 q.digits[i - t - 1] = maxDigitVal; 494 } else { 495 q.digits[i - t - 1] = Math.floor((ri * biRadix + ri1) / yt); 496 } 497 498 var c1 = q.digits[i - t - 1] * ((yt * biRadix) + yt1); 499 var c2 = (ri * biRadixSquared) + ((ri1 * biRadix) + ri2); 500 while (c1 > c2) { 501 --q.digits[i - t - 1]; 502 c1 = q.digits[i - t - 1] * ((yt * biRadix) | yt1); 503 c2 = (ri * biRadix * biRadix) + ((ri1 * biRadix) + ri2); 504 } 505 506 b = RSAUtils.biMultiplyByRadixPower(y, i - t - 1); 507 r = RSAUtils.biSubtract(r, RSAUtils.biMultiplyDigit(b, q.digits[i - t - 1])); 508 if (r.isNeg) { 509 r = RSAUtils.biAdd(r, b); 510 --q.digits[i - t - 1]; 511 } 512 } 513 r = RSAUtils.biShiftRight(r, lambda); 514 // Fiddle with the signs and stuff to make sure that 0 <= r < y. 515 q.isNeg = x.isNeg != origYIsNeg; 516 if (x.isNeg) { 517 if (origYIsNeg) { 518 q = RSAUtils.biAdd(q, bigOne); 519 } else { 520 q = RSAUtils.biSubtract(q, bigOne); 521 } 522 y = RSAUtils.biShiftRight(y, lambda); 523 r = RSAUtils.biSubtract(y, r); 524 } 525 // Check for the unbelievably stupid degenerate case of r == -0. 526 if (r.digits[0] == 0 && RSAUtils.biHighIndex(r) == 0) 527 r.isNeg = false; 528 529 return [q, r]; 530 }; 531 532 RSAUtils.biDivide = function (x, y) { 533 return RSAUtils.biDivideModulo(x, y)[0]; 534 }; 535 536 RSAUtils.biModulo = function (x, y) { 537 return RSAUtils.biDivideModulo(x, y)[1]; 538 }; 539 540 RSAUtils.biMultiplyMod = function (x, y, m) { 541 return RSAUtils.biModulo(RSAUtils.biMultiply(x, y), m); 542 }; 543 544 RSAUtils.biPow = function (x, y) { 545 var result = bigOne; 546 var a = x; 547 while (true) { 548 if ((y & 1) != 0) 549 result = RSAUtils.biMultiply(result, a); 550 y >>= 1; 551 if (y == 0) 552 break; 553 a = RSAUtils.biMultiply(a, a); 554 } 555 return result; 556 }; 557 558 RSAUtils.biPowMod = function (x, y, m) { 559 var result = bigOne; 560 var a = x; 561 var k = y; 562 while (true) { 563 if ((k.digits[0] & 1) != 0) 564 result = RSAUtils.biMultiplyMod(result, a, m); 565 k = RSAUtils.biShiftRight(k, 1); 566 if (k.digits[0] == 0 && RSAUtils.biHighIndex(k) == 0) 567 break; 568 a = RSAUtils.biMultiplyMod(a, a, m); 569 } 570 return result; 571 }; 572 573 $w.BarrettMu = function (m) { 574 this.modulus = RSAUtils.biCopy(m); 575 this.k = RSAUtils.biHighIndex(this.modulus) + 1; 576 var b2k = new BigInt(); 577 b2k.digits[2 * this.k] = 1; // b2k = b^(2k) 578 this.mu = RSAUtils.biDivide(b2k, this.modulus); 579 this.bkplus1 = new BigInt(); 580 this.bkplus1.digits[this.k + 1] = 1; // bkplus1 = b^(k+1) 581 this.modulo = BarrettMu_modulo; 582 this.multiplyMod = BarrettMu_multiplyMod; 583 this.powMod = BarrettMu_powMod; 584 }; 585 586 function BarrettMu_modulo(x) { 587 var $dmath = RSAUtils; 588 var q1 = $dmath.biDivideByRadixPower(x, this.k - 1); 589 var q2 = $dmath.biMultiply(q1, this.mu); 590 var q3 = $dmath.biDivideByRadixPower(q2, this.k + 1); 591 var r1 = $dmath.biModuloByRadixPower(x, this.k + 1); 592 var r2term = $dmath.biMultiply(q3, this.modulus); 593 var r2 = $dmath.biModuloByRadixPower(r2term, this.k + 1); 594 var r = $dmath.biSubtract(r1, r2); 595 if (r.isNeg) { 596 r = $dmath.biAdd(r, this.bkplus1); 597 } 598 var rgtem = $dmath.biCompare(r, this.modulus) >= 0; 599 while (rgtem) { 600 r = $dmath.biSubtract(r, this.modulus); 601 rgtem = $dmath.biCompare(r, this.modulus) >= 0; 602 } 603 return r; 604 } 605 606 function BarrettMu_multiplyMod(x, y) { 607 /* 608 x = this.modulo(x); 609 y = this.modulo(y); 610 */ 611 var xy = RSAUtils.biMultiply(x, y); 612 return this.modulo(xy); 613 } 614 615 function BarrettMu_powMod(x, y) { 616 var result = new BigInt(); 617 result.digits[0] = 1; 618 var a = x; 619 var k = y; 620 while (true) { 621 if ((k.digits[0] & 1) != 0) 622 result = this.multiplyMod(result, a); 623 k = RSAUtils.biShiftRight(k, 1); 624 if (k.digits[0] == 0 && RSAUtils.biHighIndex(k) == 0) 625 break; 626 a = this.multiplyMod(a, a); 627 } 628 return result; 629 } 630 631 var RSAKeyPair = function (encryptionExponent, decryptionExponent, modulus) { 632 var $dmath = RSAUtils; 633 this.e = $dmath.biFromHex(encryptionExponent); 634 this.d = $dmath.biFromHex(decryptionExponent); 635 this.m = $dmath.biFromHex(modulus); 636 // We can do two bytes per digit, so 637 // chunkSize = 2 * (number of digits in modulus - 1). 638 // Since biHighIndex returns the high index, not the number of digits, 1 has 639 // already been subtracted. 640 this.chunkSize = 2 * $dmath.biHighIndex(this.m); 641 this.radix = 16; 642 this.barrett = new $w.BarrettMu(this.m); 643 }; 644 645 RSAUtils.getKeyPair = function (encryptionExponent, decryptionExponent, modulus) { 646 return new RSAKeyPair(encryptionExponent, decryptionExponent, modulus); 647 }; 648 649 if (typeof $w.twoDigit === 'undefined') { 650 $w.twoDigit = function (n) { 651 return (n < 10 ? "0" : "") + String(n); 652 }; 653 } 654 655 // Altered by Rob Saunders (rob@robsaunders.net). New routine pads the 656 // string after it has been converted to an array. This fixes an 657 // incompatibility with Flash MX's ActionScript. 658 RSAUtils.encryptedString = function (key, s) { 659 var a = []; 660 var sl = s.length; 661 var i = 0; 662 while (i < sl) { 663 a[i] = s.charCodeAt(i); 664 i++; 665 } 666 while (a.length % key.chunkSize != 0) { 667 a[i++] = 0; 668 } 669 670 var al = a.length; 671 var result = ""; 672 var j, 673 k, 674 block; 675 for (i = 0; i < al; i += key.chunkSize) { 676 block = new BigInt(); 677 j = 0; 678 for (k = i; k < i + key.chunkSize; ++j) { 679 block.digits[j] = a[k++]; 680 block.digits[j] += a[k++] << 8; 681 } 682 var crypt = key.barrett.powMod(block, key.e); 683 var text = key.radix == 16 ? RSAUtils.biToHex(crypt) : RSAUtils.biToString(crypt, key.radix); 684 result += text + " "; 685 } 686 return result.substring(0, result.length - 1); // Remove last space. 687 }; 688 689 RSAUtils.decryptedString = function (key, s) { 690 var blocks = s.split(" "); 691 var result = ""; 692 var i, 693 j, 694 block; 695 for (i = 0; i < blocks.length; ++i) { 696 var bi; 697 if (key.radix == 16) { 698 bi = RSAUtils.biFromHex(blocks[i]); 699 } else { 700 bi = RSAUtils.biFromString(blocks[i], key.radix); 701 } 702 block = key.barrett.powMod(bi, key.d); 703 for (j = 0; j <= RSAUtils.biHighIndex(block); ++j) { 704 result += String.fromCharCode(block.digits[j] & 255, 705 block.digits[j] >> 8); 706 } 707 } 708 // Remove trailing null, if any. 709 if (result.charCodeAt(result.length - 1) == 0) { 710 result = result.substring(0, result.length - 1); 711 } 712 return result; 713 }; 714 715 RSAUtils.setMaxDigits(130); 716 717 })(window);