rsa加密:公钥加密,私钥解密。
首先,我们先要生成密钥对:
public static void createRSAKey(String privateKeyPath, String publicKeyPath) throws BasicException { KeyPairGenerator kpg = null; try { kpg = KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { throw new RsaException(e); } kpg.initialize(1024); // 指定密钥长度 KeyPair kp = kpg.genKeyPair(); // 生成密钥对 PublicKey public_key = kp.getPublic(); // 获得公钥 PrivateKey private_key = kp.getPrivate(); // 获得私钥 String publicKeyStr = Base64 .encodeBase64String(public_key.getEncoded()); // 创建公钥 FileUtil.createFile(publicKeyPath, publicKeyStr.getBytes()); String privateKeyStr = Base64.encodeBase64String(private_key .getEncoded()); // 创建私钥 FileUtil.createFile(privateKeyPath, privateKeyStr.getBytes()); }
需要注意的是,密钥的长度是跟加密后的密文长度有关。当密钥长度加倍时,rsa解密密文的最大值也要加倍。
然后,我们就要对明文进行加密解密了。但是rsa对加密明文的长度是有限制的,最大长度为117字节,否则就会抛出异常:
Data must not be longer than 117 bytes
所以我们要采用分段加密的方式:
// rsa最大加密明文大小 private static final int MAX_ENCRYPT_BLOCK = 117; // rsa最大解密密文大小 private static final int MAX_DECRYPT_BLOCK = 128; // 分段加密 private static String encryptByKey(String data, Key key) throws BasicException { Cipher cipher; try { cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, key); } catch (Exception e) { throw new RsaException(e); } int length = data.length(); int offset = 0; byte[] result = null; int i = 0; while (length - offset > 0) { byte[] cache; try { if (length - offset > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data.getBytes(), offset, length - offset); } } catch (Exception e) { throw new RsaException(e); } result = VDILicenseCreator.concat(result, cache); i++; offset = i * MAX_ENCRYPT_BLOCK; } return Base64.encodeBase64String(result); } // 分段解密 private static String decryptByKey(String data, Key key) throws BasicException { Cipher cipher; try { cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, key); } catch (Exception e) { throw new RsaException(e); } byte[] data64 = Base64.decodeBase64(data); int length = data64.length; int offset = 0; byte[] result = null; int i = 0; while (length - offset > 0) { byte[] cache; try { if (length - offset > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(data64, offset, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(data64, offset, length - offset); } } catch (Exception e) { throw new RsaException(e); } result = VDILicenseCreator.concat(result, cache); i++; offset = i * MAX_DECRYPT_BLOCK; } return new String(result); }
上面的代码中,还有一个rsa最大解密密文大小。加密分段,解密当然也要分段了。当密钥的长度为1024时,小于117字节的明文,加密后长度都是128字节(所以分段加密后,密文的长度都是128的整数倍),所以上面rsa最大解密密文大小设置为128。但是,如果密钥的长度为2048时,这个值就要随之翻倍,设置为256。如果仍设置为128,则会抛出异常:
Data must start with zero
下面备注了我们所用到的jar包:
import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64;