本文主要小结一下java里头的AES以及RSA加解密。java
使用AES加密时须要几个参数:android
AES算法下,key的长度有三种:12八、192和256 bits。因为历史缘由,JDK默认只支持不大于128 bits的密钥,而128 bits的key已可以知足商用安全需求。算法
分组密码算法只能加密固定长度的分组,可是咱们须要加密的明文长度可能会超过度组密码的分组长度,这时就须要对分组密码算法进行迭代,以便将一段很长的明文所有加密。而迭代的方法就称为分组密码的模式。
AES属于块加密(Block Cipher),块加密中有CBC、ECB、CTR、OFB、CFB等几种工做模式。安全
ECB模式因为每块数据的加密是独立的所以加密和解密均可以并行计算,ECB模式最大的缺点是相同的明文块会被加密成相同的密文块,这种方法在某些环境下不能提供严格的数据保密性
);本文使用CBC模式。并发
CBC模式对于每一个待加密的密码块在加密前会先与前一个密码块的密文异或而后再用加密器加密。第一个明文块与一个叫初始化向量的数据块异或。CBC模式相比ECB有更高的保密性,但因为对每一个数据块的加密依赖与前一个数据块的加密因此加密没法并行。与ECB同样在加密前须要对数据进行填充,不是很适合对流数据进行加密。加密
因为块加密只能对特定长度的数据块进行加密,所以CBC、ECB模式须要在最后一数据块加密前进行数据填充。
JDK则提供了PKCS5Padding。spa
使用除ECB之外的其余加密模式均须要传入一个初始向量,其大小与Block Size相等(AES的Block Size为128 bits)code
public static String genKeyAES() throws Exception { KeyGenerator kenGen = KeyGenerator.getInstance(AES); kenGen.init(KEY_SIZE); SecretKey key = kenGen.generateKey(); String base64 = Base64.getEncoder().encodeToString(key.getEncoded()); return base64; }
这里KEY_SIZE采用128
后面统一用base64将byte[]转为字符串,方便展现、排查。ip
public static byte[] aesEncryptBytes(byte[] contentBytes, byte[] keyBytes) throws Exception { return cipherOperation(contentBytes, keyBytes, Cipher.ENCRYPT_MODE); } public static byte[] aesDecryptBytes(byte[] contentBytes, byte[] keyBytes) throws Exception { return cipherOperation(contentBytes, keyBytes, Cipher.DECRYPT_MODE); } private static byte[] cipherOperation(byte[] contentBytes, byte[] keyBytes, int mode) throws Exception { SecretKeySpec secretKey = new SecretKeySpec(keyBytes,AES); byte[] initParam = SIXTEEN_CHAR_INIT_VECTOR.getBytes(CHARSET); IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam); Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING); cipher.init(mode, secretKey, ivParameterSpec); return cipher.doFinal(contentBytes); }
这里AES_CBC_PKCS5_PADDING为AES/CBC/PKCS5Padding,使用简写的AES默认就是这个值ci
public static KeyPair getKeyPair() throws Exception { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA); keyPairGenerator.initialize(KEY_SIZE); KeyPair keyPair = keyPairGenerator.generateKeyPair(); return keyPair; } public static String getPublicKey(KeyPair keyPair){ PublicKey publicKey = keyPair.getPublic(); byte[] bytes = publicKey.getEncoded(); return Base64.getEncoder().encodeToString(bytes); } public static String getPrivateKey(KeyPair keyPair){ PrivateKey privateKey = keyPair.getPrivate(); byte[] bytes = privateKey.getEncoded(); return Base64.getEncoder().encodeToString(bytes); }
这里KEY_SIZE用1024,RSA256,RSA512,RSA1024,RSA2048这四种,RSA后面的N表明位数(多少bit),位数越大,加密强度越大,须要破解须要的时间也就越长
目前主流密钥长度至少都是1024bits以上,低于1024bit的密钥已经不建议使用(安全问题)。那么上限在哪里?没有上限,多大均可以使用。因此,主流的模值是1024位
public static byte[] publicEncrypt(byte[] content,PublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance(RSA); cipher.init(Cipher.ENCRYPT_MODE,publicKey); byte[] bytes = cipher.doFinal(content); return bytes; } public static byte[] privateDecrypt(byte[] content,PrivateKey privateKey) throws Exception { Cipher cipher = Cipher.getInstance(RSA); cipher.init(Cipher.DECRYPT_MODE,privateKey); byte[] bytes = cipher.doFinal(content); return bytes; }
这里RSA即"RSA",默认是RSA/ECB/PKCS1Padding
在实际应用中,咱们会混合应用AES和RSA:
这样就充分利用了二者的优点.
public void testHyperCodec(){ KeyPair keyPair = RSAUtil.getKeyPair(); String pubKey = RSAUtil.getPublicKey(keyPair); String priKey = RSAUtil.getPrivateKey(keyPair); String password = "1234567890"; String aesRawKey = AESUtil.genKeyAES(); System.out.println("aes raw key:"+aesRawKey); String rsaEntryptAesKey = RSAUtil.publicEncryptString(aesRawKey,pubKey); System.out.println(rsaEntryptAesKey); String aesEntryptContent = AESUtil.aesEncryptStringByBase64Key(password,aesRawKey); System.out.println(aesEntryptContent); //decode String decodedAesKey = RSAUtil.privateDecryptString(rsaEntryptAesKey,priKey); String decodedPwd = AESUtil.aesDecryptStringByBase64Key(aesEntryptContent,decodedAesKey); System.out.println("aes key decoded:"+decodedAesKey); System.out.println(decodedPwd); }