消息摘要算法

消息摘要算法

友情提示,本文檔的圖床使用極簡圖床進行圖片存儲,默認存儲到七牛云空間

本文檔依賴的jar maven地址如下:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.10</version>
</dependency>
 <dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.57</version>
</dependency>

分類名詞解釋

  • MD
    message Digest 消息摘要
  • SHA
    Secure hash algorithm安全散列
  • MAC
    message authenttication code 消息認證碼

三個名詞的作用

驗證數據的完整性(比如maven倉庫的md5數據完整性比對)

消息摘要算法是數字簽名的核心算法

MD算法分類

  • MD5
  • MD家族(生成都是128位摘要信息 如果md2,md4)

MD算法特點

單項加密 不可逆

MD5的實現方

package com.ztgeo.secret;

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

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

public class MDDemo {
    
//md家族的加解密算法

private static String reqStr= "MD5需要加密的數據";

public static void main(String[] args) {
    secretMD5();
}


public static void secretMD5(){
    try {
        //使用原生jdk就可以進行md5的加密
        MessageDigest md = MessageDigest.getInstance("MD5");
        //進行消息摘要(md5加密)
        byte[] md5Bytes =md.digest(reqStr.getBytes());
        System.out.println("md5加密后未經轉換的byte[]后的結果:"+md5Bytes);  
        System.out.println("md5加密后轉換成string后的結果:"+new String(md5Bytes));    
        //轉換后的長度沒有128 只有11位 就算轉換成string也是如下亂碼:??????'??9?O??s4
        //所以md5加密后的數據 不能直接使用 應該使用16進制轉換后的結果作為加密結果  
        
        //恰巧bc和cc中都有該功能的方法 一般選擇cc中方法  
        
        System.out.println("轉換成16進制之后的加密數組:"+Hex.encodeHexString(md5Bytes));
        
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    
}

}

該算法 也同樣支持md2 只需要在獲得實例的時候傳入"MD2"即可
但是jdk沒有提供md4的實現 強制使用md4獲得實例會報錯

使用bc實現md4或者其他加密方式

private static void BCMD4(){
    //使用bc包實現md4的算法 加密  
    Digest digest = new MD4Digest();
    //預處理 md4需要加密的字符串(類似讀取 輸入流)
    digest.update(reqStr.getBytes(), 0,reqStr.getBytes().length);
    //使用byte數組去接收結果 相當于處理完了 用容器去承載結果  
    byte[] md4Byte = new byte[digest.getDigestSize()];
    ///讀出到輸入流
    digest.doFinal(md4Byte, 0);
    //這個時候結果容器被裝滿  使用bc自帶的64位轉碼進行轉碼  
    System.out.println("BC加密后的MD4加密結果:"+org.bouncycastle.util.encoders.Hex.toHexString(md4Byte));

}

當然 也可以用cc去實現相同的功能 只是在cc中并沒有提供md4的實現,猜測cc只是簡化輔助jdk的md功能 沒有做功能的延伸

//使用cc實現md的加密
//如果看源碼會發現 實際上cc并沒有去自己寫md的實現 只是引用來了jdk的md相應實現
public static void ccMD5(){
    //這里需要提的而是 cc實現 md5的方法中 有個方法簡化了hex轉化64位的操作
    System.out.println("CCmd5的簡單實現:"+DigestUtils.md5Hex(reqStr.getBytes()));
}

md算法的總結

  • 使用jdk的方法是偏底層的,不提供16進制轉換
  • bc的優勢在于提供了md4的實現(jdk和cc沒有)
  • cc實現了hex進制轉換的直接使用 但只是簡化了jdk的方法 沒有自己實現

md加密方式的應用

注冊時用戶名明文 密碼變為不可逆 密文 存入數據庫
登錄時用戶名明文 密碼直接拿去數據庫比對
這樣有效的防止了信息泄露(就算拿到數據庫還是不知道密碼)

SHA

  • 安全散列算法
  • 固定長度的摘要信息
  • 很多場景下 被稱為md5的繼承者
  • 美國國家安全局設計的(背景強大)
  • 由MD4演變而來
  • 內容稍有不同結果就大相徑庭 很難被破譯

SHA的分類

  • SHA-1
  • SHA-2
    • SHA-224
    • SHA-256
    • SHA-384
    • SHA-512

算法的實現


依然沒有cc的算法.是因為cc又是對jdk的簡化操作

SHA的算法應用

防止數據傳輸過程中被篡改,保證數據的完整性
常用的傳輸方式是在url上傳參 并發送sha的消息摘要,,對方進行消息摘要的對比 看傳輸數據是否發生了篡改

MAC

  • 兼容了md和sha的特性
  • 加入了秘鑰(hmac 含有秘鑰的sha算法)

MAC的分類

  • MD系列

    • HmacMD2
    • HmacMD4
    • HmacMD5
  • SHA系列

    • HmacSHA1
    • HmacSHA2
      • HmacSHA224
      • HmacSHA256
      • HmacSHA384
      • HmacSHA512

MAC算法的摘要長度和實現方

MAC的代碼實現

package com.ztgeo.secret;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

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

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

public class MacDemo {     
//mac安全散列算法的實現(有秘鑰)

private static String reqStr="需要被mac摘要的數據";

public static void main(String[] args) {
    jdkHmacMD5();
    bHmacMD5();
}

public static void jdkHmacMD5(){
    
    try {
        //獲得秘鑰工廠  
        KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
        
        //一下兩步是是隨機生產key  但實際情況 需要制定key
        /*//生成秘鑰  
        SecretKey key = keyGenerator.generateKey();
        //獲得秘鑰
        byte[] keyByte = key.getEncoded();*/
        
        byte[] keyByte = org.apache.commons.codec.binary.Hex.decodeHex(new char[]{'a','a','a','a','a','a','a','a','a','a'});
        
        //還原秘鑰 數組秘鑰 通過類進行還原
        SecretKey restoreKey = new SecretKeySpec(keyByte, "HmacMD5");
        //實例化MAC 使用秘鑰還原
        Mac mac = Mac.getInstance(restoreKey.getAlgorithm());
        //初始化mac
        mac.init(restoreKey);
        //執行加密(摘要) 
        byte[] HmacMd5Bytes = mac.doFinal(reqStr.getBytes());
        //輸出摘要的結果
        System.out.println("jkd hmacMD5結果:"+Hex.toHexString(HmacMd5Bytes));
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}


//bc實現mac md5算法  
public static void bHmacMD5(){
    //實例化mac
    HMac hmac = new HMac(new MD5Digest());
    //初始化mac
    hmac.init(new KeyParameter(Hex.decode("aaaaaaaaaa")));
    //讀入流
    hmac.update(reqStr.getBytes(),0,reqStr.getBytes().length);
    
    //準備容器 
    byte[] hmacMD5Bytes = new byte[hmac.getMacSize()];
    
    //放置輸出結果
    hmac.doFinal(hmacMD5Bytes, 0);
    
    //輸出結果
    System.out.println("bcHmacMD5結果:"+Hex.toHexString(hmacMD5Bytes));
    
}

}

對稱加密算法

加密秘鑰和解密秘鑰相同

對稱加密算法的特點

  • 初等的加密算法(安全級別不高)
  • DES(代表性的加密算法,長度不夠 安全性低 已被破解)
    • 3DES
  • AES(替代DES)
  • PBE
  • IDEA

DES詳解

出身

ibm提交美國,98年后被破解,目前不具備安全性

實現方式和實現方

使用jdk實現DES算法的加解密

    package com.ztgeo.secret;

import java.security.Key;
import java.security.NoSuchAlgorithmException;

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.Hex;

public class DESDemo {

private static String reqStr ="需要被加密內容!!";

public static void main(String[] args) {
        jdkDES();
}

public static void jdkDES(){
    
    try {
        //生成秘鑰材料
        /*KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
        //指定秘鑰長度  DES是56位
        keyGenerator.init(56);
        SecretKey key = keyGenerator.generateKey();
        //獲得程序產生的key
        byte[] keyByte = key.getEncoded();*/
        
        
        //當然 可以自己指byte數組類型的秘鑰
        byte[] keyByte = "15062101243".getBytes();      //秘鑰
        
        
        //秘鑰材料轉換 
        DESKeySpec desKeySpec = new DESKeySpec(keyByte);
        
        //生成真正的key
        //實例化秘鑰工廠(指定加密方式)
        SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
        Key convertSecretKey = factory.generateSecret(desKeySpec);
    
        //加密 (需要填充加解密的算法/工作方式/填充方式) 
        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        //加密模式ENCRYPT_MODE 和轉換可以使用的key
        cipher.init(cipher.ENCRYPT_MODE, convertSecretKey);
        //執行加密操作
        byte[] result = cipher.doFinal(reqStr.getBytes());
        System.out.println("使用JDK加密DES:"+Hex.encodeHexString(result));
        
        //解密操作
        //依然使用cipher進行解密 需要的秘鑰 也需要秘鑰轉換 
        cipher.init(cipher.DECRYPT_MODE, convertSecretKey);
        //執行加密操作 結果轉成string
        result = cipher.doFinal(result);
        System.out.println("使用JDK解密DES:"+new String(result));
        
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
}

//bc的DES實現 可以通過secret添加provide進行實現 實現方式和jdk類似 這里不做贅述 

}

3DES(三重DES)

三重DES的必要性

  • DES違反了柯克霍夫原則(算法半公開) 所以安全性不高
  • DES的背景是美國安全局,所以是否有后門 不敢確保

三重DES的好處

  • 密碼長度增強
  • 迭代次數增多

長度和實現方

JDK的實現

package com.ztgeo.secret;

import java.security.Key;
import java.security.SecureRandom;

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

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

public class DES3 {

private static String reqStr ="需要被加密內容!!";

public static void main(String[] args) {
            jdk3des();
}

public static void jdk3des(){
    //jdk的三重des和des實現都是類似的 我們直接copy代碼  
    try {
        //生成秘鑰材料
        KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
        //指定秘鑰長度 3DES是168位
        //keyGenerator.init(168);
        //當然 如果不想記什么算法多少位  可以使用根據getInstance對字符串變能量獲得默認長度的秘鑰  
        keyGenerator.init(new SecureRandom());
        SecretKey key = keyGenerator.generateKey();
        //獲得程序產生的key
        byte[] keyByte = key.getEncoded();
        
        
        //當然 可以自己指byte數組類型的秘鑰 但目前報錯 原因未知
        //byte[] keyByte = "15062101243".getBytes();      //秘鑰
        
        
        //秘鑰材料轉換 
        DESedeKeySpec desKeySpec = new DESedeKeySpec(keyByte);
        
        //生成真正的key
        //實例化秘鑰工廠(指定加密方式)
        SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
        Key convertSecretKey = factory.generateSecret(desKeySpec);
    
        //加密 (需要填充加解密的算法/工作方式/填充方式) 
        Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        //加密模式ENCRYPT_MODE 和轉換可以使用的key
        cipher.init(cipher.ENCRYPT_MODE, convertSecretKey);
        //執行加密操作
        byte[] result = cipher.doFinal(reqStr.getBytes());
        System.out.println("使用JDK加密3DES:"+Hex.encodeHexString(result));
        
        //解密操作
        //依然使用cipher進行解密 需要的秘鑰 也需要秘鑰轉換 
        cipher.init(cipher.DECRYPT_MODE, convertSecretKey);
        //執行加密操作 結果轉成string
        result = cipher.doFinal(result);
        System.out.println("使用JDK解密3DES:"+new String(result));
        
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    
    
}

}

AES

AES的產生原因

  • DES安全性不要
  • 3DES效率不高
  • AES是DES(包括3DES的替代品)
  • 對稱加密的首選就是AES 使用率最高
  • AES目前官方并沒有確認被破解

AES的應用范圍

AES用于移動通訊系統加密以及基于SSH協議的軟件

算法實現

jdk的實現(bc的實現和aes十分類似 不舉例了)

package com.ztgeo.secret;

import java.security.Key;
import java.security.NoSuchAlgorithmException;

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 AESDemo {

private static String reqStr ="需要被加密內容!!";

public static void main(String[] args) {
    jdkAes();
}


public static void jdkAes(){
    try {
        //生成key
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128);
        SecretKey sekey = keyGenerator.generateKey();
        //獲得程序產生的key
        byte[] keyByte = sekey.getEncoded();
        
        //轉換key
        Key key  = new SecretKeySpec(keyByte, "AES");
        
        //加密  填充
        Cipher  cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] resultByte = cipher.doFinal(reqStr.getBytes());
        System.out.println("AES加密后的內容(base64之后):"+Base64.encodeBase64String(resultByte));
        
        
        
        //解密
        cipher.init(Cipher.DECRYPT_MODE, key);
        resultByte = cipher.doFinal(resultByte);
        System.out.println("使用JDK解密AES操作:"+new String(resultByte));
        
        
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    
}


} 

對稱加密算法之----PBE

  • pbe算法結合了消息摘要算法和對稱加密算法的所有優點
  • pbe(password based encryption)基于口令的加密
  • 只是對已有算法的包裝
  • JDK,BC
  • 鹽(秘鑰口令和擾碼)
  • 是一種綜合性算法(消息摘要+對稱加密) 常見 PBEWithMD5AndDES

PBE算法的實現

演示jdk實現PBE的算法

package com.ztgeo.secret;

import java.security.Key;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

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


public class PBEDemo {

private static String reqStr = "需要被加密的內容";

public static void main(String[] args) {
        jdkPBE();
}

public static void jdkPBE(){
    try {
        //初始化鹽 鹽可以理解為隨機數  
        SecureRandom random = new SecureRandom();
        //用8位 產生鹽
        byte[] salt =  random.generateSeed(8);

        
        //口令轉秘鑰
        String password = "12345687";
        //密碼轉換成口令秘鑰  
        PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
        Key key = factory.generateSecret(pbeKeySpec);
        
        //加密
        
        //將鹽構成params
        PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 100);
        Cipher cipher  = Cipher.getInstance("PBEWITHMD5andDES");
        cipher.init(Cipher.ENCRYPT_MODE, key,parameterSpec);
        byte[] byteResult = cipher.doFinal(reqStr.getBytes());
        System.out.println("jdk使用PBE加密后的結果:"+ Base64.encodeBase64String(byteResult));
        
        //解密
        
        cipher.init(Cipher.DECRYPT_MODE,key,parameterSpec);//秘鑰 鹽
        byteResult = cipher.doFinal(byteResult);
        System.out.println("jdk使用PBE解密后的結果:"+ new String(byteResult));
        } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    
    
}

}

PBE在的實際使用

由圖中可以看出,解謎.不僅要知道解密的秘鑰,還要知道加密時實時產生的隨機數才能正確解密,極大提高了數據性;

非對稱加密算法

因為對稱加密算法是雙方秘鑰相同.所以又叫做初等加密算法

非對稱加密算法的特點

  • 高級加密算法(秘鑰不對稱)
  • 雙保險(類似vip銀行客戶保險柜原理.銀行一把鑰匙.客戶一把鑰匙)
  • 公鑰,私鑰 (都是成對出現的)

非對稱加密的分類

  • DH(Diffie-Hellman)密鑰交換算法
  • RSA-基于因子分解(三個人姓氏開頭,應用最廣)
  • ElGamal-基于離散對數
  • ECC(橢圓曲線加密)

DH加密算法

  • 非對稱加密的鼻祖
  • 是為了解決對稱加密算法密鑰的傳輸安全級別低的問題應運而生的
  • 構建本地秘鑰 解決秘鑰傳遞的問題

DH相關實現方

JDK實現加密算法使用類

加密方:

  • KeyPairGenerator 秘鑰對的 生產類
  • KeyPair 秘鑰對 可以產生公鑰和私鑰
  • PublicKey 公鑰

解密方:

  • KeyFactory 秘鑰工廠(根據規范生成公鑰私鑰) 還原秘鑰
  • X509EncodeKeySpec 根據ASN.1進行秘鑰編碼
  • DHPublicKey
  • DHParameterSpec DH算法中 參數的集合類
  • KeyPairGenerator
  • PrivateKey

秘鑰構建
KeyAgreement 提供秘鑰協議的類
SecretKey 秘密秘鑰 生成分組的秘密秘鑰

加密,解密
Cipher 加密解密 提供密碼功能類

DH加密的步驟

  1. 發送方發送公鑰載體
  2. 接收方根據發送方公鑰產生接收方公鑰載體
  3. 根據接受方公鑰載體產生本地秘鑰
  4. 發送接收方公鑰載體
  5. 接收方根據接收方的公鑰載體 產生本地秘鑰
  6. 對比雙方本地秘鑰 完全相同后發送方根據本地秘鑰加密數據
  7. 接收方 根據本地秘鑰進行 解密數據

在此過程中,雙方的本地秘鑰不同,但兩次發送,彼此依賴生成,形成完美的閉環,具體代碼如下:

package com.ztgeo.secret;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Objects;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;

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

//非對稱加密 
public class DHDemo {
private static String reqStr = "需要被加密的數據123456";

public static void main(String[] args) {
    try {
    //1.初始化發送方的秘鑰   
        
        //鑰匙對工廠產生鑰匙對
        KeyPairGenerator sendKeyPairGenerator = KeyPairGenerator.getInstance("DH");
        sendKeyPairGenerator.initialize(512);
        //鑰匙對 用來存放公鑰和私鑰
        KeyPair sendKeyPair =sendKeyPairGenerator.generateKeyPair();
        //獲得公鑰載體 發送給接收方 (網絡,文件...)
        byte[] sendPublicKeyEnc = sendKeyPair.getPublic().getEncoded();
        
        
    //2.初始化接收方秘鑰 推算出 公鑰 
        KeyFactory reciverKeyFactory  = KeyFactory.getInstance("DH");
        //秘鑰標準
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(sendPublicKeyEnc);
        //通過標準和 公鑰載體 獲得公鑰
        PublicKey reciverPublicKey = reciverKeyFactory.generatePublic(x509EncodedKeySpec);
        //獲得公鑰參數 用來構建鑰匙對
        DHParameterSpec dhParameterSpec = ((DHPublicKey)reciverPublicKey).getParams();
        
        //從發送方載體中獲得了公鑰參數 可以構建 參數對了
        KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance("DH");
        receiverKeyPairGenerator.initialize(dhParameterSpec);
        KeyPair receiverKeyPair = receiverKeyPairGenerator.generateKeyPair();
        //接收方 公鑰載體
        byte[] receiverPublicKeyEnc = receiverKeyPair.getPublic().getEncoded();
        
    //3.秘鑰構建(私鑰)  具體可分為 發送方的私鑰構建 和接收方的 私鑰構建
        //接受方
        KeyAgreement receviverKeyAgreement = KeyAgreement.getInstance("DH");
        //使用私鑰進行初始化
        receviverKeyAgreement.init(receiverKeyPair.getPrivate());
        receviverKeyAgreement.doPhase(reciverPublicKey, true);
        //本地私鑰產生 并發送
        SecretKey receiverDesKey = receviverKeyAgreement.generateSecret("DES");
    
        //發送方(根據接收方 第一次返回的公鑰載體進行生成私鑰 并反推成本地秘鑰)
        KeyFactory senderKeyFactory = KeyFactory.getInstance("DH");
        x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKeyEnc);
        PublicKey senderPublicKey = senderKeyFactory.generatePublic(x509EncodedKeySpec);
        KeyAgreement senderKeyAgreement = KeyAgreement.getInstance("DH");
        senderKeyAgreement.init(sendKeyPair.getPrivate());
        senderKeyAgreement.doPhase(senderPublicKey, true);
        SecretKey senderDesKey = senderKeyAgreement.generateSecret("DES");
    
        //接收方 根據發送方私鑰產生了 本地秘鑰  
        //發送方 也根據接收方傳過來的 公鑰 產生了本地秘鑰 
        
        //驗證 雙方本地秘鑰是否相同  
        if(Objects.equals(receiverDesKey, senderDesKey)){
            System.out.println("驗證成功,雙方產生的本地秘鑰相同!!");
        }
        
    //4.加密數據 
        //發送方根據 本地 私鑰 加密數據  
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(Cipher.ENCRYPT_MODE, senderDesKey);
        byte[] result = cipher.doFinal(reqStr.getBytes());
        System.out.println("使用DH加密的數據是:"+Base64.encodeBase64String(result));
        
    //5.客戶端解密數據  
        //接收方根據 本地秘鑰進行解密
        cipher.init(Cipher.DECRYPT_MODE, receiverDesKey);
        result = cipher.doFinal(result);
        System.out.println("使用DH解密后的數據是:"+new String(result));
        
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }

}

具體實現的流程圖如下:

流程模板分析

1、甲方(消息發送方,下同)構建密鑰對(公鑰+私鑰),甲方公布公鑰給乙方(消息接收方,下同)

2、乙方以甲方發送過來的公鑰作為參數構造密鑰對(公鑰+私鑰),將構造出來的公鑰公布給甲方

3、甲方用“甲方的私鑰+乙方的公鑰”構造本地密鑰

4、乙方用“乙方的私鑰+甲方的公鑰”構造本地的密鑰

5、這個時候,甲乙兩方本地新構造出來的密鑰應該一樣。然后就可以使用AES這類對稱加密算法結合密鑰進行數據的安全傳送了。傳送過程參考AES的相關算法

DH加密算法較為復雜,進一步學習可以參考這篇博客
http://blog.csdn.net/kongqz/article/details/6302913

非對稱加密算法-RSA

  • 唯一廣泛接受并實現
  • 可用于數據加密&數字簽名
  • 公鑰加密,私鑰解密
  • 私鑰加密,公鑰解密

RSA長度和填充及是實現方式

具體實現:

package com.ztgeo.secret;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

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

import com.sun.org.apache.xml.internal.security.encryption.CipherData;

public class RSADemo {

private static String reqStr = "需要被加解密的字符串!!12345689";

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

public static void jdkRSA(){
    try {
    //1.初始化秘鑰  
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(512);
        //公鑰 私鑰
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
        RSAPrivateKey rasPrivateKey = (RSAPrivateKey)keyPair.getPrivate();
        System.out.println("公鑰:"+Base64.encodeBase64String(rsaPublicKey.getEncoded()));
        System.out.println("私鑰:"+Base64.encodeBase64String(rasPrivateKey.getEncoded()));
    //2.使用私鑰加密
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rasPrivateKey.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(reqStr.getBytes());
        System.out.println("RSA私鑰加密后的結果:"+Base64.encodeBase64String(result));
        
    //3.發送發 發送公鑰 接收方使用公鑰解密 密文  
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
        keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        result = cipher.doFinal(result);
        System.out.println("公鑰解密的結果是:"+new String(result));
        
    } catch (Exception e) {
        e.printStackTrace();
    }
    
}
}

公鑰加密.私鑰解密

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容