时间的法外狂徒

导航

现代加密体系的各种加密方式

一、现代加密体系的概览

二、加密算法介绍

  关于编码和解码,正常的编码是指将字符串转化为特定的编码的二进制,例如,java在内存中使用unicode码,在向外发送数据时,使用不同的编码会将同样的字符串编码成不同的二进制码,如utf-8或gbk。二解码,则是将二进制码根据指定的编码方式,转化成字符串。

  base64编码,跟常用的编码方式是相反的运作,它的编码,是将二进制码转化成字符串;解码则是将字符串转化成二进制码。

1、base64位加密

  base64中64是指2的6次方,在编码时,会使用6位二进制码表示一个字符。

  base64编码表:

 

 

如图实例:字符串one使用ascii编码后的二进制码,在base64编码后是b25l。

base64编码,使用6位二进制进行编码,而一个字节有8位二进制。为了能对所有的字节进行编码,且不造成更多的base64字符。采用8和6的最小公倍数,24位二进制位一个单位,也就是说base64编码后的二进制个数是24的整倍数。

 

当有空出的字节数时:

对不能填满6位的二进制补0,完全空出的6位二进制用=代替。如下图:onex的base64编码是b25lfA==

base64加密实现——java:

在java的加密体系中,常规加密有三种支持,jdk自带的相关包,bouncy Castle对jdk的补充提供更强的加密强度,Commons Codec是apache提供的安全支持,它一般只是对jdk实现的扩展,比如jdk实现md2和md5算法,Commons Codec也只有md2和md5的实现。实际使用中可以根据需要选择bouncy Castle或Commons Codec。

package com.tsinkai.ettp.practice;

import java.io.IOException;

import org.apache.commons.codec.binary.Base64;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;    

public class Base64Pra {
    
    private static String src = "hello world!";
    
    public static void main(String[] args) {
        jdkBase64();
        commonsCodesBase64();
        bouncyCastleBase64();
    }
    
    /**
     * jdk自带的base64编码,需要在eclipse里打开相应的包,jdk内部使用,不建议使用。
     */
    public static void jdkBase64() {
        
        try {
            //编码
            BASE64Encoder  encoder = new BASE64Encoder();
            String encodeStr = encoder.encode(src.getBytes());
            System.out.println("jdk encode:" + encodeStr);
            //解码
            BASE64Decoder decoder = new BASE64Decoder();
            System.out.println("jdk decode:"+new String(decoder.decodeBuffer(encodeStr)));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * commonsCodes中的base64编码
     */
    public static void commonsCodesBase64() {
        //编码
         byte[] encodeBytes = Base64.encodeBase64(src.getBytes());
         String baseStr = Base64.encodeBase64String(src.getBytes());
         System.out.println("cc encode:" + new String(encodeBytes)+"||"+baseStr);
         
         //解码
         byte[] decodeBytes = Base64.decodeBase64(encodeBytes);
         System.out.println("cc decode:" + new String(decodeBytes));
    }
    
    /**
     * bouncyCastle中的base64编码
     */
    public static void bouncyCastleBase64() {
        //编码
        byte[] encodeBatys =  org.bouncycastle.util.encoders.Base64.encode(src.getBytes());
        System.out.println("bc encode:" + new String(encodeBatys));
        
        //解码
        System.out.println("bc decode:" + new String(org.bouncycastle.util.encoders.Base64.decode(encodeBatys)));
    }
}

 2、消息摘要算法

  消息摘要算法是一种验证消息完整性的算法,它通过一个单向hash加密函数,把字符串加密成固定长度的bit位,不同的字符串产生的输出不同,同样的字符串输出一定相同。同时它是单向加密,不能解密。但是,消息摘要有一定的碰撞率,即不同的明文可能产生相同的密文。

  在验证消息完整性时,只需要将明文字符串使用相同的摘要算法加密,跟接收到的密文进行对比,即可验证消息摘要的完整性。它是数字签名的核心算法。

  MD5和SHA1的算法已经被破解。

消息摘要的三类实现:

MD(Message Digest)

SHA(Secure Hash Algorithm)

MAC(Message Authentication Code)

a、MD算法

 

 

 MD算法的实现——java:

package com.tsinkai.ettp.practice;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD2Digest;
import org.bouncycastle.crypto.digests.MD4Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class MDPra {
    
    private static String src = "hello world";
    
    public static void main(String[] args) {
        jdkMD2();
        jdkMD5();
        
        bcMD2();
        bcMD4();
        bcMD5ForProvider();
        bcMD4ForProvider();
        
        ccMD2();
        ccMD5();
    }
    
    //JDK实现MD2
    public static void jdkMD2() {
        try {
            MessageDigest md = MessageDigest.getInstance("MD2");
            byte[] md2bytes = md.digest(src.getBytes());
            //字节数组输出要先转成16进制,可以借助HEX类转换
            System.out.println("JDK MD2:" + Hex.encodeHexString(md2bytes));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
    
    //JDK实现MD5
    public static void jdkMD5() {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] md5bytes = md.digest(src.getBytes());
            //字节数组输出要先转成16进制,可以借助HEX类转换
            System.out.println("JDK MD5:" + Hex.encodeHexString(md5bytes));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
    
    //Bouncy Castle实现MD2
    public static void bcMD2() {
        Digest digest = new MD2Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length); 
        byte[] MD2Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(MD2Bytes, 0);
        System.out.println("BC MD2:" + org.bouncycastle.util.encoders.Hex.toHexString(MD2Bytes));
    }
    
    //Bouncy Castle实现MD4
    public static void bcMD4() {
        Digest digest = new MD4Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[] MD4Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(MD4Bytes, 0);
        System.out.println("BC MD4:" + org.bouncycastle.util.encoders.Hex.toHexString(MD4Bytes));
    }
    //通过设置provider,使用jdk的包调用bouncyCastle的实现,MD5
    //该种方式的provider是sun,若是使用该方式调用MD4,则实现则是BC
    public static void bcMD5ForProvider() {
        
        try {
            Security.addProvider(new BouncyCastleProvider());
            MessageDigest md = MessageDigest.getInstance("MD5");
            System.err.println("JDKforProvider MD5:"+md.getProvider());
            byte[] md5bytes = md.digest(src.getBytes());
            //字节数组输出要先转成16进制,可以借助HEX类转换
            System.out.println("BC MD5ForProvider:" + Hex.encodeHexString(md5bytes));
            
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
    //通过设置provider,使用jdk的包调用bouncyCastle的实现,MD4
    public static void bcMD4ForProvider() {
            
            try {
                Security.addProvider(new BouncyCastleProvider());
                MessageDigest md = MessageDigest.getInstance("MD4");
                System.err.println("JDKforProvider MD4:"+md.getProvider());
                byte[] md5bytes = md.digest(src.getBytes());
                //字节数组输出要先转成16进制,可以借助HEX类转换
                System.out.println("BC MD4ForProvider:" + Hex.encodeHexString(md5bytes));
                
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    //Commons Codes实现MD2
    public static void ccMD2() {
        System.out.println("CC MD2:"+ DigestUtils.md2Hex(src.getBytes()));
    }
    
    //Commons Codes实现MD5
    public static void ccMD5() {
        System.out.println("CC MD5:"+ DigestUtils.md5Hex(src.getBytes()));
    }
}

 b.SHA算法

  相比于md5,相近的字符串加密后的密文区别很大。

  sha共有5中算法,一般般sha-1外的算法称为sha-2

算法 摘要长度 实现方
SHA-1 160 JDK、CC、BC
SHA-224 224 BC
SHA-256 256 JDK、CC、BC
SHA-384 384 JDK、CC、BC
SHA-512 512 JDK、CC、BC
package com.tsinkai.ettp.practice;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.jcajce.provider.digest.SHA3;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class SHAPra {
    private static String src = "hello world!";
    
    public static void main(String[] args) {
        jdkSHA1();
        bcSHA();
        ccSha();
    }
    
    /**
     * jdk实现方式
     */
    public static void jdkSHA1() {
        try {
            //getInstance("SHA-1")该参数可填列表:MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
            //填写SHA等同于SHA-1
            MessageDigest md = MessageDigest.getInstance("SHA");//默认调用jdk实现:sun.security.provider.SHA
//            MessageDigest md = MessageDigest.getInstance("SHA224");//默认调用bc实现:org.bouncycastle.jcajce.provider.digest.SHA224
//            MessageDigest md = MessageDigest.getInstance("SHA256");//默认调用bc实现:org.bouncycastle.jcajce.provider.digest.SHA256
//            MessageDigest md = MessageDigest.getInstance("SHA384");//默认调用bc实现:org.bouncycastle.jcajce.provider.digest.SHA384
//            MessageDigest md = MessageDigest.getInstance("SHA512");//默认调用bc实现:org.bouncycastle.jcajce.provider.digest.SHA512
//            md.update(src.getBytes());//使用update后后续方法不需要再添加字节数组
            System.out.println("jdk SHA-1:" + Hex.encodeHexString(md.digest(src.getBytes())));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        
    }
    
    /**
     * Bouncy Castle 实现方式
     */
    public static void bcSHA() {
        Digest digest = new SHA1Digest();
//        Digest digest = new SHA224Digest();
//        Digest digest = new SHA256Digest();
//        Digest digest = new SHA384Digest();
//        Digest digest = new SHA512Digest();
        digest.update(src.getBytes(),0,src.getBytes().length);
        System.out.println(digest.getDigestSize());
        byte[] sha1Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(sha1Bytes, 0);
        System.out.println("bc sha-1:" + org.bouncycastle.util.encoders.Hex.toHexString(sha1Bytes));
    }
    
    /**
     * Commons condc实现方式
     */
    public static void ccSha() {
        System.out.println("cc sha1:" + DigestUtils.sha1Hex(src));//改方法底层仍是调用MessageDigest.getInstance("SHA-1");
        System.out.println("CC SHA256:"+DigestUtils.sha256Hex(src));
        System.out.println("CC SHA384:"+DigestUtils.sha384Hex(src));
        System.out.println("CC SHA512:"+DigestUtils.sha512Hex(src));
        
    }
}

 c、mac——带有秘钥的摘要算法

package com.tsinkai.ettp.practice;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;

public class HMacPra {
    
    public static String src = "hello world";
    
    public static void main(String[] args) {
        jdkHMacMD5();
        bcHMacMD5();
    }
    
    public static void jdkHMacMD5() {
        try {
            //获得jdk默认实现的秘钥
            KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] key = secretKey.getEncoded();
            //可以自定义生成,必须是偶数位
//            byte[] key = Hex.decodeHex(new char[] {'a','a','a','a','a','a','a','a'});
            
            
            SecretKey restreSecretKey = new SecretKeySpec(key, "HmacMD5");//该步骤是为了生成一个符合HMacMD5的秘钥
            Mac mac = Mac.getInstance(restreSecretKey.getAlgorithm());
            mac.init(restreSecretKey);
            byte[] hmacMD5Bytes = mac.doFinal(src.getBytes());
            System.out.println("jdk hmacMD5:"+Hex.encodeHexString(hmacMD5Bytes));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void bcHMacMD5() {
        HMac hmac = new HMac(new MD5Digest());
        hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex.decode("123456")));
        hmac.update(src.getBytes(),0,src.getBytes().length);
        
        byte[] hMacMD5bytes = new byte[hmac.getMacSize()];
        hmac.doFinal(hMacMD5bytes, 0);
        
        System.out.println("bc hmacMD5:" + Hex.encodeHexString(hMacMD5bytes));
    }
}

3、对称加密算法

  加密和解密使用相同的秘钥。

 a、DES加密

  

package com.tsinkai.ettp.practice;

import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class DESPra {
    public static String src = "hello";
    public static void main(String[] args) {
        jdkDES();
        bcDES();
    }
    
    public static void jdkDES() {
        try {
            //生成key
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
            keyGenerator.init(56);
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] key = secretKey.getEncoded();
            
            //转化key
            DESKeySpec desKeySpec = new DESKeySpec(key);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
            SecretKey convertSecretKey = factory.generateSecret(desKeySpec);
            
            //加密
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("jdk DES encrypt:" + Base64.encodeBase64String(result));
            
            //解密
            cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
            result = cipher.doFinal(result);
            System.out.println("jdk des decrypy:" + new String(result));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }
    
    public static void bcDES() {
        //2种方式1、使用setprovider方式,2、使用bc原生的方式

        try {
            Security.addProvider(new BouncyCastleProvider());
            //生成key
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DES","BC");//通过参数指定使用provider
            System.out.println(keyGenerator.getProvider());
            keyGenerator.init(56);
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] key = secretKey.getEncoded();
            
            //转化key
            DESKeySpec desKeySpec = new DESKeySpec(key);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
            SecretKey convertSecretKey = factory.generateSecret(desKeySpec);
            
            //加密
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("bc DES encrypt:" + Base64.encodeBase64String(result));
            
            //解密
            cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
            result = cipher.doFinal(result);
            System.out.println("bc des decrypy:" + new String(result));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    
    }
}

b、AES加密

  

package com.tsinkai.ettp.practice;

import java.security.Key;

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

import org.apache.commons.codec.binary.Base64;

public class AESPra {
    public static String src = "hello";
    
    public static void main(String[] args) {
        jdkAES();
    }
    
    public static void jdkAES() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] keyBytes = secretKey.getEncoded();
            System.out.println("key0:" + Base64.encodeBase64String(keyBytes));
            //key转化
            Key key = new SecretKeySpec(keyBytes, "AES");
            System.out.println("key:" + Base64.encodeBase64String(key.getEncoded()));
            //加密
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("加:" + result.length);
            System.out.println("jdk AES encrypt:"+Base64.encodeBase64String(result));
            
            //解密
            cipher.init(Cipher.DECRYPT_MODE, key);
            System.out.println("解:"+Base64.decodeBase64(Base64.encodeBase64String(result)).length);
            result = cipher.doFinal(Base64.decodeBase64(Base64.encodeBase64String(result)));
            System.out.println("jdk AES decrypt:" + new String(result));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    
}

 

posted on 2019-08-14 17:50  抄手砚  阅读(2005)  评论(0编辑  收藏  举报