当前位置: 首页 > article >正文

javascript实现rsa算法(支持微信小程序)

概述:

本代码是本人从c代码上转换成的javascript代码,本人踏踏实实改了一个星期(累死我了),反反复复测试验证通过的。公钥计算快,私钥计算很慢。
在微信小程序上测试验证通过的,和我们常用的文件wxapp_rsa.js对比
1、代码少,才30k左右,而wxapp_rsa.js有400k;
2、功能少了对公钥文件解析(很麻烦,我基本上不会在前端用到),取代直接传密钥的各个部分(公钥指数模,私钥指数模);
3、功能少了base64处理,这功能简单很容易其他地方找到;

测试平台:

已经在如下环境中测试通过,其他平台(浏览器)应该也不会有问题:
1、nodejs中node.exe运行
2、微信小程序

功能代码:

function strRsaCtxParams() {
  this.keyn;
  this.keye;
  this.keyd;
  this.keybits;
};

function rsa_pkcs1_pad(orgdata, mode/*0:0填充,1:F填充, 2:不为0随机数填充*/, bits) {
	var outData = new Uint8Array(parseInt((bits + 7) / 8));
	var i = 0;
	var j = 0;
  
  for (i = 0; i < outData.length; i++) {
    outData[i] = 0;
  }
  //return outData;
  //mode = 1;
	if (orgdata.length > outData.length - 4) {
		throw Error('数据长度过长导致不能填充');
	}
	if (mode != 0 && mode != 1 && mode != 2) {
		throw Error('填充模式必须在0,1,2中选择');
	}
	outData[0] = 0x00;
	outData[1] = mode;
	
	for (i = 2; i < outData.length - orgdata.length - 1; i++) {
		if (mode == 0) {
			outData[i] = 0;
		} else if (mode == 1) {
			outData[i] = 0xFF;
		} else if (mode == 2) {
			outData[i] = parseInt(Math.random() * 256) & 0xff;
			if (outData[i] == 0) {
				/* 简单点,为0改为1 */
				outData[i] = 1;
			}
		}
  }
  //console.log("i1 = %d", i);
  outData[i] = 0;
  i++;
	j = 0;
	while (i < outData.length && j < orgdata.length) {
    outData[i] = orgdata[j];
    i++;
		j++;
  }
  //console.log("i2 = %d", i);
  
  return outData;
}

function rsa_set_key(keyNArray, keyEArray, keyDArray) {
  var rsaCtxParams = new strRsaCtxParams();
  //var i = 0;

  if (keyNArray == null || keyNArray.length <= 0) {
    throw Error('n的值不能为空');
  }

  rsaCtxParams.keybits = CalArrayBits(keyNArray, keyNArray.length);
  rsaCtxParams.keyn = NN_Decode(keyNArray, keyNArray.length);
  //console.log("rsaCtxParams.keyn len = %d index0=%d index1=%d index63=%d", rsaCtxParams.keyn.length, rsaCtxParams.keyn[0],  rsaCtxParams.keyn[1], rsaCtxParams.keyn[63]);
  if (keyEArray != null) {
    rsaCtxParams.keye = NN_Decode(keyEArray, keyEArray.length);
  }
  if (keyDArray != null) {
    rsaCtxParams.keyd = NN_Decode(keyDArray, keyDArray.length);
  }

  return rsaCtxParams;
}

function rsa_pub_cal(rsaCtxParams, lpIn) {
  var m = null;
  var c = null;
  var eDigits, nDigits;
  var outResult = null;
  var tmpInt = 0;

  if (rsaCtxParams.keyn == null || rsaCtxParams.keyn.length <= 0) {
    throw Error('n的值不能为空');
  }
  if (rsaCtxParams.keye == null || rsaCtxParams.keye.length <= 0) {
    throw Error('e的值不能为空');
  }

  m = NN_Decode(lpIn, lpIn.length);
  if (BignumCmp(m, rsaCtxParams.keyn) >= 0) {
    throw Error('输入数据不能大于等于n');
  }
  //console.log("m len = %d", m.length);
  //printfInts("m", m, m.length);
  nDigits = NN_Digits(rsaCtxParams.keyn, 0, rsaCtxParams.keyn.length);
  eDigits = NN_Digits(rsaCtxParams.keye, 0, rsaCtxParams.keye.length);
  //console.log("nDigits = %d  eDigits = %d", nDigits, eDigits);
  c = new Array(parseInt(((rsaCtxParams.keybits) + 31) / 32));
  init_u32array(c, c.length);
  NN_ModExp(c, m, rsaCtxParams.keye, eDigits, rsaCtxParams.keyn, nDigits, rsaCtxParams);

  tmpInt = parseInt((rsaCtxParams.keybits + 7) / 8);
  outResult = new Uint8Array(tmpInt);
  NN_Encode(outResult, 0, tmpInt, c, 0, nDigits);

  return outResult;
}

function rsa_pri_cal(rsaCtxParams, lpIn) {
  var m = null;
  var c = null;
  var nDigits = 0;
  var dDigits = 0;
  var outResult = null;
  var tmpInt = 0;

  if (rsaCtxParams.keyn == null || rsaCtxParams.keyn.length <= 0) {
    throw Error('n的值不能为空');
  }
  if (rsaCtxParams.keyd == null || rsaCtxParams.keyd.length <= 0) {
    throw Error('e的值不能为空');
  }

  c = NN_Decode(lpIn, lpIn.length);
  if (BignumCmp(c, rsaCtxParams.keyn) >= 0) {
    throw Error('输入数据不能大于等于n');
  }

  nDigits = NN_Digits(rsaCtxParams.keyn, 0, rsaCtxParams.keyn.length);
  dDigits = NN_Digits(rsaCtxParams.keyd, 0, rsaCtxParams.keyd.length);

  m = new Array(parseInt(((rsaCtxParams.keybits) + 31) / 32));
  //console.log("pro0");
  NN_ModExp(m, c, rsaCtxParams.keyd, dDigits, rsaCtxParams.keyn, nDigits, rsaCtxParams);
  //console.log("pro1");

  tmpInt = parseInt((rsaCtxParams.keybits + 7) / 8);
  outResult = new Uint8Array(tmpInt);
  NN_Encode(outResult, 0, tmpInt, m, 0, nDigits);

  return outResult;
}

function NN_Encode(a, aindex, len, b, bindex, digits) {
  var t;
  var j;
  var i, u;

  for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
    t = b[i + bindex];
    for (u = 0; j >= 0 && u < 32; j--, u += 8) {
      a[j + aindex] = (t >>> u) & 0xffffffff;
    }
  }

  for (; j >= 0; j--) {
    a[j + aindex] = 0;
  }
}

function NN_ASSIGN_DIGIT(a, aindex, b, digits) {
  NN_AssignZero(a, aindex, digits);
  a[0] = b;
}

function DIGIT_2MSB(x) {
  //(unsigned int)(((x) >> (NN_DIGIT_BITS - 2)) & 3)
  return ((((x) >>> (32 - 2)) & 3) & 0xffffffff) >>> 0;
}

//var testI = 0;

function NN_ModExp(a, b, c, cDigits, d, dDigits, rsaCtxParams) {
  var uPowerLen = parseInt((rsaCtxParams.keybits + 31) / 32);
  var bPower = new Array(3 * uPowerLen);
  var t = new Array(uPowerLen);
  var i = 0, j = 0, s = 0;
  var ci = 0;
  var ciBits = 0;

  init_u32array(bPower, bPower.length);

  //for (i = 0; i < bPower.length; i++) {
  //	bPower[i] = 0;
  //}

  //console.log("dDigits = %d", dDigits);
  //printfInts("bPower", bPower, bPower.length);
  //printfInts("b", b, b.length);
  //throw Error("11");
  //console.log("pro2");
  NN_Assign(bPower, 0, b, 0, dDigits);
  //printfInts("bPower", bPower, bPower.length);
  //printfInts("b", b, b.length);
  //throw Error("223");
  //console.log("pro3");
  NN_ModMult(bPower, uPowerLen, bPower, 0, b, 0, d, 0, dDigits, rsaCtxParams);
  //console.log("pro4");
  NN_ModMult(bPower, uPowerLen * 2, bPower, uPowerLen, b, 0, d, 0, dDigits, rsaCtxParams);
  //NN_Assign(bPower, uPowerLen, b, 0, dDigits);
  //NN_Assign(bPower, uPowerLen * 2, b, 0, dDigits);
  //printfIntsIndex("bPower0", bPower, 0, uPowerLen);
  //printfIntsIndex("bPower1", bPower, uPowerLen, uPowerLen);
  //printfIntsIndex("bPower2", bPower, uPowerLen * 2, uPowerLen);
  //console.log("pro5");
  NN_ASSIGN_DIGIT(t, 0, 1, dDigits);
  //console.log("pro6");
  cDigits = NN_Digits(c, 0, cDigits);
  //console.log("pro7");
  for (i = cDigits - 1; i >= 0; i--) {
    //console.log("pro8");
    ci = c[i];
    ciBits = 32;
    if (i == (cDigits - 1)) {
      while (0 == DIGIT_2MSB(ci)) {
        //console.log("pro9");
        ci <<= 2;
        ci &= 0xffffffff;
        //ciBits -= 2;
        ciBits = bn_u32_minus(ciBits, 2);
      }
    }
    for (j = 0; j < ciBits; j += 2, ci = (ci << 2) & 0xffffffff) {
      //console.log("pro10");
      /* Compute t = t^4 * b^s mod d, where s = two MSB's of ci. */
      NN_ModMult(t, 0, t, 0, t, 0, d, 0, dDigits, rsaCtxParams);
      //console.log("pro11");
      NN_ModMult(t, 0, t, 0, t, 0, d, 0, dDigits, rsaCtxParams);
      //console.log("pro12");
      s = DIGIT_2MSB(ci);
      //console.log("pro13");
      if ((s) != 0) {
        //console.log("pro14");
        //testI++;
        //console.log("testI = %d s = %d dDigits = %d", testI, s, dDigits);
        /*if (testI >= 412) {
        	
        	printfInts("t", t, 129);
        	printfInts("d", d, 128);
        	printfIntsIndex("bPower0", bPower, 0, 128);
        	printfIntsIndex("bPower1", bPower, uPowerLen, 128);
        	printfIntsIndex("bPower2", bPower, uPowerLen * 2, 128);
        	exit(0);
        }*/
        NN_ModMult(t, 0, t, 0, bPower, (s - 1) * uPowerLen, d, 0, dDigits, rsaCtxParams);
        //console.log("pro15");
      }
    }
  }
  NN_Assign(a, 0, t, 0, dDigits);
  //printfInts("a", a, a.length);
  //printfInts("b", b, b.length);
  //printfInts("c", c, c.length);
  //printfInts("t", t, t.length);
}

function bn_u32_compare(uint1, uint2) {
  uint1 &= 0xffffffff;
  uint2 &= 0xffffffff;

  if ((uint1 & 0x80000000) == 0 && (uint2 & 0x80000000) == 0) {
    return uint1 > uint2 ? 1 : (uint1 == uint2 ? 0 : (-1));
  }
  if ((uint1 & 0x80000000) != 0 && (uint2 & 0x80000000) != 0) {
    uint1 &= 0x7fffffff;
    uint2 &= 0x7fffffff;
    return uint1 > uint2 ? 1 : (uint1 == uint2 ? 0 : (-1));
  }
  if ((uint1 & 0x80000000) != 0) {
    return 1;
  } else {
    return -1;
  }
}

function bn_u32_add(add1, add2) {
  var i = 0;
  var tmp = 0;
  var result = 0;

  for (i = 0; i < 4; i++) {
    tmp = ((add1 >>> (i * 8)) & 0xff) + ((add2 >>> (i * 8)) & 0xff) + tmp;
    result |= ((tmp & 0xff) << (i * 8));
    tmp = tmp >>> 8;
  }

  return result & 0xffffffff;
}

function bn_u32_minus(minuend, subtractor) {
  var a = (minuend & 0xffffffff) >>> 0;
  var b = (subtractor & 0xffffffff) >>> 0;

  return (a - b) & 0xffffffff;
}

function NN_ModMult(a, aindex, b, bindex, c, cindex, d, dindex, digits, rsaCtxParams) {
  var t = new Array(2 * parseInt((rsaCtxParams.keybits + 31) / 32));

  init_u32array(t, t.length);

  //console.log("pp0");
  NN_Mult(t, 0, b, bindex, c, cindex, digits, rsaCtxParams);
  //printfIntsIndex("t", t, 0, 128);
  //printfIntsIndex("b", b, bindex, 128);
  //printfIntsIndex("c", c, cindex, 128);
  //console.log("pp1");
  NN_Mod(a, aindex, t, 0, 2 * digits, d, dindex, digits, rsaCtxParams);
}

function NN_Mod(a, aindex, b, bindex, bDigits, c, cindex, cDigits, rsaCtxParams) {
  //NN_DIGIT t[2 * MAX_NN_DIGITS];
  var t = new Array(2 * parseInt((rsaCtxParams.keybits + 31) / 32));

  init_u32array(t, t.length);

  NN_Div(t, 0, a, aindex, b, bindex, bDigits, c, cindex, cDigits, rsaCtxParams);
}

function NN_DigitBits(a) {
  var i;

  for (i = 0; i < 32; i++, a = ((a >>> 1) & 0xffffffff)) {
    if (a == 0) {
      break;
    }
  }

  return (i);
}

function NN_LShift(a, aindex, b, bindex, c, digits) {
  var temp, carry = 0;
  var tmpbindex = 0;
  var tmpaindex = 0;
  var t;

  if (c < 32 && digits != 0) {
    t = 32 - c;

    do {
      temp = b[tmpbindex + bindex];
      //b++;
      tmpbindex++;

      //*a = (temp << c) | carry;
      a[tmpaindex + aindex] = ((temp << c) | carry) & 0xffffffff;
      //a++;
      tmpaindex++;
      carry = (c != 0 ? (temp >>> t) : 0) & 0xffffffff;
      digits--;
      if (digits == 0) {
        break;
      }
    } while (true);
  }

  return (carry) & 0xffffffff;
}

function NN_RShift(a, aindex, b, bindex, c, digits) {
  var temp = 0,
    carry = 0;
  var tmpbindex = 0;
  var tmpaindex = 0;
  var t = 0;

  if (c < 32 && digits != 0) {
    //if(digits) {
    t = 32 - c;

    do {
      digits--;
      //temp = *(b+digits);
      temp = b[digits + bindex];
      //*(a+digits) = ((temp >> c) | carry);
      a[digits + aindex] = ((temp >>> c) | carry) & 0xffffffff;
      carry = (c != 0 ? (temp << t) : 0) & 0xffffffff;
    } while (digits != 0);
  }

  return ((carry) & 0xffffffff) >>> 0;
}

function TO_HIGH_HALF(x) {
  return ((x << 16) & 0xffffffff) >>> 0;
}

function subdigitmult(a, aindex, b, bindex, c, d, dindex, digits) {
  var borrow = 0,
    thigh = 0,
    tlow = 0;
  var i = 0;
  var arr = new Array(2);

  borrow = 0;

  if (c != 0) {
    for (i = 0; i < digits; i++) {
      //function dmult(a, b, high, highindex, low, lowindex)
      //dmult(c, d[i], &thigh, &tlow);
      arr[0] = thigh;
      arr[1] = tlow;
      dmult(c, d[i + dindex], arr, 0, arr, 1);
      thigh = arr[0];
      tlow = arr[1];
      //a[i] = b[i] - borrow;
      a[i + aindex] = bn_u32_minus(b[i + bindex], borrow);
      //if((a[i]) > (MAX_NN_DIGIT - borrow)) {
      if (bn_u32_compare(a[i + aindex], bn_u32_minus(0xffffffff, borrow)) > 0) {
        borrow = 1;
      } else {
        borrow = 0;
      }
      //a[i] -= tlow;
      a[i + aindex] = bn_u32_minus(a[i + aindex], tlow);
      //if((a[i]) > (MAX_NN_DIGIT - tlow)) {
      if (bn_u32_compare(a[i + aindex], bn_u32_minus(0xffffffff, tlow)) > 0) {
        //borrow++;
        borrow = bn_u32_add(borrow, 1);
      }
      //borrow += thigh;
      borrow = bn_u32_add(borrow, thigh);
    }
  }

  return (borrow) & 0xffffffff;
}

function NN_Cmp(a, aindex, b, bindex, digits) {
  if (digits != 0) {
    do {
      digits--;
      if ((a[digits + aindex] >>> 16) > (b[digits + bindex] >>> 16)) {
        return 1;
      }
      if ((a[digits + aindex] >>> 16) < (b[digits + bindex] >>> 16)) {
        return -1;
      }
      if ((a[digits + aindex] & 0xffff) > (b[digits + bindex] & 0xffff)) {
        return 1;
      }
      if ((a[digits + aindex] & 0xffff) < (b[digits + bindex] & 0xffff)) {
        return -1;
      }
      //if(*(a+digits) > *(b+digits))
      //	return(1);
      //if(*(a+digits) < *(b+digits))
      //	return(-1);
    } while (digits != 0);
  }

  return (0);
}

function NN_Sub(a, aindex, b, bindex, c, cindex, digits) {
  var temp = 0,
    borrow = 0;
  var tmpaindex = 0,
    tmpbindex = 0,
    tmpcindex = 0;

  if (digits != 0)
    do {
      //temp = (*b) - borrow;
      temp = bn_u32_minus(b[tmpbindex + bindex], borrow);
      //b++;
      //b = bn_u32_add(b, 1);
      tmpbindex++;
      //if(temp == MAX_NN_DIGIT) {
      if (bn_u32_compare(temp, 0xffffffff) == 0) {
        //temp = MAX_NN_DIGIT - (*c);
        temp = bn_u32_minus(0xffffffff, c[tmpcindex + cindex]);
        //c++;
        tmpcindex++;
      } else {
        //temp -= (*c);
        temp = bn_u32_minus(temp, c[tmpcindex + cindex]);
        //if((temp) > (MAX_NN_DIGIT - (*c))) {
        if (bn_u32_compare(temp, bn_u32_minus(0xffffffff, c[tmpcindex + cindex])) > 0) {
          borrow = 1;
        } else {
          borrow = 0;
        }
        //c++;
        tmpcindex++;
      }
      //*a = temp;
      a[tmpaindex + aindex] = temp & 0xffffffff;
      //a++;
      tmpaindex++;
      digits--;
      if (digits == 0) {
        break;
      }
    } while (true);

  return (borrow);
}

//var test2 = 0;
//var testI = 0;
function NN_Div(a, aindex, b, bindex, c, cindex, cDigits, d, dindex, dDigits, rsaCtxParams) {
  //NN_DIGIT ai, cc[2*MAX_NN_DIGITS+1], dd[MAX_NN_DIGITS], s;
  //NN_DIGIT t[2], u, v, *ccptr;
  //NN_HALF_DIGIT aHigh, aLow, cHigh, cLow;
  //int i;
  //unsigned int ddDigits, shift;
  var cc = new Array(2 * parseInt((rsaCtxParams.keybits + 31) / 32) + 1);
  var dd = new Array(2 * parseInt((rsaCtxParams.keybits + 31) / 32));
  var t = new Array(2);
  var ddDigits = 0;
  var shift = 0;
  var s, u, v;
  var ai;
  var cHigh, cLow, aHigh, aLow;
  var i = 0;
  //var ccptrindex = 0;

  init_u32array(cc, cc.length);
  init_u32array(dd, dd.length);
  NN_AssignZero(dd, 0, dd.length);

  ddDigits = NN_Digits(d, dindex, dDigits);
  if (ddDigits == 0) {
    return;
  }

  shift = 32 - NN_DigitBits(d[dindex + ddDigits - 1]);
  //console.log("shift = %d", shift);
  NN_AssignZero(cc, 0, ddDigits);
  cc[cDigits] = NN_LShift(cc, 0, c, 0, shift, cDigits);
  //console.log("cc[cDigits] = %d", cc[cDigits]);
  NN_LShift(dd, 0, d, 0, shift, ddDigits);
  s = dd[ddDigits - 1];
  //console.log("s = %d", s);
  //printfInts("cc", cc, cc.length);
  //printfInts("dd", dd, dd.length);
  //throw Error("111");
  NN_AssignZero(a, aindex, cDigits);

  //throw Error("11222");
  //test2 = 0;
  for (i = cDigits - ddDigits; i >= 0; i--) {
    test2++;
    //if (testI >= 412) {
    //	console.log("test2 = %d", test2);
    //}
    if (bn_u32_compare(s, 0xffffffff) == 0) {
      ai = (cc[i + ddDigits]) & 0xffffffff;
    } else {
      s = bn_u32_add(s, 1);
      cHigh = HIGH_HALF(s);
      cLow = LOW_HALF(s);
      t[0] = cc[i + ddDigits - 1];
      t[1] = cc[i + ddDigits];
      //if (testI >= 412 && test2 >= 13) console.log("t10 = %d %d", t[0], t[1]);
      if (cHigh == 0xffff) {
        aHigh = HIGH_HALF(t[1]);
        //if (testI >= 412 && test2 >= 13) console.log("aHigh1=%d", aHigh);
      } else {
        aHigh = parseInt((t[1] >>> 0) / ((cHigh >>> 0) + 1));
        //if (testI >= 412 && test2 >= 13) console.log("aHigh2=%d", aHigh);
      }
      u = ((aHigh >>> 0) * (cLow >>> 0)) & 0xffffffff;
      v = ((aHigh >>> 0) * (cHigh >>> 0)) & 0xffffffff;
      //if (testI >= 412 && test2 >= 13) console.log("u = %d v = %d aHigh = %d cLow = %d cHigh = %d", u, v, aHigh, cLow, cHigh);
      //if (testI >= 412 && test2 >= 13) console.log("t9 = %d %d", t[0], t[1]);
      t[0] = bn_u32_minus(t[0], TO_HIGH_HALF(u));
      //if (testI >= 412 && test2 >= 13) console.log("t91 = %d %d u = %d", t[0], t[1], u);
      if (bn_u32_compare(t[0], bn_u32_minus(0xffffffff, TO_HIGH_HALF(u))) > 0) {
        t[1] = bn_u32_minus(t[1], 1);
      }
      //if (testI >= 412 && test2 >= 13) console.log("t8 = %d %d", t[0], t[1]);
      //if (testI >= 412 && test2 >= 13) console.log("t[0] = %d t[1] = %d", t[0], t[1]);
      t[1] = bn_u32_minus(t[1], HIGH_HALF(u));
      //if (testI >= 412 && test2 >= 13) console.log("t[0] = %d t[1] = %d", t[0], t[1]);
      t[1] = bn_u32_minus(t[1], v);
      //if (testI >= 412 && test2 >= 13) console.log("t[0] = %d t[1] = %d", t[0], t[1]);
      //eeeek;
      //if (testI >= 412 && test2 >= 13) console.log("t7 = %d %d cHigh = %d, cLow = %d bn_u32_compare(t[0], cLow) = %d", t[0], t[1], cHigh, cLow, bn_u32_compare(t[0], cLow));
      while (bn_u32_compare(t[1], cHigh) > 0 || (bn_u32_compare(t[1], cHigh) == 0 && bn_u32_compare(t[0], TO_HIGH_HALF(cLow)) >= 0)) {
        //if (testI >= 412 && test2 >= 13) {
        //	console.log("rd t[0] = %d t[1] = %d cLow = %d cHigh = %d", t[0], t[1], cLow, cHigh);
        //	throw Error("");
        //}
        t[0] = bn_u32_minus(t[0], TO_HIGH_HALF(cLow));
        if (bn_u32_compare(t[0], bn_u32_minus(0xffffffff, TO_HIGH_HALF(cLow))) > 0) {
          t[1] = bn_u32_minus(t[1], 1);
        }
        t[1] = bn_u32_minus(t[1], cHigh);
        aHigh = bn_u32_add(aHigh, 1);
      }
      //if (testI >= 412 && test2 >= 13)console.log("t6 = %d %d cHigh = %d, cLow = %d", t[0], t[1], cHigh, cLow);
      if (bn_u32_compare(cHigh, 0xffff) == 0) {
        aLow = LOW_HALF(t[1]) & 0xffffffff;
        //console.log("aLow1 = %d ", aLow);
      } else {
        //aLow = parseInt((((TO_HIGH_HALF (t[1]) + HIGH_HALF (t[0])) >>> 0) & 0xffffffff) / bn_u32_add(cHigh, 1));
        aLow = (TO_HIGH_HALF(t[1]) >>> 0) + ((HIGH_HALF(t[0]) & 0xffffffff) >>> 0);
        aLow = parseInt(aLow / bn_u32_add(cHigh, 1)) & 0xffffffff;
        aLow &= 0xffffffff;
        //console.log("aLow2 = %d ", aLow);
      }
      u = ((aLow >>> 0) * (cLow >>> 0)) & 0xffffffff;
      v = ((aLow >>> 0) * (cHigh >>> 0)) & 0xffffffff;
      //(*t) -= u;
      //console.log("t5 = %d %d u = %d aLow = %d cLow = %d cHigh = %d", t[0], t[1], u, aLow, cLow, cHigh);
      t[0] = bn_u32_minus(t[0], u);
      //console.log("t4 = %d %d", t[0], t[1]);
      //if ((*t) > (MAX_NN_DIGIT - u)) {
      if (bn_u32_compare(t[0], bn_u32_minus(0xffffffff, u)) > 0) {
        //t[1]--;
        t[1] = bn_u32_minus(t[1], 1);
      }
      //console.log("t3 = %d %d", t[0], t[1]);
      //(*t) -= TO_HIGH_HALF (v);
      t[0] = bn_u32_minus(t[0], TO_HIGH_HALF(v));
      //console.log("t2 = %d %d", t[0], t[1]);
      //if ((*t) > (MAX_NN_DIGIT - TO_HIGH_HALF (v))) {
      if (bn_u32_compare(t[0], bn_u32_minus(0xffffffff, TO_HIGH_HALF(v))) > 0) {
        //t[1]--;
        t[1] = bn_u32_minus(t[1], 1);
      }
      //console.log("t1 = %d %d", t[0], t[1]);
      //*(t+1) -= HIGH_HALF (v);
      t[1] = bn_u32_minus(t[1], HIGH_HALF(v));
      //console.log("t0 = %d %d", t[0], t[1]);

      //console.log("ai1=%d aHigh = %d aLow = %d t[0] = %d t[1] = %d", ai, aHigh, aLow, t[0], t[1]);
      //while ((*(t+1) > 0) || ((*(t+1) == 0) && (*t) >= s)) {
      while (bn_u32_compare(t[1], 0) > 0 || (t[1] == 0 && bn_u32_compare(t[0], s) >= 0)) {
        //(*t) -= s;
        t[0] = bn_u32_minus(t[0], s);
        //if ((*t) > (MAX_NN_DIGIT - s)) {
        if (bn_u32_compare(t[0], bn_u32_minus(0xffffffff, s)) > 0) {
          t[1]--;
        }
        //aLow++;
        aLow = bn_u32_add(aLow, 1);
      }

      //ai = TO_HIGH_HALF (aHigh) + aLow;
      ai = bn_u32_add(TO_HIGH_HALF(aHigh), aLow);
      //console.log("ai0=%d aHigh = %d aLow = %d", ai, aHigh, aLow);
      //s--;
      s = bn_u32_minus(s, 1);
      //console.log("cHigh = %d cLow = %d", cHigh, cLow);
      //console.log("s = %d ai = %d t[0] = %d t[1] = %d cHigh = %d cLow = %d aHigh = %d aLow = %d u = %d v = %d", 
      //	s, ai, t[0], t[1], cHigh, cLow, aHigh, aLow, u, v);
      //cc[i+ddDigits] -= subdigitmult(&cc[i], &cc[i], ai, dd, ddDigits);
      //printfIntsIndex("cc", cc, 0, cc.length);
      //printfIntsIndex("dd", dd, 0, dd.length);
      //console.log("ai = %d ddDigits = %d i = %d", ai, ddDigits, i);
      cc[i + ddDigits] = bn_u32_minus(cc[i + ddDigits], subdigitmult(cc, i, cc, i, ai, dd, 0, ddDigits));
      //console.log("cc[i+ddDigits] = %d", cc[i+ddDigits]);
      //printfIntsIndex("cc", cc, 0, cc.length);
      //printfIntsIndex("dd", dd, 0, dd.length);
      //console.log("ddDigits = %d", ddDigits);
      //testI++
      //console.log("testI = %d", testI);
      //console.log("NN_Cmp(cc, i, dd, 0, ddDigits) = %d", NN_Cmp(cc, i, dd, 0, ddDigits));
      //if (testI > 2) {
      //throw Error("988");
      //}
      //console.log("testI = %d", testI);
      while (cc[i + ddDigits] != 0 || NN_Cmp(cc, i, dd, 0, ddDigits) >= 0) {
        //	console.log("0 cc[i+ddDigits] = %d ai\n", cc[i+ddDigits]);
        ai = bn_u32_add(ai, 1);
        cc[i + ddDigits] = bn_u32_minus(cc[i + ddDigits], NN_Sub(cc, i, cc, i, dd, 0, ddDigits));
        //console.log("1 cc[i+ddDigits] = %d ai\n", cc[i+ddDigits]);
        //console.log("ai");
        //throw Error("9612332");
      }
      a[i + aindex] = ai & 0xffffffff;
      //throw Error("9632");
    }
  }
  //throw Error("987412");

  NN_AssignZero(b, bindex, dDigits);
  NN_RShift(b, bindex, cc, 0, shift, ddDigits);
  //console.log("shift = %d ddDigits = %d", shift, ddDigits);
  //printfIntsIndex("b", b, bindex, ddDigits);
  //throw Error("888");
}

//var testi = 0;
function NN_Mult(a, aindex, b, bindex, c, cindex, digits, rsaCtxParams) {
  var t = new Array(2 * parseInt((rsaCtxParams.keybits + 31) / 32));
  var dhigh = 0xffffffff >>> 0,
    dlow = 0xffffffff >>> 0,
    carry = 0xffffffff >>> 0;
  var bDigits, cDigits, i, j;
  var tmpAr = new Array(2);

  init_u32array(t, t.length);
  init_u32array(tmpAr, tmpAr.length);

  //printfIntsIndex("a", a, aindex, parseInt((rsaCtxParams.keybits + 31) / 32));
  //printfIntsIndex("b", b, bindex, parseInt((rsaCtxParams.keybits + 31) / 32));
  //printfIntsIndex("c", c, cindex, parseInt((rsaCtxParams.keybits + 31) / 32));
  //throw Error("9988");

  tmpAr[0] = 0xffffffff >>> 0;
  tmpAr[1] = 0xffffffff >>> 0;
  for (i = 0; i < t.length; i++) {
    t[i] = 0xffffffff >>> 0;
  }
  NN_AssignZero(t, 0, t.length);

  bDigits = NN_Digits(b, bindex, digits);
  cDigits = NN_Digits(c, cindex, digits);

  for (i = 0; i < bDigits; i++) {
    carry = 0;
    if (b[i + bindex] != 0) {
      for (j = 0; j < cDigits; j++) {
        tmpAr[0] = dhigh;
        tmpAr[1] = dlow;
        //console.log("%d %d", b[i + bindex], c[j + cindex]);
        dmult(b[i + bindex], c[j + cindex], tmpAr, 0, tmpAr, 1);
        dhigh = tmpAr[0];
        dlow = tmpAr[1];
        //*(t+(i+j)) = *(t+(i+j)) + carry;
        //console.log("0t%d=%d dlow = %d dhigh = %d carry = %d", i + j, t[i + j], dlow, dhigh, carry);
        //testi++;
        //if (testi > 1) {
        //	throw Error("ll");
        //}
        t[i + j] += carry;
        t[i + j] &= 0xffffffff;
        //console.log("1t%d=%d dlow = %d dhigh = %d carry = %d", i + j, t[i + j], dlow, dhigh, carry);
        //if((*(t+(i+j))) < carry) {
        //if (t[i + j] < carry) {
        if (bn_u32_compare(t[i + j], carry) < 0) {
          carry = 1;
        } else {
          carry = 0;
        }
        //*(t+(i+j)) += dlow;
        t[i + j] += dlow;
        t[i + j] &= 0xffffffff;
        //console.log("2t%d=%d dlow = %d dhigh = %d carry = %d", i + j, t[i + j], dlow, dhigh, carry);
        //if((*(t+(i+j))) < dlow) {
        //if (t[i + j] < dlow) {
        if (bn_u32_compare(t[i + j], dlow) < 0) {
          //console.log("carry add");
          carry++;
        }
        carry += dhigh;
        carry &= 0xffffffff
      }
      //throw Error("aaa");
    }
    //*(t+(i+cDigits)) += carry;
    t[i + cDigits] += carry;
    t[i + cDigits] &= 0xffffffff;
  }
  //printfIntsIndex("t", t, 0, t.length);
  //throw Error("9986");

  NN_Assign(a, 0, t, 0, 2 * digits);

  //printfIntsIndex("a", a, aindex, parseInt((rsaCtxParams.keybits + 31) / 32));
  //printfIntsIndex("b", b, bindex, parseInt((rsaCtxParams.keybits + 31) / 32));
  //printfIntsIndex("c", c, cindex, parseInt((rsaCtxParams.keybits + 31) / 32));
  //throw Error("3356");
}

function LOW_HALF(val) {
  return val & 0xffff;
}

function HIGH_HALF(val) {
  return (val >>> 16) & 0xffff;
}

function init_u32array(array, len) {
  var i = 0;

  for (i = 0; i < len; i++) {
    array[i] = 0xffffffff >>> 0;
  }
}

function dmult(a, b, high, highindex, low, lowindex) {
  var al = 0xffffffff >>> 0;
  var ah = 0xffffffff >>> 0;
  var bl = 0xffffffff >>> 0;
  var bh = 0xffffffff >>> 0;
  var m1 = 0xffffffff >>> 0;
  var m2 = 0xffffffff >>> 0;
  var m = 0xffffffff >>> 0;
  var ml = 0xffffffff >>> 0;
  var mh = 0xffffffff >>> 0;
  var carry = 0xffffffff >>> 0;

  carry = 0;

  al = LOW_HALF(a);
  ah = HIGH_HALF(a);
  bl = LOW_HALF(b);
  bh = HIGH_HALF(b);

  low[lowindex] = (al * bl) & 0xffffffff;
  high[highindex] = (ah * bh) & 0xffffffff;

  //console.log("low[lowindex] = %d high[highindex] = %d", low[lowindex], high[highindex]);

  m1 = (al * bh) & 0xffffffff;
  m2 = (ah * bl) & 0xffffffff;
  m = (m1 + m2) & 0xffffffff;

  if (bn_u32_compare(m, m1) < 0) {
    carry = (1 << 16) & 0xffffffff; //(NN_DIGIT_BITS / 2);
  }

  ml = (m & 0xffff) << 16; //(NN_DIGIT_BITS / 2);
  mh = (m >> 16) & 0xffff; //(NN_DIGIT_BITS / 2);

  low[lowindex] += ml;

  if (bn_u32_compare(low[lowindex], ml) < 0) {
    carry = (carry + 1) & 0xffffffff;
  }

  high[highindex] += (carry + mh);
  low[lowindex] &= 0xffffffff;
  high[lowindex] &= 0xffffffff;
}


function NN_AssignZero(a, aindex, digits) {
  var tmpaindex = 0;

  if (digits != 0) {
    do {
      //*a++ = 0;
      //(*a) = 0;
      a[tmpaindex + aindex] = 0;
      //a++;
      tmpaindex++;
      digits--;
      if (digits == 0) {
        break;
      }
    } while (true);
  }
}

function NN_Assign(a, aindex, b, bindex, digits) {
  var tmpaindex = 0;
  var tmpbindex = 0;

  if (digits != 0) {
    /*do {
    	*a++ = *b++;
    }while(--digits);*/
    do {
      a[tmpaindex + aindex] = b[tmpbindex + bindex];
      //a++;
      //b++;
      tmpaindex++;
      tmpbindex++;
      digits--;
      if (digits == 0) {
        break;
      }
    } while (true);
  }
}

function printfInts(title, data, len) {
  printfIntsIndex(title, data, 0, len);
  /*var i = 0;
  
  for (i = 0; i < len; i++) {
  	console.log("%d %s %d", i, title == null ? "":title, data[i]);
  }*/
}

function printfIntsIndex(title, data, index, len) {
  var i = 0;

  for (i = 0; i < len; i++) {
    console.log("%d %s %d", i, title == null ? "" : title, data[i + index]);
  }
}

function NN_Digits(a, aindex, len) {
  var i = 0;

  for (i = len - 1; i >= 0; i--) {
    if (a[i + aindex] != 0) {
      return i + 1;
    }
  }

  return i;
}

function BignumCmp(a, b) {
  var amax = a.length - 1;
  var bmax = b.length - 1;
  var i = (amax > bmax ? amax : bmax);
  var aval = 0;
  var bval = 0;

  while (i) {
    aval = i > amax ? 0 : a[i];
    bval = i > bmax ? 0 : b[i];
    if (((aval >> 16) & 0xffff) < ((bval >> 16) & 0xffff)) {
      return -1;
    }
    if (((aval >> 16) & 0xffff) > ((bval >> 16) & 0xffff)) {
      return 1;
    }
    if ((aval & 0xffff) < (bval & 0xffff)) {
      return -1;
    }
    if ((aval & 0xffff) > (bval & 0xffff)) {
      return 1;
    }
    i--;
  }

  return 0;
}

function NN_Decode(bytesArray, len) {
  var bits = CalArrayBits(bytesArray, len);
  var i = 0;
  var j = 0;
  var outArray = new Array(parseInt((bits + 31) / 32));

  init_u32array(outArray, outArray.length);

  for (i = 0; i < outArray.length; i++) {
    j = bytesArray.length - (i + 1) * 4;
    //console.log("j = " + j);
    if (j >= 0) {
      outArray[i] = ((parseInt(bytesArray[j]) & 0xff) << 24) |
        ((parseInt(bytesArray[j + 1]) & 0xff) << 16) |
        ((parseInt(bytesArray[j + 2]) & 0xff) << 8) |
        ((parseInt(bytesArray[j + 3]) & 0xff) << 0);
    } else {
      outArray[i] = 0;
      if (j + 1 >= 0) {
        outArray[i] |= ((parseInt(bytesArray[j + 1]) & 0xff) << 16);
      }
      if (j + 2 >= 0) {
        outArray[i] |= ((parseInt(bytesArray[j + 2]) & 0xff) << 8);
      }
      if (j + 3 >= 0) {
        outArray[i] |= ((parseInt(bytesArray[j + 3]) & 0xff) << 0);
      }
    }
  }

  return outArray;
}


function CalArrayBits(arrayData, len) {
  var i = 0;
  var j = 0;

  for (i = 0; i < len; i++) {
    if (arrayData[i] != 0) {
      j = -1;
      break;
    }
  }

  if (j >= 0) {
    return 0;
  }

  for (j = 0; j < 8; j++) {
    if ((arrayData[i] & (0x80 >>> j)) != 0) {
      break;
    }
  }
  return 8 - j + (len - i - 1) * 8;
}

function rsa_hex_to_array(hexStrIn) {
  var i = 0;
  var cnt = 0;
  var ele = 0;
  var bytesArray = null;

  cnt = 0;
  for (i = 0; i < hexStrIn.length; i++) {
    ele = hexStrIn.charCodeAt(i);
    if (ele >= 48 && ele < 48 + 10) {
      cnt++;
    }
    if (ele >= 65 && ele < 65 + 6) {
      cnt++;
    }
    if (ele >= 97 && ele < 97 + 6) {
      cnt++;
    }
  }
  bytesArray = new Uint8Array(parseInt((cnt + 1) / 2));
  cnt = 0;
  for (i = 0; i < hexStrIn.length; i++) {
    ele = hexStrIn.charCodeAt(i);
    if (ele >= 48 && ele < 48 + 10) {
      ele -= 48;
      cnt++;
    } else if (ele >= 65 && ele < 65 + 6) {
      ele = ele - 65 + 10;
      cnt++;
    } else if (ele >= 97 && ele < 97 + 6) {
      ele = ele - 97 + 10;
      cnt++;
    } else {
      continue;
    }
    if ((cnt % 2) == 1) {
      bytesArray[parseInt((cnt - 1) / 2)] = (ele << 4) & 0xF0;
    } else {
      bytesArray[parseInt((cnt - 1) / 2)] |= ele;
    }
  }

  return bytesArray;
}

function rsa_hex_to_str(data, len) {
  var sha256_hex_digits = "0123456789abcdef";
  var output = new String();
  var i = 0;

  //console.log("ou1t = " + output);
  for (i = 0; i < len; i++) {
    //  console.log("out = " + output);
    output += sha256_hex_digits.charAt((data[i] >>> 4) & 0x0f);
    output += sha256_hex_digits.charAt((data[i]) & 0x0f);
  }

  return output;
}

module.exports = {
  rsa_set_key: rsa_set_key,
  rsa_pub_cal: rsa_pub_cal,
  rsa_pri_cal: rsa_pri_cal,
  rsa_hex_to_array: rsa_hex_to_array,
  rsa_hex_to_str: rsa_hex_to_str,
  rsa_pkcs1_pad:rsa_pkcs1_pad
}

测试代码:

如下在微信小程序中测试验证

var js_rsa = require('../../crypto/rsa.js');
testRsa() {
    var rsaCtx = null;
    var keyN = "BEC631E3067608D5065846573408462E4912D5EA343F0FB45DB7F2A1673D5A6D070DE518EBD4420A44E32188313A8B3321FFFC981FEA277BA833E224B9B21A036CE102047DFCBB0F4907EB670C9603E9FD9753681AA74873F47765B03B57E5EB184F4BAB576E4C03FAC8261A560B3EC79EBAFA92DE644362C8D79A7AD858F06CD3DA850ED467F0168B2FB49455A01CCE950ED110C78A90163B315D9C96368AE78F75B0813BEA33B50DFCDCF61D14AF8EB1313A53E3F90C43324EFB315D1FEC64851517C0068257953EE066F305410B2D729753E8D0F7F6D7089B89986B3A9A6109BCB66D4D1FFFF1DFFB347CE0C04019473FC88FA94C4C629A25460BFA900291";
    var keyD = "6D26C6FA470317D0927DC559358B1A647728D0BDDCC0CC027DB0B6A10489C50826861BB363932169F0BA27C05DB24A5CAA3265DAC03FDFF14F6EC8100D334AD0F4E5D49AAF5EFFC4221BE6E321FF5F23ED153D028E6571FDEE3CB630DBF351B86E43485F337A07022BE5826F85159008F4D7B4707DCFCE02623981C891AA697C4D746DD007330F697F8739392E9001D4FC2993C5E78D1A283C38AAED24EF4C672A1C4E72B2781759080CAE8383EEB69C8BC232360850FEBEF9D862DBC7225A9FE13F98F6BD072C7A027DEA9F9C9CDAB4D3F5F37B03B2375DA9BEF8CF1AD3CCB4C24B236685DDC82F10BA9584FA9A34D545B528B213675E969D7CA3839418AB95";
    var keyE = "010001";
    var txt = "00888888889999999999999AAAAAAAAABBBBBBBBCEDFFFFFFFFFFFFFFFFFFFFFFFFF966666666666666666666666666666666666666666666666666633333333333333333333333333333333300000000000000000000000666EEEEEEEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFFFFFDDDDDDDDDDDDBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAA88888888644444444444777777777777777799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999555555555555555555555555555555555555555522222222222222222222222222222222222222";
    var result, result2;
    var tmpdata = null;
    rsaCtx = js_rsa.rsa_set_key(js_rsa.rsa_hex_to_array(keyN), js_rsa.rsa_hex_to_array(keyE), js_rsa.rsa_hex_to_array(keyD));
    result = js_rsa.rsa_pub_cal(rsaCtx, js_rsa.rsa_hex_to_array(txt));
    console.log("rsa_pub_cal:" + js_rsa.rsa_hex_to_str(result, result.length));
    result2 = js_rsa.rsa_pri_cal(rsaCtx, result);
    console.log("rsa_pri_cal:" + js_rsa.rsa_hex_to_str(result2, result2.length));

   /* 下面的用pkcs1填充然后公玥计算,可以在后台用对应的私玥解密出来 */
    tmpdata = js_rsa.rsa_pkcs1_pad(js_rsa.rsa_hex_to_array("1122334455667788"), 2, rsaCtx.keybits);
    result = js_rsa.rsa_pub_cal(rsaCtx, tmpdata);
    console.log("rsa_pub_cal:" + js_rsa.rsa_hex_to_str(result, result.length));

    result2 = js_rsa.rsa_pri_cal(rsaCtx, result);
    console.log("rsa_pri_cal:" + js_rsa.rsa_hex_to_str(result2, result2.length));
  },

测试结果:

rsa_pub_cal:2fac299b8f780e12a331a73ca61551deb3cd41127d76d5c855624eb6d02eac9581be481fec0ec3c882e1cb26de31dffa19a689cd36a5255021fc44ab3399385f91db7352701bca8f1955237085ef2e0d216831653367799cddaf8c4b77611287fedfcc93de93d3c28461d29d609322f1b1d1b4543d1cc2921b50253fd1da15f9174a94ff8cb70cab180d56d00dd4f28e3a914abc28f770623af2eed11c560a26fe1187050038da28ad897068373b5bdfe14fb44905fcdc0cbeefde21a155ecf238423a2c967b710cbab39a235a6385c285535707c20bab1ae7601def49959cd42aa700389423fdcf17f2c42a00f2b1da8320586d24ef5d5dfe92cc203047020b
rsa_pri_cal:00888888889999999999999aaaaaaaaabbbbbbbbcedfffffffffffffffffffffffff966666666666666666666666666666666666666666666666666633333333333333333333333333333333300000000000000000000000666eeeeeeeeeeeeeeeeeeeeeefffffffffffffffffffddddddddddddbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccaaaaaaaaaaaaaaaaaaaaaaaaaa88888888644444444444777777777777777799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999555555555555555555555555555555555555555522222222222222222222222222222222222222
rsa_pub_cal:0c0b82faa9ea15227d77e043db0467261bf4957450ff3342a51f0ebc41112a0a62f509c4d8c6d6554e4d95997f89f6b4ff6ea728287bd6324f9989cdbfe9057740184eca47cb1d07bb082e8e09f4fb9e6befba4765b06fc0ddf4b9ddfa744fde3404ef5106bd772373a41bbc463c63808c972790bed8991089f62ee9f20ab638d177c0abe9b0b706639e782186515418a1bc743513051cd562a8b081b9d25b70eea813a7a48ede372833723fe4bbf7d8b4b20dc1457ae9277f4f4ff4c35873933bdb5eb99fc1bf9b1ec37a3e0ee542eadbdf89340dc90888747b221a35a43107fcdd2eeed2b9962277032b711d3713f7a1ce63318bae02ca462584850a182b32
rsa_pri_cal:0002c30f4202dcace6f9d5e2ff47c9014a4f8c7ca2dcd0fd54ee7d3eead63eb67ca9b76980a7b5d1cd72cab7c56e9aa142b59a79dcf07e5d1189ee09727b5ca372697be5cf6fda20a7cefab1c558c1a6e57609773c0355f407198250d252a4f8d01785f9271e9d160aae2ba2dc2314714fb4cca0b20320b6329224c5ba154b086d479ccd27353d9d9eaa48f5e1743b2fd44e0f46b85d894a41e239c696f1e9a71a22c83c9f69ce1541ebcd1106446c1f5c5b074ec5b580f4263930ffdf9bbdc7bf1cd6d86971744173a15d3eefbe7f1ab8c5363c5d62eccce5c404c3cb954a7f7c09a61dd75e56dcef2fbc98593dbe52f0e317ee5a5f65001122334455667788


http://www.kler.cn/a/374553.html

相关文章:

  • Chromium HTML5 新的 Input 类型tel对应c++
  • 【前端】在 Next.js 开发服务器中应该如何配置 HTTPS?
  • Nginx 文件名逻辑漏洞(CVE-2013-4547)
  • Python实现深度学习模型预测控制(tensorflow)DL-MPC(Deep Learning Model Predictive Control
  • 短信验证码发送实现(详细教程)
  • Redis 主从同步 总结
  • 外贸平台开发多语言处理的三种方式
  • Android 原子性类型都有哪些
  • npm入门教程12:npm link功能
  • “掌握大模型技术必备学习路径:探究学习大模型所需的关键能力
  • HarmonyOS应用开发者基础认证——初级闯关习题参考答案大全
  • 【AI工作流】Coze - 知识库全面指南:功能、应用场景及使用方法详解
  • 突破空间限制:4个远程控制电脑的办法!企业局域网远程连接完整版教程分享!(包教包会!)
  • JavaIO流
  • 数据结构模拟题[四]
  • 练习LabVIEW第二十九题
  • 机器学习:开启人工智能的钥匙
  • Tita:什么是 360 评估?
  • 创建线程池时为什么不建议使用Executors进行创建
  • 基于深度学习的需求预测
  • 【ES6】
  • 使用ZipOutputStream压缩文件、文件夹,最后输出
  • 高职健康管理专业校内实训基地建设方案
  • 除了wordpress CMS外,还有什么CMS值得我们使用?
  • java开发如何在单例模式下通过锁机制防止并发?
  • QT:子线程更新UI