开发者社区> 问答> 正文

RSA加密解密报错Data must not be longer than 11?400报错

我在使用RSAPrivateKey 和RSAPublicKey加密解密的的功能如下:

1、使用RSAPrivateKey 加密数据,然后使用RSAPublicKey解密数据;

2、使用RSAPublicKey加密数据,然后使用RSAPrivateKey 解密数据;

实际操作中能够实现该逻辑,但是发现我的代码在加密解密的过程中中,加密时有117bute的限制;解密事由128byte的限制。

代码如下:

package cn.fengLone.pay.util;

import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.crypto.Cipher;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * RSA私钥公钥字符串、对象生成工具
 * 
 * 本工具类提供以下几种方法:
 * 
 * 1、生成基于PublicKey 和PrivateKey对象的方法 initRSAKeys() 
 * 2、将PrivateKey对象转为私钥字符串
 * 3、将PublicKey对象转为公钥字符串 
 * 4、将私钥字符串转为PrivateKey对象 
 * 5、将公钥字符串转为PublicKey对象
 * 6、将公钥和私钥以文件形式保存
 * 7、公钥加密、私钥解密
 * 8、私钥加密、公钥解密
 * 
 * @author Guo pengFei
 * 
 * @date 2017-7-27
 * 
 * @version V1.0
 * 
 * @compeny 深证风轮科技有限公司
 * 
 * @site https://www.blog-china.cn
 * 
 */
public class RSAUtils {
	/** 指定加密算法为RSA */
	private static final String ALGORITHM = "RSA";
	/** 指定公钥存放文件 */
	private static String PUBLIC_KEY_FILE = "D://key/PublicKey.txt";
	/** 指定私钥存放文件 */
	private static String PRIVATE_KEY_FILE = "D://key/PrivateKey.txt";

	/**
	 * 以文件形式生成公钥和私钥,并保存
	 * 
	 * @return
	 * @throws Exception
	 */
	public static boolean writeKeyFile() throws Exception {
		Map<String, Object> map = initRSAKeys();
		Key publicKey = (Key) map.get("pubKey");
		Key privateKey = (Key) map.get("priKey");

		String pubKeyString = RSAUtils.getKeyString(publicKey);

		String priKeyString = RSAUtils.getKeyString(privateKey);
		System.out.println(pubKeyString);
		System.out.println();
		System.out.println(priKeyString);

		/** 用对象流将生成的密钥写入文件 */
		FileOutputStream oos1 = new FileOutputStream(PUBLIC_KEY_FILE);
		oos1.write(pubKeyString.getBytes("UTF-8")); // 可以指定编码

		FileOutputStream oos2 = new FileOutputStream(PRIVATE_KEY_FILE);
		oos2.write(priKeyString.getBytes("UTF-8")); // 可以指定编码

		/** 清空缓存,关闭文件输出流 */
		if (oos1 != null) {
			oos1.close();
		}
		if (oos2 != null) {
			oos2.close();
		}
		return true;
	}

	/**
	 * 生产RSA的私钥和公钥
	 * 
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	public static Map<String, Object> initRSAKeys()
			throws NoSuchAlgorithmException {
		// TODO Auto-generated method stub
		Map<String, Object> map = getKeys();
		// 生成公钥和私钥
		RSAPublicKey publicKey = (RSAPublicKey) map.get("public");
		RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private");

		// 模
		String modulus = publicKey.getModulus().toString();
		// 公钥指数
		String public_exponent = publicKey.getPublicExponent().toString();
		// 私钥指数
		String private_exponent = privateKey.getPrivateExponent().toString();
		// 使用模和指数生成公钥和私钥
		RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);
		RSAPrivateKey priKey = RSAUtils
				.getPrivateKey(modulus, private_exponent);

		map.put("pubKey", pubKey);
		map.put("priKey", priKey);
		return map;
	}

	/**
	 * 把公钥字符串转为对象
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static PublicKey getPublicKey(String key) throws Exception {
		byte[] keyBytes;
		keyBytes = (new BASE64Decoder()).decodeBuffer(key);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}

	/**
	 * 把私钥字符串转为对象
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static PrivateKey getPrivateKey(String key) throws Exception {
		byte[] keyBytes;
		keyBytes = (new BASE64Decoder()).decodeBuffer(key);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}

	/**
	 * 得到密钥字符串(经过base64编码)
	 * 
	 * @return
	 */
	public static String getKeyString(Key key) throws Exception {
		byte[] keyBytes = key.getEncoded();
		String s = (new BASE64Encoder()).encode(keyBytes);
		return s;
	}

	/**
	 * 生成公钥和私钥
	 * 
	 * @throws NoSuchAlgorithmException
	 * 
	 */
	private static HashMap<String, Object> getKeys()
			throws NoSuchAlgorithmException {
		HashMap<String, Object> map = new HashMap<String, Object>();
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM);
		keyPairGen.initialize(1024);
		KeyPair keyPair = keyPairGen.generateKeyPair();
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
		map.put("public", publicKey);
		map.put("private", privateKey);
		return map;
	}

	/**
	 * 使用模和指数生成RSA公钥
	 * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
	 * /None/NoPadding】
	 * 
	 * @param modulus
	 *            模
	 * @param exponent
	 *            指数
	 * @return
	 */
	private static RSAPublicKey getPublicKey(String modulus, String exponent) {
		try {
			BigInteger b1 = new BigInteger(modulus);
			BigInteger b2 = new BigInteger(exponent);
			KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
			RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
			return (RSAPublicKey) keyFactory.generatePublic(keySpec);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 使用模和指数生成RSA私钥
	 * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
	 * /None/NoPadding】
	 * 
	 * @param modulus
	 *            模
	 * @param exponent
	 *            指数
	 * @return
	 */
	private static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
		try {
			BigInteger b1 = new BigInteger(modulus);
			BigInteger b2 = new BigInteger(exponent);
			KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
			RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
			return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	/**
	 * 公钥加密
	 * 
	 * @param data
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static String encryptByPublicKey(Map<String, String> data, RSAPublicKey publicKey)
			throws Exception {
		if(data == null)
			return null;
		StringBuffer buffer = new StringBuffer();
		buffer.append("{");
		Iterator<String> iterator = data.keySet().iterator();
		while (iterator.hasNext()) {
			String key = iterator.next();
			String value = data.get(key);
			buffer.append("'").append(key).append("':'").append(value).append("',");
		}
		String result = buffer.substring(0,buffer.length()-1)+"}";
		System.out.println(result);
		
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		// 模长
		int key_len = publicKey.getModulus().bitLength() / 8;
		// 加密数据长度 <= 模长-11
		String[] datas = splitString(result, key_len - 11);
		String mi = "";
		// 如果明文长度大于模长-11则要分组加密
		for (String s : datas) {
			mi += bcd2Str(cipher.doFinal(s.getBytes()));
		}
		return mi;
	}
	
	
	
	
	/**
	 * 公钥加密
	 * 
	 * @param data
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static String encryptByPublicKey(String data, RSAPublicKey publicKey)
			throws Exception {
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		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;
	}
	
	
	/**
	 * 私钥加密过程
	 * 
	 * @param privateKey
	 *            私钥
	 * @param plainTextData
	 *            明文数据
	 * @return
	 * @throws Exception
	 *             加密过程中的异常信息
	 */
	public static String encryptByPrivateKey1(RSAPrivateKey privateKey,
			String data) throws Exception {
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, privateKey);
		// 模长
		int key_len = privateKey.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;
		
	}
	
	 /** 
     * 公钥解密过程 
     *  
     * @param publicKey 
     *            公钥 
     * @param cipherData 
     *            密文数据 
     * @return 明文 
     * @throws Exception 
     *             解密过程中的异常信息 
     */  
	public static String decryptByPublicKey(RSAPublicKey publicKey, String data)
			throws Exception {
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, publicKey);
		// 模长
		int key_len = publicKey.getModulus().bitLength() / 8;
		byte[] bytes = data.getBytes();
		byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
		System.err.println(bcd.length);
		// 如果密文长度大于模长则要分组解密
		String ming = "";
		byte[][] arrays = splitArray(bcd, key_len);
		for (byte[] arr : arrays) {
			ming += new String(cipher.doFinal(arr));
		}
		return ming;
	}
	
	
	/**
	 * 私钥解密
	 * 
	 * @param data
	 * @param privateKey
	 * @return
	 * @throws Exception
	 */
	public static String decryptByPrivateKey(String data,
			RSAPrivateKey privateKey) throws Exception {
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		// 模长
		int key_len = privateKey.getModulus().bitLength() / 8;
		byte[] bytes = data.getBytes();
		byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
		System.err.println(bcd.length);
		// 如果密文长度大于模长则要分组解密
		String ming = "";
		byte[][] arrays = splitArray(bcd, key_len);
		for (byte[] arr : arrays) {
			ming += new String(cipher.doFinal(arr));
		}
		return ming;
	}

	/**
	 * ASCII码转BCD码
	 * 
	 */
	private static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
		byte[] bcd = new byte[asc_len / 2];
		int j = 0;
		for (int i = 0; i < (asc_len + 1) / 2; i++) {
			bcd[i] = asc_to_bcd(ascii[j++]);
			bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
		}
		return bcd;
	}

	private static byte asc_to_bcd(byte asc) {
		byte bcd;

		if ((asc >= '0') && (asc <= '9'))
			bcd = (byte) (asc - '0');
		else if ((asc >= 'A') && (asc <= 'F'))
			bcd = (byte) (asc - 'A' + 10);
		else if ((asc >= 'a') && (asc <= 'f'))
			bcd = (byte) (asc - 'a' + 10);
		else
			bcd = (byte) (asc - 48);
		return bcd;
	}

	/**
	 * BCD转字符串
	 */
	private 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);
	}

	/**
	 * 拆分字符串
	 */
	private 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;
	}

	/**
	 * 拆分数组
	 */
	private static byte[][] splitArray(byte[] data, int len) {
		int x = data.length / len;
		int y = data.length % len;
		int z = 0;
		if (y != 0) {
			z = 1;
		}
		byte[][] arrays = new byte[x + z][];
		byte[] arr;
		for (int i = 0; i < x + z; i++) {
			arr = new byte[len];
			if (i == x + z - 1 && y != 0) {
				System.arraycopy(data, i * len, arr, 0, y);
			} else {
				System.arraycopy(data, i * len, arr, 0, len);
			}
			arrays[i] = arr;
		}
		return arrays;
	}
}

其中,我使用encryptByPrivateKey1()方法进行加密,使用decryptByPublicKey()方法进行解密;

调用方法示例如下:

	static void testEn() {
		String tempVale = "{'order_id':'20171020172857','total_pay':'301','client_ip':'10.12.123.23','order_name':'测试商品','order_id':'20171020172857','pay_type':'003'}";
		String privateKey = "MIIBNgIBADANBgkqhkiG9w0BAQEFAASCASAwggEcAgEAAoGBAIEYqSVG3maZt1l4dvbQSQFwiGuT4jaA8DR8/4s1Fi18pvP395Z8y9GSyIoPWoQN/XcHT/nHkeSsz6O2ohSVDugf4C/UfWVZQInOYcs1rXsVvTLchai/amEOZXKz8D27kIok9omIRm3d0Sa1Vlrr3N7e4Bhmp7dWXl5LI/cGzMELAgEAAoGAP18GsSjPxdfRXFc5NsFaBR3jqcNneU/kGi/+FazSnTOilQJ1hGbweokubi9JRKfFc6egR8ICyRlXuErP14CwVuK9HWyDckCZNjBn/5mzaYJgqZL7Fzg/kDm28s2csWAiASzEW+Kmzp9QKNsHM4VqAzJsAYgjQBZYQTZiWb3KDCECAQACAQACAQACAQACAQA==";
		try {
			RSAPrivateKey pri = (RSAPrivateKey) RSAUtils
					.getPrivateKey(privateKey);
			String sign_value = RSAUtils.encryptByPrivateKey1(pri, tempVale);

			System.out.println("respPost==" + sign_value);

			RSAPublicKey pub = (RSAPublicKey) RSAUtils
					.getPublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCBGKklRt5mmbdZeHb20EkBcIhrk+I2gPA0fP+LNRYtfKbz9/eWfMvRksiKD1qEDf13B0/5x5HkrM+jtqIUlQ7oH+Av1H1lWUCJzmHLNa17Fb0y3IWov2phDmVys/A9u5CKJPaJiEZt3dEmtVZa69ze3uAYZqe3Vl5eSyP3BszBCwIDAQAB");

			String ming = RSAUtils.decryptByPublicKey(pub, sign_value);
			System.out.println(ming);

		} catch (Exception e) {
			e.printStackTrace();

		}

	}

但是我查阅了很多资料,不知道分组加密和解密的代码逻辑该怎么写,有大神们解决下吗?

谢谢!

 

展开
收起
爱吃鱼的程序员 2020-06-08 09:57:04 1300 0
1 条回答
写回答
取消 提交回答
  • https://developer.aliyun.com/profile/5yerqm5bn5yqg?spm=a2c6h.12873639.0.0.6eae304abcjaIB

    如楼上所说,RSA加密是有长度限制的.单纯用RSA加密较长数据时得使用分段加密,效率低下.用RSA+AES是比较主流的做法:AES加密数据产生密文,RSA加密AES密钥产生加密后的AES密钥,然后将密文和加密后的AES密钥一起传输

    RSA 加密长字符串,效率不高,实践中,很少用RSA加密长字符串。
    常见的办法是RSA交换密码, 用密码做AES对称加密。
     

    楼主您好,所有非对称加密,密钥长度直接影响可以加密的内容长度,如果你现在用的是RSA128位加密,可以试试做RSA的256位加密

    2020-06-08 09:57:22
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
基于可信计算与加密计算 打造云上原生计算安全 立即下载
\"视频服务特色解决方案——直播连麦与点播加密 \" 立即下载
量子加密通信技术 立即下载