前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 安全

Android 安全

作者头像
Yif
发布2019-12-26 15:04:56
1.1K0
发布2019-12-26 15:04:56
举报
文章被收录于专栏:Android 进阶Android 进阶
undefined
undefined

MD5

加密与摘要是不一样的,加密的数据是完整的,通过解密可以获取完整的数据。

摘要得到的消息是不完整的,通过摘要的数据不能获取到原数据。

MD5长度默认是128bit,这样表达不好,所以将二级制转换成16进制,4bit代表一个16进制,所有128/4=32 ,所以为32位16进制。 MD5 16位与32位区别是将32位后面的16位去掉,得到的16位

MD5作用

  • 一致性检验
  • 数字签名
  • 安全访问,就是对数据加密存到数据库或服务器中,只有对应的密钥才能访问

MD5是不可逆的,没有对应的算法,无法从生产MD5值逆向获取到原数据,除非采用暴力破解,彩虹表法。

MD5不可逆原因

由于它是一种散列数,也叫哈希数,它是一种单向密码体制,即明文到密文不可逆映射,即只有加密过程,没有解密过程。哈希函数可以将任意长度的输入变化成固定长度的输入,针对不同的输入得到不同的输出,如果两个不同的消息得到相同的哈希值,就称为碰撞,它具有抗碰撞性,需要大量的时间才能够找到不同的输入得到相同的输出结果。也是不可逆的。使用hash计算原文存在丢失,一个MD5可以对应多个原文,即有限的MD5与无限的原文,一个MD5有128bit二进制,有2^128中可能。

彩虹表

可以根据彩虹表破解,相当于已知到一堆字符串的md5值是什么,然后将这些存储起来反向查询。但是多次md5,也是不安全的,因为我们在彩虹表会存一堆字符串2次md5值,3次md5值等。 这里就有人会问到什么是彩虹表,摘抄维基百科: 它是一个用于加密散列函数逆运算预先计算好的表。常用于破解加密后的密码散列。查找表包含有限字符固定长度的纯文本密码,是一种空间换时间实践,在暴力破解中,使用更多的存储空间与较少的计算能力,但比每一次输入散列查找表使用更少的储存空间与更多的计算能力

可以通过以下方法增加破解难度:

  • 由于sha1,sha256,sha512也是类似于md5,所以可以通过,md5后再sha1等增加“一点”安全性,减少彩虹表破解可能性
  • 真正公认的方法是md5或sha1加“盐”,就是要进行md5的字符串,加上个随机字符串,再进行md5加密,这个随机字符串存储在该用户的字段中

这里就涉及一个新的名词,盐。那什么是盐呢。

  • 在密码学中,是指在散列之前,将散列内容任意固定位置插入特定的字符串,这种插入字符串的方式称为加盐,在大部分情况,盐不需要保密,盐可以是随机字符串,也可以是随机位置,这样安全性就大大提高。 加盐好处:
  • 通常情况,当字段通过MD5加密,散列后的值是无法通过算法获取原始值,但是在一个大型的彩虹表中,通过在表中搜多该MD5值,有可能短时间获取散列值。但是加盐后的散列值,即使通过彩虹表获取散列后的数值对应的原始内容,但是加盐后插入的字符串扰乱了真正的密码,是的获取真正密码的概率大大降低。

MD5算法特点

  • 压缩性,任意长度的数据,算出MD5的值都是固定的
  • 容易计算,从原始数据计算出MD5值很容易
  • 抗修改性,对原数据进行任何改动,哪怕只修改1个字节,最后得到的MD5值区别都很大
  • 强抗碰撞:想找到两个不同数据,使它们MD5值相同非常困难

MD5用途

  • 文件校验,对文件进行MD5校验,就能得到文件在传输过程中有没有被篡改
  • 密码加密

MD5加密方法

  1. 初始化MessageDigest对象
  2. 传入需要计算的字符串,先使用getBytes方法生成字符串数据,在调用update方法进行更新摘要
  3. 计算摘要值,调用MessageDisgest对象的disgest方法完成计算,计算结果通过字节类型返回
  4. 处理计算结果

普遍使用加密方式有:位运算,格式化字符串,使用算法将加密后的数据转换成16进制

代码:

代码语言:javascript
复制
public class MD5Util {  
    public final static String getMD5String(String s) {  
        char hexDigits[] = { '0', '1', '2', '3', '4',  
                '5', '6', '7', '8', '9',  
                'A', 'B', 'C', 'D', 'E', 'F' };  
        try {  
            byte[] btInput = s.getBytes();  
            //获得MD5摘要算法的 MessageDigest 对象  
            MessageDigest mdInst = MessageDigest.getInstance("MD5");  
            //使用指定的字节更新摘要  
            mdInst.update(btInput);  
            //获得密文  
            byte[] md = mdInst.digest();  
            //把密文转换成十六进制的字符串形式  
            int j = md.length;  
            char str[] = new char[j * 2];  
            int k = 0;  
            for (int i = 0; i < j; i++) {  
                byte byte0 = md[i];  
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];  
                str[k++] = hexDigits[byte0 & 0xf];  
            }  
            return new String(str);  
        }  
        catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
}

MD5与Base64结合使用

base64是将任意序列的8位字节描述一种不易为人识别的形式,该算法是用64个字符来表示任意二进制数据的方法。通常用于邮件,http加密,登录用户名密码加密,可以进行加密与解密,建议它只是一种编码格式,并不是一种加密算法,不要用来加密数据

MD5加密后还要使用Base64编码原因:

  • 使用Base64算法编码后得到32位字符串长度值,有利于在数据库中进行存储

后起之秀

MD5SHA-1是最常用的摘要算法,一个生成16字节一个生成20位字节长度,但是安全强度比较低,都被TLS(传输层安全,一种安全通信协议)禁用。

目前推荐的是SHA-2。SHA-2 实际上是一系列摘要算法的统称,总共有 6 种,常用的有 SHA224、SHA256、SHA384,分别能够生成 28 字节、32 字节、48 字节的摘要。 摘要算法保证了“数字摘要”和原文是完全等价的。所以,我们只要在原文后附上它的摘要,就能够保证数据的完整性。

对称式加密

DES与AES

  • DES默认是56位加密密钥,已经不安全
  • AES加密模式不要使用ECB模式,它不安全,所以推荐使用CBCCFB模式,并且使用PKCS5Padding进行填充。 使用CBC模式,需要一个IV参量,就是之前随机生成的指定长度字符串,来增强加密。

最早有 ECB、CBC、CFB、OFB 等几种分组模式,但都陆续被发现有安全漏洞,所以现在基本都不怎么用了。最新的分组模式被称为 AEAD(Authenticated Encryption with Associated Data),在加密的同时增加了认证的功能,常用的是 GCM、CCMPoly1305。 把上面这些组合起来,就可以得到 TLS 密码套件中定义的对称加密算法。比如:

AES128-GCM,意思是密钥长度为 128 位的 AES 算法,使用的分组模式是 GCM;ChaCha20-Poly1305 的意思是 ChaCha20 算法,使用的分组模式是 Poly1305

PKCS5Padding中,明确定义Block的大小是8位,而在PKCS7Padding定义中,对于块的大小是不确定的,可以在1-255之间,填充值的算法都是一样的value=k - (l mod k) ,K=块大小,l=数据长度,如果l=8, 则需要填充额外的8个byte的8 而使用NoPadding模式,要求输入的长度必须为16字节的倍数,又设置了CBC模式,还需附带一个IV参量,增加加密算法强度,而CFB不需要IV参量。其他模式加密数据长度为16*(n+1)的倍数。

代码:

代码语言:javascript
复制
    private final static String HEX = "0123456789ABCDEF";
    private  static final String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";//AES是加密方式 CBC是工作模式 PKCS5Padding是填充模式
    private  static final String AES = "AES";//AES 加密
    private  static final String  SHA1PRNG="SHA1PRNG";//// SHA1PRNG 强随机种子算法, 要区别4.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;
    }
    // 对密钥进行处理
    private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance(AES);
        //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(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;
    }/*
     * 加密
     */
    public static String encrypt(String key, String cleartext) {
        if (TextUtils.isEmpty(cleartext)) {
            return cleartext;
        }
        try {
            byte[] result = encrypt(key, cleartext.getBytes());
            return Base64Encoder.encode(result);
        } 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;
    }
    /*
     * 解密
     */
    public static String decrypt(String key, String encrypted) {
        if (TextUtils.isEmpty(encrypted)) {
            return encrypted;
        }
        try {
            byte[] enc = Base64Decoder.decodeToBytes(encrypted);
            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;
    }

RSA

非对称式加密。用私钥加密必须通过公钥解密,用公钥加密必须通过私钥解密 密钥不要低于512位,512位与1024位都已经被成功破解,所以建议使用2048位密钥长度,进行数字签名

android系统的RSA实现是"RSA/None/NoPadding",而标准JDK实现是"RSA/None/PKCS1Padding" ,这样会造成了在android机上加密后无法在服务器上解密的原因,所以得统一成JDK标准实现

RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据,否则就会报错(javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes) , RSA 是常用的非对称加密算法。研究发现是由于待加密的数据超长所致。 RSA 算法规定:待加密的字节数不能超过密钥的长度值除以 8 再减去 11(即:KeySize / 8 - 11

私钥的加解密都很耗时,所以可以根据不同的需求采用不能方案来进行加解密。个人觉得服务器要求解密效率高,客户端私钥加密,服务器公钥解密比较好

RSA算法是最流行的公钥密码算法,使用长度可以变化的密钥。RSA是第一个既能用于数据加密也能用于数字签名的算法。

RSA算法原理如下:

  1. 随机选择两个大质数p和q,p不等于q,计算N=pq
  2. 选择一个大于1小于N的自然数e,e必须与(p-1)(q-1)互素
  3. 用公式计算出d:d×e = 1 (mod (p-1)(q-1))
  4. 销毁p和q

最终得到的N和e就是“公钥”,d就是“私钥”,发送方使用N去加密数据,接收方只有使用d才能解开数据内容。

RSA的安全性依赖于大数分解,小于1024位的N已经被证明是不安全的,而且由于RSA算法进行的都是大数计算,使得RSA最快的情况也比DES慢上倍,这是RSA最大的缺陷,因此通常只能用于加密少量数据或者加密密钥,但RSA仍然不失为一种高强度的算法。

后起之秀

ECC(Elliptic Curve Cryptography)是非对称加密里的“后起之秀”,它基于“椭圆曲线离散对数”的数学难题,使用特定的曲线方程和基点生成公钥和私钥,子算法 ECDHE 用于密钥交换,ECDSA 用于数字签名。 目前比较常用的两个曲线是 P-256secp256r1,在 OpenSSL 称为 prime256v1)和 x25519P-256 是 NIST(美国国家标准技术研究所)和 NSA(美国国家安全局)推荐使用的曲线,而 x25519 被认为是最安全、最快速的曲线。 比起 RSAECC 在安全强度和性能上都有明显的优势。160 位的 ECC 相当于 1024 位的 RSA,而 224 位的 ECC 则相当于 2048 位的 RSA。因为密钥短,所以相应的计算量、消耗的内存和带宽也就少,加密解密的性能就上去了。

SQL 注入

SQL注入攻击指的是未将数据与代码进行严格的隔离,导致用户在读取数据时,错误将代码当做数据执行,导致一些安全问题,典型的例子是当对SQL语句进行拼接操作时,直接将未加转义的用户输入内容作为变量。

预防注入:

  • 过滤用户输入的参数中的特殊字符,降低注入风险
  • 禁止通过字符串拼接SQL语句,严格使用参数绑定传入的SQL参数
  • 合理使用数据库访问框架提供的防注入机制
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年7月21日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MD5
    • MD5作用
      • MD5不可逆原因
        • 彩虹表
            • MD5算法特点
              • MD5用途
                • MD5加密方法
                  • MD5与Base64结合使用
                    • 后起之秀
                    • 对称式加密
                      • DES与AES
                        • RSA
                          • 后起之秀
                          • SQL 注入
                          相关产品与服务
                          数据库
                          云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档