一、简介

数据安全

  • 防窃听
  • 防篡改
  • 防伪造 古代加密方式:
  • 移位密码:HELLO => IFMMP ** 按照英文顺序往后移动一位**
  • 替代密码:HELLO =>p12,5,3 或者是用某一本书的第几页第几行第几个字达到替换密码的目的

这些都是靠人的想象和直觉来涉及的,非常不靠谱,而现代计算机加密:

  • ** 建立在严格的数据理论基础上 **
  • ** 密码学逐渐发展成一门学科 **

** 总结 **

  • 设计一个安全的加密算法非常困难
  • 验证一个加密算法是否安全更加困难
  • 当前被认为安全的加密算法仅仅是迄今为止尚未被攻破
  • ** 不要 **自己设计加密算法
  • ** 不要 **自己实现加密算法
  • ** 不要 **自己修改已有的加密算法

二、URL编码

一、什么是URL编码? URL编码是浏览器发送数据给服务器时使用的编码。

  • key1=value1&key2=value2&key3=valuye
  • q=%E4%B8%AD%E6%96%87

什么是编码? ascii码就是一种编码,例如

字母 编码(16进制)
A 0x41
B 0x42
C 0x43
D 0x44
... ...

汉字 Unicode编码 UTF-8编码
0x4e2d 0xe4b8ad
0x6587 0xe69687
0x7f16 0xe7bc96
0x7801 0xe7a081
... ... ...

URL编码规则是什么?

  • A-Z,a-z,0-9以及**-_.***保持不变
  • 其他字符以%XX表示 例如: 1.<:%3C 2.中:%E4%B8%AD(utf-8:0xe4b8ad)

例子

/**
 * URL编码
 */
public class SecURL {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String original = "URL 参数";
        String encoded = URLEncoder.encode(original,"UTF-8");
        System.out.println("编码后:"+encoded);
        String ori = new String(URLDecoder.decode(encoded,"UTF-8"));
        System.out.println("解码后:"+ori);
    }
}

总结

  • URL编码是编码算法,不是加密算法
  • URL编码的目的是把任意文本数据编码为%前缀表示的文本,编码后的文本仅包含A-Z,a-z,0-9以及**-_.**,%*便于浏览器和服务器处理

二、Base64编码 *** 什么是Base64编码?** 是一种把二进制数据用文本表示的编码算法,例如:byte[]{0xe4,0xb8,0xad} ==> "5Lit"

| 索引 | 编码 | 索引 |编码|索引|编码| | -------- | -------- | -------- | | 0 | A | 26 |a|52|0| | 1 | B | 27 |b|53|1| | 2 | C | 28 | c|...|...| | 3 | D | 29 | d|61|9| | ... | ... | ... | ...|62|+| | 25 | Z | 51 | z|63|/| 目的

  • 是一种用文本(A-Z,a-z,0-9,+/=)表示二进制内容的方式
  • 适用于文本协议
  • 效率下降 因为二进制经过base64编码它的长度会增加三分之一,如果数组的长度不是3的整数倍,末尾补0x00或0x00 0x00 编码后加=表示补充了1个字节 编码后加==表示补充了2个字节 应用
  • 电子邮件协议
/**
 * Base64编码
 */
public class SecBase64 {

	public static void main(String[] args) throws Exception {
		String original = "Hello\u00ff编码测试";
		//withoutPadding()可以去掉编码后“=”这个字节,有没有=对于解码来说没有影响
		String b64 = Base64.getEncoder().withoutPadding().encodeToString(original.getBytes("UTF-8"));
		System.out.println(b64);
		String ori = new String(Base64.getDecoder().decode(b64), "UTF-8");
		System.out.println(ori);
	}
}

由于标准的base64在url中会引起冲突,所以在url中使用base64编码会使用另外一种。 在java中,使用url的base64编码它会把“+”变为“-”,把“/"变为“_”这样在传递url参数的时候不会引起冲突

总结

  • Base64是编码算法,不是加密算法
  • Base64编码的目的是把任意二进制数据编码为文本(长度增加1/3)
  • 其他编码:Base32、Base48、Base58

三、摘要算法

一、什么是摘要算法? 摘要算法是一种能产生特殊输出格式的算法,这种算法的特点是:无论用户输入多少长度的原始数据,经过计算后输出的密文都是固定长度的,只要原数据稍有改变,输出的“摘要”便完全不同,因此,基于这种原理的算法便能对数据完整性提供较为健全的保障。         常用的摘要算法主要有MD5和SHA1。D5的输出结果为16字节(128位),SHA1的输出结果为20字节(160位)。 摘要算法(又称哈希算法/数字指纹) *** 计算任意成都数据的摘要(固定长度)**

  • 相同的输入数据始终得到相同的输出
  • 不同的输入数据尽量得到不同的输出

目的:

  • 验证原始数据是否被篡改

例如: 输入:任意长度的数据(byte[]) 输出:固定长度的数据(byte[n]) hash("hello") = 0x5e918d2 hash("hello,java") = 0x7a9d88e8 hash("hello,bob") = 0xa0dbae2f

Java的Object.hashCode()方法就是一个摘要算法 这就是说相同的输入必须得到相同的输出,当我们重新equals()方法的时候也要同时重新hashCode()方法


什么是碰撞? 两个不同的输入得到了相同的输出 例如: hash("abc") = 0x12345678 hash("xyz") = 0x12345678 这个时候我们就说发生了碰撞,碰撞能不能呢,碰撞是不能避免的。 输出的字节是固定的,而输入的字节是不确定的

输出n bits 范围
0000000000
0000000001 1
0000000010 2
... ...
11111111111 62235

Hash算法的安全性?

  • 碰撞率低
  • 不能猜测输出
  • 输入任意一个bit的变化都会造成完全不同的输出
  • 很难从输出反推出输入(只能依靠暴力穷举)

常用摘要算法

彩虹表*** 什么是彩虹表呢?是一个预先计算好的常用的字符和md5的一个对照表。 抵御彩虹表***

  • 对每个口令额外添加随机数盐值(salt)
public static void main(String[] args) throws Exception{

        String str = "MD5摘要算法测试";
        byte[] bytes = toMD5(str.getBytes("UTF-8"));
        //以16进制的方式,打印出byte数组
        System.out.println(String.format("%032x",new BigInteger(1,bytes)));
    }
    public static byte[] toMD5(byte[] input){
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("MD5");
        }catch (Exception e){
            throw new RuntimeException(e);
        }
        md.update(input);
        return md.digest();
    }

public static void main(String[] args) throws Exception{

        String password = "helloworld";
        String salt = "Random salt";
        byte[] bytes = toMD5((salt+password).getBytes("UTF-8"));
        //以16进制的方式,打印出byte数组
        System.out.println(String.format("%032x",new BigInteger(1,bytes)));
    }
    public static byte[] toMD5(byte[] input){
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("MD5");
        }catch (Exception e){
            throw new RuntimeException(e);
        }
        md.update(input);
        return md.digest();
    }


二、SHA-1

  • 也是一种哈希算法
  • 输出160bits / 20 bytes
  • 美国国家安全局开发
  • SHA-0/SHA-1/SHA-256/SHA-512

例子:同md5

public static void main(String[] args) throws Exception{

        String str = "MD5摘要算法测试";
        byte[] bytes = toMD5(str.getBytes("UTF-8"));
        //由于SHA-1输出是40个字节,所以用%040x来表示输出
        System.out.println(String.format("%040x",new BigInteger(1,bytes)));
    }
    public static byte[] toMD5(byte[] input){
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("SHA-1");
        }catch (Exception e){
            throw new RuntimeException(e);
        }
        md.update(input);
        return md.digest();
    }

jdk并未包含RipeMD160算法,需要单独下载jar包放入jdk中


三、BouncyCastle

  • 第三方提供的一组加密/哈希算法
  • 提供JDK没有提供的算法 ,例如:RipeMD160哈希算法

如何使用第三方提供的算法?

  • 添加第三方jar至classpath
  • 注册第三方算法提供方
  • 正常使用JDK提供的接口


四、Hmac Hmac:Hash-based Message Authentication Code

  • 基于密钥的消息认证码算法
  • 更安全的消息摘要算法 HmacMD5可以看做带安全Salt的MD5
public class Hmac {

    public static byte[] hmac(String hmacAlgorithm, SecretKey skey,byte[] input)throws Exception{
        Mac mac = Mac.getInstance(hmacAlgorithm);
        mac.init(skey);
        mac.update(input);
        return mac.doFinal();
    }

    public static void main(String[] args) throws Exception {
        String algorithm = "HmacSHA1";
        //String algorithm = "HmacSHA256";
        //原始数据
        String data = "hello world";
        //随机生成一个key
        KeyGenerator keyGen = KeyGenerator.getInstance(algorithm);
        SecretKey skey = keyGen.generateKey();
        //打印key
        byte[] key = skey.getEncoded();
        BigInteger bigInteger = new BigInteger(1, key);
        System.out.println("Key:"+bigInteger.toString(key.length/2));
        //用这个key计算
        byte[] result = hmac(algorithm,skey,data.getBytes("UTF-8"));
        BigInteger resultInteger = new BigInteger(1, result);
        System.out.println("Hash:"+resultInteger.toString(result.length/2));
    }
}

总结:

  • Hmac并不是重新发明的一种算法,而是把Key混入摘要的算法
  • 可以配合MD5、SHA-1等摘要算法
  • 摘要长度和原摘要算法长度相同

四、对称加密算法

一.什么是对称加密算法

  • 加密和解密使用同一个密钥,例如:WinRAR

二、常用的加密算法 它们的密钥长度各不相同,密钥长度决定了加密的强度。工作模式和填充模式可以看做是加密算法的参数和格式的选择,jdk提供的算法并没有提供所有的工作模式及填充模式。 des算法因为密钥果断可以在短时间内暴力破解,已经被淘汰