emmmmmm就是呢,我今天研究了一下非对称数据加密RSA的使用,算法什么的暂时不研究,加密算法还有很多,以后再研究吧,就酱(>人<;)。非对称加密算法需要两个密钥:公开密钥(publicKey)和私有密钥(privateKey);如果用公有密钥加密,对应的就是要私有密钥才能解密;反过来就是私钥加密,公钥解密。
然后就来实现一下RSA加密的工具类吧
注意:RSA加密明文最大长度是117字节,解密要求密文最大长度为128字节,所以再加密和解密的时候要分段进行,就是每117字节就加密,然后再把这一节节拼起来。
1 public class RSAUtil { 2 3 public static String KEY_PAIRGENO = "RSA"; 4 public static String PUBLIC_KEY = "PUBLIC_KEY"; 5 public static String PRIVATE_KEY = "PRIVATE_KEY"; 6 public static final String CHARSET = "UTF-8"; 7 8 public static HashMap<String, String> keyMap = new HashMap<>(2); 9 10 public static void init() throws Exception { 11 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_PAIRGENO); 12 keyPairGen.initialize(1024); 13 KeyPair keyPair = keyPairGen.generateKeyPair(); 14 String publicKey = getPublicKeyStr(keyPair.getPublic()); 15 String privateKey = getPrivateKeyStr(keyPair.getPrivate()); 16 17 keyMap.put(PUBLIC_KEY, publicKey); 18 keyMap.put(PRIVATE_KEY,privateKey); 19 } 20 21 22 private static String getPrivateKeyStr(PrivateKey privateKey) throws Exception { 23 return Base64.encodeBase64URLSafeString(privateKey.getEncoded()); 24 } 25 26 private static String getPublicKeyStr(PublicKey publicKey) throws Exception { 27 return Base64.encodeBase64URLSafeString(publicKey.getEncoded()); 28 } 29 30 /** 31 * 把字符串公钥转为 RSAPublicKey 公钥 32 */ 33 public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException { 34 //通过X509编码的Key指令获得公钥对象 35 KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIRGENO); 36 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey)); 37 RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec); 38 return key; 39 } 40 41 /** 42 * 把字符串私钥转为 RSAPrivateKey 私钥 43 */ 44 public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException { 45 //通过PKCS#8编码的Key指令获得私钥对象 46 KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIRGENO); 47 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)); 48 RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec); 49 return key; 50 } 51 52 /** 53 * 公钥加密, 加密明文最大长度是117字节 54 */ 55 public static String encryptByPublicKey(String msg, RSAPublicKey publicKey) throws Exception{ 56 Cipher cipher = Cipher.getInstance(KEY_PAIRGENO); 57 cipher.init(Cipher.ENCRYPT_MODE,publicKey); 58 int keySize = publicKey.getModulus().bitLength();//1024 59 byte[] data = msg.getBytes(CHARSET); 60 byte[] encryptedData = rsaSplitCode(cipher, data, Cipher.ENCRYPT_MODE, keySize); 61 String mi= Base64.encodeBase64URLSafeString(encryptedData); 62 return mi; 63 64 65 } 66 67 /* 68 * 私钥解密,解密要求密文最大长度为128字节 69 * */ 70 public static String decryptByPrivateKey(String rsaMsg, RSAPrivateKey privateKey) throws Exception{ 71 Cipher cipher = Cipher.getInstance(KEY_PAIRGENO); 72 cipher.init(Cipher.DECRYPT_MODE, privateKey); 73 int keySize = privateKey.getModulus().bitLength();//长度是1024 74 byte[] data = Base64.decodeBase64(rsaMsg); 75 byte[] decryptedData = rsaSplitCode(cipher, data, Cipher.DECRYPT_MODE, keySize); 76 String ming = new String(decryptedData, CHARSET); 77 return ming; 78 } 79 80 /*私钥加密*/ 81 public static String encryptByPrivate(String msg, RSAPrivateKey privateKey) throws Exception{ 82 Cipher ciper = Cipher.getInstance(KEY_PAIRGENO); 83 ciper.init(Cipher.ENCRYPT_MODE,privateKey); 84 int keySize = privateKey.getModulus().bitLength(); 85 byte[] data = msg.getBytes(CHARSET); 86 byte[] encryptedData = rsaSplitCode(ciper, data, Cipher.ENCRYPT_MODE,keySize); 87 String mi = Base64.encodeBase64URLSafeString(encryptedData); 88 return mi; 89 } 90 91 /*公钥解密*/ 92 public static String decrytByPublic(String msg, RSAPublicKey publicKey) throws Exception{ 93 Cipher ciper = Cipher.getInstance(KEY_PAIRGENO); 94 ciper.init(Cipher.DECRYPT_MODE, publicKey); 95 int keySize = publicKey.getModulus().bitLength(); 96 byte[] data = Base64.decodeBase64(msg); 97 byte[] decryptedData = rsaSplitCode(ciper, data, Cipher.DECRYPT_MODE,keySize); 98 String ming = new String(decryptedData,CHARSET); 99 return ming; 100 } 101 102 103 104 private static byte[] rsaSplitCode(Cipher cipher, byte[] data,int opmode ,int keySize){ 105 int maxBlock = 0; 106 if(opmode == Cipher.DECRYPT_MODE) 107 maxBlock = keySize / 8;//解密要求最大长度是128 108 else 109 maxBlock = keySize / 8 -11; //加密要求最大长度是117 110 111 int inputLen = data.length; 112 ByteArrayOutputStream out = new ByteArrayOutputStream(); 113 int offSet = 0; 114 byte[] cache; 115 int i = 0; 116 // 对数据分段解密 117 try { 118 while (inputLen - offSet > 0) { 119 if (inputLen - offSet > maxBlock) { 120 cache = cipher.doFinal(data, offSet, maxBlock); 121 } else { 122 cache = cipher.doFinal(data, offSet, inputLen - offSet); 123 } 124 out.write(cache, 0, cache.length); 125 i++; 126 offSet = i * maxBlock; 127 } 128 byte[] bytes = out.toByteArray(); 129 out.close(); 130 return bytes; 131 } catch (Exception e) { 132 throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e); 133 } 134 } 135 136 137 138 139 140 public static void main(String[] args) throws Exception { 141 init(); 142 String msg = "我是冬竹"; 143 System.out.println("公钥加密-私钥解密:"); 144 String mi = encryptByPublicKey(msg, getPublicKey(keyMap.get(PUBLIC_KEY))); 145 System.out.println("密文:" + mi); 146 147 String ming = decryptByPrivateKey(mi , getPrivateKey(keyMap.get(PRIVATE_KEY))); 148 System.out.println("明文:" + ming); 149 150 System.out.println("私钥加密-公钥解密:"); 151 String mi2 = encryptByPrivate(msg, getPrivateKey(keyMap.get(PRIVATE_KEY))); 152 System.out.println("密文:" + mi2); 153 154 String ming2 = decrytByPublic(mi2 , getPublicKey(keyMap.get(PUBLIC_KEY))); 155 System.out.println("明文:" + ming); 156 } 157 158 }
这这这好长啊........
说一下这个过程:
1. keyPair.getPublic() 获得的字节数组 用encodeBase64URLSafeString() 编码成字符串,也就是我们有时候用的那种很多字母的那种公钥(私钥)
2. 用decodeBase64() 把公钥解码成字节数组,然后通过X509编码的Key指令获得公钥对象 RSAPublicKey
加密字符串的过程:
1. msg.getBytes() 获得字符数组, 然后用rsaSplitCode() 方法加密,再用encodeBase64URLSafeString编码成字符串(密文)
解密字符串的过程:
1. decodeBase64() 把密文解码成字符数组,再用new String()方法转为字符串
然后我用的Base64类是commons-net-3.1.jar 里的,这个是我的maven仓库里(maven真的太方便了(●ˇ?ˇ●))
放上这个:https://github.com/MoisAbby/XZUtils, 以后会把我攒的好用的东西都放上来