RSA加解密:
@Log4j
public class RSAMorliaCipher implements IMorliaCipher{
private static final String RSA_PUB_KEY_STRING = "publickey";
private static final String RSA_PRI_KEY_STRING = "privatekey";
private static Cipher pubCipher = null;
private static Cipher priCipher = null;
static {
try {
//生成base64编码的公钥
byte[] decoded = Base64.decodeBase64(RSA_PUB_KEY_STRING);
RSAPublicKey publicKey2 = (RSAPublicKey) KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(decoded));
//RSA
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.PUBLIC_KEY, publicKey2);
pubCipher = cipher;
}catch (Exception e) {
log.error("RSA public key cipher init failed!!");
}
try {
//base64编码的私钥
byte[] decoded = Base64.decodeBase64(RSA_PRI_KEY_STRING);
RSAPrivateKey privateKey2 = (RSAPrivateKey) KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey2);
priCipher = cipher;
}catch (Exception e) {
log.error("RSA private key cipher init failed!!");
}
}
@Override
public String encrypt(String data, String key) throws Exception {
return Base64.encodeBase64String(pubCipher.doFinal(data.getBytes()));
}
@Override
public String decrypt(String data, String key) throws Exception {
return new String(priCipher.doFinal(Base64.decodeBase64(data.getBytes())));
}
public void generateKeyPair() throws NoSuchAlgorithmException {
//KeyPairGenerator类用于生成私钥和公钥对,基于RSA算法
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
//初始化秘钥对生成器,秘钥大小为96-1024
keyPairGenerator.initialize(1024, new SecureRandom());
//生成一个密钥对,
KeyPair keyPair = keyPairGenerator.generateKeyPair();
//生成私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
//生成公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//生成公钥字符串
String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
//生成私钥字符串
String privateKeyString = new String(Base64.encodeBase64(privateKey.getEncoded()));
log.debug(publicKeyString);
log.debug(privateKeyString);
}
@Override
public void registerCipher() {
MorliaKeyFactory.registerCipher("RSA", new RSAMorliaCipher());
}
}
RSA是长用的非对称加密算法,其规定每次加密的字节数,不能超过秘钥的长度值减去11,而每次加密得到的密文长度,却恰恰是秘钥的长度。所以,如果要加密较长的数据,可以采用数据截取的方法,分段加密。
AES是SecureRandom进行加解密:
@Log4j
public class AESRandomMorliaCipher implements IMorliaCipher{
private static final String CIPHER_TYPE = "AES/ECB/PKCS5Padding";
private static final String RANDOM_TYPE = "SHA1PRNG";
private static final String CHAR_SET = "UTF-8";
private static KeyGenerator keyGenerator = null;
private static Cipher cipher = null;
static {
try {
keyGenerator = KeyGenerator.getInstance("AES");
cipher = Cipher.getInstance(CIPHER_TYPE);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
log.error("init AES random error!!");
}
}
@Override
public String encrypt(String data, String key) throws Exception {
return Base64.encodeBase64String(cipher(data.getBytes(), key, Cipher.ENCRYPT_MODE));
}
@Override
public String decrypt(String data, String key) throws Exception {
return new String(cipher(Base64.decodeBase64(data), key, Cipher.DECRYPT_MODE),"UTF-8");
}
private byte[] cipher(byte[] data, String key, int mode) throws Exception {
SecureRandom secureRandom = SecureRandom.getInstance(RANDOM_TYPE);
secureRandom.setSeed(key.getBytes(CHAR_SET));
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
byte[] keyBytes = secretKey.getEncoded();
Key key2 = new SecretKeySpec(keyBytes, "AES");
cipher.init(mode, key2);
return cipher.doFinal(data);
}
@Override
public void registerCipher() {
MorliaKeyFactory.registerCipher("AES-Random", new AESRandomMorliaCipher());
}
}
如果是IOS客户端和JAVA服务器端交互,需要使用下面的IV向量加密。
AES使用IV向量来进行加解密:
@Log4j
public class AESIVMorliaCipher implements IMorliaCipher{
private static final String CIPHER_TYPE = "AES/CBC/PKCS5Padding";
private static final String IV_STRING = "------16bytes----";
private static IvParameterSpec ivParameterSpec;
private static Cipher cipher = null;
static {
try {
cipher = Cipher.getInstance(CIPHER_TYPE);
ivParameterSpec = new IvParameterSpec(IV_STRING.getBytes());
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
log.error("init AES IV error!!");
}
}
@Override
public String encrypt(String data, String key) throws Exception {
return Base64.encodeBase64String(cipher(data.getBytes(), key, Cipher.ENCRYPT_MODE));
}
@Override
public String decrypt(String data, String key) throws Exception {
return new String(cipher(Base64.decodeBase64(data), key, Cipher.DECRYPT_MODE),"UTF-8");
}
private byte[] cipher(byte[] data, String key, int mode) throws Exception {
byte[] keyBytes = key.getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
cipher.init(mode, secretKeySpec,ivParameterSpec);
return cipher.doFinal(data);
}
@Override
public void registerCipher() {
MorliaKeyFactory.registerCipher("AES-IV", new AESIVMorliaCipher());
}
}
此处加密的key是16位的,如果修改为32位或者更高位的的将会报java.security.InvalidKeyException: Illegal key size
解决办法:
下载对应的jar文件替换原有的,
jdk1.8的http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html。
其他版本的与之类似,下载好后解压,主要用到local_policy.jar和US_export_policy.jar,将其复制到JAVA_HOME下的\jre\lib\security中替换即可。
Factory工厂类通过包路径来自动注册算法对象
public interface IMorliaCipher {
String encrypt(String data, String key) throws Exception;
String decrypt(String data, String key) throws Exception;
void registerCipher();
}
@Log4j
public class MorliaKeyFactory {
private static final String CIPHER_BASE_INTERFACE = "IMorliaCipher";
private static final String CIPHER_BASE_PACKAGE = "com.morlia.platform.common.init.encrypt.cipher";
private static Map<String, IMorliaCipher> map = new HashMap<String, IMorliaCipher>();
static {
try {
autoRegisterCipher();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IOException e) {
log.error("cipher init error!!" + e);
}
}
public static void registerCipher(String cipherType, IMorliaCipher cipher) {
map.put(cipherType, cipher);
}
private static void autoRegisterCipher() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
List<String> classNameList = getClassNameFromPackge(CIPHER_BASE_PACKAGE);
for(String className : classNameList) {
Class<?> clazz = Class.forName(className);
for(Class<?> class1 : clazz.getInterfaces()) {
if(class1.getSimpleName().equals(CIPHER_BASE_INTERFACE)) {
IMorliaCipher cipher = (IMorliaCipher) clazz.newInstance();
cipher.registerCipher();
}
}
}
}
private static List<String> getClassNameFromPackge(String packageName) throws IOException {
List<String> returnClassList = new ArrayList<String>();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
String strFile = packageName.replaceAll("\\.", "/");
Enumeration<URL> urls = loader.getResources(strFile);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if(url != null) {
String pkgPath = url.getPath();
File dirFile = new File(pkgPath);
if(!dirFile.exists() || !dirFile.isDirectory()) {
log.warn("Cipher register failed!!");
return null;
}
File[] files = dirFile.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.getName().endsWith(".class");
}
});
for(File file : files) {
String className = file.getName().substring(0,file.getName().length() - 6);
returnClassList.add(packageName + "." + className);
}
}
}
return returnClassList;
}
}