加密使用的是公钥对数据进行加密,而且当你使用一把1024bit的rsa公钥的时候,你一次只能加密最多117byte的数据,如果数据量超过这个数,可能会涉及到对数据进行分段加密的问题。而且现在rsa 1024bit长度的钥匙已经被证明了不够安全,应该尽量使用2048bit长度的钥匙。2048bit长度的钥匙一次可以加密245byte长度的数据。这个计算方法是 2048bit/8 = 256byte - 11byte = 245byte长数据。就是钥匙长度减去11byte得到的自己最大能一次加密多长的数据。如果超过了就会报错,所以很多平台要求对数据用公钥进行加密,就可能涉及到分段加密的问题。同时要注意的是,解密的时候不存在这11byte的减少。就是说一把1024bit的钥匙可以解密128byte长的数据而2048bit的可以解密256byte的数据。
RSA非对称加密内容长度有限制,1024位key的最多只能加密117位数据,否则就会报错(javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes)
解决办法是用对称加密(AES/DES etc)加密数据,然后用RSA公钥加密对称加密的密钥,用RSA的私钥解密得到对称加密的密钥,然后完成反向操作得到明文。
from Crypto import Random #from Crypto.Hash import SHA from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 #from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5 from Crypto.PublicKey import RSA import base64 #伪随机数生成器 random_generator = Random.new().read # rsa算法生成实例 rsa = RSA.generate(2048, random_generator) # master的秘钥对的生成 private_pem = rsa.exportKey() with open('master-private.pem', 'wb+') as f: f.write(private_pem) public_pem = rsa.publickey().exportKey() with open('master-public.pem', 'wb') as f: f.write(public_pem) # ghost的秘钥对的生成 private_pem = rsa.exportKey() with open('master-private.pem', 'wb') as f: f.write(private_pem) public_pem = rsa.publickey().exportKey() with open('master-public.pem', 'wb') as f: f.write(public_pem) message = 'hello ghost, this is a plian text' cipher_text ='' with open('master-public.pem', 'rb+') as f: key = f.read() rsakey = RSA.importKey(key) cipher = Cipher_pkcs1_v1_5.new(rsakey) cipher_text = base64.b64encode(cipher.encrypt(bytes(message,"utf-8"))) print(cipher_text) text='' with open('master-private.pem', 'rb+') as f: key = f.read() rsakey = RSA.importKey(key) cipher = Cipher_pkcs1_v1_5.new(rsakey) text = str(cipher.decrypt(base64.b64decode(cipher_text), random_generator),"utf-8") print(text) assert text == message, 'decrypt falied'
java版分段加密
import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.crypto.Cipher; private static final String EQUAL_FLAG = "="; private static final String APPEND_FLAG = "&"; /** * 字节数据转字符串专用集合 */ private static final char[] HEX_CHAR= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; /** * 加密算法RSA */ public static final String KEY_ALGORITHM = "RSA"; /** * 签名算法 */ public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; /** * 获取公钥的key */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** * 获取私钥的key */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * RSA加密明文大小 */ private static final int MAX_ENCRYPT_BLOCK = 117; /** * RSA解密密文大小 */ private static final int MAX_DECRYPT_BLOCK = 128; /** * <p> * 生成密钥公钥和私 * </p> * * @return * @throws Exception */ public static Map<String, Object> genKeyPair() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** * <p> * 用私钥对信息生成数字签名 * </p> * * @param data 已加密数�? * @param privateKey 私钥(BASE64编码) * * @return * @throws Exception */ public static String sign(byte[] data, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(privateK); signature.update(data); return Base64Utils.encode(signature.sign()); } /** * <p> * 校验数字签名 * </p> * * @param data 已加密数�? * @param publicKey 公钥(BASE64编码) * @param sign 数字签名 * * @return * @throws Exception * */ public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(publicK); signature.update(data); return signature.verify(Base64Utils.decode(sign)); } /** * <P> * 私钥解密 * </p> * * @param encryptedData 已加密数�? * @param privateKey 私钥(BASE64编码) * @return * @throws Exception */ public static byte[] decryptByPrivateKey(String date) throws Exception { byte[] encryptedData = Base64Utils.decode(date.replace(" ", "+")) ; byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); // Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段解�? while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** * <p> * 公钥解密 * </p> * * @param encryptedData 已加密数�? * @param publicKey 公钥(BASE64编码) * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段解�? while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** * 字节数据转十六进制字符串 * @param data 输入数据 * @return 十六进制内容 */ public static String byteArrayToString(byte[] data){ StringBuilder stringBuilder= new StringBuilder(); for (int i=0; i<data.length; i++){ //取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右�? stringBuilder.append(HEX_CHAR[(data[i] & 0xf0)>>> 4]); //取出字节的低四位 作为索引得到相应的十六进制标识符 stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]); /* if (i<data.length-1){ stringBuilder.append(' '); } */ } return stringBuilder.toString(); } /** * <p> * 公钥加密 * </p> * * @param data 源数�? * @param publicKey 公钥(BASE64编码) * @return * @throws Exception */ public static String encryptByPublicKey(byte[] data) throws Exception { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); // 对数据加�? // Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段加�? while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); // return encryptedData; return Base64Utils.encode(encryptedData); } /** * <p> * 私钥加密 * </p> * * @param data 源数�? * @param privateKey 私钥(BASE64编码) * @return * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段加�? while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; } /** * <p> * 获取私钥 * </p> * * @param keyMap 密钥�? * @return * @throws Exception */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return Base64Utils.encode(key.getEncoded()); } /** * <p> * 获取公钥 * </p> * * @param keyMap 密钥�? * @return * @throws Exception */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return Base64Utils.encode(key.getEncoded()); } /** * function:将json格式的字符串转化成键值对&形式,并且按ACSII码从小到大排�? * */ public static String formatSignMsg(Map<String, String> paraMap,boolean urlencode,boolean keyLowerCase) { // System.out.println("1.\n"+paraMap); StringBuffer buff = new StringBuffer(); List<Map.Entry<String, String>> keyList = new ArrayList<Map.Entry<String, String>>(paraMap.entrySet()); Collections.sort(keyList,new Comparator<Map.Entry<String, String>>() { @Override public int compare(Map.Entry<String, String> src,Map.Entry<String, String> tar) { return (src.getKey()).toString().compareTo(tar.getKey()); } }); for (int i = 0; i < keyList.size(); i++) { Map.Entry<String, String> item = keyList.get(i); String key = item.getKey(); String val = item.getValue(); if (key!=null && !"".equals(key)) { if (urlencode) { try { val = URLEncoder.encode(val, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } } buff.append(keyLowerCase?key.toLowerCase():key); buff.append(EQUAL_FLAG); buff.append(val); buff.append(APPEND_FLAG); } } if (buff.length() > 0) { System.out.println("2.\n"+buff.substring(0, buff.length() - 1)); return buff.substring(0, buff.length() - 1); }else return null; } public final static String Sha1(String s) { char hexDigits[]={'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; try { byte[] btInput = s.getBytes("UTF-8"); MessageDigest mdInst = MessageDigest.getInstance("sha-1"); mdInst.update(btInput); byte[] md = mdInst.digest(); int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } // System.out.println("aaa:\n"+new String(str)); return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 16进制的字符串表示转成字节数组 * * @param hexString * 16进制格式的字符串 * @return 转换后的字节数组 **/ public static byte[] hexStr2ByteArray(String hexString) { if (hexString==null) throw new IllegalArgumentException("this hexString must not be empty"); hexString = hexString.toLowerCase(); final byte[] byteArray = new byte[hexString.length() / 2]; int k = 0; for (int i = 0; i < byteArray.length; i++) { //因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先 //将hex 转换成byte "&" 操作为了防止负数的自动扩展 // hex转换成byte 其实只占用了4位,然后把高位进行右移四位 // 然后“|”操作 低四位 就能得到 两个 16进制数转换成一个byte. // byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff); byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff); byteArray[i] = (byte) (high << 4 | low); k += 2; } return byteArray; } }