Android 数据加密方法 AES DES RSA AndroidKeyStore

Java概述

一、使用SecretKeySpec生成秘钥进行对称加密

一个问题 如果创建密码器的时候,
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
TRANSFORMATION = "AES"如果和生成秘钥的算法一样设置为 “AES/CBC/PKCS5PADDING”,就会报下面的错,

java.security.InvalidKeyException: no IV set when one expected

没有理解为什么啊。请路过的大佬指点。。

/**
 * 对称加密数据
 * 

* 使用SecretKeySpec生成秘钥,用AES/DES方式生成秘钥 * 每次加解密都生成同样的秘钥 */ public class SymmetricEncryUtils { //AES ,DES // 算法/模式/补码方式 //与给定的密钥内容相关联的 密钥算法的名称 // private static String ALGRITHM = "AES/CBC/PKCS5PADDING"; private static String ALGRITHM = "DES/CBC/PKCS5Padding"; // private static String TRANSFORMATION = "AES"; private static String TRANSFORMATION = "DES"; public static byte[] generateRandomString() { Random random = new Random(); //AES秘钥规定是16位秘钥 //DES 8bytes byte[] rand = new byte[8]; random.nextBytes(rand); return rand; } private static final byte[] ALIAS = generateRandomString(); public static String encrypt(String content) { try { // 创建秘钥 SecretKeySpec keySpec = new SecretKeySpec(ALIAS, ALGRITHM); // 创建密码器 Cipher cipher = Cipher.getInstance(TRANSFORMATION); // 初始化加密器 cipher.init(Cipher.ENCRYPT_MODE, keySpec); // 加密 return Base64.encodeToString(cipher.doFinal(content.getBytes("UTF-8")), Base64.NO_WRAP); } 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(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ""; } public static String decrypt(String content) { try { // 创建秘钥 SecretKeySpec keySpec = new SecretKeySpec(ALIAS, ALGRITHM); // 创建密码器 Cipher cipher = Cipher.getInstance(TRANSFORMATION); // 初始化解密器 cipher.init(Cipher.DECRYPT_MODE, keySpec); // 解密 return new String(cipher.doFinal(Base64.decode(content, Base64.NO_WRAP)), "UTF-8"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return ""; } }

二、使用keyGenerator 生成一个秘钥,保存在Androidkeystore里面

但是这里面解密要用到加密时候cipher对象获取的iv

encryptIv = cipher.getIV();

难道每个加密数据还要对应保存其加密时候的iv吗?

请大佬指点。

还有KeyGenerator初始化时的Spec对象,Android6.0以上可以使用 KeyGenParameterSpec来生成,但是低版本用哪个对象生成呢?搜了半天没解决。

/**
 * 通过AES加密方式,用KeyGenerator生成秘钥,保存在Android Keystore中
 * 对数据进行加解密
 * 

* 1、创建秘钥,保存在AndroidKeystore里面,秘钥别名为alias * 2、创建并初始化cipher对象,获取秘钥,对数据进行加解密 */ public class AESKeystoreUtils { private static final String ALIAS = "123"; // 算法/模式/补码方式 private static String TRANSFORMATION = "AES/GCM/NoPadding"; private static byte[] encryptIv; /** * 创建秘钥 */ private static void createKey() { //获取Android KeyGenerator的实例 //设置使用KeyGenerator的生成的密钥加密算法是AES,在 AndroidKeyStore 中保存密钥/数据 final KeyGenerator keyGenerator; AlgorithmParameterSpec spec = null; try { keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); //使用KeyGenParameterSpec.Builder 创建KeyGenParameterSpec ,传递给KeyGenerators的init方法 //KeyGenParameterSpec 是生成的密钥的参数 //setBlockMode保证了只有指定的block模式下可以加密,解密数据,如果使用其它的block模式,将会被拒绝。 //使用了“AES/GCM/NoPadding”变换算法,还需要设置KeyGenParameterSpec的padding类型 //创建一个开始和结束时间,有效范围内的密钥对才会生成。 Calendar start = new GregorianCalendar(); Calendar end = new GregorianCalendar(); end.add(Calendar.YEAR, 10);//往后加十年 //todo 高于6.0才可以使用KeyGenParameterSpec 来生成秘钥,低版本呢? if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { spec = new KeyGenParameterSpec.Builder(ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setCertificateNotBefore(start.getTime()) .setCertificateNotAfter(end.getTime()) .build(); } else { // spec = new ; } keyGenerator.init(spec); keyGenerator.generateKey(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchProviderException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } } public static String encryptData(String needEncrypt) { if (!isHaveKeyStore()) { createKey(); } try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry(ALIAS, null); SecretKey secretKey = secretKeyEntry.getSecretKey(); //KeyGenParameterSpecs中设置的block模式是KeyProperties.BLOCK_MODE_GCM,所以这里只能使用这个模式解密数据。 Cipher cipher = Cipher.getInstance(TRANSFORMATION); cipher.init(Cipher.ENCRYPT_MODE, secretKey); //ciphers initialization vector (IV)的引用,用于解密 encryptIv = cipher.getIV(); return Base64.encodeToString(cipher.doFinal(needEncrypt.getBytes()), Base64.NO_WRAP); } catch (KeyStoreException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (UnrecoverableEntryException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); return "空指针异常"; } return ""; } public static String decryptData(String needDecrypt) { if (!isHaveKeyStore()) { createKey(); } try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry(ALIAS, null); SecretKey secretKey = secretKeyEntry.getSecretKey(); //KeyGenParameterSpecs中设置的block模式是KeyProperties.BLOCK_MODE_GCM,所以这里只能使用这个模式解密数据。 Cipher cipher = Cipher.getInstance(TRANSFORMATION); //需要为GCMParameterSpec 指定一个认证标签长度(可以是128、120、112、104、96这个例子中我们能使用最大的128), // 并且用到之前的加密过程中用到的IV。 GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, encryptIv); cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec); return new String(cipher.doFinal(Base64.decode(needDecrypt, Base64.NO_WRAP))); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnrecoverableEntryException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } return ""; } /** * 是否创建过秘钥 * * @return */ private static boolean isHaveKeyStore() { try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); KeyStore.Entry keyentry = keyStore.getEntry(ALIAS, null); if (null != keyentry) { return true; } } catch (KeyStoreException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (UnrecoverableEntryException e) { e.printStackTrace(); } return false; } }

三、使用RAS + AndroidKeyStore方式加密数据

通过keypairGenerator生成秘钥对,公钥用于加密数据,私钥用于解密数据。

但是有个问题是:

keyPairGenerator.generateKeyPair();

生成秘钥这一步,涉及到大量的运算?view明显的停顿了一下,log显示:

Skipped 129 frames!  The application may be doing too much work on its main thread.

待解决的问题。大佬路过请指示。

public class RSAKeystoreUtils {

    private static final String AndroidKeyStore = "AndroidKeyStore";
    //RSA/ECB/PKCS1Padding
    //RSA/ECB/OAEPWithSHA-256AndMGF1Padding
    private static final String RSA_MODE_OAEP = "RSA/ECB/PKCS1Padding";
    private static final String KEY_ALIAS = "123";

    /**
     * 创建秘钥
     */
    public static void createKey() {
        KeyPairGenerator keyPairGenerator = null;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, AndroidKeyStore);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }
        AlgorithmParameterSpec spec;
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        end.add(Calendar.YEAR, 30);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            spec = new KeyGenParameterSpec.Builder(KEY_ALIAS, KeyProperties.PURPOSE_DECRYPT|KeyProperties.PURPOSE_ENCRYPT)
                    .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                    .setCertificateNotBefore(start.getTime())
                    .setCertificateNotAfter(end.getTime())
                    .build();
        } else {
            spec = new KeyPairGeneratorSpec.Builder(App.getInstance())
                    .setAlias(KEY_ALIAS)
                    .setSubject(new X500Principal("CN=" + KEY_ALIAS))
                    .setSerialNumber(BigInteger.TEN)
                    .setStartDate(start.getTime())
                    .setEndDate(end.getTime())
                    .build();

        }
        try {
            keyPairGenerator.initialize(spec);
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        keyPairGenerator.generateKeyPair();
    }


    public static String encryptData(String data) {
        if (!isHaveKeyStore()) {
            createKey();
        }

        try {
            Cipher cipher = Cipher.getInstance(RSA_MODE_OAEP);
            KeyStore keyStore = KeyStore.getInstance(AndroidKeyStore);
            keyStore.load(null);

            PublicKey publicKey = keyStore.getCertificate(KEY_ALIAS).getPublicKey();

            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            return Base64.encodeToString(cipher.doFinal(data.getBytes("UTF-8")), Base64.NO_WRAP);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
            return "空指针异常";
        }

        return "加密数据失败";
    }

    public static String decryptData(String data) {

        try {
            Cipher cipher = Cipher.getInstance(RSA_MODE_OAEP);
            KeyStore keyStore = KeyStore.getInstance(AndroidKeyStore);
            keyStore.load(null);

            KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(KEY_ALIAS, null);
            PrivateKey privateKey = privateKeyEntry.getPrivateKey();

            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            return new String(cipher.doFinal(Base64.decode(data, Base64.NO_WRAP)), "UTF-8");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
            return "空指针异常";
        } catch (UnrecoverableEntryException e) {
            e.printStackTrace();
        }

        return "解密数据失败";

    }


    /**
     * 是否创建过秘钥
     *
     * @return
     */
    private static boolean isHaveKeyStore() {
        try {
            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);

            if (keyStore.containsAlias(KEY_ALIAS)) {
                return true;
            }

        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        }
        return false;
    }


}

 

 

 

你可能感兴趣的:(Android,安卓开发遇到问题总结)