Android平台AES对称加密踩过的坑

本文分享了作者在Android开发中使用SharedPreferences结合AES加密技术的经验,详细介绍了如何实现字符串的安全存储,并特别指出在不同API版本间加密库的差异及其带来的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间对Android下sharepreference储存字符串做了个AES对称加密,废话不多说,直接上正确姿势的加密代码

<pre class="java" name="code">package com.android.androidframework.utils;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * Author KINCAI
 * .
 * description AES加密器
 * .
 * Time 2016-10-25 21:21
 */
public class AESEncryptorUtils {
    /**
     * 加密
     * @param seed 密钥
     * @param encrypt 需要加密的字符串
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encrypt(String seed, String encrypt) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, encrypt.getBytes());
        return toHex(result);
    }

    /**
     * 解密
     * @param seed 密钥
     * @param encrypted 加密过的字符串
     * @return 解密后的字符串
     * @throws Exception
     */
    public static String decrypt(String seed, String encrypted) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = toByte(encrypted);
        byte[] result = decrypt(rawKey, enc);
        return new String(result);
    }


    /**
     * 通过加密库 加密算法生成字节数组
     * 注意:在api版本17以前 随机数生成器SecureRandom.getInstance默认使用Crypto内容提供者的加密库
     * 而api>=17版本中随机数生成器SecureRandom.getInstance默认使用OpenSSL内容提供者的加密库
     * 为了兼容 请使用Crypto加密库
     * @param seed 密钥
     * @return 字节数组
     * @throws Exception
     */
    private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG","Crypto");
        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;

    }

    /**
     * 加密
     * @param raw 随机字节数组
     * @param encryptByte 需要加密的字符串的字节数组
     * @return 字节数组
     * @throws Exception
     */
    private static byte[] encrypt(byte[] raw, byte[] encryptByte) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(encryptByte);
        return encrypted;

    }


    /**
     * 解密
     * @param raw 随机字节数组
     * @param encrypted 已经加密的字符串的字节数组
     * @return 字节数组
     * @throws Exception
     */
    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;
    }


    /**
     *
     * @param txt
     * @return
     */
    public static String toHex(String txt) {
        return toHex(txt.getBytes());

    }


    /**
     *
     * @param hex
     * @return
     */
    public static String fromHex(String hex) {
        return new String(toByte(hex));

    }


    /**
     *
     * @param hexString
     * @return
     */
    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;

    }

    /**
     *
     * @param buf
     * @return
     */
    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";

    /**
     *
     * @param sb
     * @param b
     */
    private static void appendHex(StringBuffer sb, byte b) {
        sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));

    }
}



重点讲一下遇到的坑,看getRawKey()方法


看红框代码,是随机数生成器,有两个参数,第一个参数是加密算法,这里选择的是sha1的加密算法,第二个是加密库内容提供者名字,这个参数可以不填,在api版本17以前 Crypto内容提供者的加密库, 而api>=17版本中默认使用OpenSSL内容提供者的加密库,笔者这里一开始使用的是一个参数的getInstance,也就是默认的加密库,在api大于17的机子上跑了结果每一次加密的结果都是不一样的,如果用默认的加密后,再解密会出现javax.crypto.BadPaddingException: pad block corrupted 异常,一开始懵逼了。

好吧,就到这里,想知道为什么异常的可以进一步了解,这里就不做解释。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值