js使用rsa加密大数据块的java实现

网上很多资料讲rsa的js实现与java实现,当数据量较小时基本都没问题,但加密的数据块过大时js与java加密的结果始终不一样,究其原因问题还是出在java代码上。对于大数据块java端要分块加密(这部分网上也有很多资料提及但加密结果与js加密的并不一样),这里说下我自己亲身实践的结果。对要加密的字符串按每62个字符做分割,对分割的每组数据分别加密然后用空格连接,这样加密的结果就和js端加密的结果一样了。

JAVA RSA加密工具类

/**
 * @author Administrator
 *
 */
public class RSAUtil
{

	public static final String NOPADDING = "RSA/NONE/NoPadding";
	public static final String PKCS1PADDING = "RSA/ECB/PKCS1Padding";

	public static String encrypt(String e, String n, String s) throws Exception
	{
		return encrypt(e, n, s, PKCS1PADDING);
	}

	public static String encrypt(String e, String n, String s, String transformation) throws Exception
	{
		RSAPublicKey key = (RSAPublicKey) getPublicKey(n, e);
		// return encryptByPublicKey(s, key);
		Cipher cipher = Cipher.getInstance(transformation, new BouncyCastleProvider());
		cipher.init(Cipher.ENCRYPT_MODE, key);
		byte[] result = cipher.doFinal(s.getBytes());
		return HttpUtils.convertToHexString(result);
	}

	public static PublicKey getPublicKey(String modulus, String publicExponent) throws NoSuchAlgorithmException, InvalidKeySpecException
	{
		BigInteger bigIntModulus = new BigInteger(modulus, 16);
		BigInteger bigIntPrivateExponent = new BigInteger(publicExponent, 16);
		RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPrivateExponent);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA", new BouncyCastleProvider());
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}

	/**
	 * * 加密 *
	 * 
	 * @param key
	 *            加密的密钥 *
	 * @param data
	 *            待加密的明文数据 *
	 * @return 加密后的数据 *
	 * @throws Exception
	 */
	public static String encryptWithSize(String e, String n, String text) throws Exception
	{
		try
		{
			RSAPublicKey pk = (RSAPublicKey) getPublicKey(n, e);
			byte[] data = text.getBytes();
			Cipher cipher = Cipher.getInstance("RSA/NONE/NoPadding", new BouncyCastleProvider());
			cipher.init(Cipher.ENCRYPT_MODE, pk);
			int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
			// 加密块大小为127
			// byte,加密后为128个byte;因此共有2个加密块,第一个127
			// byte第二个为1个byte
			int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
			int leavedSize = data.length % blockSize;
			int blocksSize = leavedSize != 0 ? data.length / blockSize + 1 : data.length / blockSize;
			byte[] raw = new byte[outputSize * blocksSize];
			int i = 0;
			while (data.length - i * blockSize > 0)
			{
				if (data.length - i * blockSize > blockSize)
					cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);
				else
					cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);
				// 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把 byte[]放到
				// ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了
				// OutputSize所以只好用dofinal方法。

				i++;
			}
			return HttpUtils.convertToHexString(raw);
		}
		catch (Exception exp)
		{
			throw new Exception(exp.getMessage());
		}
	}

	/**
	 * 公钥加密
	 * 
	 * @param data
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception
	{
		Cipher cipher = Cipher.getInstance("RSA/NONE/NoPadding", new BouncyCastleProvider());
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		// 模长
		int key_len = publicKey.getModulus().bitLength() / 8;
		// 加密数据长度 <= 模长-11
		String[] datas = splitString(data, key_len - 11);
		String mi = "";
		// 如果明文长度大于模长-11则要分组加密
		for (String s : datas)
		{
			mi += bcd2Str(cipher.doFinal(s.getBytes()));
		}
		return mi;
	}

	/**
	 * 拆分字符串
	 */
	public static String[] splitString(String string, int len)
	{
		int x = string.length() / len;
		int y = string.length() % len;
		int z = 0;
		if (y != 0)
		{
			z = 1;
		}
		String[] strings = new String[x + z];
		String str = "";
		for (int i = 0; i < x + z; i++)
		{
			if (i == x + z - 1 && y != 0)
			{
				str = string.substring(i * len, i * len + y);
			}
			else
			{
				str = string.substring(i * len, i * len + len);
			}
			strings[i] = str;
		}
		return strings;
	}

	/**
	 * BCD转字符串
	 */
	public static String bcd2Str(byte[] bytes)
	{
		char temp[] = new char[bytes.length * 2], val;

		for (int i = 0; i < bytes.length; i++)
		{
			val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
			temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');

			val = (char) (bytes[i] & 0x0f);
			temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
		}
		return new String(temp);
	}
}



对加密块的处理

	/**
	 * 通过指定长度分割字符串
	 * 
	 * @param str
	 * @param len
	 * @return
	 */
	private List<String> splitStr(String str, int len) {
		List<String> list = new ArrayList<String>();
		String value = str;
		while (value.length() > len) {
			String sub = value.substring(0, len);
			list.add(sub);
			value = value.substring(len);
		}
		list.add(value);
		return list;
	}

	/**
	 * 分组加密数据
	 * 
	 * @param strList
	 * @return
	 * @throws Exception
	 */
	private String encryParams(List<String> strList) throws Exception {
		StringBuffer sb;
		String result;
		StringBuffer retStr = new StringBuffer();
		for (int i = 0; i < strList.size(); i++) {
			sb = new StringBuffer(strList.get(i));
			result = RSAUtil.encrypt("10001", rsakey, sb.reverse().toString(), RSAUtil.NOPADDING);
			retStr.append(result).append(" ");
		}
		return retStr.toString().trim();
	}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值