java 实现RSA 加密解密工具类及其内部简单流程

来源:互联网 发布:三位水仙花数c语言程序 编辑:程序博客网 时间:2024/06/08 06:20

1.RSA加密简介

RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。1987年首次公布,当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。
今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。但在分布式计算和量子计算机理论日趋成熟的今天,RSA加密安全性受到了挑战。
RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
RSA算法已被写入相应Java工具类里面,这里不做原理介绍,只介绍如何利用java类去实现加密解密过程

2.java工具类实现

import java.security.Key;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;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.X509EncodedKeySpec;import java.util.HashMap;import javax.crypto.Cipher;import com.sun.org.apache.xml.internal.security.utils.Base64;public class RsaUtil {public static String KEY_PAIRGENO = "RSA";public static String PUBLIC_KEY = "PUBLIC_KEY";public static String PRIVATE_KEY = "PRIVATE_KEY";public static HashMap<String, Object> keyMap;public static HashMap<String, Object> initKey() throws Exception {KeyPairGenerator keyPairGeno = KeyPairGenerator.getInstance("RSA");keyPairGeno.initialize(1024);KeyPair keyPair = keyPairGeno.generateKeyPair();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();keyMap = new HashMap<String, Object>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}public static String getPublicKey() {Key key = (Key) keyMap.get(PUBLIC_KEY);byte[] bytes = key.getEncoded();return Base64.encode(bytes);}public static String getPrivateKey() {Key key = (Key) keyMap.get(PRIVATE_KEY);byte[] bytes = key.getEncoded();return Base64.encode(bytes);}// 通过公钥byte[]将公钥还原,适用于RSA算法public static PublicKey getPublicKey(byte[] keyBytes) throws Exception {X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PublicKey publicKey = keyFactory.generatePublic(keySpec);return publicKey;}// 通过私钥byte[]将公钥还原,适用于RSA算法public static PrivateKey getPrivateKey(byte[] keyBytes) throws Exception {PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PrivateKey privateKey = keyFactory.generatePrivate(keySpec);return privateKey;}/** * 公钥加密 *  * @param data * @param publicKey * @return * @throws Exception */public static String encryptByPublicKey(String data, RSAPublicKey publicKey)throws Exception {Cipher cipher = Cipher.getInstance(KEY_PAIRGENO);cipher.init(Cipher.ENCRYPT_MODE, publicKey);// 模长int key_len = publicKey.getModulus().bitLength() / 8;// 加密数据长度 <= 模长-11String[] datas = splitString(data, key_len - 11);String mi = "";// 如果明文长度大于模长-11则要分组加密for (String s : datas) {mi += bcd2Str(cipher.doFinal(s.getBytes()));}return mi;}/** * 私钥解密 *  * @param data * @param privateKey * @return * @throws Exception */public static String decryptByPrivateKey(String data,RSAPrivateKey privateKey) throws Exception {Cipher cipher = Cipher.getInstance(KEY_PAIRGENO);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);// 如果密文长度大于模长则要分组解密String ming = "";byte[][] arrays = splitArray(bcd, key_len);for (byte[] arr : arrays) {ming += new String(cipher.doFinal(arr));}return ming;}/** * ASCII码转BCD码 *  */public 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;}public 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);elsebcd = (byte) (asc - 48);return bcd;}/** * 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);}/** * 拆分字符串 */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;}/** *拆分数组 */public 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;}}


3.加密解密过程

public static void main(String[] args) throws Exception {    try {        RsaUtil.initKey();//执行完后可通过getPublicKey()或getPrivateKey()方法获取这这一对密钥(随机生成)} catch (Exception e) {e.printStackTrace();}String pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPlQvtX35lWpNkuFpB5/+TkBuruYIOjt7xWsAJ"+"QL2nUI5Opn6Ug2NpwvwBV/kXIaNRGj8ih96tKIjSTe8qdXeLyjhRNdk0Sb300/Zv8NvVhxLiNEsc"+"3uR2BvV03in/blhYfCoU0D6Wwyl6tz3ucjRKr0hUcgUX+AqJHuiPIbwzYwIDAQAB";String priKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAM+VC+1ffmVak2S4WkHn/5OQG6u5"+"gg6O3vFawAlAvadQjk6mfpSDY2nC/AFX+Rcho1EaPyKH3q0oiNJN7yp1d4vKOFE12TRJvfTT9m/w"+"29WHEuI0Sxze5HYG9XTeKf9uWFh8KhTQPpbDKXq3Pe5yNEqvSFRyBRf4Coke6I8hvDNjAgMBAAEC"+"gYEAtv2QNyAgf16aYoa1YjYPMlkuW3K8OPMvi5pRgZal2ZIE8UaKfYdZosk1eEXCGucXXo6Bq4IV"+"BZafDq2PMWG+EFDtH9yVylQvvdOF0wB82vSYIdohmRiv9/Nz0lGiEpgkNOPl3llWl9CIoU6IPI4F"+"mRpB8/qpR38R0TLTXy8mnkkCQQD1NrFaXdGLJJtmtWboZ3rJRfyeugeBE+sgtZ7lR1nhGCT3jdtm"+"c+lFZyuVaRexW142ujRs5s8t2gUTpZeRnnKtAkEA2LaXzGQdIIbc0VCoOqND0lMz2srYw9Y4cERW"+"wJYFwVSvrY83wU1uVEt/bknKGe0BTELkZ7tpZaDAN0ltdtwQTwJBAI0umTxDShNH12VySjbC5ZIf"+"BozI5OsvcbAagcrWouwTv6z8cvbxA7ze4twabvbBeWQfH3IYDe8DWOrv621/Ad0CQAFm7QR9gVK8"+"jKEuDGiUtdOehi9cMJrTv/m593W3gsIFcj2FN68geR5CfsiP4abZSbDcne2t4LivmY7CAttKATEC"+"QQDxsduPOS2bxut5XDXkdxtklUF77unjj3fRdu3S00SEc9CBRdcQwmIqolUvIgrsOr3o7xTheIEb"+"s8Zqt9218PZU";String ming = "abc";//用公钥加密String mi = RsaUtil.encryptByPublicKey(ming, (RSAPublicKey)RsaUtil.getPublicKey(Base64.decode(pubKey)));System.out.println("mi : "+mi);//用私钥解密System.out.println("ming : "+RsaUtil.decryptByPrivateKey(mi,(RSAPrivateKey)RsaUtil.getPrivateKey(Base64.decode(priKey))));   }}


4.执行结果

mi : 6FD269662D1308FA27885C6028B33807BCCBF2464E6DB8B934FEAF2C2C91DDD510BAC1D9A4F24A05B9B39480C11C77926F6FF61A366AB060A6B21878D110C023B09D06FB3E1E91C94F4436F2DE41D8013968F60E24D6652CCE74B06F4010585B11C56D78FFA0A3686A7B2D180BEB66CFF2EC81F24AA52B9427AA96B2DA4FE066ming : abc

5.当安卓端传密文到服务器端解密报错时。

   1.注意明文长度是否超过密文长度减去11字节 
   2.注意android默认RSA加密与java jdk默认RSA加密方式不一致
   3.Cipher是线程不安全的,在多线程中注意同步问题。

   参考资料:http://blog.csdn.net/u010670151/article/details/53006232 
                       http://blog.csdn.net/defonds/article/details/42775183




0 0