一、问题
在Java 后端发来的AES加密数据时,发现Android APP不能解密 而且Android 端 加密同样的数据返回的结果居然不一致,所以我在网上查询后,发现在SecureRandom在产生安全随机数时 Windows系统和Linux系统的机制不一样,所以在同样的java AES加密源码加密同意的数据产生不一样的加密结果。
下面我给出网络的常用的AES加密的源码。
网络常用的AES加解密源码:
/**
* AES加密字符串
*
* @param content
* 需要被加密的字符串
* @param password
* 加密需要的密码
* @return 密文
*/
public static byte[] encrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
kgen.init(128, new SecureRandom(password.getBytes()));// 利用用户密码作为随机数初始化出
// 128位的key生产者
//加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回
// null。
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
return result;
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**
* 解密AES加密过的字符串
*
* @param content
* AES加密过过的内容
* @param password
* 加密时的密码
* @return 明文
*/
public static byte[] decrypt(byte[] content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器
byte[] result = cipher.doFinal(content);
return result; // 明文
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
二、解决源码
我的解决方案是自己写AES的秘钥生成128位的Key和使用Java Base64加密生成加密数据字符串;这样可以避免因为系统的随机数机制不同而不能加解密。
我的AES源码:
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
/**
* AES加密工具
* <p>
* 加密流程 AES -> BAse64
* 解密流程 Base64 -> AES
*/
public class AESUtil {
//补充字典
private final static String DIC = "1231g81f5456hhssg84h1f9q3f2x789s";
// 加密
public static String encrypt(String str, String key) {
if (str == null || "".equals(str))
return null;
if (key == null || "".equals(key))
return null;
try {
byte[] enCodeFormat = generateKey(key);// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回
SecretKeySpec skey = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.ENCRYPT_MODE, skey);// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(str.getBytes("UTF-8"));// 加密
return Base64.getUrlEncoder().encodeToString(result);
} catch (Exception e) {
LogUtil.e(e.toString());
return null;
}
}
// 解密
public static String decrypt(String str, String key) {
if (str == null || "".equals(str))
return null;
if (key == null || "".equals(key))
return null;
try {
byte[] enCodeFormat = generateKey(key);// 返回基本编码格式的密钥
SecretKeySpec skey = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, skey);// 初始化为解密模式的密码器
byte[] base64 = Base64.getUrlDecoder().decode(str.getBytes("UTF-8"));
byte[] result = cipher.doFinal(base64);
return new String(result, "UTF-8"); // 明文
} catch (Exception e) {
LogUtil.e(e.getMessage());
return null;
}
}
/**
* 自定义 秘钥补充
*
* @param key
* @return
* @throws Exception
*/
private static byte[] generateKey(String key) throws Exception {
byte[] dics = DIC.getBytes("UTF-8");
byte[] bkeys = key.getBytes("UTF-8");
byte[] keys = bkeys;
int keylength = bkeys.length;
if (keylength > 0 && keylength < 16) {
keys = new byte[16];
System.arraycopy(bkeys, 0, keys, 0, keylength);
for (int i = keylength; i < 16; i++) {
keys[i] = dics[i];
}
}
if (keylength > 16 && keylength < 24) {
keys = new byte[24];
System.arraycopy(bkeys, 0, keys, 0, keylength);
for (int i = keylength; i < 24; i++) {
keys[i] = dics[i];
}
}
if (keylength > 24 && keylength < 32) {
keys = new byte[32];
System.arraycopy(bkeys, 0, keys, 0, keylength);
for (int i = keylength; i < 32; i++) {
keys[i] = dics[i];
}
}
if (keylength > 32) {
keys = new byte[32];
System.arraycopy(bkeys, 0, keys, 0, 32);
}
return keys;
}
generateKey()的用于生成AES使用的128位秘钥;
注意:DIC这个秘钥补充字典 这个可以自己定义,但是一定要和java 后端一致。
加密解密时使用Base64我有相关的文章可以去参考一下:
如果对您有一些意义,希望您给博主一些鼓励(点赞、关注、收藏),如果有错误欢迎大家评论。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/128356.html