Android9 AES加密报错问题

本博客写给自己记录,也供大家参考(Android 9 = Android P=API 28)

通常的AES加密方式不再重复,很多博客都有些,基本上都是这样:

private static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance(AES);
    //for android
    SecureRandom sr = null;
    // 在4.2以上版本中,SecureRandom获取方式发生了改变
    int sdk_version = android.os.Build.VERSION.SDK_INT;
    if (sdk_version > 23) {  // Android  6.0 以上
        sr = SecureRandom.getInstance(SHA1PRNG, new CryptoProvider());
    } else if (sdk_version >= 17) {   //4.2及以上
        sr = SecureRandom.getInstance(SHA1PRNG, "Crypto");
    } else {
        sr = SecureRandom.getInstance(SHA1PRNG);
    }
    // for Java
    // secureRandom = SecureRandom.getInstance(SHA1PRNG);
    sr.setSeed(seed);
    kgen.init(128, sr); //256 bits or 128 bits,192bits
    //AES中128位密钥版本有10个加密循环,192比特密钥版本有12个加密循环,256比特密钥版本则有14个加密循环。
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}

大多数博客写到的SecureRandom.getInstance为空的解决方案都是用CryptoProvider处理,如下

 public static class CryptoProvider extends Provider {
        /**
         * Creates a Provider and puts parameters
         */
        CryptoProvider() {
            super("Crypto", 1.0, "HARMONY (SHA1 digest; SecureRandom; SHA1withDSA signature)");
            put("SecureRandom.SHA1PRNG",
                    "org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl");
            put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
        }
    }

但在android 9(API28)开始,这样调用也会获取不到SecureRandom,这是谷歌的坑,好了,怎么改,看下面

获取SecureRandom实际上也就是为了获取SecretKeySpec,这里android 9可以直接获取,如下

private static SecretKeySpec deriveKeyInsecurely(String password) {
        byte[] passwordBytes = password.getBytes(StandardCharsets.US_ASCII);
        return new SecretKeySpec(InsecureSHA1PRNGKeyDerivator.deriveInsecureKey(passwordBytes, 32), "AES");
    }

所以这里的代码就改成(只举例加密):

 private static byte[] encrypt(String key, byte[] clear) throws Exception {
        LogUtils.d("加密", "API::" + android.os.Build.VERSION.SDK_INT);
        SecretKeySpec skeySpec = null;
        if (android.os.Build.VERSION.SDK_INT >= 28) {
            skeySpec = deriveKeyInsecurely(key);
        } else {
            byte[] raw = getRawKey(key.getBytes());
            skeySpec = new SecretKeySpec(raw, AES);
        }
        Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
        byte[] encrypted = cipher.doFinal(clear);
        
        return encrypted;
    }

好了,有人复制过去代码了,没问题,只是你可能会找不到InsecureSHA1PRNGKeyDerivator这个类,怎么办?

这里:

package com.hly.gps.unique;


/**
 * Stripped-down version of the SHA1PRNG provided by the Crypto provider.
 * <p>
 * The Crypto provider that offers this functionality was deprecated on Android.
 * <p>
 * Use this class only to retrieve encrypted data that couldn't be retrieved otherwise.
 */
public class InsecureSHA1PRNGKeyDerivator {
    /**
     * Only public method. Derive a key from the given seed.
     * <p>
     * Use this method only to retrieve encrypted data that couldn't be retrieved otherwise.
     *
     * @param seed           seed used for the random generator, usually coming from a password
     * @param keySizeInBytes length of the array returned
     */
    public static byte[] deriveInsecureKey(byte[] seed, int keySizeInBytes) {
        InsecureSHA1PRNGKeyDerivator derivator = new InsecureSHA1PRNGKeyDerivator();
        derivator.setSeed(seed);
        byte[] key = new byte[keySizeInBytes];
        derivator.nextBytes(key);
        return key;
    }

    // constants to use in expressions operating on bytes in int and long variables:
    // END_FLAGS - final bytes in words to append to message;
    //             see "ch.5.1 Padding the Message, FIPS 180-2"
    // RIGHT1    - shifts to right for left half of long
    // RIGHT2    - shifts to right for right half of long
    // LEFT      - shifts to left for bytes
    // MASK      - mask to select counter's bytes after shift to right
    private static final int[] END_FLAGS = {0x80000000, 0x800000, 0x8000, 0x80};
    private static final int[] RIGHT1 = {0, 40, 48, 56};
    private static final int[] RIGHT2 = {0, 8, 16, 24};
    private static final int[] LEFT = {0, 24, 16, 8};
    private static final int[] MASK = {0xFFFFFFFF, 0x00FFFFFF, 0x0000FFFF,
            0x000000FF};
    // HASHBYTES_TO_USE defines # of bytes returned by "computeHash(byte[])"
    // to use to form byte array returning by the "nextBytes(byte[])" method
    // Note, that this implementation uses more bytes 
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值