加密算法整理

對稱加密:加密和解密使用相同的密鑰。
非對稱加密:加密和解密採用不一樣的密鑰。數字簽名中的公鑰和私鑰就是兩種不一樣的密鑰。
摘要算法:把任意長度的輸入數據計算輸出固定長度的數據,相同數據計算輸出相同的結果,不一樣數據計算後儘可能輸出不一樣的結果。
 
 
對稱加密:
1、AES (Advanced Encryption Standard), 是DES算法的替代者。
AES支持三種長度的密鑰(128位,192位,256位)
AES加密步驟:
  1、把明文按照128bit大小拆分紅若干個明文塊,最後一個明文塊補足128bit.
  2、將每個明文塊按加密器和密鑰分別加密成密文塊
  3、拼接全部的密文塊,成爲最終的密文結果。
 
說明1: AES使用分組加密特性,在對明文加密時,並非把整段明文一次加密成一段密文,而是把明文拆分紅一個個獨立的明文塊(128bit),每一個明文塊通過AES加密碼後生成一個個獨立的密文民塊,把這些密文塊拼接在一塊兒,就是最終的AES加密結果。若明文不能被128整除,則最後一個明文塊須要填充補足到128bit.
補足到128bit有以下幾種方式:
  • NoPadding 不作任何填充,但要求明文必須是16字段的整數倍。
  • PKCS5Padding(默認)若是明文塊少於16個字節(128bit),在明文塊未尾補足相應數量的字符,且每一個字節的值等於缺乏的字符數。
  • ISO10126Padding: 若是明文塊少於16個字節(128bit),在明文塊未尾補足相應數量的字節,最後一個字符值等於缺乏的字符數,其餘字符填充隨機數
 
說明2: AES提供了五種不一樣的把明文塊加密成密文塊的工做模式,在加密時使用了一種加密模式,在解密時必須也使用相同模式解密。
                            圖片來源於( https://www.sohu.com/a/201169795_466846)
具體多少輪,根據密鑰長度肯定:
AES128: 10輪;AES192: 12輪;AES256: 14輪
 
說明3:AES加密算法提供了5種不一樣的工做模式:ECB CBC CTR CFB OFB
  ECB:Electronic Codebook Book, 最簡單的工做模式,在該模式下,每個明文塊的加密是獨立的,互不干擾。
  CBC: Cipher Block Chaining , 能夠將相同的明文段加密成不一樣的密文段。
   CBC在加密裏,須要使用IV,爲一個8位字符,初始化IV只有在第一塊加密時纔會使用,而第N場的加密IV則是用的N-1(N>1)個加密後的二進制數組。上圖中+號爲異或操做。
 
AES解密使用反向操做獲得原始明文。
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

public class AESTest {

    public static final String password = "1";

    public static void main(String[] args) {
        String source = "Hello world.....";
        Key key = createKey(password);
        byte[] encryptCode = jdkAES(source, key);
        decrypt(encryptCode, key);
    }

    public static Key createKey(String password){
        try{
            KeyGenerator keyGenerator;
            keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128, new SecureRandom(password.getBytes()));
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] keyBytes = secretKey.getEncoded();
            Key key = new SecretKeySpec(keyBytes, "AES");
            return key;
        } catch (NoSuchAlgorithmException e){
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] jdkAES(String context, Key key){
        try{
            //加密/解密算法-工做模式-填充模式
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PAdding");
            cipher.init(cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(context.getBytes());
            System.out.println("jdk aes:" + new String(Base64.getEncoder().encode(result)));
            return result;
        }catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException
        | BadPaddingException e){
            e.printStackTrace();
            return null;
        }
    }
    public static void decrypt(byte[] result , Key key){
        Cipher cipher;
        try{
            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key);
            result = cipher.doFinal(result);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        System.out.println("jdk aes descrypt:" + new String(result));
    }
}
 
2、DES(Data Encryption Standard),數據加密標準。
DES使用64位分組長度和56位密鑰長度,將64位輸入轉換爲64位密文輸出,加密與解密使用相同中的步驟和密鑰。
密鑰長度爲64位,但只有56位參與DES運算(第8/16/24/32/40/48/56/65是校驗位,分組後的明文組與56位密鑰按位替代或交換的方式造成密文組。
** DES使用56位密鑰,以現代計算能力,24小時內便可被破解
 
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;


public class DESTest {



    //偏移變量,固定佔8位字節
    //若爲CBC分隔模式,則可添加IV,做用至關於salt,
    public static final String IV_PARAMETER = "12345678";

    private static final String CHARSET = "utf-8";

    public static Key generateKey(String password) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
        DESKeySpec keySpec = new DESKeySpec(password.getBytes(CHARSET));
        //加密/解密算法-工做模式-填充模式
        //默認使用ECB的分隔方式
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        return keyFactory.generateSecret(keySpec);
    }


    public static String encrypt(String password, String data) {
        try {
            Key secretKey = generateKey(password);
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));

            return new String(Base64.getEncoder().encode(bytes));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decrypt(String password, String encrytedStr){
        try {
            Key secretKey = generateKey(password);
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
            cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
            return new String(cipher.doFinal(Base64.getDecoder().decode(encrytedStr.getBytes(CHARSET))), CHARSET);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }

    }

    public static void main(String[] args) {
        // * 此處密鑰只使用前8位字節,若不足8位,則爲拋出(InvalidKeyException: Wrong key size) 異常
        String password = "1aaabbbcccfewfewfew";
        String source = "hello world...";
        String encrypt = encrypt(password, source);
        System.out.println(encrypt);
        System.out.println(decrypt(password, encrypt));
    }
}
 
3、3DES(Triple DES) 是DES向AES過渡的加密算法,將DES重複3次造成密文。
3DES的密鑰長度爲(56*3=168或112)位,在加密過程當中有解密,若3次密鑰相同,則轉變成了普通DES。
3DES密鑰長度較長,安全性較高。
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;


/**
 * 3DES Test
 */
public class DESedeTest {



    //偏移變量,固定佔8位字節
    public static final String IV_PARAMETER = "12345678";

    private static final String CHARSET = "utf-8";

    public static Key generateKey(String password) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
        DESedeKeySpec keySpec = new DESedeKeySpec(password.getBytes(CHARSET));
        //加密/解密算法-工做模式-填充模式
        //默認使用ECB的方式
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
        return keyFactory.generateSecret(keySpec);
    }

    public static String encrypt(String password, String data) {
        try {
            Key secretKey = generateKey(password);
            Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
            // 能夠不使用iv
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
            byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));

            return new String(Base64.getEncoder().encode(bytes));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decrypt(String password, String encrytedStr){
        try {
            Key secretKey = generateKey(password);
            Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
            cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
            return new String(cipher.doFinal(Base64.getDecoder().decode(encrytedStr.getBytes(CHARSET))), CHARSET);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }

    }

    public static void main(String[] args) {
        // * 此處密鑰只使用前24位字節,若不足24位,則爲拋出(InvalidKeyException: Wrong key size) 異常
        String password = "123456789012345678901234";
        String source = "hello world...";
        String encrypt = encrypt(password, source);
        System.out.println(encrypt);
        System.out.println(decrypt(password, encrypt));
    }
}
 
非對稱加密:
非對稱加密須要兩個密鑰:公鑰(publickey)和私鑰(privatekey)。公鑰加密,私鑰解密;私鑰加密,公鑰解密。
 
1、RSA
RSA是目前使用最普遍的公鑰密碼體制之一。RSA密碼體制既能夠用於加密又能夠用於數字簽名。其它全性是基於極其困難的大整數分解(兩個素數的乘積)
在使用時生成一對RSA密鑰,由用戶保存私鑰,公鑰能夠對外公開。爲了提升保密強度,RSA密鑰至少爲500位長,通常推薦1024位。
因爲加解密速度慢,通常使用對稱加密算法與RSA結合使用,報文使用DES或AES加密,密鑰經過RSA加密後一塊兒傳輸。
 
import javax.crypto.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSATest {

    private static String publicKeyStr = "";
    private static String privateKeyStr = "";

    public static void generateKey() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024, new SecureRandom());
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());
//        System.out.println(publicKeyStr);
//        System.out.println(privateKeyStr);
    }

    public static String encrypt(String str, String publicKeyStr) throws Exception {
        byte[] decoded = Base64.getDecoder().decode(publicKeyStr);
        PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes()));
        return outStr;
    }

    public static String decrypt(String str, String privateKeyStr) throws Exception{
        byte[] inputByte = Base64.getDecoder().decode(str.getBytes());
        byte[] decoded = Base64.getDecoder().decode(privateKeyStr);
        PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

    public static void main(String[] args) throws Exception {
        generateKey();
        String message = "12345678";
        System.out.println("source:" + message);
        String messageEncrypt = encrypt(message, publicKeyStr);
        System.out.println("encrypted:" + messageEncrypt);
        String messageDecrypt = decrypt(messageEncrypt, privateKeyStr);
        System.out.println("decrypted:" + messageDecrypt);
    }
}
 
2、DSA
DSA通常用於數字簽名和認證,基於整數有限域離散對數難題的,其安全性與RSA相比差很少
DSA作簽名時速度更快,但作簽名驗證時速度較慢,通常狀況驗證簽名的次數多於簽名的次數。
 
 
摘要算法:
1、MD5(Message Digest Algorithm)
MD5是一種哈希算法,輸入做意長度的信息,通過處理,輸出爲128位的信息,不一樣的輸入獲得不一樣的輸出結果。
 
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Test {
    public static byte[] toMD5(byte[] input){
        MessageDigest md = null;
        try{
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e){
            e.printStackTrace();
        }
        md.update(input);
        return md.digest();
    }

    public static void main(String[] args) {
        String str = "123456";
        byte[] r = toMD5(str.getBytes());
        //MD5返回16個byte(java基本類型) 每一個byte佔8位,共128位
        //以16進制的方式轉換爲字符串
        System.out.println(new BigInteger(1, r).toString(16));

        String salt = "random";
        byte[] saltDigest = toMD5((str + salt).getBytes());
        System.out.println(new BigInteger(1, saltDigest).toString(16));

    }
}
 
2、SHA-1(Secure Hash Algorithm)
SHA-1主要適用於簽名標準(DSS)裏定義的數字簽名算法。對於輸入信息,輸出爲160bit的數據。 它同類型算法有SHA-256和SHA-512.
SHA-1在Java中的實現與MD5相似。
 
國密算法:
國密即國家密碼局認定的國產密碼算法。主要有SM1,SM2,SM3,SM4。密鑰長度和分組長度均爲128位。
  • SM1 爲對稱加密。其加密強度與AES至關。該算法不公開,調用該算法時,須要經過加密芯片的接口進行調用。
  • 採用該算法已經研製了系列芯片、智能IC卡、智能密碼鑰匙、加密卡、加密機等安全產品,普遍應用於電子政務、電子商務及國民經濟的各個應用領域(包括國家政務通、警務通等重要領域)。
  • SM2爲非對稱加密,基於ECC。該算法已公開。因爲該算法基於ECC,故其簽名速度與祕鑰生成速度都快於RSA。ECC 256位(SM2採用的就是ECC 256位的一種)安全強度比RSA 2048位高,但運算速度快於RSA。
  • SM3 消息摘要。能夠用MD5做爲對比理解。該算法已公開。校驗結果爲256位。
  • SM4 無線局域網標準的分組數據算法。對稱加密,密鑰長度和分組長度均爲128位。
因爲SM一、SM4加解密的分組大小爲128bit,故對消息進行加解密時,若消息長度過長,須要進行分組,要消息長度不足,則要進行填充
 
 
reference:
相關文章
相關標籤/搜索