20190802 加解密算法

比较主流的做法是RSA+AES

1、AES加密数据产生密文。

2、使用RSA加密AES的密钥,产生加密后的AES密钥,然后将密文data和加密后的AES密钥一起传输。

密文数据和通过RAS加密后的AES密钥

 

注意事项:

1、如果用RSA加密数据的话,有数据长度的要求,否则会抛异常;RSA加密是有长度限制的.单纯用RSA加密较长数据时得使用分段加密,效率低下.用RSA+AES是比较主流的做法:AES加密数据产生密文,RSA加密AES密钥产生加密后的AES密钥,然后将密文和加密后的AES密钥一起传输。

2、密码空字符串不需要加密存储。

3、RSA加密长字符串,效率效率不高,实践中, 很少用RSA加密长字符串。常见的办法是RSA交换密码,用AES做对称加密。

关注点: 数据传输过程中的安全问题,对性能的影响,高等加密算法。

RSA非对称加密:数字加密与数字签名,大数因子分解,工作模式,填充模式。

RSA加密、签名区别:加密是为了防止信息被泄露,而签名是为了防止信息被篡改。

流程:生成公私钥、前端通过公钥加密、后端通过私钥解密。

需求:要求登时将密码加密之后再进行传输到后端。

 

RSA加密简介:RSA加密是一种非对称加密。可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程,分别称为公钥和私钥。两者之间有数学相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥,公钥是公开的(可能同时多人持有)。

 

第一个场景:战场上,B要给A传递一条消息,内容为某一指令。

RSA的加密过程如下:

(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。

(2)A传递自己的公钥给B,B用A的公钥对消息进行加密。

(3)A接收到B加密的消息,利用A自己的私钥对消息进行解密。

在这个过程中,只有2次传递过程,第一次是A传递公钥给B,第二次是B传递加密消息给A,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行解密,防止了消息内容的泄露。

 

第二个场景:A收到B发的消息后,需要进行回复“收到”。

RSA签名的过程如下:

(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。

(2)A用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给B。

(3)B收到消息后,在获取A的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是A回复的。

  在这个过程中,只有2次传递过程,第一次是A传递加签的消息和消息本身给B,第二次是B获取A的公钥,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带签名的回复给B,防止了消息内容的篡改。

 

但是,综合两个场景你会发现,第一个场景虽然被截获的消息没有泄露,但是可以利用截获的公钥,将假指令进行加密,然后传递给A。第二个场景虽然截获的消息不能被篡改,但是消息的内容可以利用公钥验签来获得,并不能防止泄露。

在实际应用中,要根据情况使用,也可以同时使用加密和签名,比如A和B都有一套自己的公钥和私钥,当A要给B发送消息时,先用B的公钥对消息加密,再对加密的消息使用A的私钥加签名,达到既不泄露也不被篡改,更能保证消息的安全性。

总结:公钥加密、私钥解密、私钥签名、公钥验签。

 

Cipher提供加解密API,其中RSA非对称加密解密内容长度是有限制的,加密长度不超过117Byte,解密长度不超过128Byte,报错如下:javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes。

 

服务器端数据脱敏处理后,再返回给客户端。

 

加密算法

1、对称加密与非对称加密,对称加密算法指加密和解密用相同的密钥.

2、加解密存在性能问题,如何更好的规避性能问题?

3、AES高级加密标准;将二进制转换成十六进制,在转化成字符串。二进制不能直接转化成字符串。

4、加密函数:设AES加密函数为E,则 C = E(K, P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C。

5、AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。分组加密。每组长度不相同,就填充0;

AES加密:16进制与二进制转换;加密/解密算法;工作模式;填充方式。

6、对称加密算法:加密速度非常快;非对称加密:加密解密的速度比较慢。

7、RAS加密原理:使用RSA公钥对同一数据加密,每次的结果都不一样;对数据的padding即填充有关。加密前,操作中都需要对待处理的数据先进行填充,然后再对填充后的数据进行加密处理。

针对公钥处理的数据,其填充内容为伪随机的16进制字符串,每次操作的填充内容都不一样。这就是为什么每次使用公钥加密数据得到的结果都不一样了。

8、通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。

9、M5D是摘要算法,不是加密算法。

 

如何保证密钥安全?

生产环境密钥和线下环境密钥不能一致,并且生产环境密钥放在配置中心,仅仅小部分人有权限查看。

 

//密钥算法public static final String KEY_ALGORITHM = "AES";

//加解密算法/工作模式/填充方式.

//Java6.0支持PKCS5Padding填充方式,BouncyCastle支持PKCS7Padding填充方式.

public static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

KeyGenerator 密钥生成器

 

AES属于块加密

对越长的字符串进行加密,代价越大,所以通常对明文进行分段,然后对每段明文进行加密,最后再拼成一个字符串。块加密的一个要面临的问题就是如何填满最后一块?所以这就是PADDING的作用,使用各种方式填满最后一块字符串,所以对于解密端,也需要用同样的PADDING来找到最后一块中的真实数据的长度。

 

常用的加密解密算法

高级加密标准(英语:Advanced Encryption Standard,缩写:AES)

对称加密算法也就是加密和解密用相同的密钥。

AES加密函数,AES解密函数。

å å¯æµç¨å¾

密钥K:用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。

1)密钥k不可以直接在网络上传输,否则会导致密钥泄漏。

2)通过非对称加密算法加密密钥,再通过网络传输给对方,或者直接面对面商量密钥。

 

设AES加密函数为E,则 C = E(K, P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C。

(明文,密钥,密文,加密函数)

 

对称加密算法

加密和解密用到的密钥是相同的,这种加密方式加密速度非常快,适合经常发送数据的场合。缺点是密钥的传输比较麻烦。

非对称加密算法

加密和解密用的密钥是不同的,这种加密方式是用数学上的难解问题构造的,通常加密解密的速度比较慢,适合偶尔发送数据的场合。优点是密钥传输方便。常见的非对称加密算法为RSA。

 

实际中,一般是通过RSA加密AES的密钥,传输到接收方,接收方解密得到AES密钥,然后发送方和接收方用AES密钥来通信。

AES的密钥------->用RSA加密------->传输到接收方------->解密得到AES密钥

 

怎么理解密钥K?

密钥其实就是一个字符串,可以自己定义。

 

package com.yunque.www.springbootdemo.utils;

import org.apache.tomcat.util.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

/**
 * 加解密工具类
 */
public class EncryptUtils {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public String encryptType;
    public static String aesKey;

    static {
        EncryptUtils encryptUtils = new EncryptUtils();
        //设置密钥
        encryptUtils.setAesKey("zJJ$c5md3uuhW00W");
        //设置加解密算法
        encryptUtils.setEncryptType("AES");

    }

    public EncryptUtils() {

    }

    public String getEncryptType() {
        return encryptType;
    }

    public void setEncryptType(String encryptType) {
        this.encryptType = encryptType;
    }

    public static String getAesKey() {
        return aesKey;
    }

    public static void setAesKey(String aesKey) {
        EncryptUtils.aesKey = aesKey;
    }

    /**
     * 加密处理
     *
     * @param input
     * @return
     */
    public static String encrypt(String input) {
        if (null == input) {
            return null;
        } else {
            try {
                Object var1 = null;
                SecretKeySpec aes = new SecretKeySpec(aesKey.getBytes(), "AES");
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, aes);
                byte[] bytes = cipher.doFinal(input.getBytes());
                return new String(Base64.encodeBase64(bytes));
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }

    /**
     * 解密处理
     *
     * @param input 输入参数
     * @return
     */
    public static String dencrypt(String input) {
        if (null == input) {
            return null;
        } else {
            try {
                byte[] bytes = input.getBytes();
                byte[] aesArray = Base64.decodeBase64(bytes);
                SecretKeySpec aes = new SecretKeySpec(aesKey.getBytes(), "AES");
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                cipher.init(Cipher.DECRYPT_MODE, aes);
                byte[] crypt = cipher.doFinal(aesArray);
                return new String(crypt);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }


    public static void main(String[] args) {
        //todo:对称加密  手机号
        //1)两次密码的md5值是一样的,密码不可以是明文
        //2)手机号加密解密处理
        String phone = "13024112580";
        String result = encrypt(phone);
        System.out.println(result);

        String secrt = "RM2u9gTX+tBS5+Cv6/xnBg==";
        String dencrypt = dencrypt(secrt);
        System.out.println(dencrypt);
    }


}

Base64是一种基于64个字符的编码算法

为什么要进行base64编码

base64 最早就是用来邮件传输协议中的,原因是邮件传输协议只支持 ascii 字符传递,因此如果要传输二进制文件,如:图片、视频是无法实现的。因此 base64 就可以用来将二进制文件内容编码为只包含 ascii 字符的内容

我们知道在计算机中任何数据都是按ascii码存储的,而ascii码的128~255之间的值是不可见字符。而在网络上交换数据时,比如说从A地传到B地,往往要经过多个路由设备,由于不同的设备对字符的处理方式有一些不同,这样那些不可见字符就有可能被处理错误,这是不利于传输的。所以就先把数据先做一个Base64编码,统统变成可见字符,这样出错的可能性就大降低了。

System.out.println(new String(Base64.encodeBase64("123".getBytes())));
System.out.println(new String(Base64.decodeBase64("MTIz".getBytes())));

 

对证书来说,特别是根证书,一般都是作Base64编码的,因为它要在网上被许多人下载。电子邮件的附件一般也作Base64编码的,因为一个附件数据往往是有不可见字符的。视频,文件都需要经过Base64才能在网络中进行传输。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值