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;    }}

 

 

 

更多相关文章

  1. Android中UDP发送报文
  2. [译]Android架构组件 – 查看ViewModel – 第二部分
  3. DEX 方法超过64K限制和gradle编译OOM问题解决
  4. Selector的用法
  5. android数据持久化总结
  6. Greendao简单使用
  7. Android:Xml(读取与存储)
  8. 开发第四天
  9. Android搭建客户端连接java构建的服务端

随机推荐

  1. C数组实现静态链表及常用操作(模拟无指针
  2. 企业之战|Kubernetes持续集成实践
  3. 企业实战|Kubernetes持续交付实践一
  4. Ceph搭建硬件建议详解
  5. 臺灣精益老專家:看板的系統思維
  6. 搜索引擎技术原理
  7. Python Flask高级编程之从0到1开发《鱼书
  8. Kafka原理详解
  9. 【故障】win10系统使用打印功能就蓝屏
  10. MongoDB用户权限管理