[html]  ​​view plain​​​  ​​​copy​




  1. package utils;



[html]  ​​view plain​​​  ​​​copy​




  1. import java.io.ByteArrayOutputStream;
  2. import java.security.Key;
  3. import java.security.KeyFactory;
  4. import java.security.KeyPair;
  5. import java.security.KeyPairGenerator;
  6. import java.security.PrivateKey;
  7. import java.security.PublicKey;
  8. import java.security.Signature;
  9. import java.security.interfaces.RSAPrivateKey;
  10. import java.security.interfaces.RSAPublicKey;
  11. import java.security.spec.PKCS8EncodedKeySpec;
  12. import java.security.spec.X509EncodedKeySpec;
  13. import java.util.HashMap;
  14. import java.util.Map;
  15. import javax.crypto.Cipher;
  16. /**
  17. * <p>
  18. * RSA公钥/私钥/签名工具包
  19. * </p>
  20. * <p>
  21. * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman)
  22. * </p>
  23. * <p>
  24. * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>
  25. * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/>
  26. * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全
  27. * </p>
  28. *
  29. * @author IceWee
  30. * @date 2012-4-26
  31. * @version 1.0
  32. */
  33. public class RSAUtils {
  34. /**
  35. * 加密算法RSA
  36. */
  37. public static final String KEY_ALGORITHM = "RSA";
  38. /**
  39. * 签名算法
  40. */
  41. public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
  42. /**
  43. * 获取公钥的key
  44. */
  45. private static final String PUBLIC_KEY = "RSAPublicKey";
  46. /**
  47. * 获取私钥的key
  48. */
  49. private static final String PRIVATE_KEY = "RSAPrivateKey";
  50. /**
  51. * RSA最大加密明文大小
  52. */
  53. private static final int MAX_ENCRYPT_BLOCK = 117;
  54. /**
  55. * RSA最大解密密文大小
  56. */
  57. private static final int MAX_DECRYPT_BLOCK = 128;
  58. /**
  59. * <p>
  60. * 生成密钥对(公钥和私钥)
  61. * </p>
  62. *
  63. * @return
  64. * @throws Exception
  65. */
  66. public static Map<String, Object> genKeyPair() throws Exception {
  67. KeyPairGenerator keyPairGen = KeyPairGenerator
  68. .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. *            已加密数据
  85. * @param privateKey
  86. *            私钥(BASE64编码)
  87. *
  88. * @return
  89. * @throws Exception
  90. */
  91. public static String sign(byte[] data, String privateKey) throws Exception {
  92. byte[] keyBytes = Base64Utils.decode(privateKey);
  93. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
  94. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  95. PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
  96. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
  97. signature.initSign(privateK);
  98. signature.update(data);
  99. return Base64Utils.encode(signature.sign());
  100. }
  101. /**
  102. * <p>
  103. * 校验数字签名
  104. * </p>
  105. *
  106. * @param data
  107. *            已加密数据
  108. * @param publicKey
  109. *            公钥(BASE64编码)
  110. * @param sign
  111. *            数字签名
  112. *
  113. * @return
  114. * @throws Exception
  115. *
  116. */
  117. public static boolean verify(byte[] data, String publicKey, String sign)
  118. throws Exception {
  119. byte[] keyBytes = Base64Utils.decode(publicKey);
  120. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
  121. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  122. PublicKey publicK = keyFactory.generatePublic(keySpec);
  123. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
  124. signature.initVerify(publicK);
  125. signature.update(data);
  126. return signature.verify(Base64Utils.decode(sign));
  127. }
  128. /**
  129. * <P>
  130. * 私钥解密
  131. * </p>
  132. *
  133. * @param encryptedData
  134. *            已加密数据
  135. * @param privateKey
  136. *            私钥(BASE64编码)
  137. * @return
  138. * @throws Exception
  139. */
  140. public static byte[] decryptByPrivateKey(byte[] encryptedData,
  141. String privateKey) throws Exception {
  142. byte[] keyBytes = Base64Utils.decode(privateKey);
  143. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
  144. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  145. Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
  146. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  147. cipher.init(Cipher.DECRYPT_MODE, privateK);
  148. int inputLen = encryptedData.length;
  149. ByteArrayOutputStream out = new ByteArrayOutputStream();
  150. int offSet = 0;
  151. byte[] cache;
  152. int i = 0;
  153. // 对数据分段解密
  154. while (inputLen - offSet > 0) {
  155. if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
  156. cache = cipher
  157. .doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
  158. } else {
  159. cache = cipher
  160. .doFinal(encryptedData, offSet, inputLen - offSet);
  161. }
  162. out.write(cache, 0, cache.length);
  163. i++;
  164. offSet = i * MAX_DECRYPT_BLOCK;
  165. }
  166. byte[] decryptedData = out.toByteArray();
  167. out.close();
  168. return decryptedData;
  169. }
  170. /**
  171. * <p>
  172. * 公钥解密
  173. * </p>
  174. *
  175. * @param encryptedData
  176. *            已加密数据
  177. * @param publicKey
  178. *            公钥(BASE64编码)
  179. * @return
  180. * @throws Exception
  181. */
  182. public static byte[] decryptByPublicKey(byte[] encryptedData,
  183. String publicKey) throws Exception {
  184. byte[] keyBytes = Base64Utils.decode(publicKey);
  185. X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
  186. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  187. Key publicK = keyFactory.generatePublic(x509KeySpec);
  188. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  189. cipher.init(Cipher.DECRYPT_MODE, publicK);
  190. int inputLen = encryptedData.length;
  191. ByteArrayOutputStream out = new ByteArrayOutputStream();
  192. int offSet = 0;
  193. byte[] cache;
  194. int i = 0;
  195. // 对数据分段解密
  196. while (inputLen - offSet > 0) {
  197. if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
  198. cache = cipher
  199. .doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
  200. } else {
  201. cache = cipher
  202. .doFinal(encryptedData, offSet, inputLen - offSet);
  203. }
  204. out.write(cache, 0, cache.length);
  205. i++;
  206. offSet = i * MAX_DECRYPT_BLOCK;
  207. }
  208. byte[] decryptedData = out.toByteArray();
  209. out.close();
  210. return decryptedData;
  211. }
  212. /**
  213. * <p>
  214. * 公钥加密
  215. * </p>
  216. *
  217. * @param data
  218. *            源数据
  219. * @param publicKey
  220. *            公钥(BASE64编码)
  221. * @return
  222. * @throws Exception
  223. */
  224. public static byte[] encryptByPublicKey(byte[] data, String publicKey)
  225. throws Exception {
  226. byte[] keyBytes = Base64Utils.decode(publicKey);
  227. X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
  228. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  229. Key publicK = keyFactory.generatePublic(x509KeySpec);
  230. // 对数据加密
  231. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  232. cipher.init(Cipher.ENCRYPT_MODE, publicK);
  233. int inputLen = data.length;
  234. ByteArrayOutputStream out = new ByteArrayOutputStream();
  235. int offSet = 0;
  236. byte[] cache;
  237. int i = 0;
  238. // 对数据分段加密
  239. while (inputLen - offSet > 0) {
  240. if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
  241. cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
  242. } else {
  243. cache = cipher.doFinal(data, offSet, inputLen - offSet);
  244. }
  245. out.write(cache, 0, cache.length);
  246. i++;
  247. offSet = i * MAX_ENCRYPT_BLOCK;
  248. }
  249. byte[] encryptedData = out.toByteArray();
  250. out.close();
  251. return encryptedData;
  252. }
  253. /**
  254. * <p>
  255. * 私钥加密
  256. * </p>
  257. *
  258. * @param data
  259. *            源数据
  260. * @param privateKey
  261. *            私钥(BASE64编码)
  262. * @return
  263. * @throws Exception
  264. */
  265. public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
  266. throws Exception {
  267. byte[] keyBytes = Base64Utils.decode(privateKey);
  268. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
  269. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  270. Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
  271. Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  272. cipher.init(Cipher.ENCRYPT_MODE, privateK);
  273. int inputLen = data.length;
  274. ByteArrayOutputStream out = new ByteArrayOutputStream();
  275. int offSet = 0;
  276. byte[] cache;
  277. int i = 0;
  278. // 对数据分段加密
  279. while (inputLen - offSet > 0) {
  280. if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
  281. cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
  282. } else {
  283. cache = cipher.doFinal(data, offSet, inputLen - offSet);
  284. }
  285. out.write(cache, 0, cache.length);
  286. i++;
  287. offSet = i * MAX_ENCRYPT_BLOCK;
  288. }
  289. byte[] encryptedData = out.toByteArray();
  290. out.close();
  291. return encryptedData;
  292. }
  293. /**
  294. * <p>
  295. * 获取私钥
  296. * </p>
  297. *
  298. * @param keyMap
  299. *            密钥对
  300. * @return
  301. * @throws Exception
  302. */
  303. public static String getPrivateKey(Map<String, Object> keyMap)
  304. throws Exception {
  305. Key key = (Key) keyMap.get(PRIVATE_KEY);
  306. return Base64Utils.encode(key.getEncoded());
  307. }
  308. /**
  309. * <p>
  310. * 获取公钥
  311. * </p>
  312. *
  313. * @param keyMap
  314. *            密钥对
  315. * @return
  316. * @throws Exception
  317. */
  318. public static String getPublicKey(Map<String, Object> keyMap)
  319. throws Exception {
  320. Key key = (Key) keyMap.get(PUBLIC_KEY);
  321. return Base64Utils.encode(key.getEncoded());
  322. }
  323. }

Base64Utils文件



[html]  ​​view plain​​​  ​​​copy​




  1. package utils;
  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 com.sun.org.apache.xml.internal.security.utils.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. }

测试用例:






[html]  ​​view plain​​​  ​​​copy​




  1. package util;
  2. import java.util.Map;
  3. import RSAUtils;
  4. public class RSATester {
  5. static String publicKey;
  6. static String privateKey;
  7. static {
  8. try {
  9. Map<String, Object> keyMap = RSAUtils.genKeyPair();
  10. publicKey = RSAUtils.getPublicKey(keyMap);
  11. privateKey = RSAUtils.getPrivateKey(keyMap);
  12. System.err.println("公钥: \n\r" + publicKey);
  13. System.err.println("私钥: \n\r" + privateKey);
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. public static void main(String[] args) throws Exception {
  19. test();
  20. testSign();
  21. }
  22. static void test() throws Exception {
  23. System.err.println("公钥加密——私钥解密");
  24. String source = "这是一行没有任何意义的文字,你看完了等于没看,不是吗?";
  25. System.out.println("\r加密前文字:\r\n" + source);
  26. byte[] data = source.getBytes();
  27. byte[] encodedData = RSAUtils.encryptByPublicKey(data, publicKey);
  28. System.out.println("加密后文字:\r\n" + new String(encodedData));
  29. byte[] decodedData = RSAUtils.decryptByPrivateKey(encodedData, privateKey);
  30. String target = new String(decodedData);
  31. System.out.println("解密后文字: \r\n" + target);
  32. }
  33. static void testSign() throws Exception {
  34. System.err.println("私钥加密——公钥解密");
  35. String source = "这是一行测试RSA数字签名的无意义文字";
  36. System.out.println("原文字:\r\n" + source);
  37. byte[] data = source.getBytes();
  38. byte[] encodedData = RSAUtils.encryptByPrivateKey(data, privateKey);
  39. System.out.println("加密后:\r\n" + new String(encodedData));
  40. byte[] decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey);
  41. String target = new String(decodedData);
  42. System.out.println("解密后: \r\n" + target);
  43. System.err.println("私钥签名——公钥验证签名");
  44. String sign = RSAUtils.sign(encodedData, privateKey);
  45. System.err.println("签名:\r" + sign);
  46. boolean status = RSAUtils.verify(encodedData, publicKey, sign);
  47. System.err.println("验证结果:\r" + status);
  48. }
  49. }


生成RSA密钥、保存到文件、从文件读取、加密、解密等操作



[html]  ​​view plain​​​  ​​​copy​




  1. import java.security.Key;
  2. import java.security.KeyFactory;
  3. import java.security.KeyPair;
  4. import java.security.KeyPairGenerator;
  5. import java.security.NoSuchAlgorithmException;
  6. import java.security.PrivateKey;
  7. import java.security.PublicKey;
  8. import java.security.SecureRandom;
  9. import java.security.interfaces.RSAPrivateKey;
  10. import java.security.interfaces.RSAPublicKey;
  11. import java.security.spec.InvalidKeySpecException;
  12. import java.security.spec.PKCS8EncodedKeySpec;
  13. import java.security.spec.X509EncodedKeySpec;
  14. import javax.crypto.Cipher;
  15. import org.apache.commons.configuration.ConfigurationException;
  16. import org.apache.commons.configuration.PropertiesConfiguration;
  17. import org.bouncycastle.jce.provider.BouncyCastleProvider;
  18. public class RSATest {
  19. public static void main(String[] args) {
  20. try {
  21. RSATest encrypt = new RSATest();
  22. String encryptText = "encryptText";
  23. // Generate keys
  24. KeyPair keyPair = encrypt.generateKey();
  25. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  26. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  27. byte[] e = encrypt.encrypt(publicKey, encryptText.getBytes());
  28. byte[] de = encrypt.decrypt(privateKey, e);
  29. System.out.println(toHexString(e));
  30. System.out.println(toHexString(de));
  31. } catch (Exception e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. public KeyPair generateKey() throws NoSuchAlgorithmException {
  36. KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
  37. keyPairGen.initialize(1024, new SecureRandom());
  38. KeyPair keyPair = keyPairGen.generateKeyPair();
  39. return keyPair;
  40. }
  41. public void saveKey(KeyPair keyPair, String publicKeyFile,
  42. String privateKeyFile) throws ConfigurationException {
  43. PublicKey pubkey = keyPair.getPublic();
  44. PrivateKey prikey = keyPair.getPrivate();
  45. // save public key
  46. PropertiesConfiguration publicConfig = new PropertiesConfiguration(
  47. publicKeyFile);
  48. publicConfig.setProperty("PULIICKEY", toHexString(pubkey.getEncoded()));
  49. publicConfig.save();
  50. // save private key
  51. PropertiesConfiguration privateConfig = new PropertiesConfiguration(
  52. privateKeyFile);
  53. privateConfig.setProperty("PRIVATEKEY",
  54. toHexString(prikey.getEncoded()));
  55. privateConfig.save();
  56. }
  57. /**
  58. * @param filename
  59. * @param type:
  60. *            1-public 0-private
  61. * @return
  62. * @throws ConfigurationException
  63. * @throws NoSuchAlgorithmException
  64. * @throws InvalidKeySpecException
  65. */
  66. public Key loadKey(String filename, int type)
  67. throws ConfigurationException, NoSuchAlgorithmException,
  68. InvalidKeySpecException {
  69. PropertiesConfiguration config = new PropertiesConfiguration(filename);
  70. KeyFactory keyFactory = KeyFactory.getInstance("RSA",
  71. new BouncyCastleProvider());
  72. if (type == 0) {
  73. // privateKey
  74. String privateKeyValue = config.getString("PULIICKEY");
  75. PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
  76. toBytes(privateKeyValue));
  77. PrivateKey privateKey = keyFactory.generatePrivate(priPKCS8);
  78. return privateKey;
  79. } else {
  80. // publicKey
  81. String privateKeyValue = config.getString("PRIVATEKEY");
  82. X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(
  83. toBytes(privateKeyValue));
  84. PublicKey publicKey = keyFactory.generatePublic(bobPubKeySpec);
  85. return publicKey;
  86. }
  87. }
  88. /**
  89. * Encrypt String.
  90. *
  91. * @return byte[]
  92. */
  93. protected byte[] encrypt(RSAPublicKey publicKey, byte[] data) {
  94. if (publicKey != null) {
  95. try {
  96. Cipher cipher = Cipher.getInstance("RSA",
  97. new BouncyCastleProvider());
  98. cipher.init(Cipher.ENCRYPT_MODE, publicKey);
  99. return cipher.doFinal(data);
  100. } catch (Exception e) {
  101. e.printStackTrace();
  102. }
  103. }
  104. return null;
  105. }
  106. /**
  107. * Basic decrypt method
  108. *
  109. * @return byte[]
  110. */
  111. protected byte[] decrypt(RSAPrivateKey privateKey, byte[] raw) {
  112. if (privateKey != null) {
  113. try {
  114. Cipher cipher = Cipher.getInstance("RSA",
  115. new BouncyCastleProvider());
  116. cipher.init(Cipher.DECRYPT_MODE, privateKey);
  117. return cipher.doFinal(raw);
  118. } catch (Exception e) {
  119. e.printStackTrace();
  120. }
  121. }
  122. return null;
  123. }
  124. public static String toHexString(byte[] b) {
  125. StringBuilder sb = new StringBuilder(b.length * 2);
  126. for (int i = 0; i < b.length; i++) {
  127. sb.append(HEXCHAR[(b[i] & 0xf0) >>> 4]);
  128. sb.append(HEXCHAR[b[i] & 0x0f]);
  129. }
  130. return sb.toString();
  131. }
  132. public static final byte[] toBytes(String s) {
  133. byte[] bytes;
  134. bytes = new byte[s.length() / 2];
  135. for (int i = 0; i < bytes.length; i++) {
  136. bytes[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2),
  137. 16);
  138. }
  139. return bytes;
  140. }
  141. private static char[] HEXCHAR = { '0', '1', '2', '3', '4', '5', '6', '7',
  142. '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  143. }



Java中RSA非对称密钥加解密使用示例

一、简介:

  RSA加密算法是最常用的非对称加密算法,CFCA在证书服务中离不了它。RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。这个算法经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定RSA的安全性,但这恰恰说明该算法有一定的可信性,目前它已经成为最流行的公开密钥算法。

  二、RSA的公钥、私钥的组成,以及加密、解密的公式可见于下表

  三、使用方式:

  ① 假设A、B机器进行通信,已A机器为主;

  ② A首先需要用自己的私钥为发送请求数据签名,并将公钥一同发送给B;

  ③ B收到数据后,需要用A发送的公钥进行验证,已确保收到的数据是未经篡改的;

  ④ B验签通过后,处理逻辑,并把处理结果返回,返回数据需要用A发送的公钥进行加密(公钥加密后,只能用配对的私钥解密);

  ⑤ A收到B返回的数据,使用私钥解密,至此,一次数据交互完成。

  四、代码示例:

  1、第一步获取私钥,为签名做准备。



[html]  ​​view plain​​​  ​​​copy​




  1. /**
  2. * 读取私钥  返回PrivateKey
  3. * @param path  包含私钥的证书路径
  4. * @param password  私钥证书密码
  5. * @return 返回私钥PrivateKey
  6. * @throws KeyStoreException
  7. * @throws NoSuchAlgorithmException
  8. * @throws CertificateException
  9. * @throws IOException
  10. * @throws UnrecoverableKeyException
  11. */
  12. private static PrivateKey getPrivateKey(String path,String password)
  13. throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
  14. IOException, UnrecoverableKeyException {
  15. KeyStore ks = KeyStore.getInstance("PKCS12");
  16. FileInputStream fis = new FileInputStream(path);
  17. char[] nPassword = null;
  18. if ((password == null) || password.trim().equals("")) {
  19. nPassword = null;
  20. } else {
  21. nPassword = password.toCharArray();
  22. }
  23. ks.load(fis, nPassword);
  24. fis.close();
  25. Enumeration<String> en = ks.aliases();
  26. String keyAlias = null;
  27. if (en.hasMoreElements()) {
  28. keyAlias = (String) en.nextElement();
  29. }
  30. return (PrivateKey) ks.getKey(keyAlias, nPassword);
  31. }



2、签名示例:通过第一步得到的私钥,进行签名操作,具体请看以下代码:



[html]  ​​view plain​​​  ​​​copy​




  1. /**
  2. * 私钥签名: 签名方法如下:BASE64(RSA(MD5(src),privatekey)),其中src为需要签名的字符串,
  3. privatekey是商户的CFCA证书私钥。
  4. * @param plainText 待签名字符串
  5. * @param path 签名私钥路径
  6. * @param password  签名私钥密码
  7. * @return 返回签名后的字符串
  8. * @throws Exception
  9. */
  10. public static String sign(String plainText,String path,String password)
  11. throws Exception  {
  12. /*
  13. * MD5加密
  14. */
  15. MessageDigest md5 = MessageDigest.getInstance("MD5");
  16. md5.update(plainText.getBytes("utf-8"));
  17. byte[] digestBytes = md5.digest();
  18. /*
  19. * 用私钥进行签名 RSA
  20. * Cipher负责完成加密或解密工作,基于RSA
  21. */
  22. Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
  23. //ENCRYPT_MODE表示为加密模式
  24. cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey(path, password));
  25. //加密
  26. byte[] rsaBytes = cipher.doFinal(digestBytes);
  27. //Base64编码
  28. return Base64.byteArrayToBase64(rsaBytes);}

3、B收到数据后,需要使用A提供的公钥信息进行验签,此处使用公钥的N、E进行验签

  首先通过公钥N、E得到公钥PublicKey,如下:



[html]  ​​view plain​​​  ​​​copy​




  1. /**
  2. * 根据公钥n、e生成公钥
  3. * @param modulus   公钥n串
  4. * @param publicExponent  公钥e串
  5. * @return 返回公钥PublicKey
  6. * @throws Exception
  7. */
  8. public static PublicKey getPublickKey(String modulus, String publicExponent)
  9. throws Exception {
  10. KeySpec publicKeySpec = new RSAPublicKeySpec(
  11. new BigInteger(modulus, 16), new BigInteger(publicExponent, 16));
  12. KeyFactory factory = KeyFactory.getInstance("RSA");
  13. PublicKey publicKey = factory.generatePublic(publicKeySpec);
  14. return publicKey;
  15. }


得到公钥PublicKey后,再去验证签名,代码如下:




[html]  ​​view plain​​​  ​​​copy​




  1. /**
  2. * 用公钥证书进行验签
  3. * @param message  签名之前的原文
  4. * @param cipherText  签名
  5. * @param pubKeyn 公钥n串
  6. * @param pubKeye 公钥e串
  7. * @return boolean 验签成功为true,失败为false
  8. * @throws Exception
  9. */
  10. public static boolean verify(String message, String cipherText,String pubKeyn,
  11. String pubKeye) throws Exception {
  12. Cipher c4 = Cipher.getInstance("RSA/ECB/PKCS1Padding");
  13. // 根据密钥,对Cipher对象进行初始化,DECRYPT_MODE表示解密模式
  14. c4.init(Cipher.DECRYPT_MODE, getPublickKey(pubKeyn,pubKeye));
  15. // 解密
  16. byte[] desDecTextBytes = c4.doFinal(Base64.base64ToByteArray(cipherText));
  17. // 得到前置对原文进行的MD5
  18. String md5Digest1 = Base64.byteArrayToBase64(desDecTextBytes);
  19. MessageDigest md5 = MessageDigest.getInstance("MD5");
  20. md5.update(message.getBytes("utf-8"));
  21. byte[] digestBytes = md5.digest();
  22. // 得到商户对原文进行的MD5
  23. String md5Digest2 = Base64.byteArrayToBase64(digestBytes);
  24. // 验证签名
  25. if (md5Digest1.equals(md5Digest2)) {
  26. return true;
  27. } else {
  28. return false;
  29. }
  30. }


 至此,签名验签已经完毕

  4、提供一个从.cer文件读取公钥的方法:



[html]  ​​view plain​​​  ​​​copy​




  1. /**
  2. * 读取公钥cer
  3. * @param path .cer文件的路径  如:c:/abc.cer
  4. * @return  base64后的公钥串
  5. * @throws IOException
  6. * @throws CertificateException
  7. */
  8. public static String getPublicKey(String path) throws IOException,
  9. CertificateException{
  10. InputStream inStream = new FileInputStream(path);
  11. ByteArrayOutputStream out = new ByteArrayOutputStream();
  12. int ch;
  13. String res = "";
  14. while ((ch = inStream.read()) != -1) {
  15. out.write(ch);
  16. }
  17. byte[] result = out.toByteArray();
  18. res = Base64.byteArrayToBase64(result);
  19. return res;
  20. }