Java安全密碼學-(七)數字簽名

簡介

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

 

基本原理

張三和AB寫郵件的時候爲了安全都需要加密。於是張三想到了數字簽名:

整個思路是這個樣子的:

第一步:加密採用非對稱加密,張三有三把鑰匙,兩把公鑰,送給朋友。一把私鑰留給自己。

第二步:A或者B寫郵件給張三:A先用公鑰對郵件加密,然後張三收到郵件之後使用私鑰解密。

第三步:張三寫郵件給A或者B:

(1)張三寫完郵件,先用hash函數生成郵件的摘要,附着在文章上面,這就完成了數字簽名,然後張三再使用私鑰加密。就可以把郵件發出去了。

(2)A或者是B收到郵件之後,先把數字簽名取下來,然後使用自己的公鑰解密即可。這時候取下來的數字簽名中的摘要若和張三的一致,那就認爲是張三發來的,再對信件本身使用Hash函數,將得到的結果,與上一步得到的摘要進行對比。如果兩者一致,就證明這封信未被修改過。

 

數字證書

上面提到我們對簽名進行驗證時,需要用到公鑰。如果公鑰是僞造的,那我們無法驗證數字簽名了,也就根本不可能從數字簽名確定對方的合法性了。這時候證書就閃亮登場了。我們可能都有考各種證書的經歷,比如說普通話證書,四六級證書等等,但是歸根結底,到任何場合我們都能拿出我們的證書來證明自己確實已經考過了普通話,考過了四六級。這裏的證書也是同樣的道理。

如果不理解證書的作用,我們可以舉一個例子,比如說我們的畢業證書,任何公司都會承認。爲什麼會承認?因爲那是國家發得,大家都信任國家。也就是說只要是國家的認證機構,我們都信任它是合法的。

 

網頁加密

我們看一個應用“數字證書”的實例:https協議。這個協議主要用於網頁加密

首先,客戶端向服務器發出加密請求。

服務器用自己的私鑰加密網頁以後,連同本身的數字證書,一起發送給客戶端。

客戶端(瀏覽器)的“證書管理器”,有“受信任的根證書頒發機構”列表。客戶端會根據這張列表,查看解開數字證書的公鑰是否在列表之內。

如果數字證書記載的網址,與你正在瀏覽的網址不一致,就說明這張證書可能被冒用,瀏覽器會發出警告。

如果這張數字證書不是由受信任的機構頒發的,瀏覽器會發出另一種警告。

如果數字證書是可靠的,客戶端就可以使用證書中的服務器公鑰,對信息進行加密,然後與服務器交換加密信息。

import java.security.*;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class SignatureDemo {
    public static void main(String[] args) throws Exception {
        String a = "123";

        PublicKey publicKey = RsaDemo.loadPublicKeyFromFile("RSA", "a.pub");
        PrivateKey privateKey = RsaDemo.loadPrivateKeyFromFile("RSA", "a.pri");

        String signaturedData = getSignature(a, "sha256withrsa", privateKey);

        boolean b = verifySignature(a, "sha256withrsa", publicKey, signaturedData);

    }

    /**
     * 生成簽名
     *
     * @param input      : 原文
     * @param algorithm  : 算法
     * @param privateKey : 私鑰
     * @return : 簽名
     * @throws Exception
     */
    private static String getSignature(String input, String algorithm, PrivateKey privateKey) throws Exception {
        // 獲取簽名對象
        Signature signature = Signature.getInstance(algorithm);
        // 初始化簽名
        signature.initSign(privateKey);
        // 傳入原文
        signature.update(input.getBytes());
        // 開始簽名
        byte[] sign = signature.sign();
        // 對簽名數據進行Base64編碼
        return Base64.encode(sign);
    }

    /**
     * 校驗簽名
     *
     * @param input          : 原文
     * @param algorithm      : 算法
     * @param publicKey      : 公鑰
     * @param signaturedData : 簽名
     * @return : 數據是否被篡改
     * @throws Exception
     */
    private static boolean verifySignature(String input, String algorithm, PublicKey publicKey, String signaturedData) throws Exception {
        // 獲取簽名對象
        Signature signature = Signature.getInstance(algorithm);
        // 初始化簽名
        signature.initVerify(publicKey);
        // 傳入原文
        signature.update(input.getBytes());
        // 校驗數據
        return signature.verify(Base64.decode(signaturedData));

    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章