亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用數(shù)字簽名實現(xiàn)數(shù)據(jù)庫記錄防篡改(Java實現(xiàn))

 更新時間:2017年01月25日 08:26:25   作者:小小Prince  
本文主要介紹了Java中使用數(shù)字簽名實現(xiàn)數(shù)據(jù)庫記錄防篡改的方法與步驟。具有很好的參考價值,下面跟著小編一起來看下吧

本文大綱

一、提出問題

二、數(shù)字簽名

三、實現(xiàn)步驟

四、參考代碼

五、后記

六、參考資料

一、提出問題

最近在做一個項目,需要對一個現(xiàn)成的產(chǎn)品的數(shù)據(jù)庫進行操作,增加額外的功能。為此,需要對該產(chǎn)品對數(shù)據(jù)庫有什么操作進行研究(至于怎么監(jiān)控一個產(chǎn)品的操作會引發(fā)什么數(shù)據(jù)庫操作,以后會詳細解說)。本來已經(jīng)對數(shù)據(jù)庫的操作了如指掌的,無意中發(fā)現(xiàn)數(shù)據(jù)庫表里的每條記錄都會有這樣一個字段:

這感覺不妙了,字段名叫signature,顧名思義,就是簽名的意思呀。難道數(shù)據(jù)庫表中的每條記錄都會有簽名?也就是說如果我不能正確生成簽名,而直接改記錄中的字段,會被程序認為非法篡改了數(shù)據(jù)?那以后我的產(chǎn)品設(shè)計,是否也可采用這種方式來對每條記錄做簽名,防止數(shù)據(jù)被非法篡改,例如日志表中的數(shù)據(jù)?抱著這一發(fā)現(xiàn)以及這一連串的問題,我進行了以下的研究。在這里我將研究整理了一下,分享給大家。

二、數(shù)字簽名

要解決上面的問題,首先就要對最基礎(chǔ)的知識進行了解。這里最基礎(chǔ)的知識,無疑就是什么是數(shù)字簽名了。很多同學(xué)可能對這個名詞并不陌生,但估計大多數(shù)人都是對其一知半解,會把散列、非對稱加密、數(shù)字簽名、數(shù)字證書的幾個概念混為一談,造成混亂。所以我先對相關(guān)概念進行解釋,再往下講。如果很熟悉這方面的同學(xué)可以跳過此部分,但對于絕大多數(shù)同學(xué)來說,不建議這樣做?;A(chǔ)沒搭好,直接看怎么實現(xiàn),換了個說法又不知道怎么去做了。要想提高個人能力,做到舉一反三很重要。

言歸正傳,先對跟數(shù)字簽名有關(guān)的密碼學(xué)知識簡單說一下。加密方法分兩大類,分別是單鑰加密和雙鑰加密,數(shù)字簽名涉及到雙鑰加密。關(guān)于雙鑰加密,主要涉及到以下幾個要點[1]:

  • 雙鑰加密的密鑰有兩把,一把是公開的公鑰,一把是不公開的私鑰
  • 公鑰和私鑰是一一對應(yīng)的關(guān)系,有一把公鑰就必然有一把與之對應(yīng)的、獨一無二的私鑰,反之亦成立。
  • 所有的(公鑰, 私鑰)對都是不同的。
  • 用公鑰可以解開私鑰加密的信息,反之亦成立。
  • 同時生成公鑰和私鑰應(yīng)該相對比較容易,但是從公鑰推算出私鑰,應(yīng)該是很困難或者是不可能的。
  • 在雙鑰體系中,公鑰用來加密信息,私鑰用來數(shù)字簽名。
  • 還有一點關(guān)于數(shù)字證書的。因為任何人都可以生成自己的公鑰私鑰對,所以為了防止有人散布偽造的騙取信任,就需要一個可靠的第三方機構(gòu)來生成經(jīng)過認證的公鑰、私鑰對。簡單來說,數(shù)字證書是權(quán)威的第三方機構(gòu)頒發(fā)的,用來認證某對公鑰私鑰的證書,經(jīng)過這個數(shù)字證書認證的公鑰私鑰,就可以明確屬于某人或者某機構(gòu),是合法的,可信任的。就如同身份證,是證明你身份的一個證件。所以數(shù)字證書跟數(shù)字簽名是兩回事,要分清楚。

數(shù)字簽名,顧名思義,就類似于一種寫在紙上的普通的物理簽名,不同的是,數(shù)字簽名是電子信息化的,采用雙鑰加密的技術(shù)實現(xiàn),是一種用于鑒別數(shù)字信息的方法。處理的過程,簡單說就是將文件內(nèi)容進行hash散列,信息發(fā)送者對散列后的字符串使用私鑰加密,得到的最終字符串就是簽名。然后將得到的簽名字符串添加到文件信息的后面一同發(fā)送出去。接收者獲取到文件信息和簽名后,使用公鑰對簽名進行解密,就得到文件內(nèi)容加密后的hash散列。此時,他可以對獲取到的文件內(nèi)容做hash散列,與簽名中的hash散列進行匹對,從而鑒別出最終獲取信息的真?zhèn)?。主要過程如這四幅圖所示[2]:

對文件內(nèi)容進行hash散列,生成摘要

對生成的摘要,使用私鑰進行加密,形成簽名

將得到的簽名,附到文件內(nèi)容后部,就想到與簽名簽到文件尾部那樣子

使用公鑰對簽名進行解密,得到摘要,并與獲取到的文件內(nèi)容生成的摘要做對比,以確定是否被篡改

想了解更詳細的數(shù)字證書相關(guān)內(nèi)容,可以訪問此地址:http://www.youdzone.com/signature.html。里面解釋得很形象,應(yīng)該一看就明白的了。

三、實現(xiàn)步驟

看到這里,開篇提出的問題也就呼之欲出了。沒錯,就是使用數(shù)字簽名技術(shù),將數(shù)據(jù)庫中的重要字段進行簽名,將簽名結(jié)果作為記錄的一列存在記錄中。這樣當有人入侵數(shù)據(jù)庫,惡意修改字段,程序讀數(shù)據(jù)時拿簽名校驗一下,就知道數(shù)據(jù)是否有被修改過了。

在java.security包中,有很多有用的類,用以進行安全機制的開發(fā)。對于要創(chuàng)建數(shù)字簽名,我們主要用到以下的接口或類:

接口名

描述

PrivateKey

A private key

PublicKey

A public key

接口

 類名

描述

Signature

The Signature class is used to provide applications the functionality of a digital signature algorithm.

KeyPair

This class is a simple holder for a key pair (a public key and a private key)

KeyPairGenerator

The KeyPairGenerator class is used to generate pairs of public and private keys.

對于接口和類的描述,我直接引用了Oracle上的J2SE 7的API描述[3],就不翻譯成中文了,以防詞不達意。大家看英文應(yīng)該能更精確的明白其意思。

利用上述的接口和類,就可以進行數(shù)字簽名和驗證了,下面分三部分進行基本步驟的描述。

第一部分:生成密鑰并存儲

  • 生成KeyPairGenerator實例,并調(diào)用其genKeyPair()方法生成KeyPair對象。
  • 利用ObjectOutputStream實例,將KeyPair對象寫到文件中,從而把密鑰保存到文件中。

第二部分:進行數(shù)字簽名

  • 從密鑰文件中讀取KeyPair對象。
  • 調(diào)用KeyPair對象的getPrivate()和getPublic()方法,分別獲取PrivateKey和PublicKey。
  • 利用密鑰的指定算法生成Signature實例,然后利用PrivateKey和文件內(nèi)容,分別調(diào)用其initSign()和update()方法,最后調(diào)用sign()方法生成數(shù)字簽名。

第三部分:進行簽名驗證

  • 從密鑰文件中讀取KeyPair對象。
  • 調(diào)用KeyPair對象的getPrivate()和getPublic()方法,分別獲取PrivateKey和PublicKey。
  • 利用密鑰的指定算法生成Signature實例,然后利用PublicKey和文件內(nèi)容,分別調(diào)用其initSign()和update()方法,最后利用數(shù)字簽名調(diào)用verify()方法驗證簽名。

四、參考代碼

根據(jù)上面的步驟描述,基本可以寫出程序來了。下面是參考代碼,未必盡善盡美,但是基本功能都體現(xiàn)到了,供你參考。

工程結(jié)構(gòu):

DataSecurity類:

package com.hzj.security;
import java.io.UnsupportedEncodingException;
import java.nio.charset.CharsetEncoder;
import java.security.KeyPair;
import com.hzj.util.StringHelper;
public class DataSecurity {
 private KeyPair keyPair;
 private static final String KEY_FILE = "/ca.key";
 private DataSignaturer dataSignaturer;
 public DataSecurity() {
 try {
 this.keyPair = KeyPairUtil.loadKeyPair(getClass().getResourceAsStream("/ca.key"));
 this.dataSignaturer = new DataSignaturer(this.keyPair.getPublic(), this.keyPair.getPrivate());
 } catch (RuntimeException e) {
 System.out.println("沒有找到KeyPair文件[/ca.key]!");
 }
 }
 /**
 * 驗證數(shù)字簽名
 * @param data
 * @param signs
 * @return
 */
 public boolean verifySign(String data, String signs) {
 if ((data == null) || (signs == null)) {
 System.out.println("參數(shù)為Null");
 }
 boolean verifyOk = false;
 try {
 verifyOk = this.dataSignaturer.verifySign(data.getBytes("UTF-8"), StringHelper.decryptBASE64(signs));
 } catch (RuntimeException e) {
 System.out.println("fail!data=" + data + ", sign=" + signs + ", exception:" + e.getMessage());
 } catch (UnsupportedEncodingException e) {
 System.out.println("不支持UTF-8字符集");
 } catch (Exception e) {
 System.out.println("Exception:" + e.getMessage());
 }
 if (!verifyOk) {
 System.out.println("fail!data=" + data + ", sign=" + signs + ", verifyOk=false!");
 }
 return verifyOk;
 }
 /**
 * 生成數(shù)字簽名
 * @param data
 * @return
 */
 public String sign(String data)
 {
 if (data == null) {
 System.out.println("參數(shù)為Null");
 }
 String sign = null;
 try
 {
 sign = StringHelper.encryptBASE64(this.dataSignaturer.sign(data.getBytes("UTF-8")));
 }
 catch (UnsupportedEncodingException e)
 {
 System.out.println("不支持UTF-8字符集");
 }
 catch (Exception e)
 {
 System.out.println(e.getMessage());
 }
 return sign;
 }
 }

DataSignaturer類:

package com.hzj.security;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
public class DataSignaturer {
 private PrivateKey privateKey;
 private PublicKey publicKey;
 public DataSignaturer(PublicKey publicKey, PrivateKey privateKey){
 this.privateKey = privateKey;
 this.publicKey = publicKey;
 }
 /**
 * 進行數(shù)字簽名
 * @param data
 * @return
 */
 public byte[] sign(byte[] data) {
 if (this.privateKey == null) {
 System.out.println("privateKey is null");
 return null;
 }
 Signature signer = null;
 try {
 signer = Signature.getInstance(this.privateKey.getAlgorithm());
 } catch (NoSuchAlgorithmException e) {
 System.out.println(e.getMessage());
 }
 try {
 signer.initSign(this.privateKey);
 } catch (InvalidKeyException e) {
 System.out.println(e.getMessage());
 }
 try {
 signer.update(data);
 return signer.sign();
 } catch (SignatureException e) {
 System.out.println(e.getMessage());
 return null;
 } catch (NullPointerException e) {
 System.out.println(e.getMessage());
 return null;
 }
 }
 /**
 * 驗證數(shù)字簽名
 * @param data
 * @param signature
 * @return
 */
 public boolean verifySign(byte[] data, byte[] signature) {
 if (this.publicKey == null) {
 System.out.println("publicKey is null");
 return false;
 }
 Signature signer = null;
 try {
 signer = Signature.getInstance(this.publicKey.getAlgorithm());
 } catch (NoSuchAlgorithmException e) {
 System.out.println(e.getMessage());
 return false;
 }
 try {
 signer.initVerify(this.publicKey);
 } catch (InvalidKeyException e) {
 System.out.println(e.getMessage());
 return false;
 }
 try {
 signer.update(data);
 return signer.verify(signature);
 } catch (SignatureException e) {
 System.out.println(e.getMessage());
 return false;
 }
 }
}

KeyPair類:

package com.hzj.security;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
public class KeyPairUtil {
 // 采用的雙鑰加密算法,既可以用DSA,也可以用RSA
 public static final String KEY_ALGORITHM = "DSA";
 /**
 * 從輸入流中獲取KeyPair對象
 * @param keyPairStream
 * @return
 */
 public static KeyPair loadKeyPair(InputStream keyPairStream) {
 if (keyPairStream == null) {
 System.out.println("指定的輸入流=null!因此無法讀取KeyPair!");
 return null;
 }
 try {
 ObjectInputStream ois = new ObjectInputStream(keyPairStream);
 KeyPair keyPair = (KeyPair) ois.readObject();
 ois.close();
 return keyPair;
 } catch (Exception e) {
 System.out.println(e.getMessage());
 }
 return null;
 }
 /**
 * 將整個KeyPair以對象形式存儲在OutputStream流中, 當然也可以將PublicKey和PrivateKey作為兩個對象分別存到兩個OutputStream流中,
 * 從而私鑰公鑰分開,看需求而定。
 * @param keyPair 公鑰私鑰對對象
 * @param out 輸出流
 * @return
 */
 public static boolean storeKeyPair(KeyPair keyPair, OutputStream out) {
 if ((keyPair == null) || (out == null)) {
 System.out.println("keyPair=" + keyPair + ", out=" + out);
 return false;
 }
 try {
 ObjectOutputStream oos = new ObjectOutputStream(out);
 oos.writeObject(keyPair);
 oos.close();
 return true;
 } catch (FileNotFoundException e) {
 System.out.println(e.getMessage());
 } catch (IOException e) {
 System.out.println(e.getMessage());
 }
 return false;
 }
 /**
 * 生成KeyPair公鑰私鑰對
 * 
 * @return
 */
 public static KeyPair initKeyPair() throws NoSuchAlgorithmException{
 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
 keyPairGen.initialize(1024);
 return keyPairGen.genKeyPair();
 }
 /**
 * 生成密鑰,并存儲
 * @param out
 * @return
 * @throws NoSuchAlgorithmException
 */
 public static boolean initAndStoreKeyPair(OutputStream out) throws NoSuchAlgorithmException {
 return storeKeyPair(initKeyPair(), out);
 }
}

StringHelper類:

package com.hzj.util;
import sun.misc.BASE64Encoder;
import sun.misc.BASE64Decoder;
public class StringHelper {
 /** 
 * BASE64Encoder 加密 
 * @param data 要加密的數(shù)據(jù) 
 * @return 加密后的字符串 
 */ 
 public static String encryptBASE64(byte[] data) { 
 BASE64Encoder encoder = new BASE64Encoder(); 
 String encode = encoder.encode(data); 
 return encode; 
 } 
 /** 
 * BASE64Decoder 解密 
 * @param data 要解密的字符串 
 * @return 解密后的byte[] 
 * @throws Exception 
 */ 
 public static byte[] decryptBASE64(String data) throws Exception { 
 BASE64Decoder decoder = new BASE64Decoder(); 
 byte[] buffer = decoder.decodeBuffer(data); 
 return buffer; 
 } 
}

Program類:

package com.hzj.main;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.security.NoSuchAlgorithmException;
import com.hzj.security.DataSecurity;
import com.hzj.security.KeyPairUtil;
public class Program {
 public static void main(String[] args) {
 // 1.生成證書
// File file = new File("ca.key");
// try {
// FileOutputStream fileOutputStream = new FileOutputStream(file);
// KeyPairUtil.initAndStoreKeyPair(fileOutputStream);
// } catch (FileNotFoundException | NoSuchAlgorithmException e) {
// e.printStackTrace();
// }
 // 2.生成數(shù)字簽名
// DataSecurity dataSecurity = new DataSecurity();
// String sign = dataSecurity.sign("大家好");
// System.out.println("sign:" + sign);
 //3.驗證數(shù)字簽名
 DataSecurity dataSecurity = new DataSecurity();
 boolean result = dataSecurity.verifySign("大家好", "MCwCFCDs3sBw/fXK9flndl0M5lAUiPYFAhR9vyNNc91UiUBxFwK3GzLLjWgTkQ==");
 System.out.println("result:" + result);
 }
}

這里需要注意的是,為什么要對數(shù)字簽名進行進行Base64編碼呢?這是因為生成的數(shù)字簽名是byte[]型的,無論對應(yīng)哪一種字符集來轉(zhuǎn)化成String,都會有亂碼出現(xiàn)。所以,采用Base64進行編碼,就可以得到一串可見的字符串,方便存儲和重新調(diào)用。

五、后記

寫到這里,本文的內(nèi)容就基本上完結(jié)了。有人看到這里就會問,這不是說數(shù)據(jù)庫記錄防篡改嘛,一直都在講數(shù)字簽名,究竟怎么個防篡改?前文已經(jīng)對數(shù)字簽名的一些基本原理,使用的場景,開發(fā)的步驟、代碼等進行了描述,開篇是也描述了項目中遇到的數(shù)據(jù)庫中的問題。將這些信息綜合起來,應(yīng)該就知道怎么將數(shù)字簽名應(yīng)用到數(shù)據(jù)庫記錄中來作為數(shù)據(jù)庫防篡改的工具了。知道工具怎么用是基礎(chǔ),會用工具來完成自己想做的事情,就是進階了。祝你步步高升!

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!

相關(guān)文章

  • C#實現(xiàn)表格數(shù)據(jù)轉(zhuǎn)實體的示例代碼

    C#實現(xiàn)表格數(shù)據(jù)轉(zhuǎn)實體的示例代碼

    在實際開發(fā)過程中,特別是接口對接之類的,對于這種需求是屢見不鮮,現(xiàn)在很多在線平臺也都提供了像json轉(zhuǎn)實體、sql轉(zhuǎn)實體等。本文將用C#實現(xiàn)這一功能,需要的可以參考一下
    2022-09-09
  • 同步調(diào)用和異步調(diào)用WebService

    同步調(diào)用和異步調(diào)用WebService

    本文給大家介紹webservice同步調(diào)用和異步調(diào)用,同步調(diào)用就是一個同步操作會阻塞整個當前的進程,直到這個操作完成才能執(zhí)行下一段代碼,異步調(diào)用不會阻塞啟動操作的調(diào)用線程,調(diào)用程序必須通過輪流檢測,或者等待完成信號來發(fā)現(xiàn)調(diào)用的完成。小伙伴們跟著小編一起學(xué)習(xí)
    2015-09-09
  • C#利用Windows自帶gdi32.dll實現(xiàn)抓取屏幕功能實例

    C#利用Windows自帶gdi32.dll實現(xiàn)抓取屏幕功能實例

    這篇文章主要介紹了C#利用Windows自帶gdi32.dll實現(xiàn)抓取屏幕功能,是C#程序設(shè)計中常見的一個重要技巧,需要的朋友可以參考下
    2014-08-08
  • C#文件流進行壓縮和解壓縮的方法

    C#文件流進行壓縮和解壓縮的方法

    這篇文章主要介紹了C#文件流進行壓縮和解壓縮的方法,涉及C#文件流操作的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • C#調(diào)用dll報錯:無法加載dll,找不到指定模塊的解決

    C#調(diào)用dll報錯:無法加載dll,找不到指定模塊的解決

    這篇文章主要介紹了C#調(diào)用dll報錯:無法加載dll,找不到指定模塊的解決問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 分享WCF文件傳輸實現(xiàn)方法---WCFFileTransfer

    分享WCF文件傳輸實現(xiàn)方法---WCFFileTransfer

    這篇文章主要介紹了分享WCF文件傳輸實現(xiàn)方法---WCFFileTransfer,需要的朋友可以參考下
    2015-11-11
  • C#中DataTable刪除行的方法分析

    C#中DataTable刪除行的方法分析

    這篇文章主要介紹了C#中DataTable刪除行的方法,包括了常見的幾種刪除方法的分析,需要的朋友可以參考下
    2014-09-09
  • C#使用NOPI庫實現(xiàn)導(dǎo)入Excel文檔

    C#使用NOPI庫實現(xiàn)導(dǎo)入Excel文檔

    NPOI中N指代的是.Net,POI是一個完全開源的Java寫成的庫,能夠在沒有安裝微軟Office或者相應(yīng)環(huán)境的情況下讀寫Excel、Word等微軟OLE2組件文檔,幾乎支持所有的Office97~Office2007的文件格式。所以NPOI就是POI項目的.Net版本。
    2017-05-05
  • c#中分割字符串的幾種方法

    c#中分割字符串的幾種方法

    c#中分割字符串的幾種方法...
    2007-04-04
  • C#雙緩沖技術(shù)實例詳解

    C#雙緩沖技術(shù)實例詳解

    這篇文章主要介紹了C#雙緩沖技術(shù),結(jié)合實例形式較為詳細的分析了C#雙緩沖的功能,實現(xiàn)技巧與相關(guān)注意事項,需要的朋友可以參考下
    2016-02-02

最新評論