Java中加密算法介紹及其實現

1.Base64編碼算法

Base64簡介

Base64是網絡上最多見的用於傳輸8Bit字節碼的編碼方式之一,Base64就是一種基於64個可打印字符來表示二進制數據的方法。可查看RFC2045~RFC2049,上面有MIME的詳細規範。html

Base64編碼是從二進制到字符的過程,可用於在HTTP環境下傳遞較長的標識信息。例如,在Java Persistence系統Hibernate中,就採用了Base64來將一個較長的惟一標識符(通常爲128-bit的UUID)編碼爲一個字符串,用做HTTP表單和HTTP GET URL中的參數。在其餘應用程序中,也經常須要把二進制數據編碼爲適合放在URL(包括隱藏表單域)中的形式。此時,採用Base64編碼具備不可讀性,須要解碼後才能閱讀。java

碼錶git

索引 編碼 索引 編碼 索引 編碼 索引 編碼
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w
15 P 32 g 49 x
16 Q 33 h 50 y

特色:加密原理簡單github

Base64實現

通常的來講加密數據須要使用到以下三個包
JDK:java.security
CC: Commons Codec
BC: Bouncy Castle算法

JDK實現

JDK 1.7寫法apache

//加密
public static String jdkBase64Encoder(String str){
    BASE64Encoder encoder = new BASE64Encoder();
    return encoder.encode(str.getBytes());
}
//解密
public static String jdkBase64decoder(String str) throws IOException {
    BASE64Decoder decoder = new BASE64Decoder();
    return new String(decoder.decodeBuffer(str));
}
//調用
public static void main(String[] args) throws IOException {
    System.out.println("原始字符串: " + BASE_STRING);
    String enStr = jdkBase64Encoder(BASE_STRING);
    System.out.println("Base64編碼後: " + enStr);
    String deStr = jdkBase64decoder(enStr);
    System.out.println("Base64解碼後: "+deStr);
}

結果安全

原始字符串: security base64
Base64編碼後: c2VjdXJpdHkgYmFzZTY0
Base64解碼後: security base64網絡

JDK1.8+寫法併發

public static String jdkBase64Encoder(String str){
    String desc = Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8));  
    System.out.println("加密後的字符串爲:"+desc);  
}

public static String jdkBase64decoder(String str) throws IOException {
    String unDecodeStr=new String(Base64.getDecoder().decode(str),StandardCharsets.UTF_8);  
    System.out.println("解密後的字符串爲"+unDecodeStr);  
}

Commons Codec實現

CC包的寫法是簡化了許多,相似JDK1.8的寫法。
MAVEN依賴dom

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.10</version>
</dependency>
import org.apache.commons.codec.binary.Base64;

import java.io.IOException;

/**
 * CommonCodec Base64
 * @author yanlong
 */
public class CCBase64 {
    private static final String BASE_STRING ="security base64";

    public static void main(String[] args) throws IOException {
        System.out.println("原始字符串: " + BASE_STRING);
        byte[] encStr = Base64.encodeBase64(BASE_STRING.getBytes());
        System.out.println("Base64編碼後: " + new String(encStr));
        String deStr = new String(Base64.encodeBase64(encStr));
        System.out.println("Base64解碼後: "+deStr);
    }
}

Bouncy Castle實現

MAVEN依賴

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.55</version>
</dependency>
import org.bouncycastle.util.encoders.Base64;

public class BCBase64 {
    private static final String BASE_STRING ="security base64";

    public static void main(String[] args) {
        System.out.println("原始字符串: " + BASE_STRING);
        byte[] encStr = Base64.encode(BASE_STRING.getBytes());
        System.out.println("Base64編碼後: " + new String(encStr));
        String deStr = new String(Base64.decode(encStr));
        System.out.println("Base64解碼後: "+deStr);

    }
}

BC的調用代碼相較於CC和JDK更少了。

2.消息摘要算法(Message-Digest Algorithm)及其實現

MD算法簡介

消息摘要算法的主要特徵是加密過程不須要密鑰,而且通過加密的數據沒法被解密,只有輸入相同的明文數據通過相同的消息摘要算法才能獲得相同的密文。消息摘要算法不存在密鑰的管理與分發問題,適合於分佈式網絡上使用。因爲其加密計算的工做量至關巨大,因此之前的這種算法一般只用於數據量有限的狀況下的加密,例如計算機的口令就是用不可逆加密算法加密的。近年來,隨着計算機性能的飛速改善,加密速度再也不成爲限制這種加密技術發展的桎梏,於是消息摘要算法應用的領域不斷增長。

消息摘要算法主要應用在數字簽名領域,做爲對明文的摘要算法。著名的摘要算法有RSA公司的MD5算法和SHA-1算法及其大量的變體。

特色:單向加密,長度統一

MD算法實現

通常的加密算法實現經過兩個包實現
JDK:java.security
BC: Bouncy Castle

1.MD2

public static void jdkMD2(String str) throws NoSuchAlgorithmException {
    MessageDigest messageDigest = MessageDigest.getInstance("MD2");
    byte[] enStr = messageDigest.digest(str.getBytes());
    //將二進制轉換爲16進制輸出
    System.out.println("JDK的MD2摘要:"+new String(Hex.encodeHex(enStr)));
}

2.MD4

public static void BCMD4(String str) throws NoSuchAlgorithmException {
    Digest digest = new MD4Digest();
    byte[] b = str.getBytes();
    digest.update(b,0,b.length);
    byte[] enStr = new byte[digest.getDigestSize()];
    digest.doFinal(enStr,0);
    //將二進制轉換爲16禁止輸出
    System.out.println("B C的MD4摘要:"+new String(org.bouncycastle.util.encoders.Hex.toHexString(enStr)));
}

3.MD5

BC實現

public static void BCMD5(String str) throws NoSuchAlgorithmException {
      Digest digest = new MD5Digest();
      byte[] b = str.getBytes();
      digest.update(b,0,b.length);
      byte[] enStr = new byte[digest.getDigestSize()];
      digest.doFinal(enStr,0);
      //將二進制轉換爲16禁止輸出
      System.out.println("B C的MD5摘要:"+new String(org.bouncycastle.util.encoders.Hex.toHexString(enStr)));
  }

JDK實現

public static void jdkMD5(String str) throws NoSuchAlgorithmException {
    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
    byte[] enStr = messageDigest.digest(str.getBytes());
    //將二進制轉換爲16進制輸出
    System.out.println("JDK的MD5摘要:"+Hex.encodeHex(enStr));
}

調用

public static void main(String[] args) throws NoSuchAlgorithmException {
    BCMD4(BASE_STRING);
    BCMD5(BASE_STRING);
    jdkMD2(BASE_STRING);
    jdkMD5(BASE_STRING);
}

結果

B C的MD4摘要:28427b7d90e25002467da60396b79a94
B C的MD5摘要:6ddee10117cee5ef77cae7e747385ee2
JDK的MD2摘要:3cce751973fd1c6957b4d60bbf0d9153
JDK的MD5摘要:6ddee10117cee5ef77cae7e747385ee2

4.SHA

通常的加密算法實現經過兩個包實現
JDK:java.security
BC: Bouncy Castle
CC通常是對JDK簡化操做

SHA-1

JDK實現

public static void jdkSHA1(String str) throws NoSuchAlgorithmException {
   MessageDigest messageDigest = MessageDigest.getInstance("SHA");
   byte[] enStr = messageDigest.digest(str.getBytes());
   //將二進制轉換爲16進制輸出
   System.out.println("JDK的SHA摘要:"+new String(Hex.encodeHex(enStr)));
}

BC實現

public static void BCSHA1(String str) throws NoSuchAlgorithmException {
      Digest digest = new SHA1Digest();
      byte[] b = str.getBytes();
      digest.update(b,0,b.length);
      byte[] enStr = new byte[digest.getDigestSize()];
      digest.doFinal(enStr,0);
      //將二進制轉換爲16禁止輸出
      System.out.println("B C的SHA1摘要:"+new String(org.bouncycastle.util.encoders.Hex.toHexString(enStr)));
  }

CC實現

public static void CCSHA1(String str){
    String enStr = DigestUtils.sha1Hex(BASE_STRING.getBytes());
    System.out.println("C C的SHA1摘要:"+enStr);

}
SHA224

BC單獨實現

public static void BCSHA224(String str) throws NoSuchAlgorithmException {
    Digest digest = new SHA224Digest();
    byte[] b = str.getBytes();
    digest.update(b,0,b.length);
    byte[] enStr = new byte[digest.getDigestSize()];
    digest.doFinal(enStr,0);
    //將二進制轉換爲16禁止輸出
    System.out.println("B C的SHA224摘要:"+new String(org.bouncycastle.util.encoders.Hex.toHexString(enStr)));
}

JDK實現與BC配合實現

public static void jdkAndBCSHA224(String str) throws NoSuchAlgorithmException {
    Security.addProvider(new BouncyCastleProvider());
    MessageDigest messageDigest = MessageDigest.getInstance("SHA224");
    byte[] enStr = messageDigest.digest(str.getBytes());
    //將二進制轉換爲16禁止輸出
    System.out.println("JDK+BC的SHA224摘要:"+new String(Hex.encodeHex(enStr)));
}

調用

public static void main(String[] args) throws NoSuchAlgorithmException {
    jdkSHA1(BASE_STRING);
    BCSHA1(BASE_STRING);
    CCSHA1(BASE_STRING);
    BCSHA224(BASE_STRING);
    jdkAndBCSHA224(BASE_STRING);
}

結果

JDK的SHA1摘要:4a6db077ec2ea85697bfe5e97feffed7616dda96
B C的SHA1摘要:4a6db077ec2ea85697bfe5e97feffed7616dda96
C C的SHA1摘要:4a6db077ec2ea85697bfe5e97feffed7616dda96
B C的SHA224摘要 :f86ded290c11f45253ba0a47c30a23ab7121721e76f8dc071aee98cc
JDK+BC的SHA224摘要:f86ded290c11f45253ba0a47c30a23ab7121721e76f8dc071aee98cc

MAC 加祕鑰的摘要算法

JDK實現

public static void jdkHmacMD5(String str) throws Exception {
    //初始化 KeyGenerator
    KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
    //生成祕鑰
    SecretKey secretKey = keyGenerator.generateKey();
    //獲取祕鑰
    byte[] key = secretKey.getEncoded();

    //還原祕鑰
    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacMD5");
    //獲取mac實例 初始化MAC
    Mac mac = Mac.getInstance(secretKeySpec.getAlgorithm());
    mac.init(secretKey);
    //執行摘要算法
    byte[] encBytes = mac.doFinal(str.getBytes());
    System.out.println(Hex.toHexString(encBytes));
}

BC實現

public static void BCHmacMD5(String str){

    HMac hMac = new HMac(new MD5Digest());
    hMac.init(new KeyParameter(Hex.decode("aaaaaaaaaa")));
    hMac.update(str.getBytes(),0,str.getBytes().length);
    byte[] hmacMD5 = new byte[hMac.getMacSize()];
    hMac.doFinal(hmacMD5,0);
    System.out.println(Hex.toHexString(hmacMD5));

}

3.對稱加密算法(Symmetric-key algorithm)

對稱加密算法(Symmetric-key algorithm)簡介

對稱加密算法是應用較早的加密算法,技術成熟。在對稱加密算法中,數據發信方將明文(原始數據)和加密密鑰一塊兒通過特殊加密算法處理後,使其變成複雜的加密密文發送出去。收信方收到密文後,若想解讀原文,則須要使用加密用過的密鑰及相同算法的逆算法對密文進行解密,才能使其恢復成可讀明文。在對稱加密算法中,使用的密鑰只有一個,發收信雙方都使用這個密鑰對數據進行加密和解密,這就要求解密方事先必須知道加密密鑰。

對稱加密(也叫私鑰加密)指加密和解密使用相同密鑰的加密算法。有時又叫傳統密碼算法,就是加密密鑰可以從解密密鑰中推算出來,同時解密密鑰也能夠從加密密鑰中推算出來。而在大多數的對稱算法中,加密密鑰和解密密鑰是相同的,因此也稱這種加密算法爲祕密密鑰算法或單密鑰算法。它要求發送方和接收方在安全通訊以前,商定一個密鑰。對稱算法的安全性依賴於密鑰,泄漏密鑰就意味着任何人均可以對他們發送或接收的消息解密,因此密鑰的保密性對通訊的安全性相當重要。

特色:解密加密使用相同祕鑰,計算量小,算法簡單,加密效率高

對稱加密算法實現

DES加密 (不安全)

Jdk實現DES

public static void jdkDES(String str) throws Exception {
     //系統自動生成key
     byte[] key = KeyGenerator.getInstance("DES").generateKey().getEncoded();

     //轉換祕鑰
     DESKeySpec desKeySpec = new DESKeySpec(key);
     SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
     Key convertSecretKey = secretKeyFactory.generateSecret(desKeySpec);

     //加密
     //加密模式 DES
     Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
     //初始化加密工具
     cipher.init(Cipher.ENCRYPT_MODE,convertSecretKey);
     byte[] enBytes = cipher.doFinal(str.getBytes());
     //展現
     System.out.println("Jdk DES Encrypt:"+ Hex.toHexString(enBytes));

     //解密
     cipher.init(Cipher.DECRYPT_MODE,convertSecretKey);
     byte[] deBytes = cipher.doFinal(enBytes);
     System.out.println("Jdk DES Decrypt:"+new String(deBytes));

 }

BC實現DES

public static void BCDES(String str) throws Exception {
        //向JDK中添加算法
        Security.addProvider(new BouncyCastleProvider());
        //系統自動生成key
        byte[] key = KeyGenerator.getInstance("DES").generateKey().getEncoded();

        //轉換祕鑰
        DESKeySpec desKeySpec = new DESKeySpec(key);
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
        Key convertSecretKey = secretKeyFactory.generateSecret(desKeySpec);

        //加密
        //加密模式 DES
        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        //初始化加密工具
        cipher.init(Cipher.ENCRYPT_MODE,convertSecretKey);
        byte[] enBytes = cipher.doFinal(str.getBytes());
        //展現
        System.out.println("Jdk DES Encrypt:"+ Hex.toHexString(enBytes));

        //解密
        cipher.init(Cipher.DECRYPT_MODE,convertSecretKey);
        byte[] deBytes = cipher.doFinal(enBytes);
        System.out.println("Jdk DES Decrypt:"+new String(deBytes));

    }

TripleDES(三重DES)

JDK實現

public static void  jdkTripleDES(String str) throws Exception{
     //系統自動生成key
     KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
     //依據算法自定義Key長度 init(168);
     keyGenerator.init(new SecureRandom());
     byte[] key = keyGenerator.generateKey().getEncoded();

     //轉換祕鑰
     DESedeKeySpec desKeySpec = new DESedeKeySpec(key);
     SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
     Key convertSecretKey = secretKeyFactory.generateSecret(desKeySpec);

     //加密
     //加密模式 DES
     Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
     //初始化加密工具
     cipher.init(Cipher.ENCRYPT_MODE,convertSecretKey);
     byte[] enBytes = cipher.doFinal(str.getBytes());
     //展現
     System.out.println("Jdk TripleDES Encrypt:"+ Hex.toHexString(enBytes));

     //解密
     cipher.init(Cipher.DECRYPT_MODE,convertSecretKey);
     byte[] deBytes = cipher.doFinal(enBytes);
     System.out.println("Jdk TripleDES Decrypt:"+new String(deBytes));
 }

BC+JDK實現

public static void  BCTripleDES(String str) throws Exception{
    Security.addProvider(new BouncyCastleProvider());
    //系統自動生成key
    KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
    //依據算法自定義Key長度 init(168);
    keyGenerator.init(new SecureRandom());
    byte[] key = keyGenerator.generateKey().getEncoded();

    //轉換祕鑰
    DESedeKeySpec desKeySpec = new DESedeKeySpec(key);
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
    Key convertSecretKey = secretKeyFactory.generateSecret(desKeySpec);

    //加密
    //加密模式 DES
    Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
    //初始化加密工具
    cipher.init(Cipher.ENCRYPT_MODE,convertSecretKey);
    byte[] enBytes = cipher.doFinal(str.getBytes());
    //展現
    System.out.println("BC+Jdk TripleDES Encrypt:"+ Hex.toHexString(enBytes));

    //解密
    cipher.init(Cipher.DECRYPT_MODE,convertSecretKey);
    byte[] deBytes = cipher.doFinal(enBytes);
    System.out.println("BC+Jdk TripleDES Decrypt:"+new String(deBytes));
}

AES加密

AES加密及其解密須要的參數

AES加密流程

public static void jdkAES(String str) throws Exception {
    //系統自動生成key
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
    keyGenerator.init(128);
    byte[] key = keyGenerator.generateKey().getEncoded();

    //轉換祕鑰
    Key convertSecretKey = new SecretKeySpec(key, "AES");

    //加密
    //加密模式 DES
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    //初始化加密工具
    cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
    byte[] enBytes = cipher.doFinal(str.getBytes());
    //展現
    System.out.println("Jdk DES Encrypt:" + Hex.toHexString(enBytes));

    //解密
    cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
    byte[] deBytes = cipher.doFinal(enBytes);
    System.out.println("Jdk DES Decrypt:" + new String(deBytes));
}

BC+JDK實現相似於DES的方式

PBE(Password Based Encryption)加密

PBE(Password Based Encryption,基於口令加密)是一種基於口令的加密算法,其特色是使用口令代替了密鑰,而口令由用戶本身掌管,採用隨機數雜湊多重加密等方法保證數據的安全性。PBE算法在加密過程當中並非直接使用口令來加密,而是加密的密鑰由口令生成,這個功能由PBE算法中的KDF函數完成。KDF函數的實現過程爲:將用戶輸入的口令首先經過「鹽」(salt)的擾亂產生準密鑰,再將準密鑰通過散列函數屢次迭代後生成最終加密密鑰,密鑰生成後,PBE算法再選用對稱加密算法對數據進行加密,能夠選擇DES、3DES、RC5等對稱加密算法。

經常使用加密方式

加密流程

JDK實現

/**
 * 基於口令的對稱加密算法PBE
 */
public class PBE {

    private static final String BASE_STRING ="security PBETest";

    private static final String BASE_PWD="security Pwd";

    public static void main(String[] args) throws Exception {
        jdkPBE(BASE_STRING);

    }

    public static void jdkPBE(String str) throws Exception {
        //初始化鹽
        SecureRandom random = new SecureRandom();
        byte[] salt = random.generateSeed(8);

        //口令於祕鑰
        PBEKeySpec pbeKeySpec = new PBEKeySpec(BASE_PWD.toCharArray());
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
        Key key = factory.generateSecret(pbeKeySpec);

        //加密
        PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt,100);
        Cipher cipher = Cipher.getInstance("PBEWITHMD5andDES");
        cipher.init(Cipher.ENCRYPT_MODE,key,pbeParameterSpec);
        byte[] enBytes = cipher.doFinal(str.getBytes());
        System.out.println("JDK PBE 加密:"+ Base64.encodeBase64String(enBytes));

        cipher.init(Cipher.DECRYPT_MODE,key,pbeParameterSpec);
        byte[] deBytes = cipher.doFinal(enBytes);
        System.out.println("JDK PBE 解密:"+new String(deBytes));
    }
}

其餘實現方式只需修改加密方式

4.非對稱加密算法

非對稱加密算法簡介

非對稱加密算法須要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私有密鑰是一對,若是用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;若是用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。由於加密和解密使用的是兩個不一樣的密鑰,因此這種算法叫做非對稱加密算法。 非對稱加密算法實現機密信息交換的基本過程是:甲方生成一對密鑰並將其中的一把做爲公用密鑰向其它方公開;獲得該公用密鑰的乙方使用該密鑰對機密信息進行加密後再發送給甲方;甲方再用本身保存的另外一把專用密鑰對加密後的信息進行解密。

另外一方面,甲方可使用乙方的公鑰對機密信息進行簽名後再發送給乙方;乙方再用本身的私匙對數據進行驗籤。
甲方只能用其專用密鑰解密由其公用密鑰加密後的任何信息。 非對稱加密算法的保密性比較好,它消除了最終用戶交換密鑰的須要。
非對稱密碼體制的特色:算法強度複雜、安全性依賴於算法與密鑰可是因爲其算法複雜,而使得加密解密速度沒有對稱加密解密的速度快。對稱密碼體制中只有一種密鑰,而且是非公開的,若是要解密就得讓對方知道密鑰。因此保證其安全性就是保證密鑰的安全,而非對稱密鑰體制有兩種密鑰,其中一個是公開的,這樣就能夠不須要像對稱密碼那樣傳輸對方的密鑰了。這樣安全性就大了不少。

特色:加密等級高,傳輸安全

非對稱加密算法實現

DH祕鑰交換算法

解決對稱加密傳輸安全的問題、構建本地祕鑰。

祕鑰長度 默認 工做模式 填充方式 實現方
512~1024位 1024位 JDK
流程

1.發送方構建公鑰私鑰。
2.發送方發佈發送方公鑰。
3.接收方接收發送方公鑰構建接收方公鑰私鑰。
4.接收方發佈接收方公鑰。
5.發送方經過發送方的私鑰和接收方的公鑰構建對稱加密祕鑰用於加密。
6.接收方經過接收方的私鑰和發送方的公鑰構建對稱加密祕鑰用於解密。
7.發送方經過祕鑰加密數據併發送。
8.接收方接收數據並經過祕鑰解密數據。

1.初始化發送方祕鑰

  • KeyPairGenerator 生成Keypair
  • KeyPair 祕鑰對(公鑰 私鑰)
  • Publickey 公鑰

2.初始化接收方祕鑰

  • KeyFactory 生成祕鑰
  • X509EncodedKeySpec 根據ASN.1進行編碼 按照某種規範生成祕鑰
  • DHPublicKey DH公鑰
  • DHParameterSpec DH參數集合
  • KeyGenerator
  • PricateKey 私鑰

3.祕鑰構建

  • KeyAgreement 祕鑰提供協議
  • SecretKey 祕密祕鑰對稱祕鑰 生成分組祕密祕鑰
  • KeyFactory
  • X509EncodedKeySpec
  • Publickey

4.加密、解密

  • Cipher 加密解密提供密碼功能 JCE核心
//流程實現
public static void jdkDHFlow() throws Exception {
    //1.發送方構建公鑰私鑰
    KeyPair senderKeyPair = jdkSenderPublicKey();
    //2.發送方發佈公鑰
    byte[] senderPublicKeyEncode = senderKeyPair.getPublic().getEncoded();
    //3.接收方構建公鑰私鑰->接收方經過發送方公鑰構建公鑰私鑰
    KeyPair receiverKeyPair = jdkreceiverPublicKey(senderPublicKeyEncode);
    //4.接收方發佈公鑰
    byte[] receiverPublicKeyEncode = receiverKeyPair.getPublic().getEncoded();
    //5.發送方構建對稱加密的祕鑰->依據接收方公鑰和本身的公鑰私鑰構建
    SecretKey senderDesKey = jdkGetSecretKey(senderKeyPair,receiverPublicKeyEncode);
    //6.接收方構建對稱加密祕鑰->依據發送方公鑰和接收方公鑰私鑰構建
    SecretKey receiverDesKey = jdkGetSecretKey(receiverKeyPair,senderPublicKeyEncode);
    //對比雙方對稱加密祕鑰是否安相同 查看是否測試成功
    if(Objects.equals(receiverDesKey,senderDesKey)){
        System.out.println("雙方祕鑰相同");
    }
    //7.發送方加密
    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.ENCRYPT_MODE,senderDesKey);
    byte[] result = cipher.doFinal(BASE_STRING.getBytes());
    System.out.println("JDK DH 加密:"+ Base64.encodeBase64String(result));
    //8.接收方解密
    cipher.init(Cipher.DECRYPT_MODE,receiverDesKey);
    result = cipher.doFinal(result);
    System.out.println("JDK DH 解密:"+new String(result));
}

/**
  * 發送方構建發送方公鑰
  * @return 構建完成的公鑰
  */
 public static KeyPair jdkSenderPublicKey() throws NoSuchAlgorithmException {
     //1.初始化發送方祕鑰
     KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("DH");
     senderKeyPairGenerator.initialize(512);
     //生成祕鑰
     KeyPair senderKeyPair = senderKeyPairGenerator.generateKeyPair();
     return  senderKeyPair;
 }

 /**
  * 依據發送方公鑰生成接收方公鑰
  * @param senderPublicKey 發送方公鑰
  * @return 接收方公鑰
  */
 public static KeyPair jdkreceiverPublicKey(byte[] senderPublicKey) throws Exception {
     KeyFactory receiverKeyFactory = KeyFactory.getInstance("DH");
     X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKey);
     PublicKey receiverPublicKey = receiverKeyFactory.generatePublic(x509EncodedKeySpec);
     //使用和發送方同樣的參數初始化
     DHParameterSpec dhParameterSpec = ((DHPublicKey) receiverPublicKey).getParams();
     KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance("DH");
     //發送方公鑰解析出來的dhParameterSpec
     receiverKeyPairGenerator.initialize(dhParameterSpec);
     KeyPair receiverKeyPair = receiverKeyPairGenerator.generateKeyPair();
     return receiverKeyPair;
 }

 /**
  * 本身的公鑰私鑰與對方的公鑰構建 對稱祕鑰
  * @param keyPair 本身祕鑰對
  * @param publicKey 對方公鑰
  * @return 本地對稱加密祕鑰
  */
 public static SecretKey jdkGetSecretKey(KeyPair keyPair,byte[] publicKey) throws Exception {
     KeyFactory keyFactory = KeyFactory.getInstance("DH");
     X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey);
     PublicKey senderPublicKey = keyFactory.generatePublic(x509EncodedKeySpec);
     KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
     keyAgreement.init(keyPair.getPrivate());
     keyAgreement.doPhase(senderPublicKey,true);
     SecretKey secretKey = keyAgreement.generateSecret("DES");
     return  secretKey;
 }

RSA因子分解算法

惟一普遍接受的實現類型
數字加密&數字簽名
公鑰加密 私鑰解密
私鑰加密 公鑰解密

工做實現以及填充模式

加解密流程

package asymmetrickeyencryption;

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

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 大數因子分解 64的整數倍
 */
public class RSA {

    private static final String BASE_STRING = "security DHTest";

    public static void main(String[] args) throws Exception {
        jdkRSA();

    }

    public static void jdkRSA() throws Exception {
        //1.初始化祕鑰
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(512);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        System.out.println("RSAPublicKey:" + Base64.encodeBase64String(rsaPublicKey.getEncoded()));
        System.out.println("RSAPrivateKey:" + Base64.encodeBase64String(rsaPrivateKey.getEncoded()));

        //2.私鑰加密
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        byte[] result = cipher.doFinal(BASE_STRING.getBytes());
        System.out.println("JDK RSA 私鑰加密:" + Base64.encodeBase64String(result));
        //公鑰解密
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
        KeyFactory keyFactory1 = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        Cipher cipher1 = Cipher.getInstance("RSA");
        cipher1.init(Cipher.DECRYPT_MODE, publicKey);
        result = cipher1.doFinal(result);
        System.out.println("JDK RSA 公鑰解密:" + new String(result));


        //3 公鑰加密
        x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
        keyFactory = KeyFactory.getInstance("RSA");
        publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        result = cipher.doFinal(BASE_STRING.getBytes());
        System.out.println("JDK RSA 公鑰加密:" + Base64.encodeBase64String(result));

        //私鑰解密
        pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
        keyFactory = KeyFactory.getInstance("RSA");
        privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        result = cipher.doFinal(result);
        System.out.println("JDK RSA 私鑰解密:" + new String(result));


    }

}

ELGamal離散對數加密算法

工做實現以及填充模式

加解密流程

祕鑰的構建

public static void BCElGamal() throws Exception {
    //添加bc加密工具
    Security.addProvider(new BouncyCastleProvider());
    //生成祕鑰
    AlgorithmParameterGenerator algorithmParameterGenerator = AlgorithmParameterGenerator.getInstance("ElGamal");
    algorithmParameterGenerator.init(256);
    AlgorithmParameters algorithmParameters = algorithmParameterGenerator.generateParameters();
    DHParameterSpec dhParameterSpec = algorithmParameters.getParameterSpec(DHParameterSpec.class);
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ElGamal");
    keyPairGenerator.initialize(dhParameterSpec,new SecureRandom());
    KeyPair keyPair = keyPairGenerator.generateKeyPair();
    PublicKey publicKey = keyPair.getPublic();
    PrivateKey privateKey = keyPair.getPrivate();
    System.out.println("ElGamal 公鑰:" + Base64.encodeBase64String(publicKey.getEncoded()));
    System.out.println("ElGamal 私鑰:" + Base64.encodeBase64String(privateKey.getEncoded()));

}

加密解密方式與RSA相同

數字簽名

數字簽名(又稱公鑰數字簽名、電子簽章)是一種相似寫在紙上的普通的物理簽名,可是使用了公鑰加密領域的技術實現,用於鑑別數字信息的方法。一套數字簽名一般定義兩種互補的運算,一個用於簽名,另外一個用於驗證。
數字簽名,就是隻有信息的發送者才能產生的別人沒法僞造的一段數字串,這段數字串同時也是對信息的發送者發送信息真實性的一個有效證實。
數字簽名是非對稱密鑰加密技術與數字摘要技術的應用。

特色: 數據完整性驗證、認證數據來源、抗否定等

RSA算法

加解密流程

僅僅實現簽名 驗籤

public static void jdkRSA() throws  Exception{
   //初始化祕鑰
   KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
   keyPairGenerator.initialize(512);
   KeyPair keyPair =keyPairGenerator.generateKeyPair();
   RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
   RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();

   //執行簽名
   //用私鑰簽名
   PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
   KeyFactory keyFactory = KeyFactory.getInstance("RSA");
   PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
   Signature signature = Signature.getInstance("MD5withRSA");
   signature.initSign(privateKey);
   signature.update(BASE_STRING.getBytes());
   byte[] result = signature.sign();
   System.out.println("JDK RSA 簽名:"+ Hex.toHexString(result));


   //用公鑰驗籤
   X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
   keyFactory = KeyFactory.getInstance("RSA");
   PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
   signature = Signature.getInstance("MD5withRSA");
   signature.initVerify(publicKey);
   signature.update(BASE_STRING.getBytes());
   boolean res = signature.verify(result);
   System.out.println("JDK RSA 驗籤:"+res);
}

DSA算法

DSA 算法和RSA算法徹底類似

public static void DSA() throws Exception{
    //建立祕鑰
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
    keyPairGenerator.initialize(512);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();
    DSAPublicKey dsaPublicKey = (DSAPublicKey) keyPair.getPublic();
    DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) keyPair.getPrivate();

    //簽名
    PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(dsaPrivateKey.getEncoded());
    KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    Signature signature = Signature.getInstance("SHA1withDSA");
    signature.initSign(privateKey);
    signature.update(BASE_STRING.getBytes());
    byte[] result = signature.sign();
    System.out.println("JDK DSA 簽名:"+ Base64.encodeBase64String(result));

    //驗籤
    X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(dsaPublicKey.getEncoded());
    keyFactory = KeyFactory.getInstance("DSA");
    PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
    signature = Signature.getInstance("SHA1withDSA");
    signature.initVerify(publicKey);
    signature.update(BASE_STRING.getBytes());
    boolean res = signature.verify(result);
    System.out.println("JDK DSA 驗籤是否經過:"+res);
}

ECDSA算法(橢圓曲線數字簽名算法)

速度快、強度高、簽名短的特色;
序列號驗證算法
加解密流程

public static void jdkECDSA() throws Exception{
        //生成祕鑰
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
        keyPairGenerator.initialize(256);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        ECPublicKey ecPublicKey = (ECPublicKey) keyPair.getPublic();
        ECPrivateKey ecPrivateKey = (ECPrivateKey) keyPair.getPrivate();

        //簽名
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(ecPrivateKey.getEncoded());
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Signature signature = Signature.getInstance("SHA256withECDSA");
        signature.initSign(privateKey);
        signature.update(BASE_STRING.getBytes());
        byte[] result = signature.sign();
        System.out.println("JDK ECDSA 簽名:"+ Base64.encodeBase64String(result));


        //驗籤
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(ecPublicKey.getEncoded());
        keyFactory = KeyFactory.getInstance("EC");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        signature = Signature.getInstance("SHA256withECDSA");
        signature.initVerify(publicKey);
        signature.update(BASE_STRING.getBytes());
        boolean res = signature.verify(result);
        System.out.println("JDK ECDSA 驗簽結果:"+res);

    }

加密技術的應用--數字簽名RSA版本

三方支付系統簽名驗證流程

甲方傳輸一段報文給乙方

甲方發送操做:

  1. 甲方 組織報文
  2. 使用甲方私鑰簽名報文(摘要算法)
  3. 將報文和簽名合併
  4. 使用乙方公鑰將合併後的數據加密(非對稱加密)
  5. 傳輸到乙方

乙方接收操做:

  1. 使用乙方私鑰將加密數據打開 (非對稱加密)
  2. 分開報文和簽名
  3. 使用甲方公鑰從新簽名報文(摘要算法)
  4. 驗證乙方簽名後的報文和甲方傳輸的報文是否同樣
  5. 若是同樣接收數據成功

源碼

https://github.com/yanlong300/security/

相關文章
相關標籤/搜索