常见加密算法附JAVA代码案例

1、对称加密算法(AES、DES、3DES)

对称加密算法是指加密和解密采用相同的密钥,是可逆的(即可解密)。

AES加密算法是密码学中的高级加密标准,采用的是对称分组密码体制,密钥长度的最少支持为128。AES加密算法是美国联邦政府采用的区块加密标准,这个标准用来替代原先的DES,已经被多方分析且广为全世界使用。

AES数学原理详解:AES加密 - block2016 - 博客园

优点:加密速度快

缺点:密钥的传递和保存是一个问题,参与加密和解密的双方使用的密钥是一样的,这样密钥就很容易泄露。

2、非对称加密算法(RSA、DSA、ECC)也叫公钥加密

非对称加密算法是指加密和解密采用不同的密钥(公钥和私钥),因此非对称加密也叫公钥加密,是可逆的(即可解密)。公钥密码体制根据其所依据的难题一般分为三类:大素数分解问题类、离散对数问题类、椭圆曲线类。

RSA加密算法是基于一个十分简单的数论事实:将两个大素数(也就是质数:质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数,例如:17、19、23、29、31、37、41等)相乘十分容易,但是想要对其乘积进行因式分解极其困难,因此可以将乘积公开作为加密密钥。虽然RSA的安全性一直未能得到理论上的证明,但它经历了各种攻击至今未被完全攻破。 

RSA公私钥生成流程

  1. 随机找两个素数P和Q,P与Q越大,越安全。(例如:61和53)

  2. 计算p和q的乘积n。(n=61×53=3233,n的长度就是密钥长度。3233写成二进制是110010100001,一共有12位,所以这个密钥就是12位。)

  3. 计算 n 的欧拉函数φ(n)。(根据公式φ(n)=(p-1)(q-1)算出φ(3233)等于60×52,即3120)

  4. 随机选择一个整数e,条件是1<e<φ(n),且e与φ(n) 互质。(条件是1<e<φ(n),且e与φ(n) 互质。1到3120之间,随机选择了17。)

  5. 有一个整数d,可以使得ed 除以φ(n) 的余数为 1。(ed ≡ 1 (mod φ(n)),即17*2753 mode 3120=1)

  6. 将n和e封装成公钥,n和d封装成私钥。(n=3233,e=17,d=2753,所以公钥就是:3233,17,私钥就是:3233, 2753。)

RSA加密

首先对明文进行比特串分组,使得每个分组对应的十进制数小于n,然后依次对每个分组m做一次加密,所有分组的密文构成的序列就是原始消息的加密结果,即m满足0<=m<n,则加密算法为:c=m^e mod n; c为密文,且0<=c<n。

欧拉函数

一.什么是欧拉函数
欧拉函数就是指:对于一个正整数n,小于或等于n的正整数中与n互质的正整数个数(包括1)的个数,记作 φ ( n )

所以其通式为: φ ( n ) = n * (1 - 1/p1) * (1 - 1/p2) * …… * (1 - 1/pn),其中p1,p2……pn为n的所有质因数,例如:φ ( 10 ) 的质因数为2,5,所有φ ( 10 ) = 10 * (1 - 1/2) * (1 - 1/5) = 4(1,3,7,9这四个数)
同时φ ( 1 ) = 1;

二.欧拉函数的一些性质
若n为质数,则φ ( n ) = n - 1;
若m与n互质,则φ ( n*m ) = φ ( n ) * φ ( m );
若正整数n与a互质,那么就有
若n为奇数时,φ ( 2n ) = φ ( n );
若n = pk且p是质数,那么φ ( n ) = (p - 1) * pk-1 = pk - pk-1

优点:512位(或是1024位)秘钥,计算量极大,难破解。加密和解密的密钥不一致,公钥是可以公开的,只需保证私钥不被泄露即可,这样就密钥的传递变的简单很多,从而降低了被破解的几率。

缺点:加密速度慢

RSA加密算法既可以用来做数据加密,也可以用来数字签名。

数据加密过程:甲方用乙方的公钥加密,乙方用自己的私钥解密(甲方为发送者,乙方为接受者,乙方事先提供自己的公钥给甲方,简称:公钥加密,私钥解密

数字签名过程:甲方用甲方的私钥加密,乙方用甲方的公钥解密(甲方为发送者,乙方为接受者,乙方解密成功说明就是甲方加的密,甲方就不可以抵赖,乙方解密需要甲方提供的公钥,简称:私钥签名,公钥验签

详细数学原理见 【来龙去脉系列】RSA算法原理

ECC加密算法是基于椭圆曲线上离散对数计算问题(ECDLP)的ECC算法。ECC算法的数学理论非常深奥和复杂,在工程应用中比较难于实现,但它的单位安全强度相对较高。

用国际上公认的对于ECC算法最有效的攻击方法--Pollard rho方法去破译和攻击ECC算法,它的破译或求解难度基本上是指数级的。正是由于RSA算法ECC算法这一明显不同,使得ECC算法的单位安全强度高于RSA算法,也就是说,要达到同样的安全强度,ECC算法所需的密钥长度远比RSA算法低。有研究表示160位的椭圆密钥与1024位的RSA密钥安全性相同。在私钥的加密解密速度上,ECC算法比RSA、DSA速度更快。存储空间占用更小。

3、线性散列算法(MD5、SHA1、HMAC)

MD5全称是Message-Digest Algorithm 5(信息摘要算法5),单向的算法不可逆(被MD5加密的数据不能被解密)。MD5加密后的数据长度要比加密数据小的多,且长度固定,且加密后的串是唯一的,MD5散列值长度位128位。

适用场景:常用在不可还原的密码存储、信息完整性校验等。

信息完整性校验:典型的应用是对一段信息产生信息摘要,以防止被篡改。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。

SHA-1 与 MD5 的比较

SHA-1摘要比MD5摘要长32 位,散列值长度160位,所以SHA-1对强行攻击有更大的强度,比MD5更安全。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对MD5是2^128数量级的操作,而对SHA-1则是2^160数量级的操作。

在相同的硬件上,SHA-1 的运行速度比 MD5 慢。

4、混合加密

由于以上加密算法都有各自的缺点(RSA加密速度慢、AES密钥存储问题、MD5加密不可逆),因此实际应用时常将几种加密算法混合使用。

例如:RSA+DES,RSA+AES:

采用DES对数据进行加密,而RSA对DES的密钥加密,这样集成了两种加密算法的优点,既保证了数据加密的速度,又实现了安全方便的密钥管理。

那么,采用多少位的密钥合适呢?一般来讲密钥长度越长,安全性越高,但是加密速度越慢。所以密钥长度也要合理的选择,一般RSA建议采用1024位的数字,AES建议采用128位即可。

这里写图片描述

混合加密代码案例:RSA+DES

    /**
     * RSA加密
     * @param data 待加密数据
     * @param publicKey 公钥
     */
    public static String rsaEncrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return Base64.encodeBase64String(encryptedData);
    }

    /**
     * RSA解密
     * @param secretData 待解密数据
     * @param privateKey 私钥
     */
    public static String rsaDecrypt(String secretData, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] dataBytes = Base64.decodeBase64(secretData);
        int inputLen = dataBytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return new String(decryptedData, StandardCharsets.UTF_8);// 解密后的内容
    }


    /**
     * DES加密
     * @param data 待加密数据
     * @param desKey 长度要是8的倍数且不能小于8位
     * @return String
     */
    public static String desEncrypt(String data, String desKey) {
        try{
            if (desKey== null || desKey.length() < 8) {
                throw new RuntimeException("加密失败,desKey不能小于8位");
            }
            SecureRandom random = new SecureRandom();
            DESKeySpec desKeySpec = new DESKeySpec(desKey.getBytes());
            //创建一个密匙工厂,然后用它把DESKeySpec转换成
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKeySpec);
            //Cipher对象实际完成加密操作
            Cipher cipher = Cipher.getInstance("DES");
            //用密匙初始化Cipher对象
            cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
            //现在,获取数据并加密
            //正式执行加密操作
            byte[] encryptedData = cipher.doFinal(data.getBytes());
            return Base64.encodeBase64String(encryptedData);
        }catch(Throwable e){
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * DES解密
     * @param secretData base64编码得解密数据
     * @param desKey
     * @return byte[]
     * @throws Exception
     */
    public static String desDecrypt(String secretData, String desKey) throws Exception {
        // DES算法要求有一个可信任的随机数源
        SecureRandom random = new SecureRandom();
        // 创建一个DESKeySpec对象
        DESKeySpec desKeySpec = new DESKeySpec(desKey.getBytes(StandardCharsets.UTF_8));
        // 创建一个密匙工厂
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        // 将DESKeySpec对象转换成SecretKey对象
        SecretKey securekey = keyFactory.generateSecret(desKeySpec);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, random);
        // 真正开始解密操作
        byte[] decryptedData = cipher.doFinal(Base64.decodeBase64(secretData));
        return new String(decryptedData,StandardCharsets.UTF_8);
    }

    /**
     * RSA和DES混合加密
     * @param data 待加密数据
     * @param publicKey RSA公钥
     * @return
     */
    public static Map<String,Object> encrypt(String data, String publicKey) throws Exception {
        String desKey = getRandomKey();//随机生成密钥
        String encryptData = desEncrypt(data,desKey);//用des加密原数据
        String encryptDESKey = rsaEncrypt(desKey,getPublicKey(publicKey));//用RSA加密deskey
        Map dataMap = new HashMap();
        dataMap.put("secretData",encryptData);
        dataMap.put("desKey",encryptDESKey);
        log.info("待加密随机DES秘钥->desKey:"+desKey);
        return dataMap;
    }

    /**
     * RSA和DES混合解密
     * @param secretData 待解密数据
     * @param desKey 通过Rsa加密的DESKey
     * @param privateKey RSA私钥
     * @return
     */
    public static String decrypt(String secretData, String desKey, String privateKey) throws Exception {
        //使用Rsa解密DESKey,用到私钥privateKey
        String decryptDESKey = rsaDecrypt(desKey,getPrivateKey(privateKey));
        log.info("已解密随机DES秘钥->desKey:"+decryptDESKey);
        //再使用des解密数据,用到已解密出的DESKey
        return desDecrypt(secretData,decryptDESKey);
    }

    public static void main(String[] args) throws Exception {
        String str  = "你好啊,JAVA!";
        log.info("待加密数据:"+str.trim());
        Map keyMap = getKeyPairMap();//RSA生成秘钥对
        String publicKey = keyMap.get("publicKey").toString();//Rsa公钥
        String privateKey = keyMap.get("privateKey").toString();//Rsa私钥
        log.info("RSA秘钥对->publicKey:"+publicKey);
        log.info("RSA秘钥对->privateKey:"+privateKey);
        Map<String,Object> dataMap = encrypt(str.trim(), publicKey);
        log.info("已加密数据:" + JSONObject.toJSONString(dataMap));
        String desKey = dataMap.get("desKey").toString();//已加密的desKey
        log.info("已加密的DES秘钥->desKey:"+desKey);
        String secretData = dataMap.get("secretData").toString();//待解密数据
        String data = decrypt(secretData, desKey, privateKey);
        log.info("已解密数据:" + data.trim());
    }

运行结果如下:

5、Base64

严格意义讲,Base64并不能算是一种加密算法,而是一种编码格式,是网络上最常见的用于传输8bid字节代码的编码方式之一。

Base64编码可用于在HTTP环境下传递较长的标识信息,Base编码不仅不仅比较简单,同时也据有不可读性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值