1. 程式人生 > 其它 >一條SQL語句的執行計劃變化探究(r10筆記第3天)

一條SQL語句的執行計劃變化探究(r10筆記第3天)

一、概念

密碼學指的就是加密技術,通過加密技術我們可以將普通訊息轉換為難以理解的密文形式,解密就是相反的。

二、分類

加密一般分為對稱加密和非對稱加密。

  1. 對稱加密 - 使用相同的金鑰來對明文進行加密和對密文進行解密,可使用的演算法有AES、DES、3DES、Blowfish。對稱加密又可分為分組加密和流加密。

    • 分組加密 - 也叫作塊加密,將明文按一定的位長進行分組並進行必要的填充,對每一塊資料進行加密。明文組通過加密運算得到密文組,密文組通過解密得到原始明文組。
    • 流加密 - 一次加密明文中的一個位元組或字母。

    它比非對稱加密速度更快,更高效,通常用於批量加密或大量資料加密場景。但它涉及到大規模金鑰分配管理問題。

  2. 非對稱加密 - 傳送方使用公鑰進行加密,接收方使用私鑰進行解密。可使用的演算法為RSA、ECC。非對稱加密的缺點是加解密速度要遠遠慢於對稱加密,在某些極端情況下,甚至能比對稱加密慢上1000倍。優點是安全性更高,公鑰是公開的,祕鑰是自己儲存的,不需要將私鑰給別人

三、分組加密的模式

3.1. 電子密碼本(ECB)

ECB模式全稱是Electronic CodeBook模式,ECB模式非常簡單,就是將明文按照固定長度進行分塊,對不足長度的分塊進行填充,最後將每塊加密後的資料按照順序連線在一起即可。

特點:

這種模式的優點就是簡單,有利於平行計算,誤差不會被傳送。缺點就是ECB會將相同的純文字塊加密為相同的密文塊,因此無法很好地隱藏資料模式。不建議將ECB用於加密協議。

當使用ECB模式對使用大面積均勻顏色的點陣圖影象進行加密時,可以看到ECB可以在密文中保留明文資料模式的程度的一個顯著示例。在對每個畫素的顏色進行加密的同時,仍可以識別出整個影象,因為原始畫素中相同顏色的畫素的模式仍保留在加密版本中。

3.2. 密文分組連結模式(CBC)

CBC模式的全稱是Cipher Block Chaining模式(密文分組連結模式),之所以叫這個名字,是因為密文分組像鏈條一樣相互連線在一起。在CBC模式下,每個明文塊在加密之前均與先前的密文塊進行異或,這樣,每個密文塊都取決於到該點為止已處理的所有明文塊,它的實現機制使加密的各段資料之間有了聯絡。為了使每個訊息都是唯一的,必須在第一個塊中使用初始化向量。

特點:

不容易主動攻擊,安全性好於ECB,缺點是加密是順序的不能並行化計算。

3.3. 密文反饋模式(CFB)

CFB模式全稱Cipher FeedBack模式(密文反饋模式)。在CFB模式中,前一個密文分組會被送回到密碼演算法的輸入端。所謂反饋,這裡指的就是返回輸入端的意思。此模式類似於CBC,可以將塊密碼變為自同步的流密碼;工作過程亦非常相似,CFB的解密過程幾乎就是顛倒的CBC的加密過程


特點

和CBC相比,不需要將訊息填充為密碼塊大小的倍數。

3.4. 輸出反饋模式(OFB)

OFB模式的全稱是output-Feedback模式(輸出反饋模式)。在OFB模式中,密碼演算法的輸出會反饋到密碼演算法的輸入中。

OFB模式不是通過密碼演算法對明文直接加密的,而是通過將“明文分組”和“密碼演算法的輸出”進行XOR來產生“密文分組”的。

OFB模式和CFB模式的區別僅僅在於密碼演算法的輸入。

CFB模式中,密碼演算法的輸入是前一個密文分組,也就是將密文分組反饋到密碼演算法中,因此有了“密文反饋演算法”這個名字。

OFB模式中,密碼演算法的輸入則是密碼演算法前一個輸出,也就是將輸出反饋給密碼演算法,因此就有了“輸出反饋模式”這個名字。

3.5. 計數器模式(CTR)

CTR模式全稱CounTeR模式(計數器模式)。CTR模式是一種通過將逐次累加的計數器進行加密來生成金鑰流的流密碼。

最後我們通過一張加密舉例示意圖來看看Java中如何實現這幾種分組模式,在Java中將加解密從分組模式中剝離開來,完全交給SymmetricCipher進行加解密操作:

四、Cipher

此類安全API為應用程式提供了加解密服務,它必須制定一個演算法名稱,此演算法名稱包含了加解密演算法名稱、分組模式名稱、以及填充方案,例如AES/CBC/NoPadding、AES/CBC/PKCS5Padding、AES/ECB/ISO10126Padding,以反斜槓為分隔符,每部分說明如下:

  • 第一個為演算法名稱,常用的分組加解密演算法有AES、DES、DESede、Blowfish等,這個演算法名稱應用程式必須給出明確的值

  • 第二個為分組密碼的模式,可以不指定(預設為ECB模式)

  • 第三個為填充方案,可以不指定(預設為PKCS5Padding)。

    NoPadding-不填充;

    PKCS5Padding-使用PKCS5規則進行填充,即使用固定值進行填充;

    ISO10126Padding-使用ISO10126規則進行填充,即使用SecureRandom來產生安全隨機數進行填充。

然後我們在使用Cipher進行加密或解密前,需要呼叫init進行初始化操作,目的是為了讓服務知道本次操作模式是加密還是解密、加解密的金鑰、以及分組密碼使用的初始化向量IV。對於操作模式有以下幾種型別:

  • ENCRYPT_MODE - 加密模式
  • DECRYPT_MODE - 解密模式
  • WRAP_MODE - 對某一個金鑰進行加密
  • UNWRAP_MODE - 對某一個金鑰進行解密
  1. 加解密的粗略使用:
// 建立一個AES金鑰
KeyGenerator kg = KeyGenerator.getInstance("AES");
SecretKey key = kg.generateKey();

// 原文
byte[] a = new byte[] {43,21,122, 124,5,3,64,3,1,34,65,12, 5, 4,3,21,13,31,6};

// 構建Cipher服務例項
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

// 加密前進行初始化操作
cipher.init(Cipher.ENCRYPT_MODE, key);
// 得到加密後的資料
byte[] b1 =  cipher.doFinal(a);

// 解密時需要加密相同的初始化向量IV
byte[] iv = cipher.getIV();
// 解密前進行初始化操作
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
// 對加密的資料進行解密,最終得到解密後的資料
byte[] b2 = cipher.doFinal(b1);

// 判斷解密後的資料和原文是否一致
System.out.println(Arrays.equals(b2, a));
  1. 重要的api說明:
/**
 * 加密或解密前進行初始化操作,用於設定當前服務是加密還是解密,同時初始化當前加解密所需的金鑰。注意
 * 如果是分組解密,則同時需要設定加密時相同的初始化向量IV。
 *
 * @param 宣告本次服務是加密還是解密
 * @param 加解密所需的金鑰
 * @exception InvalidKeyException 
 * @throws UnsupportedOperationException
 */
public final void init(int opmode, Key key);

/**
 * 更新輸入要加解密的資料,然後返回加解密後的資料。此方法將會對符合分塊大小的資料進行加解密操作,然後將不足分塊大小的最後一塊
 * 資料放入快取中,等待下一次進行update或doFinal時在繼續處理。
 *
 * @param 本次輸入的加解密資料
 * @return 基於本次輸入資料,進行加解密後的資料。如果本次輸入資料小於分塊大小,會返回空的陣列,因為所有資料已快取
 * @exception IllegalStateException if this cipher is in a wrong state
 * (e.g., has not been initialized)
 */
public final byte[] update(byte[] input);

/**
 * 進行最終的加解密操作,對遺留在快取的資料、本次輸入的資料進行最終加解密操作,此過程也會進行填充操作(如果應用程式指定了的話),
 * 然後返回加解密後的資料,本方法呼叫後會進行重置操作,可以使用本例項繼續進行加密或解密
 *
 * @param 本次輸入的加解密資料
 * @return 基於本次輸入資料,進行加解密後的資料。如果本次輸入資料和快取中沒有任何資料,那麼將會填充整個分塊大小的資料然後進行加解密
 * @exception IllegalStateException 
 * @exception IllegalBlockSizeException 
 * @exception BadPaddingException
 * @exception AEADBadTagException 
 */
public final byte[] doFinal(byte[] input);

/**
 * 對金鑰進行加密操作,返回加密後的資料
 *
 * @param 待加密的金鑰
 * @return 加密後的資料
 * @exception IllegalStateException 
 * @exception IllegalBlockSizeException 
 * @exception InvalidKeyException 
 * @throws UnsupportedOperationException 
 */
public final byte[] wrap(Key key);

/**
 * 對已加密的資料進行解密,然後得到相關的金鑰實體物件Key
 *
 * @param 已加密的資料
 * @param 金鑰的演算法名稱
 * @param 金鑰的型別,例如對稱金鑰、私鑰、公鑰。SECRET_KEY;PRIVATE_KEY;PUBLIC_KEY
 *
 * @return 相關的金鑰實體物件Key
 * @exception IllegalStateException 
 * @exception NoSuchAlgorithmException
 * @exception InvalidKeyException
 * @throws UnsupportedOperationException
 */
public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType);