三大常用机密算法原理与基础使用MD5、3DES、RSA

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/muskter/article/details/71093626

概述

数据在存储和传输的过程中,可能会面临被窃听、篡改等风险。同时,还可能有人伪装成为客户端进行破坏性的操作,因此为了保证数据的机密性、完整性、不可否认性、认证功能,我们通常对数据的存储和传输进行加密。这里我学习了生产中常用的三种加密算法,MD5、3DES、RSA。

1. MD5

MD5,全名Message Digest Algorithm 5,是一种摘要算法,通过内置的hash算法将信息摘要成为定长的十六进制字串。

具体算法:
  1.数据填充:在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448。因此,信息的位长(Bits Length)将被扩展至N*512+448,N为一个非负整数,N可以是零。填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。
  2.增加长度信息:果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。
  3.hash算法:四个链接变量,四个循环运算
  4个常数:
    A = 0x67452301,
    B = 0x0EFCDAB89,
    C = 0x98BADCFE,
    D = 0x10325476;
  将上面四个链接变量复制到另外四个变量中:A到a,B到b,C到c,D到d。 主循环有四轮,每轮循环都很相似。第一轮进行16次操作。每次操作对a、b、c和d中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量(文本中的一个子分组和一个常数)。
  再将所得结果向右环移一个不定的数,并加上a、b、c或d中之一。最后用该结果取代a、b、c或d中之一。 以一下是每次操作中用到的四个非线性函数(每轮一个)。
    F(X,Y,Z)=(X∧Y)∨(( X)∧Z)
    G(X,Y,Z)=(X∧Z)∨(Y∧( Z))
    H(X,Y,Z)=X?Y?Z
    I(X,Y,Z)=Y?(X∨( Z))
    其中,?是异或,∧是与,∨是或, 是反符号。
  如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。F是一个逐位运算的函数。即,如果X,那么Y,否则Z。函数H是逐位奇偶操作符。所有这些完成之后,将A,B,C,D分别加上a,b,c,d。然后用下一分组数据继续运行算法,最后的输出是A,B,C和D的级联。最后得到的A,B,C,D就是输出结果,A是低位,D为高位,DCBA组成128位输出结果(32位16进制)。

技巧: 接口提供和接口使用双方同样可以约定秘钥(key),尽管MD5没有使用特定key加密的方法,
但是如果双方都在加密前的明文末尾加上这个key,然后再去加密,也可以起到秘钥的作用。

2. 3DES

  DES是Data Encryption Standard(数据加密标准),DES是一个分组加密算法,典型的DES以64位为分组对数据加密,加密和解密用的是同一个算法。它的密钥长度是56位(因为每个第8 位都用作奇偶校验),密钥可以是任意的56位的数,所以保密性依赖于密钥。

DES加密的算法框架如下:
  首先要生成一套加密密钥,从用户处取得一个64位长的密码口令,然后通过等分、移位、选取和迭代形成一套16个加密密钥,分别供每一轮运算中使用。DES对64位(bit)的明文分组M进行操作,M经过一个初始置换IP,置换成m0。将m0明文分成左半部分和右半部分m0 = (L0,R0),各32位长。然后进行16轮完全相同的运算(迭代),这些运算被称为函数f,在每一轮运算过程中数据与相应的密钥结合。
  在每一轮中,密钥位移位,然后再从密钥的56位中选出48位。通过扩展置换将数据的右半部分扩展成48位,并通过一个异或操作替代成新的48位数据,再将其压缩置换成32位。这四步运算构成了函数f。然后,通过另一个异或运算,函数f的输出与左半部分结合,其结果成为新的右半部分,原来的右半部分成为新的左半部分。将该操作重复16次。
经过16轮迭代后,左,右半部分合在一起经过一个末置换(数据整理),这样就完成了加密过程。
加密流程如图所示:
这里写图片描述

3. RSA :

  与DES不同,RSA算法中,每个通信主体都有两个钥匙,一个公钥一个私钥。就是有2把钥匙:使用publicKey可以对数据进行加密,使用私钥才能对数据进行解密。
算法原理参见:
http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
http://blog.csdn.net/sunmenggmail/article/details/11994013

对以上三个加密算法进行的简单的使用测试,代码如下:

import java.io.UnsupportedEncodingException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Encoder;

public class TestEncrypt {

    public static BASE64Encoder encoder = new BASE64Encoder();  
    public static void main(String[] args) throws Exception {

        String string = "hahahahahahahaaldsfangnaKCFAK";
        System.out.println("加密前长度"+string.length());
        String paramKey = "addf";

        testMD5(string);
        testDes(string, paramKey);
        testRSA(string);

    }

    public static void testMD5(String string) {
        byte[] bytes = string.getBytes();
        String sign = MD5EncoderMethod(string);
        System.out.println("MD5十六进制摘要:"+sign+"---->>> length ::"+ sign.length());
        System.out.println();

    }

    public static String MD5EncoderMethod(String string) {

        MessageDigest md5 = null;

        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        byte[] bytes = string.getBytes();
        byte[] md5Bytes = md5.digest(bytes);

        System.out.println("md5.digest后:"+encoder.encode(md5Bytes)+"---->>md5.digest byteArray.length:"+md5Bytes.length);

        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }       
        return hexValue.toString();
    }

    public static void testDes(String string, String paramKey) throws Exception {
        try {
            Cipher cipher = Cipher.getInstance("DESede");
            SecretKey sKey = new SecretKeySpec(build3DesKey(paramKey), "DESede");
            cipher.init(Cipher.ENCRYPT_MODE, sKey);
            byte[] bytes = cipher.doFinal(string.getBytes());
            System.out.println("DES加密后:"+encoder.encode(bytes)+"  ——————》DES加密后长度:"+bytes.length);
            cipher.init(Cipher.DECRYPT_MODE, sKey);
            System.out.println("DES解密后: "+new String(cipher.doFinal(bytes)));
            System.out.println();
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    public static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException {
        final byte[] key = new byte[24]; // 声明一个24位的字节数组,默认里面都是0
        final byte[] temp = keyStr.getBytes("UTF-8"); // 将字符串转成字节数组

        /*
         * 执行数组拷贝 System.arraycopy(源数组,从源数组哪里开始拷贝,目标数组,拷贝多少位)
         */
        if (key.length > temp.length) {
            // 如果temp不够24位,则拷贝temp数组整个长度的内容到key数组中
            System.arraycopy(temp, 0, key, 0, temp.length);
        } else {
            // 如果temp大于24位,则拷贝temp数组24个长度的内容到key数组中
            System.arraycopy(temp, 0, key, 0, key.length);
        }
        return key;
    }

    public static void testRSA(String string) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            HashMap<String, Object> keMap = getKeys();
            RSAPublicKey pubKey = (RSAPublicKey) keMap.get("public");
            System.out.println(pubKey.toString());
            RSAPrivateKey priKey = (RSAPrivateKey) keMap.get("private");
            System.out.println(priKey.toString());
            cipher.init(cipher.ENCRYPT_MODE, pubKey);
            byte[] bytes = cipher.doFinal(string.getBytes());           
            System.out.println("RSA公钥加密后的字符串::"+encoder.encode(bytes)+" --->>加密后长度"+bytes.length);

            cipher.init(Cipher.DECRYPT_MODE, priKey);
            bytes = cipher.doFinal(bytes);
            System.out.println("RSA私钥解密后的字符串::"+new String(bytes,"UTF-8")+" --->>解密后长度"+bytes.length);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成公钥和私钥
     */
    public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException {
        HashMap<String, Object> map = new HashMap<String, Object>();
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        map.put("public", publicKey);
        map.put("private", privateKey);
        return map;
    }

}

测试输出
这里写图片描述

展开阅读全文

没有更多推荐了,返回首页