zoukankan      html  css  js  c++  java
  • 加密算法

    加密,是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使获得了已加密的信息,但因不知解密的方法,仍然无法了解信息的内容。

     

    双向加密:大体意思就是明文加密后形成密文,可以通过算法还原成明文。
    单向加密:只是对信息进行了摘要计算,不能通过算法生成明文,单向加密从严格意思上说不能算是加密的一种,应该算是摘要算法。
     
    主要算法提供方
    JDK:java.security和javax.crypto包下的类
    Bouncy Castle(丰富JDK中加密算法的不足)jar包:bcprov-jdk15on-1.57.jar
    Commons Codec(简化JDK中加密的操作)jar包是:commons-codec-1.10.jar
     

    1、Base64

    采用Base64编码具有不可读性,多用于网络中传输的数据进行编码,严格意义上属于编码的格式,有64个字符的对应的编码,Base64就是将内容按照该格式进行编码。可以对数据编码和解码,是可逆的,安全度较低,不过,也可以作为最基础最简单的加密算法用于加密要求较弱的情况。
    JDk实现主要使用用BASE64Encoder和BASE64Decoder类的方法(注意:在Eclipse中使用JDK的Base64可能会出现找不到的问题,是因为Base64Encoder并不属于JDK标准库范畴,但是又包含在了JDK中,需要我们手动导入jrelib目录下的rt.jar包即可)。
    注意点:
    1、标准的Base64并不适合直接放在URL里传输;
    2、不是加密算法,而是一种将数据编码为64位二进制字符;
    package com.paic.java8;
    
    import java.io.UnsupportedEncodingException;
    import java.util.Arrays;
    import java.util.Base64;
    import java.util.UUID;
    
    public class Base64Demo {
    
        public static void main(String args[]) {
            try {
    
                // 使用基本编码
                String bStr = "I am a hero!";
                System.out.println("字符串:"+bStr);
                String base64encodedString = Base64.getEncoder().encodeToString(bStr.getBytes("utf-8"));
                System.out.println("基本(编码) :" + base64encodedString);
    
                // 解码
                byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
                System.out.println("基本(解码): " + new String(base64decodedBytes, "utf-8"));
    
                //-----------------------
                String urlStr = "TutorialsPoint?java8";
                System.out.println("URL字符串:"+urlStr);
                base64encodedString = Base64.getUrlEncoder().encodeToString(urlStr.getBytes("utf-8"));
                System.out.println("URL(编码) :" + base64encodedString);
                base64decodedBytes = Base64.getUrlDecoder().decode(base64encodedString);
                System.out.println("URL(解码): " + new String(base64decodedBytes, "utf-8"));
    
                //---------------------------
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < 10; ++i) {
                    stringBuilder.append(UUID.randomUUID().toString());
                }
                System.out.println("MIME字符串 :"+stringBuilder.toString());
                byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");
                String mimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);
                System.out.println("MIME(编码) :" + mimeEncodedString);
                base64decodedBytes = Base64.getMimeDecoder().decode(mimeEncodedString);
                System.out.println("MIME(解码): " + new String(base64decodedBytes, "utf-8"));
    
            } catch (UnsupportedEncodingException e) {
                System.out.println("Error :" + e.getMessage());
            }
        }
    }
    字符串:I am a hero!
    基本(编码) :SSBhbSBhIGhlcm8h
    基本(解码): I am a hero!
    URL字符串:TutorialsPoint?java8
    URL(编码) :VHV0b3JpYWxzUG9pbnQ_amF2YTg=
    URL(解码): TutorialsPoint?java8
    MIME字符串 :ff3eb049-2440-4776-ba6d-becccda60c6f5def99b1-2009-433b-a09c-7fc393305e0641629364-0a92-4d5e-8c5d-1c5ad6a14025ec2ad8ce-2a51-4a0e-b633-ddbb9b2671a15a4fe3e9-7217-4209-a2f1-c478f29cf2dc591579bb-5e31-4984-b4c2-a960924e06e125b28902-aea3-4f76-bcd2-afe533a65cccb66a5eda-71e4-46ba-93fa-0ce685e7e67b9f704c87-34a0-441c-88fc-867a861d771d450d445d-a7ef-4309-b884-f787615f0512
    MIME(编码) :ZmYzZWIwNDktMjQ0MC00Nzc2LWJhNmQtYmVjY2NkYTYwYzZmNWRlZjk5YjEtMjAwOS00MzNiLWEw
    OWMtN2ZjMzkzMzA1ZTA2NDE2MjkzNjQtMGE5Mi00ZDVlLThjNWQtMWM1YWQ2YTE0MDI1ZWMyYWQ4
    Y2UtMmE1MS00YTBlLWI2MzMtZGRiYjliMjY3MWExNWE0ZmUzZTktNzIxNy00MjA5LWEyZjEtYzQ3
    OGYyOWNmMmRjNTkxNTc5YmItNWUzMS00OTg0LWI0YzItYTk2MDkyNGUwNmUxMjViMjg5MDItYWVh
    My00Zjc2LWJjZDItYWZlNTMzYTY1Y2NjYjY2YTVlZGEtNzFlNC00NmJhLTkzZmEtMGNlNjg1ZTdl
    NjdiOWY3MDRjODctMzRhMC00NDFjLTg4ZmMtODY3YTg2MWQ3NzFkNDUwZDQ0NWQtYTdlZi00MzA5
    LWI4ODQtZjc4NzYxNWYwNTEy
    MIME(解码): ff3eb049-2440-4776-ba6d-becccda60c6f5def99b1-2009-433b-a09c-7fc393305e0641629364-0a92-4d5e-8c5d-1c5ad6a14025ec2ad8ce-2a51-4a0e-b633-ddbb9b2671a15a4fe3e9-7217-4209-a2f1-c478f29cf2dc591579bb-5e31-4984-b4c2-a960924e06e125b28902-aea3-4f76-bcd2-afe533a65cccb66a5eda-71e4-46ba-93fa-0ce685e7e67b9f704c87-34a0-441c-88fc-867a861d771d450d445d-a7ef-4309-b884-f787615f0512
    View Code

    2、摘要算法

    摘要算法主要分为MD,SHA和Hmac算法(已经被攻破,彩虹表和MD5站点)。摘要算法其实是用于效验数据完整性的,我们在下载某些文件时,会有MD5和SHA1值提供我们校验下载的文件是否完整,可以用于根据数据生成其唯一的摘要值,无法根据摘要值知道原数据,属于不可逆的。
    原理:摘要由一个单向Hash加密函数对消息进行作用而产生,HASH函数的抗冲突性使得如果一段明文稍有变化,哪怕只更改该段落的一个字母,通过哈希算法作用后都将产生不同的值。而HASH算法的单向性使得要找到哈希值相同的两个不同的输入消息,在计算上是不可能的。所以数据的哈希值,即消息摘要,可以检验数据的完整性
     
    主要过程如下:

     说明:

    1、以上是坏蛋不知密钥情况下,发送请求,第三方根据请求参数+密钥生成sign与请求的sign比较;

    2、而如果坏蛋通过截获的sign,解密md5获得明文,并且通过大量的请求分析出密钥与消息体的拼接规则,则依然存在安全问题;

    MD5

    注意:这里128位是二进制,换算16进制32位

    如:

    package com.paic.java8;
    
    import org.apache.commons.codec.binary.Hex;
    
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    public class MDXDemo {
    
        public static void main(String[] args) {
            String screctKey = "123";
            String content = "Hello";
            encrypt(content,screctKey);
        }
    
        /**
         * 加密
         * @param content
         * @param screctKey
         */
        public static void encrypt(String content,String screctKey){
            MessageDigest md5= null;
            MessageDigest md2= null;
    
            //内容 + 密钥
            //原因:如果单单只是内容,攻击方也是可以通过MD5得到sign1,拼接攻击方不知到的密钥,在攻击方篡改内容后将得到不同的sign2
            //当然攻击方可以根据sign1解密从而获得密钥
            String src = content + screctKey;
            try {
                md5 = MessageDigest.getInstance("MD5");
                md2 = MessageDigest.getInstance("MD2");
                byte[] digest5 = md5.digest(src.getBytes());
                byte[] digest2 = md2.digest(src.getBytes());
                System.out.println("JDK MD5: "+ Hex.encodeHexString(digest5));
                System.out.println("JDK MD2: "+ Hex.encodeHexString(digest2));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    }

    32位字符

    JDK MD5: d0aabe9a362cb2712ee90e04810902f3
    JDK MD2: 014b1eb8d5557bb786b83a18c9fbbe2e

    解密,在线上测试下:https://www.somd5.com/

    SHA

     安全性:SHA1所产生的摘要比MD5长32位。若两种散列函数在结构上没有任何问题的话,SHA1比MD5更安全

    package com.paic.java8;
    
    import org.apache.commons.codec.binary.Hex;
    import org.apache.commons.codec.digest.DigestUtils;
    
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    public class SHAXDemo {
    
        public static void main(String[] args) {
            String content = "Hello";
            jdkSHA1(content);
            ccsha(content);
        }
    
        /**
         * JDK实现方式(同样是使用MessageDigest)
         * @param src
         */
        public static void jdkSHA1(String src){
            MessageDigest digest;
            try {
                digest = MessageDigest.getInstance("SHA");
                digest.update(src.getBytes());
                System.out.println("JDK SHA1:"+Hex.encodeHexString(digest.digest()));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * cc的实现方式
         * @param src
         */
        public static void ccsha(String src){
            System.out.println("CC  SHA1:"+ DigestUtils.sha1Hex(src));
        }
    
        //BC略...
    }

    JDK SHA1:f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0
    CC   SHA1:f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0

    Hmac

    含有密钥的摘要算法,也有简称mac,密钥不同摘要也不同

    package com.paic.java8.encry;
    
    import org.apache.commons.codec.DecoderException;
    import org.apache.commons.codec.binary.Hex;
    import org.apache.commons.codec.digest.DigestUtils;
    
    import javax.crypto.KeyGenerator;
    import javax.crypto.Mac;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    
    public class HmacDemo {
    
        public static void main(String[] args) {
            encrypt("Hello","aaaaaaaaaa");
        }
    
        /**
         * JDK的实现方式  BC略
         * @param content
         * @param key
         */
        public static void encrypt(String content,String key){
            SecretKey secretKey = getSecretKey(key);
    
            try {
                Mac mac= Mac.getInstance(secretKey.getAlgorithm());
    
                //初始化mac
                mac.init(secretKey);
                byte[] hmacMD5Bytes=mac.doFinal(content.getBytes());
    
                //jdk hmacMD5: bfb61695a42d5d16add45743a4e0eea4
                System.out.println("jdk hmacMD5: "+Hex.encodeHexString(hmacMD5Bytes));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 获取默认密钥
         * @return
         */
        public static SecretKey getDefaultSecretKey() {
            SecretKey secretKey = null;
            //初始化KeyGenerator
            KeyGenerator keyGenerator = null;
            try {
                keyGenerator = KeyGenerator.getInstance("HmacMD5");
                //产生密钥
                secretKey = keyGenerator.generateKey();
    
    
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return secretKey;
        }
    
        /**
         * 自定义密钥
         * @param key
         * @return
         */
        public static SecretKey getSecretKey(String key){
            SecretKey secretKey = null;
            byte[] keyByteArr= null;
            try {
                //长度必须偶数
                boolean flag = (null == key)? true : ((key.length()) & 1) != 0;
                if(flag){
                    throw new DecoderException("Key长度必须偶数");
                }
                keyByteArr = Hex.decodeHex(key.toCharArray());
                secretKey = new SecretKeySpec(keyByteArr,"HmacMD5");
            } catch (DecoderException e) {
                e.printStackTrace();
            }
            return secretKey;
        }
    }
        /**
         * BC方式
         */
        public static void bcHmacMd5(){
    
            String src = "Hello,World";
    
            HMac hMac=new HMac(new MD5Digest());
            hMac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex.decode("aaaaaaaaaa")));  //需要十位密钥
            hMac.update(src.getBytes(),0,src.getBytes().length);
    
            byte[] hmacMD5=new byte[hMac.getMacSize()];
            hMac.doFinal(hmacMD5, 0);
            System.out.println("bc hmacMD5: "+org.bouncycastle.util.encoders.Hex.toHexString(hmacMD5));
    
        }

    3、对称加密

    所谓对称是说发送方和接收方的密钥是一样的,因为密钥一样所以安全性跟非对称比较来说就不太安全了。

    DES

    package com.paic.java8.encry;
    
    import org.apache.commons.codec.binary.Hex;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    import javax.crypto.*;
    import javax.crypto.spec.DESKeySpec;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.Security;
    import java.security.spec.InvalidKeySpecException;
    
    public class DesSemo {
    
        public static void main(String[] args) {
            //jdkDES加密: cfa7121606a4413138d8d3781afeaa1c
            try {
    
                SecretKey key = getSecretKey("aaaabbbbcc");
                byte[] content = jdkDESEncrypt("Hello DES", key);
                jdkDESDecrypt(content, key);
    
                bcDES();
    
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
        }
    
        public static SecretKey getDefaultSecretKey() {
            KeyGenerator keyGenerator = null;
            SecretKey secretKey = null;
            try {
                keyGenerator = KeyGenerator.getInstance("DES");
                keyGenerator.init(56);      //指定key长度,同时也是密钥长度(56位)
                secretKey = keyGenerator.generateKey(); //生成key的材料
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return secretKey;
        }
    
        /**
         * key 长度 > 8
         *
         * @param key
         * @return
         * @throws InvalidKeyException
         */
        public static SecretKey getSecretKey(String key) throws InvalidKeyException {
            SecretKey secretKey = null;
    
            byte[] keyByteArr = key.getBytes();
    
            if (keyByteArr.length - 0 < 8) {
                throw new InvalidKeyException("Wrong key size");
            }
    
            DESKeySpec desKeySpec = null;
            try {
                desKeySpec = new DESKeySpec(keyByteArr);
                SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
                secretKey = factory.generateSecret(desKeySpec);
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                e.printStackTrace();
            }
    
            return secretKey;
        }
    
        /**
         * DES 加密
         *
         * @param content
         * @param key2
         */
        public static byte[] jdkDESEncrypt(String content, SecretKey key2) {
            //加密
            Cipher cipher = null;
    
            byte[] result = null;
            try {
                //算法类型/工作方式/填充方式
                cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
                //指定为加密模式
                cipher.init(Cipher.ENCRYPT_MODE, key2);
                result = cipher.doFinal(content.getBytes());
    
                //转换为十六进制
                //desResult = Hex.encodeHexString(result);
    
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
            return result;
        }
    
        /**
         * 解密
         *
         * @param encrypt
         * @param key
         */
        public static void jdkDESDecrypt(byte[] encrypt, SecretKey key) {
            Cipher cipher = null;
            try {
                cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
                //解密
                cipher.init(Cipher.DECRYPT_MODE, key);  //相同密钥,指定为解密模式
                byte[] result = cipher.doFinal(encrypt);   //根据加密内容解密
                System.out.println("jdkDES解密: " + new String(result));  //转换字符串
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
    
        }
    
        /**
         * BC方式
         */
        public static void bcDES(){
            String src = "Hello DES";
            try {
                //通过改变provider的方式
                Security.addProvider(new BouncyCastleProvider());
    
                //生成key,使用bc需要在后面指定"BC"
                KeyGenerator keyGenerator=KeyGenerator.getInstance("DES","BC");
    
                keyGenerator.getProvider();
    
                keyGenerator.init(56);      //指定key长度,同时也是密钥长度
                SecretKey secretKey = keyGenerator.generateKey(); //生成key的材料
                byte[] key = secretKey.getEncoded();  //生成key
    
                //key转换成密钥
                DESKeySpec desKeySpec=new DESKeySpec(key);
                SecretKeyFactory factory=SecretKeyFactory.getInstance("DES");
                SecretKey key2 = factory.generateSecret(desKeySpec);      //转换后的密钥
    
                //加密
                Cipher cipher=Cipher.getInstance("DES/ECB/PKCS5Padding");  //算法类型/工作方式/填充方式
                cipher.init(Cipher.ENCRYPT_MODE, key2);
                byte[] result=cipher.doFinal(src.getBytes());
                System.out.println("bcDES加密: "+Hex.encodeHexString(result));  //转换为十六进制
    
                //解密
                cipher.init(Cipher.DECRYPT_MODE,key2);  //相同密钥
                result = cipher.doFinal(result);   //根据加密内容解密
                System.out.println("bcDES解密: "+new String(result));  //转换字符串
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    3DES

    package com.paic.java8.encry;
    
    import org.apache.commons.codec.binary.Hex;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESedeKeySpec;
    import java.security.SecureRandom;
    import java.security.Security;
    
    public class Des3Demo {
    
        private static String src="Hello 3DES";
    
        public static void main(String[] args) {
    
        }
    
        /**
         * jdk方式
         */
        public static void jdkDES(){
            try {
                //生成key
                KeyGenerator keyGenerator=KeyGenerator.getInstance("DESede");
                //keyGenerator.init(112);      //3DES需要112 or 168位
                keyGenerator.init(new SecureRandom());   //或者使用这种方式默认长度,无需指定长度
                SecretKey secretKey = keyGenerator.generateKey(); //生成key的材料
                byte[] key = secretKey.getEncoded();  //生成key
    
                //key转换成密钥
                DESedeKeySpec desKeySpec=new DESedeKeySpec(key);
                SecretKeyFactory factory=SecretKeyFactory.getInstance("DESede");
                SecretKey key2 = factory.generateSecret(desKeySpec);      //转换后的密钥
    
                //加密
                Cipher cipher=Cipher.getInstance("DESede/ECB/PKCS5Padding");  //算法类型/工作方式/填充方式
                cipher.init(Cipher.ENCRYPT_MODE, key2);   //指定为加密模式
                byte[] result=cipher.doFinal(src.getBytes());
                System.out.println("jdk3DES加密: "+ Hex.encodeHexString(result));  //转换为十六进制
    
                //解密
                cipher.init(Cipher.DECRYPT_MODE,key2);  //相同密钥,指定为解密模式
                result = cipher.doFinal(result);   //根据加密内容解密
                System.out.println("jdk3DES解密: "+new String(result));  //转换字符串
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * BC方式
         */
        public static void bcDES(){
            try {
                //通过改变provider的方式,其他操作一样
                Security.addProvider(new BouncyCastleProvider());
    
                //生成key
                KeyGenerator keyGenerator=KeyGenerator.getInstance("DESede");
                keyGenerator.init(new SecureRandom());
                SecretKey secretKey = keyGenerator.generateKey(); //生成key的材料
                byte[] key = secretKey.getEncoded();  //生成key
    
                //key转换成密钥
                DESedeKeySpec desKeySpec=new DESedeKeySpec(key);
                SecretKeyFactory factory=SecretKeyFactory.getInstance("DESede");
                SecretKey key2 = factory.generateSecret(desKeySpec);      //转换后的密钥
    
                //加密
                Cipher cipher=Cipher.getInstance("DESede/ECB/PKCS5Padding");  //算法类型/工作方式/填充方式
                cipher.init(Cipher.ENCRYPT_MODE, key2);   //指定为加密模式
                byte[] result=cipher.doFinal(src.getBytes());
                System.out.println("jdk3DES加密: "+Hex.encodeHexString(result));  //转换为十六进制
    
                //解密
                cipher.init(Cipher.DECRYPT_MODE,key2);  //相同密钥,指定为解密模式
                result = cipher.doFinal(result);   //根据加密内容解密
                System.out.println("jdk3DES解密: "+new String(result));  //转换字符串
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    AES

    4、非对称加密

     待续

  • 相关阅读:
    ubuntu18.04安装dash-to-dock出错的问题
    使用SVN+Axure RP 8.0创建团队项目
    软件工程实践专题第一次作业
    C#单问号(?)与双问号(??)
    词根 ten 展开 持有 /tin/tent/tain “to hold”
    vscode 对js文件不格式化的修正方案 settings.json
    open cv java 可以 对图片进行分析,得到数据。考试答题卡 2B铅笔涂黑嘎达 识别
    bounties 赏金 bon = good 来自法语 bonjour 早上好
    class cl表示 汇聚 集合 ss表示 阴性 这里表示抽象
    git svn 提交代码日志填写规范 BUG NEW DEL CHG TRP gitz 日志z
  • 原文地址:https://www.cnblogs.com/xiaozhuanfeng/p/10913529.html
Copyright © 2011-2022 走看看