【开发新人】记录我今天做AES加密踩的坑

今天经理要我做下加密,到网上查了下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加密,可以避免直接对中文进行加密
最后亲测这个办法可行。
 
 
最后贴上最后解析出来的图
 
 
 
 

第一次写文章写不好,还请见谅。委屈


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值