JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为12 ...

论坛 期权论坛 脚本     
匿名技术用户   2020-12-22 01:32   70   0

该工具类中用到了BASE64,需要借助第三方类库:javabase64-1.3.1.jar

下载地址:http://download.csdn.net/detail/centralperk/5025595

注意:
RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。
RSA加密对明文的长度是有限制的,如果加密数据过大会抛出如下
异常:


 
  1. Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes

  2. at com.sun.crypto.provider.RSACipher.a(DashoA13*..)

  3. at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)

  4. at javax.crypto.Cipher.doFinal(DashoA13*..)

RSAUtils.java


 
  1. package security;

  2. import java.io.ByteArrayOutputStream;

  3. import java.security.Key;

  4. import java.security.KeyFactory;

  5. import java.security.KeyPair;

  6. import java.security.KeyPairGenerator;

  7. import java.security.PrivateKey;

  8. import java.security.PublicKey;

  9. import java.security.Signature;

  10. import java.security.interfaces.RSAPrivateKey;

  11. import java.security.interfaces.RSAPublicKey;

  12. import java.security.spec.PKCS8EncodedKeySpec;

  13. import java.security.spec.X509EncodedKeySpec;

  14. import java.util.HashMap;

  15. import java.util.Map;

  16. import javax.crypto.Cipher;

  17. /** *//**

  18. * <p>

  19. * RSA公钥/私钥/签名工具包

  20. * </p>

  21. * <p>

  22. * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman)

  23. * </p>

  24. * <p>

  25. * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>

  26. * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/>

  27. * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全

  28. * </p>

  29. *

  30. * @author IceWee

  31. * @date 2012-4-26

  32. * @version 1.0

  33. */

  34. public class RSAUtils {

  35. /** *//**

  36. * 加密算法RSA

  37. */

  38. public static final String KEY_ALGORITHM = "RSA";

  39. /** *//**

  40. * 签名算法

  41. */

  42. public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

  43. /** *//**

  44. * 获取公钥的key

  45. */

  46. private static final String PUBLIC_KEY = "RSAPublicKey";

  47. /** *//**

  48. * 获取私钥的key

  49. */

  50. private static final String PRIVATE_KEY = "RSAPrivateKey";

  51. /** *//**

  52. * RSA最大加密明文大小

  53. */

  54. private static final int MAX_ENCRYPT_BLOCK = 117;

  55. /** *//**

  56. * RSA最大解密密文大小

  57. */

  58. private static final int MAX_DECRYPT_BLOCK = 128;

  59. /** *//**

  60. * <p>

  61. * 生成密钥对(公钥和私钥)

  62. * </p>

  63. *

  64. * @return

  65. * @throws Exception

  66. */

  67. public static Map<String, Object> genKeyPair() throws Exception {

  68. KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);

  69. keyPairGen.initialize(1024);

  70. KeyPair keyPair = keyPairGen.generateKeyPair();

  71. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

  72. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

  73. Map<String, Object> keyMap = new HashMap<String, Object>(2);

  74. keyMap.put(PUBLIC_KEY, publicKey);

  75. keyMap.put(PRIVATE_KEY, privateKey);

  76. return keyMap;

  77. }

  78. /** *//**

  79. * <p>

  80. * 用私钥对信息生成数字签名

  81. * </p>

  82. *

  83. * @param data 已加密数据

  84. * @param privateKey 私钥(BASE64编码)

  85. *

  86. * @return

  87. * @throws Exception

  88. */

  89. public static String sign(byte[] data, String privateKey) throws Exception {

  90. byte[] keyBytes = Base64Utils.decode(privateKey);

  91. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

  92. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

  93. PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);

  94. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

  95. signature.initSign(privateK);

  96. signature.update(data);

  97. return Base64Utils.encode(signature.sign());

  98. }

  99. /** *//**

  100. * <p>

  101. * 校验数字签名

  102. * </p>

  103. *

  104. * @param data 已加密数据

  105. * @param publicKey 公钥(BASE64编码)

  106. * @param sign 数字签名

  107. *

  108. * @return

  109. * @throws Exception

  110. *

  111. */

  112. public static boolean verify(byte[] data, String publicKey, String sign)

  113. throws Exception {

  114. byte[] keyBytes = Base64Utils.decode(publicKey);

  115. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

  116. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

  117. PublicKey publicK = keyFactory.generatePublic(keySpec);

  118. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

  119. signature.initVerify(publicK);

  120. signature.update(data);

  121. return signature.verify(Base64Utils.decode(sign));

  122. }

  123. /** *//**

  124. * <P>

  125. * 私钥解密

  126. * </p>

  127. *

  128. * @param encryptedData 已加密数据

  129. * @param privateKey 私钥(BASE64编码)

  130. * @return

  131. * @throws Exception

  132. */

  133. public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)

  134. throws Exception {

  135. byte[] keyBytes = Base64Utils.decode(privateKey);

  136. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

  137. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

  138. Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);

  139. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

  140. cipher.init(Cipher.DECRYPT_MODE, privateK);

  141. int inputLen = encryptedData.length;

  142. ByteArrayOutputStream out = new ByteArrayOutputStream();

  143. int offSet = 0;

  144. byte[] cache;

  145. int i = 0;

  146. // 对数据分段解密

  147. while (inputLen - offSet > 0) {

  148. if (inputLen - offSet > MAX_DECRYPT_BLOCK) {

  149. cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);

  150. } else {

  151. cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);

  152. }

  153. out.write(cache, 0, cache.length);

  154. i++;

  155. offSet = i * MAX_DECRYPT_BLOCK;

  156. }

  157. byte[] decryptedData = out.toByteArray();

  158. out.close();

  159. return decryptedData;

  160. }

  161. /** *//**

  162. * <p>

  163. * 公钥解密

  164. * </p>

  165. *

  166. * @param encryptedData 已加密数据

  167. * @param publicKey 公钥(BASE64编码)

  168. * @return

  169. * @throws Exception

  170. */

  171. public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)

  172. throws Exception {

  173. byte[] keyBytes = Base64Utils.decode(publicKey);

  174. X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);

  175. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

  176. Key publicK = keyFactory.generatePublic(x509KeySpec);

  177. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

  178. cipher.init(Cipher.DECRYPT_MODE, publicK);

  179. int inputLen = encryptedData.length;

  180. ByteArrayOutputStream out = new ByteArrayOutputStream();

  181. int offSet = 0;

  182. byte[] cache;

  183. int i = 0;

  184. // 对数据分段解密

  185. while (inputLen - offSet > 0) {

  186. if (inputLen - offSet > MAX_DECRYPT_BLOCK) {

  187. cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);

  188. } else {

  189. cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);

  190. }

  191. out.write(cache, 0, cache.length);

  192. i++;

  193. offSet = i * MAX_DECRYPT_BLOCK;

  194. }

  195. byte[] decryptedData = out.toByteArray();

  196. out.close();

  197. return decryptedData;

  198. }

  199. /** *//**

  200. * <p>

  201. * 公钥加密

  202. * </p>

  203. *

  204. * @param data 源数据

  205. * @param publicKey 公钥(BASE64编码)

  206. * @return

  207. * @throws Exception

  208. */

  209. public static byte[] encryptByPublicKey(byte[] data, String publicKey)

  210. throws Exception {

  211. byte[] keyBytes = Base64Utils.decode(publicKey);

  212. X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);

  213. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

  214. Key publicK = keyFactory.generatePublic(x509KeySpec);

  215. // 对数据加密

  216. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

  217. cipher.init(Cipher.ENCRYPT_MODE, publicK);

  218. int inputLen = data.length;

  219. ByteArrayOutputStream out = new ByteArrayOutputStream();

  220. int offSet = 0;

  221. byte[] cache;

  222. int i = 0;

  223. // 对数据分段加密

  224. while (inputLen - offSet > 0) {

  225. if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {

  226. cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);

  227. } else {

  228. cache = cipher.doFinal(data, offSet, inputLen - offSet);

  229. }

  230. out.write(cache, 0, cache.length);

  231. i++;

  232. offSet = i * MAX_ENCRYPT_BLOCK;

  233. }

  234. byte[] encryptedData = out.toByteArray();

  235. out.close();

  236. return encryptedData;

  237. }

  238. /** *//**

  239. * <p>

  240. * 私钥加密

  241. * </p>

  242. *

  243. * @param data 源数据

  244. * @param privateKey 私钥(BASE64编码)

  245. * @return

  246. * @throws Exception

  247. */

  248. public static byte[] encryptByPrivateKey(byte[] data, String privateKey)

  249. throws Exception {

  250. byte[] keyBytes = Base64Utils.decode(privateKey);

  251. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

  252. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

  253. Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);

  254. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

  255. cipher.init(Cipher.ENCRYPT_MODE, privateK);

  256. int inputLen = data.length;

  257. ByteArrayOutputStream out = new ByteArrayOutputStream();

  258. int offSet = 0;

  259. byte[] cache;

  260. int i = 0;

  261. // 对数据分段加密

  262. while (inputLen - offSet > 0) {

  263. if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {

  264. cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);

  265. } else {

  266. cache = cipher.doFinal(data, offSet, inputLen - offSet);

  267. }

  268. out.write(cache, 0, cache.length);

  269. i++;

  270. offSet = i * MAX_ENCRYPT_BLOCK;

  271. }

  272. byte[] encryptedData = out.toByteArray();

  273. out.close();

  274. return encryptedData;

  275. }

  276. /** *//**

  277. * <p>

  278. * 获取私钥

  279. * </p>

  280. *

  281. * @param keyMap 密钥对

  282. * @return

  283. * @throws Exception

  284. */

  285. public static String getPrivateKey(Map<String, Object> keyMap)

  286. throws Exception {

  287. Key key = (Key) keyMap.get(PRIVATE_KEY);

  288. return Base64Utils.encode(key.getEncoded());

  289. }

  290. /** *//**

  291. * <p>

  292. * 获取公钥

  293. * </p>

  294. *

  295. * @param keyMap 密钥对

  296. * @return

  297. * @throws Exception

  298. */

  299. public static String getPublicKey(Map<String, Object> keyMap)

  300. throws Exception {

  301. Key key = (Key) keyMap.get(PUBLIC_KEY);

  302. return Base64Utils.encode(key.getEncoded());

  303. }

  304. }


Base64Utils.java


 
  1. package security;

  2. import java.io.ByteArrayInputStream;

  3. import java.io.ByteArrayOutputStream;

  4. import java.io.File;

  5. import java.io.FileInputStream;

  6. import java.io.FileOutputStream;

  7. import java.io.InputStream;

  8. import java.io.OutputStream;

  9. import it.sauronsoftware.base64.Base64;

  10. /** *//**

  11. * <p>

  12. * BASE64编码解码工具包

  13. * </p>

  14. * <p>

  15. * 依赖javabase64-1.3.1.jar

  16. * </p>

  17. *

  18. * @author IceWee

  19. * @date 2012-5-19

  20. * @version 1.0

  21. */

  22. public class Base64Utils {

  23. /** *//**

  24. * 文件读取缓冲区大小

  25. */

  26. private static final int CACHE_SIZE = 1024;

  27. /** *//**

  28. * <p>

  29. * BASE64字符串解码为二进制数据

  30. * </p>

  31. *

  32. * @param base64

  33. * @return

  34. * @throws Exception

  35. */

  36. public static byte[] decode(String base64) throws Exception {

  37. return Base64.decode(base64.getBytes());

  38. }

  39. /** *//**

  40. * <p>

  41. * 二进制数据编码为BASE64字符串

  42. * </p>

  43. *

  44. * @param bytes

  45. * @return

  46. * @throws Exception

  47. */

  48. public static String encode(byte[] bytes) throws Exception {

  49. return new String(Base64.encode(bytes));

  50. }

  51. /** *//**

  52. * <p>

  53. * 将文件编码为BASE64字符串

  54. * </p>

  55. * <p>

  56. * 大文件慎用,可能会导致内存溢出

  57. * </p>

  58. *

  59. * @param filePath 文件绝对路径

  60. * @return

  61. * @throws Exception

  62. */

  63. public static String encodeFile(String filePath) throws Exception {

  64. byte[] bytes = fileToByte(filePath);

  65. return encode(bytes);

  66. }

  67. /** *//**

  68. * <p>

  69. * BASE64字符串转回文件

  70. * </p>

  71. *

  72. * @param filePath 文件绝对路径

  73. * @param base64 编码字符串

  74. * @throws Exception

  75. */

  76. public static void decodeToFile(String filePath, String base64) throws Exception {

  77. byte[] bytes = decode(base64);

  78. byteArrayToFile(bytes, filePath);

  79. }

  80. /** *//**

  81. * <p>

  82. * 文件转换为二进制数组

  83. * </p>

  84. *

  85. * @param filePath 文件路径

  86. * @return

  87. * @throws Exception

  88. */

  89. public static byte[] fileToByte(String filePath) throws Exception {

  90. byte[] data = new byte[0];

  91. File file = new File(filePath);

  92. if (file.exists()) {

  93. FileInputStream in = new FileInputStream(file);

  94. ByteArrayOutputStream out = new ByteArrayOutputStream(2048);

  95. byte[] cache = new byte[CACHE_SIZE];

  96. int nRead = 0;

  97. while ((nRead = in.read(cache)) != -1) {

  98. out.write(cache, 0, nRead);

  99. out.flush();

  100. }

  101. out.close();

  102. in.close();

  103. data = out.toByteArray();

  104. }

  105. return data;

  106. }

  107. /** *//**

  108. * <p>

  109. * 二进制数据写文件

  110. * </p>

  111. *

  112. * @param bytes 二进制数据

  113. * @param filePath 文件生成目录

  114. */

  115. public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {

  116. InputStream in = new ByteArrayInputStream(bytes);

  117. File destFile = new File(filePath);

  118. if (!destFile.getParentFile().exists()) {

  119. destFile.getParentFile().mkdirs();

  120. }

  121. destFile.createNewFile();

  122. OutputStream out = new FileOutputStream(destFile);

  123. byte[] cache = new byte[CACHE_SIZE];

  124. int nRead = 0;

  125. while ((nRead = in.read(cache)) != -1) {

  126. out.write(cache, 0, nRead);

  127. out.flush();

  128. }

  129. out.close();

  130. in.close();

  131. }

  132. }

RSATester.java


 
  1. package security;

  2. import java.util.Map;

  3. public class RSATester {

  4. static String publicKey;

  5. static String privateKey;

  6. static {

  7. try {

  8. Map<String, Object> keyMap = RSAUtils.genKeyPair();

  9. publicKey = RSAUtils.getPublicKey(keyMap);

  10. privateKey = RSAUtils.getPrivateKey(keyMap);

  11. System.err.println("公钥: \n\r" + publicKey);

  12. System.err.println("私钥: \n\r" + privateKey);

  13. } catch (Exception e) {

  14. e.printStackTrace();

  15. }

  16. }

  17. public static void main(String[] args) throws Exception {

  18. test();

  19. testSign();

  20. }

  21. static void test() throws Exception {

  22. System.err.println("公钥加密——私钥解密");

  23. String source = "这是一行没有任何意义的文字,你看完了等于没看,不是吗?";

  24. System.out.println("\r加密前文字:\r\n" + source);

  25. byte[] data = source.getBytes();

  26. byte[] encodedData = RSAUtils.encryptByPublicKey(data, publicKey);

  27. System.out.println("加密后文字:\r\n" + new String(encodedData));

  28. byte[] decodedData = RSAUtils.decryptByPrivateKey(encodedData, privateKey);

  29. String target = new String(decodedData);

  30. System.out.println("解密后文字: \r\n" + target);

  31. }

  32. static void testSign() throws Exception {

  33. System.err.println("私钥加密——公钥解密");

  34. String source = "这是一行测试RSA数字签名的无意义文字";

  35. System.out.println("原文字:\r\n" + source);

  36. byte[] data = source.getBytes();

  37. byte[] encodedData = RSAUtils.encryptByPrivateKey(data, privateKey);

  38. System.out.println("加密后:\r\n" + new String(encodedData));

  39. byte[] decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey);

  40. String target = new String(decodedData);

  41. System.out.println("解密后: \r\n" + target);

  42. System.err.println("私钥签名——公钥验证签名");

  43. String sign = RSAUtils.sign(encodedData, privateKey);

  44. System.err.println("签名:\r" + sign);

  45. boolean status = RSAUtils.verify(encodedData, publicKey, sign);

  46. System.err.println("验证结果:\r" + status);

  47. }

  48. }

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP