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);