iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
0
Security

看完眼眶濕濕的App開發者慘烈對抗險惡資安環境血與淚的控訴!系列 第 19

Day 19. 對稱式加密演算法 - DES & 3DES

DES

數據加密標準(英語:Data Encryption Standard,縮寫為DES)是一種對稱密鑰加密塊密碼算法,1976年被美國聯邦政府的國家標準局確定為聯邦資料處理標準(FIPS),隨後在國際上廣泛流傳開來。它基於使用56位密鑰的對稱算法。這個算法因為包含一些機密設計元素,相對短的密鑰長度以及懷疑內含美國國家安全局(NSA)的後門而在開始時有爭議,DES因此受到了強烈的學院派式的審查,並以此推動了現代的塊密碼及其密碼分析的發展。

DES現在已經不是一種安全的加密方法,主要因為它使用的56位密鑰過短。1999年1月,distributed.net與電子前哨基金會合作,在22小時15分鐘內即公開破解了一個DES密鑰。也有一些分析報告提出了該算法的理論上的弱點,雖然在實際中難以應用。為了提供實用所需的安全性,可以使用DES的派生算法3DES來進行加密,雖然3DES也存在理論上的攻擊方法。在2001年,DES作為一個標準已經被高級加密標準(AES)所替換。另外,DES已經不再作為國家標準科技協會(前國家標準局)的一個標準。

資料來源:Wiki - DES

3DES

三重數據加密算法(英語:Triple Data Encryption Algorithm,縮寫為TDEA,Triple DEA),或稱3DES(Triple DES),是一種對稱密鑰加密塊密碼,相當於是對每個數據塊應用三次數據加密標準(DES)算法。由於計算機運算能力的增強,原版DES密碼的密鑰長度變得容易被暴力破解;3DES即是設計用來提供一種相對簡單的方法,即通過增加DES的密鑰長度來避免類似的攻擊,而不是設計一種全新的塊密碼算法。

資料來源:Wiki - DES

Note: 也有人會簡寫為 TDES

DES 已不是安全的演算法,容易被暴力破解,基於3DES 是緣由於DES 產生出來的設計,因此在這也在讓大家理解DES與 3DES 關連性。

3DES 簡易加密流程

image-20201004163732197

3DES 實際流程雖然是將 DES重覆三次,但並不是進行三次加密(加密—加密—加密) ,因此上圖流程是錯

正確的3DES 流程是使用 加密—解密—加密,大概是下圖這種感覺,這流程太難畫成圖解說明emoticon37.gif

image-20201004223845720

  • 第一把金鑰 - 加密
  • 第二把金鑰 - 解密
  • 第三把金鑰 - 加密

金鑰注意事項

DES密鑰的長度實質上是56bit,因此3DES的密鑰長度就是168bit (最長)

3DES 金鑰有三種使用模式

  1. 三個金鑰是獨立的。

    • 常用名稱為3TDEA或「三倍長度金鑰」(triple-length keys)
    • 強度最高,擁有3 x 56 = 168個獨立的金鑰位
  2. 兩把金鑰不同 (金鑰長度不足已棄用)

    • K1和K2是獨立的,而K3=K1。常用名稱為2TDEA,或「雙倍長度金鑰」
    • 雙重DES僅需要256步即可進行攻擊
  3. 三個金鑰均相等 (金鑰長度不足已棄用)

    • K1=K2=K3

    • 金鑰選項3等同與DES,只有56個金鑰位。跟DES 相容

安全性

有3個獨立金鑰的3DES 的金鑰長度為168位元(三個56位的DES金鑰),但由於中途相遇攻擊,它的有效安全性僅為112位元。

對於三個獨立金鑰,已知最佳攻擊需要約232組已知明文,2113部,290次DES加密以及288位記憶體。這在現在是不現實的,因此NIST認為金鑰選項1可以使用到2030年(這目前推算)

其餘兩種模式,都已證明不安全

使用 3DES

IOS

方法1 (swift)

pod 'SCrypto', '~> 2.0.0'
let plaintext = "咩".data(using: String.Encoding.utf8)!
let sharedSecretKey = "Secret key".data(using: String.Encoding.utf8)!
let IV = "0000000000000000".data(using: String.Encoding.utf8)!

let encrypted = try! plaintext.encrypt(.tripleDES, options: .PKCS7Padding, key: sharedSecretKey, iv: IV)     

let decrypted = try! ciphertext.decrypt(.tripleDES, options: .PKCS7Padding, key: sharedSecretKey, iv: IV)

方法2(obj-c)

採用舊版 CommonCrypto 套件

CommonCrypto 是由AlanQuatermain/aqtoolkit 移植出來的此為obj-c library 且最後更新 2013/3

pod 'CommonCrypto', '~> 1.1'

另外如果要在swift 需要人做好的 Swift wrapper 使用 https://github.com/alexaubry/Crypto 也是個不錯的選擇

NodeJS / ES6

const CryptoJS = require("crypto-js");

const message = "咩"
const key = "Secret key"

var encrypted = CryptoJS.TripleDES.encrypt(message, key);
var decrypted = CryptoJS.TripleDES.decrypt(encrypted, key);
console.log(`加密:${encrypted.toString()}`)
console.log(`解密:${decrypted.toString(CryptoJS.enc.Utf8)}`)

Android / JAVA

package com.qust;  
import java.io.UnsupportedEncodingException;  
import javax.crypto.Cipher;  
import javax.crypto.SecretKey;  
import javax.crypto.spec.SecretKeySpec;  
/** 
 *  
 * @ClassName: com.qust.SecretUtils 
 * @Description: 3DES加密解密工具類 
 * @author zhaokaiqiang 
 * @date 2014-11-13 下午11:28:14 
 *  
 */
publicclass DES3Utils {  
    // 定義加密演算法,DESede即3DES
    privatestaticfinal String Algorithm = "DESede";  
    // 加密金鑰
    privatestaticfinal String PASSWORD_CRYPT_KEY = "zhaokaiqiang1992";  
    /** 
     * 加密方法 
     *  
     * @param src 
     *            源資料的位元組陣列 
     * @return 
     */
    publicstaticbyte[] encryptMode(byte[] src) {  
        try {  
            // 生成金鑰
            SecretKey deskey = new SecretKeySpec(  
                    build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);  
            // 例項化Cipher
            Cipher cipher = Cipher.getInstance(Algorithm);  
            cipher.init(Cipher.ENCRYPT_MODE, deskey);  
            return cipher.doFinal(src);  
        } catch (java.security.NoSuchAlgorithmException e1) {  
            e1.printStackTrace();  
        } catch (javax.crypto.NoSuchPaddingException e2) {  
            e2.printStackTrace();  
        } catch (java.lang.Exception e3) {  
            e3.printStackTrace();  
        }  
        returnnull;  
    }  
    /** 
     * 解密函式 
     *  
     * @param src 
     *            密文的位元組陣列 
     * @return 
     */
    publicstaticbyte[] decryptMode(byte[] src) {  
        try {  
            SecretKey deskey = new SecretKeySpec(  
                    build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);  
            Cipher c1 = Cipher.getInstance(Algorithm);  
            c1.init(Cipher.DECRYPT_MODE, deskey);  
            return c1.doFinal(src);  
        } catch (java.security.NoSuchAlgorithmException e1) {  
            e1.printStackTrace();  
        } catch (javax.crypto.NoSuchPaddingException e2) {  
            e2.printStackTrace();  
        } catch (java.lang.Exception e3) {  
            e3.printStackTrace();  
        }  
        returnnull;  
    }  
    /** 
     * 根據字串生成金鑰24位的位元組陣列 
     *  
     * @param keyStr 
     * @return 
     * @throws UnsupportedEncodingException 
     */
    publicstaticbyte[] build3DesKey(String keyStr)  
            throws UnsupportedEncodingException {  
        byte[] key = newbyte[24];  
        byte[] temp = keyStr.getBytes("UTF-8");  
        if (key.length > temp.length) {  
            System.arraycopy(temp, 0, key, 0, temp.length);  
        } else {  
            System.arraycopy(temp, 0, key, 0, key.length);  
        }  
        return key;  
    }  
}  
package com.qust;  
publicclass Main {  
    publicstaticvoid main(String[] args) {  
        String msg = "使用3DES對資料進行加密";  
        System.out.println("【加密前】:" + msg);  
        // 加密
        byte[] secretArr = DES3Utils.encryptMode(msg.getBytes());  
        System.out.println("【加密後】:" + new String(secretArr));  
        // 解密
        byte[] myMsgArr = DES3Utils.decryptMode(secretArr);  
        System.out.println("【解密後】:" + new String(myMsgArr));  
    }  
}  

踩坑

不同平台/語言運算出來的3DES 結果不同,這是最容易踩坑的地方

原因是每個3DES 大家會發現輸入參數通常只有一個,而不是三個參數,

library 會輸入 的 String 擷取成三段做成三個獨立金鑰

如果輸入參數長度不夠,每個 library 填充的方式都不一樣,有的會重覆原本之前資料,有些會補0

所以需要注意這個問題

有興趣可以參考 swift - 3DES加密结果与示例不同

小結

介紹了 DES 以及 3DES 歷史、簡單流程、加密方式以及如何使用,以前DES / 3DES 使用的非常的廣泛

但由於電腦效能不斷提昇,金鑰限制是3DES的缺點,即便3DES 目前雖也還有人在使用但也慢慢即將退出密碼學這個舞台,很多密碼函式庫也會聲明不會支援DES 或 3DES 之類演算法

swift-crypto

Note that Swift Crypto does not intend to support all possible cryptographic primitives. Swift Crypto will focus on safe, modern cryptographic primitives that are broadly useful and that do not easily lend themselves to misuse. This means that some cryptographic algorithms may never be supported: for example, 3DES is highly unlikely to ever be supported by Swift Crypto due to the difficulty of safely deploying it and its legacy status. Please be aware when proposing the addition of new primitives to Swift Crypto that the proposal may be refused for this reason.

引用 Apple https://github.com/apple/swift-crypto

另外使用3DES 還有運算模式(Mode)以及填充模式(Padding) 就先不深入討論,後續再來聊聊有什麼差別

參考資料

https://www.coder.work/article/2371416

https://en.wikipedia.org/wiki/Triple_DES

https://en.wikipedia.org/wiki/DES


上一篇
Day 018. 聽起來好像很厲害的 - 密碼學
下一篇
Day 20. 對稱式加密演算法 - 大家都愛用的 AES
系列文
看完眼眶濕濕的App開發者慘烈對抗險惡資安環境血與淚的控訴!31

尚未有邦友留言

立即登入留言