今天经理要我做下加密,到网上查了下Android SDK 目前支持4种加密算法:MD5 ,SHA,HMAC,AES。其中,前面三种为不可逆加密算法,AES,为可逆加密算法。于是我打算采用AES加密。
下面是我找的AES加密的算法,到网上找了很多,下面贴出可以在Andorid端进行解密的代码(Seed要用16个字符)
public static String encrypt(String seed, String cleartext) throws Exception { //byte[] rawKey = getRawKey(seed.getBytes()); byte[] rawKey = seed.getBytes(); byte[] result = encrypt(rawKey, cleartext.getBytes()); return toHex(result); } public static String decrypt(String seed, String encrypted) throws Exception { //byte[] rawKey = getRawKey(seed.getBytes()); byte[] rawKey = seed.getBytes(); byte[] enc = toByte(encrypted); byte[] result = decrypt(rawKey, enc); return new String(result); } private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(seed); kgen.init(128, sr); // 192 and 256 bits may not be available SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(clear); return encrypted; } private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] decrypted = cipher.doFinal(encrypted); return decrypted; } public static String toHex(String txt) { return toHex(txt.getBytes()); } public static String fromHex(String hex) { return new String(toByte(hex)); } public static byte[] toByte(String hexString) { int len = hexString.length()/2; byte[] result = new byte[len]; for (int i = 0; i < len; i++) result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue(); return result; } public static String toHex(byte[] buf) { if (buf == null) return ""; StringBuffer result = new StringBuffer(2*buf.length); for (int i = 0; i < buf.length; i++) { appendHex(result, buf[i]); } return result.toString(); } private final static String HEX = "0123456789ABCDEF"; private static void appendHex(StringBuffer sb, byte b) { sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f)); }
用法:
// 使用该方法 String seed = "1111111111111111"; String originalText = "要加密的内容"; String encryptingCode = 类名(将上面的代码封装到类里).encrypt(masterPassword,original Text);
Log.d(TAG, "加密结果为: "+ encryptingCode);String decryptingCode = 类名(将上面的代码封装到类里).decrypt(masterPassword, encryptingCode);
Log.d(TAG, "解密结果为: "+ decryptingCode);
AES解密的时候一开始总是报错:
javax.crypto.BadPaddingException: pad block corrupted
但是用了上的代码然后把seed换成16位的就可以正常的解出来了。
一开始用的是Android 7.0的虚拟机然后系统会告诉你:
********** PLEASE READ ************ E/System: * E/System: * New versions of the Android SDK no longer support the Crypto provider. E/System: * If your app was relying on setSeed() to derive keys from strings, you E/System: * should switch to using SecretKeySpec to load raw key bytes directly OR E/System: * use a real key derivation function (KDF). See advice here : E/System: * http://android-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html E/System: *********************************** E/System: Returning an instance of SecureRandom from the Crypto provider E/System: as a temporary measure so that the apps targeting earlier SDKs E/System: keep working. Please do not rely on the presence of the Crypto E/System: provider in the codebase, as our plan is to delete it E/System: completely in the future.
=========================百度翻译=============================
**********请阅读************
电子/系统:*
电子系统:*新版本的Android SDK不支持加密提供程序。
电子系统:*如果你的应用程序依赖setseed()得到钥匙串,你
电子系统:*应切换到使用secretkeyspec加载原始密钥字节直接或
电子系统:*使用真正的密钥导出函数(KDF)。看这里的建议:
电子系统:* http://android-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html
电子系统:***********************************
电子系统:从提供的加密提供程序返回的实例
电子系统:作为临时措施,针对早期的SDK应用程序
电子/系统:保持工作。请不要依赖于密码的存在
电子系统:在代码的提供者,我们的计划是要删除它
电子/系统:完全在未来。
查了下发现:Android N 中已弃用“Crypto”安全提供程序,上面的红色地址已经给出了解决方案
使用AES去解密获得的字符串发现中文乱码,到网上查了原因:
客户端AES加密的时候,对明文进行分块,每块16个字符,分别对每一块进行加密时,某一个中间字符结果为0,导致加密结果字符串在0处截断,后面字符串丢弃,所以解密的时候出现异常。
解决办法:
把strcat和strcpy全改为memcpy,strlen改为实际长度之后,排除字符串中'\0'的干扰,加解密正常
我是个新人小白看不懂,于是想了个办法绕开中文的办法,先采用Base64加密,再用AES加密,可以避免直接对中文进行加密
最后亲测这个办法可行。
第一次写文章写不好,还请见谅。