1.2 密碼學及安全技術
1.2.1 密碼學知識
1.2.1.1 Hash函式
-
Hash(雜湊)
雜湊函式是一類數學函式,可以在有限合理的時間內,將任意長度的訊息壓縮為
固定長度的輸出值,並且是不可逆的。其輸出值稱為雜湊值,也稱為雜湊值。
-
雜湊演算法的應用:
訊息認證:確保收到的訊息和傳送的訊息都是未被篡改的。
數字簽名:對訊息摘要進行數字簽名與對訊息本身進行數字簽名等效。
口令的安全性:僅將口令的雜湊值進行儲存,進行口令檢驗時僅需對比雜湊值即可,即使攻擊者獲取了口令的雜湊值,也無法計算出口令。
資料完整性:具有抗資料篡改的能力。 -
Hash函式在區塊鏈中的應用
在區塊鏈系統中,雜湊演算法得到了廣泛的使用。
在區塊鏈系統中,區塊之間的連結就是透過區塊的雜湊值串聯起來的。除此以外,還有梅克爾樹的生成計算,交易事務的雜湊值計算等。
區塊鏈是一個使用雜湊指標構建的連結串列
-
Merkle tree
Merkle(默克爾)樹,又叫雜湊樹,是一種典型的二叉樹結構,由一個根節點、一組中間節點和一組葉節點組成
應用場景:
快速比較大量資料
快速定位修改
1.2.1.2橢圓曲線加密演算法
即:Elliptic Curve Cryptography,簡稱ECC,是基於橢圓曲線數學理論實現的一種非對稱加密演算法。 相比RSA,ECC優勢是可以使用更短的金鑰,來實現與RSA相當或更高的安全。據研究,160位ECC加密安全性相當於1024位RSA加密,210位ECC加密安全性相當於2048位RSA加密。
1.2.2 安全技術
1.2.2.1 數字簽名
用於防止訊息篡改和抵賴的場景
數字簽名基於非對稱加密,既可以用於證實內容的完整性,又同時可以確 認來源(或不可抵賴,Non-Repudiation)。
數字簽名的全過程分兩大部分,即簽名與驗證。一側為簽名,一側為驗證 過程。
1.2.2.2 數字證照
1.2.2.3 PKI體系
1.2.2.4 同態加密
本質上,同態加密是指這樣一種加密函式,對明文進行環上的加法和乘法運算再加密,與加密後對密文進行相應的運算,結果是等價的。由於這個良好的性質,人們可以委託第三方對資料進行處理而不洩露資訊。具有同態性質的加密函式是指兩個明文a、b滿足Dec(En(a)⊙En(b))=a⊕b的加密函式,其中En是加密運算,Dec是解密運算,⊙、⊕分別對應明文和密文域上的運算。當⊕代表加法時,稱該加密為加同態加密:當⊕代表乘法時,稱該加密為乘同態加密。
全同態加密是指同時滿足加同態和乘同態性質,可以進行任意多次加和乘運算的加密函式。用數學公式來表達,即Dec(f(En(m1),En(m2),…,En(mk)))=f(m1,m2,…,mk),或寫成:f(En(m1),En(m2),…,En(mk))=En(f(m1,m2,…,mk)),如果f是任意函式,稱為全同態加密。
1.2.2.5 布隆過濾器
class BloomHash {
/**
* Hash工具類返回的hashcode的最大長度<br>
* maxLength為2的n次方,返回的hashcode為[0,2^n-1]
*/
public int maxLength;
// Hash函式生成雜湊碼的關鍵字
public int seed;
public BloomHash(int maxLength, int seed) {
this.maxLength = maxLength;
this.seed = seed;
}
/**
* 返回字串string的hashcode,大小為[0,maxLength-1]
*
* @param string
* @return
*/
public int hashCode(String string) {
int result = 0;
// 這個構建hashcode的方式類似於java的string的hashcode方法
// 只是我這裡是可以設定的seed,它那裡是31
for (int i = 0; i < string.length(); i++) {
char a = string.charAt(i);
int b = seed * a; // 隱式的把字元轉換為整數(ASSIC碼)
result = result + b;
}
/**
* public static int indexFor(int m, int n){ return m & (n - 1); } public static
* void main(String[] args) { System.out.println("19 與 16 求餘 = "+ indexFor(19,
* 16) ); System.out.println("19 與 16 求餘 = "+ 19 % 16 ); }
* 此方法中n為2的指數值,則其二進位制形式的表示中只存在一個1,其餘位都為0, 例如: 0000 1000、0100 0000、0010
* 0000等等。則n-1的二進位制形式就為1的位數變為0, 其右邊位全變為1,例如16的二進位制 0001 0000 -1 = 0000
* 1111測試m為19的二進位制 0001 0011 & 0000 1111 = 0000 0011 = 3,地位保留的結果便是餘數。此位運算也是
* HashMap中確定元素鍵(key)值所在雜湊陣列下標位置的核心方法,此位運算(hash & (length - 1)) 的效率極高於hash %
* length的求餘, 所以也解釋為什麼HashMap的擴容始終為2的倍數(2的指數值)。
*/
// 保證結果在[0,maxLength-1]:equal to 'result % maxLength'
return result & (maxLength - 1);
}
}
public class BloomFilter {
// 構建hash函式的關鍵字,總共7個
private static final int[] HashSeeds = new int[] { 3, 5, 7, 11, 13, 17, 19 };
// Hash工具類的陣列
private static BloomHash[] HashList = new BloomHash[HashSeeds.length];
// BloomFilter的長度,最好為插入數量的10倍,目前為2的20次方,大約100萬個
private static final int BloomLength = 1 << 20;
// 對位的操作類,java自帶的BitSet,共BloomLength個bit
private BitSet bitSet = new BitSet(BloomLength);
public BloomFilter() {
// 初始化Hash工具類的陣列,每個hash工具類的hash函式都不同
for (int i = 0; i < HashSeeds.length; i++) {
HashList[i] = new BloomHash(BloomLength, HashSeeds[i]);
}
}
/**
* 在布隆過濾器中加入值value,在多個hash函式生成的hashcode對應的位置上,置1
*
* @param value字串,如果為數字,可以自己轉化成string
*/
public void addValue(String value) {
for (int i = 0; i < HashSeeds.length; i++) {
// 根據對應的hash函式得到hashcode
int hashcode = HashList[i].hashCode(value);
// 在點陣圖中,將對應的位,設定為1
bitSet.set(hashcode);
}
}
/**
* 在布隆過濾器中,檢驗是否可能有值value
*
* @param value
* @return 如果返回false,則一定沒有<br>
* 如果返回true,就代表有可能有
*/
public boolean existsValue(String value) {
boolean result = true;
for (int i = 0; i < HashSeeds.length; i++) {
// 根據對應的hash函式得到hashcode
int hashcode = HashList[i].hashCode(value);
/**
* 隱式把boolean轉換為整數進行按位與運算 “短路” 主要用於邏輯運算子中,即 “ ! && || "這三種運算子 短路 就是知如果左側的
* 表示式能確定運算後的結果,則不再計算右側的表示式。 如(1>2)&&(2<3) 明明左側已經為假 了 我 不用計算右側我一定知道 此表達是為假
*/
// 將result與對應位置上的0或1 做與運算
// 如果全為1,則result最後為1
// 如果有一個位置上為0,則最後result為0
result = result & bitSet.get(hashcode);
}
return result;
}
}