美文网首页工具类相关Android面试
Android中常用的加密方式

Android中常用的加密方式

作者: 吾乃韩小呆 | 来源:发表于2018-05-31 19:02 被阅读26次

    Android面试的时候,尤其是面试一些金融公司的时候经常性的问道:“你会不会加密?”,“加密方式是什么?”,“大概什么样的加密原理呢?”。其实,大多数人都是一脸懵逼,我也懵逼过。痛下决心总结一下,写的不好,大家见笑了。

    一、Rsa加密

    1、RSA是第一种既可以用于数据加密,也可以用于数字签名的算法;

    2、算法原理:

    1)、随机产生两个大的质数m、n且m!=n,计算K1=mn;
    2)、选择一个大于1小于k1的自然数k2,k2必须与(m-1)(n-1)互为素数;
    3)、计算得到d--->d x k2=1(mod(m-1)(n-1));
    4)、销毁mn;
    最终产生的k1和k2为“公钥”,d为“私钥”,发送方使用k1进行加密,接收方使用d进行解密。

    3、注意:

    1、RSA的安全性依赖于大数分解,小于1024位的k1被认为是不安全的;
    2、RSA的计算速度慢。

    4、使用

    1、生成密钥对

    
        /**
         * 随机生成RSA密钥对
         *
         * @param keyLength 密钥长度,范围:512~2048
         *                  一般1024
         * @return
         */
        public static KeyPair generateRSAKeyPair(int keyLength) {
            try {
                KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
                kpg.initialize(keyLength);
                return kpg.genKeyPair();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                return null;
            }
        }
    

    2、公钥加密

      /**
         * 用公钥对字符串进行加密
         *
         * @param data 原文
         */
        public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
            // 得到公钥
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
            KeyFactory kf = KeyFactory.getInstance(RSA);
            PublicKey keyPublic = kf.generatePublic(keySpec);
            // 加密数据
            Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
            cp.init(Cipher.ENCRYPT_MODE, keyPublic);
            return cp.doFinal(data);
        }
    

    3、私钥加密

    /**
         * 私钥加密
         *
         * @param data       待加密数据
         * @param privateKey 密钥
         * @return byte[] 加密数据
         */
        public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
            // 得到私钥
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
            KeyFactory kf = KeyFactory.getInstance(RSA);
            PrivateKey keyPrivate = kf.generatePrivate(keySpec);
            // 数据加密
            Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
            cipher.init(Cipher.ENCRYPT_MODE, keyPrivate);
            return cipher.doFinal(data);
        }
    

    有加密自然也得有解密
    1、公钥解密

     /**
         * 公钥解密
         *
         * @param data      待解密数据
         * @param publicKey 密钥
         * @return byte[] 解密数据
         */
        public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
            // 得到公钥
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
            KeyFactory kf = KeyFactory.getInstance(RSA);
            PublicKey keyPublic = kf.generatePublic(keySpec);
            // 数据解密
            Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, keyPublic);
            return cipher.doFinal(data);
        }
    

    2、私钥解密

    /**
         * 使用私钥进行解密
         */
        public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) throws Exception {
            // 得到私钥
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
            KeyFactory kf = KeyFactory.getInstance(RSA);
            PrivateKey keyPrivate = kf.generatePrivate(keySpec);
    
            // 解密数据
            Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
            cp.init(Cipher.DECRYPT_MODE, keyPrivate);
            byte[] arr = cp.doFinal(encrypted);
            return arr;
        }
    

    用到的全局变量

    // 非对称加密密钥算法
      public static final String RSA = "RSA";
       //加密填充方式
        public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";
       //秘钥默认长度
        public static final int DEFAULT_KEY_SIZE = 2048;
       // 当要加密的内容超过bufferSize,则采用partSplit进行分块加密
        public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes();  
        // 当前秘钥支持加密的最大字节数
        public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;
    

    关于加密填充方式:之前以为上面这些操作就能实现rsa加解密,以为万事大吉了,呵呵,这事还没完,悲剧还是发生了,Android这边加密过的数据,服务器端死活解密不了,原来android系统的RSA实现是"RSA/None/NoPadding",而标准JDK实现是"RSA/None/PKCS1Padding",这造成了在android机上加密后无法在服务器上解密的原因,所以在实现的时候这个一定要注意。

    二、DES加密

    1、简单介绍

    DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究,后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,24小时内即可被破解。

    划重点 :DES不太安全。

    2、静态秘钥DES加密方式使用

    1)、DES加密代码

     /**
         *DES 加密
         *
         * @param message 原文
         * @param key     密钥,长度不能够小于8位
         * @return
         * @throws Exception
         */
        public static String desEncrypt(String message, String key) throws Exception {
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
            IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
            byte[] encryptbyte = cipher.doFinal(message.getBytes());
            return new String(Base64.encode(encryptbyte, Base64.DEFAULT)).trim();
        }
    

    2、DES解密代码

    /**
         * DES解密
         *
         * @param message 密文
         * @param key     密钥,长度不能够小于8位
         * @return
         * @throws Exception
         */
        public static String desDecrypt(String message, String key) throws Exception {
    
            byte[] bytesrc = Base64.decode(message.getBytes(), Base64.DEFAULT);
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
            IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));
            cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
            byte[] retByte = cipher.doFinal(bytesrc);
            return new String(retByte);
        }
    

    3、动态秘钥加密方式

    1、DES加密常用的常量

        private final static String HEX = "0123456789ABCDEF";
        //DES是加密方式 CBC是工作模式 PKCS5Padding是填充模式
        private final static String TRANSFORMATION = "DES/CBC/PKCS5Padding";
        //初始化向量参数,AES 为16bytes. DES 为8bytes.
        private final static String IVPARAMETERSPEC = "01020304";
        //DES是加密方式
        private final static String ALGORITHM = "DES";
       // SHA1PRNG 强随机种子算法, 要区别4.2以上版本的调用方法
        private static final String SHA1PRNG = "SHA1PRNG";
    

    2、动态生成秘钥

      /*
     * 生成随机数,可以当做动态的密钥 加密和解密的密钥必须一致,不然将不能解密
     */
        public static String generateKey() {
            try {
                SecureRandom localSecureRandom = SecureRandom.getInstance(SHA1PRNG);
                byte[] bytes_key = new byte[20];
                localSecureRandom.nextBytes(bytes_key);
                String str_key = toHex(bytes_key);
                return str_key;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        //二进制转字符
        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 static void appendHex(StringBuffer sb, byte b) {
            sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
        }
    

    3、处理秘钥
    方式一、

      // 对密钥进行处理
        private static Key getRawKey(String key) throws Exception {
            KeyGenerator kgen = KeyGenerator.getInstance(ALGORITHM);
            //for android
            SecureRandom sr = null;
            // 在4.2以上版本中,SecureRandom获取方式发生了改变
            if (android.os.Build.VERSION.SDK_INT >= 17) {
                sr = SecureRandom.getInstance(SHA1PRNG, "Crypto");
            } else {
                sr = SecureRandom.getInstance(SHA1PRNG);
            }
            // for Java
            // secureRandom = SecureRandom.getInstance(SHA1PRNG);
            sr.setSeed(key.getBytes());
            kgen.init(64, sr); //DES固定格式为64bits,即8bytes。
            SecretKey skey = kgen.generateKey();
            byte[] raw = skey.getEncoded();
            return new SecretKeySpec(raw, ALGORITHM);
        }
    

    方式二

    / 对密钥进行处理
        private static Key getRawKey(String key) throws Exception {
            DESKeySpec dks = new DESKeySpec(key.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
            return keyFactory.generateSecret(dks);
        }
    

    4、加密实现

    /**
         * DES算法,加密
         *
         * @param data 待加密字符串
         * @param key  加密私钥,长度不能够小于8位
         * @return 加密后的字节数组,一般结合Base64编码使用
         */
        public static String encode(String key, String data) {
            return encode(key, data.getBytes());
        }
    
    
        /**
         * DES算法,加密
         *
         * @param data 待加密字符串
         * @param key  加密私钥,长度不能够小于8位
         * @return 加密后的字节数组,一般结合Base64编码使用
         */
        public static String encode(String key, byte[] data) {
            try {
                Cipher cipher = Cipher.getInstance(TRANSFORMATION);
                IvParameterSpec iv = new IvParameterSpec(IVPARAMETERSPEC.getBytes());
                cipher.init(Cipher.ENCRYPT_MODE, getRawKey(key), iv);
                byte[] bytes = cipher.doFinal(data);
                return Base64.encodeToString(bytes, Base64.DEFAULT);
            } catch (Exception e) {
                return null;
            }
        }
    

    5、解密实现

     /**
         * 获取编码后的值
         *
         * @param key
         * @param data
         * @return
         */
        public static String decode(String key, String data) {
            return decode(key, Base64.decode(data, Base64.DEFAULT));
        }
    
        /**
         * DES算法,解密
         *
         * @param data 待解密字符串
         * @param key  解密私钥,长度不能够小于8位
         * @return 解密后的字节数组
         */
        public static String decode(String key, byte[] data) {
            try {
                Cipher cipher = Cipher.getInstance(TRANSFORMATION);
                IvParameterSpec iv = new IvParameterSpec(IVPARAMETERSPEC.getBytes());
                cipher.init(Cipher.DECRYPT_MODE, getRawKey(key), iv);
                byte[] original = cipher.doFinal(data);
                String originalString = new String(original);
                return originalString;
            } catch (Exception e) {
                return null;
            }
        }
    

    三、AES加密

    1、简单介绍

    高级加密标准

    2、加密使用方法

    1、AES用到的常量

      private final static String HEX = "0123456789ABCDEF";
       //AES是加密方式 CBC是工作模式 PKCS5Padding是填充模式
       private  static final String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
       //AES 加密
       private  static final String AES = "AES";
       // SHA1PRNG 强随机种子算法, 要区别4.2以上版本的调用方法
       private  static final String  SHA1PRNG="SHA1PRNG";
    

    2、动态生成秘钥

      public static String generateKey() {
            try {
                SecureRandom localSecureRandom = SecureRandom.getInstance(SHA1PRNG);
                byte[] bytes_key = new byte[20];
                localSecureRandom.nextBytes(bytes_key);
                String str_key = toHex(bytes_key);
                return str_key;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    

    3、对秘钥进行处理

       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;
            // Android  6.0 以上
            if(sdk_version>23){
                sr = SecureRandom.getInstance(SHA1PRNG,new CryptoProvider());
            //4.2及以上
            }else if(android.os.Build.VERSION.SDK_INT >= 17){  
                sr = SecureRandom.getInstance(SHA1PRNG, "Crypto");
            }else {
                sr = SecureRandom.getInstance(SHA1PRNG);
            }
    
    
            // for Java
            // secureRandom = SecureRandom.getInstance(SHA1PRNG);
            sr.setSeed(seed);
            //256 bits or 128 bits,192bits
            kgen.init(128, sr); 
            //AES中128位密钥版本有10个加密循环,192比特密钥版本有12个加密循环,256比特密钥版本则有14个加密循环。
            SecretKey skey = kgen.generateKey();
            byte[] raw = skey.getEncoded();
            return raw;
        }
    
    

    4、加密

     public static String encrypt(String key, String cleartext) {
            if (TextUtils.isEmpty(cleartext)) {
                return cleartext;
            }
            try {
                byte[] result = encrypt(key, cleartext.getBytes());
                return new String(Base64.encode(result,Base64.DEFAULT));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    

    或者

      private static byte[] encrypt(String key, byte[] clear) throws Exception {
            byte[] raw = getRawKey(key.getBytes());
            SecretKeySpec 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;
        }
    

    5、解密

     public static String decrypt(String key, String encrypted) {
            if (TextUtils.isEmpty(encrypted)) {
                return encrypted;
            }
            try {
                byte[] enc = Base64.decode(encrypted,Base64.DEFAULT);
                byte[] result = decrypt(key, enc);
                return new String(result);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    

    或者

    private static byte[] decrypt(String key, byte[] encrypted) throws Exception {
            byte[] raw = getRawKey(key.getBytes());
            SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
            Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
            byte[] decrypted = cipher.doFinal(encrypted);
            return decrypted;
        }
    

    6、辅助方法

      //二进制转字符
        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 static void appendHex(StringBuffer sb, byte b) {
            sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
        }
    
    
     // 增加  CryptoProvider  类
    
        public static  class CryptoProvider extends Provider {
            /**
             * Creates a Provider and puts parameters
             */
            public 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");
            }
        }
    

    本文参考:
    《安卓AES加解密(兼容Android7.0)》
    《Android数据加密之Rsa加密》

    相关文章

      网友评论

        本文标题:Android中常用的加密方式

        本文链接:https://www.haomeiwen.com/subject/nhcidftx.html