--- title : 13_EZAES --- # EZAES by WL, Liu Date : 2021-10-22 --- ## 壹、簡介 此程式碼包括加密與解密功能,主要目標為執行配置所需配置,包括加密區塊大小、初始向量、產生金鑰物件,然後進行加密,本程式碼利用函式庫BCrypt中的AES進行撰寫。 ## 標頭檔 ```cpp= #pragma once #include <Windows.h> #include <bcrypt.h> class EZAES { BCRYPT_HANDLE m_hProv; BCRYPT_KEY_HANDLE m_hKey; ULONG m_cbBlock; PUCHAR m_pbIV; ULONG m_cbIV; PUCHAR m_pbKeyObject; ULONG m_cbKeyObject; ``` * 第8行,演算提供者之handle。 * 第9行,金鑰的handle。 * 第10行,區塊大小。 * 第11行,初始向量的記憶體位置。 * 第12行,初始向量的記憶體大小。 * 第13行,金鑰的記憶體位置。 * 第14行,金鑰的記憶體大小。 ```cpp=15 public: EZAES(); ~EZAES(); BOOL GenKey(PUCHAR, ULONG); BOOL Init(); BOOL Encrypt(PUCHAR, ULONG, PUCHAR, ULONG, PULONG); BOOL Decrypt(PUCHAR, ULONG, PUCHAR, ULONG, PULONG); }; typedef EZAES* PEZAES; ``` * 第18行,產生金鑰。 * 第20行,執行加密。 * 第21行,執行解密。 ## 主程式 ```cpp= #include "EZAES.h" #include "../config.h" #include <bcrypt.h> #pragma comment(lib, "Bcrypt.lib") ``` ### 開始加密 ```cpp=6 EZAES::EZAES() { m_hProv = INVALID_HANDLE_VALUE; m_hKey = INVALID_HANDLE_VALUE; m_pbIV = NULL; m_pbKeyObject = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider( &m_hProv, BCRYPT_AES_ALGORITHM, NULL, 0))) { DEBUG("BCryptOpenAlgorithmProvider returns 0x%x\n", status); return; } ``` * 第8到第12行,將參數初始化為0。 * 第14到第19行,開啟演算法提供者。 * 第16行,選擇AES演算法。 * 第20到第23行,若發生錯誤,則回傳錯誤代碼並標示錯誤"BCryptOpenAlgorithmProvider returns",並且結束程式。 ```cpp=24 ULONG cbData; if (!NT_SUCCESS(status = BCryptGetProperty( m_hProv, BCRYPT_BLOCK_LENGTH, (PUCHAR)&m_cbBlock, sizeof(m_cbBlock), &cbData, 0))) { DEBUG("BCryptGetProperty returns 0x%x\n", status); return; } ``` * 第26到第32行,取得加密區塊大小,並存放至第24行所設立之參數。 * 第34到第37行,若發生錯誤,則回傳錯誤代碼並標示錯誤"BCryptGetProperty returns",並且結束程式。 ```cpp=38 m_cbIV = m_cbBlock; m_pbIV = (PUCHAR)HeapAlloc( GetProcessHeap(), 0, m_cbIV); ``` * 第38行,將初始向量大小設為加密區塊之大小。 * 第39及第40行,配置初始向量。 ```cpp=41 if (!NT_SUCCESS(status = BCryptGetProperty( m_hProv, BCRYPT_OBJECT_LENGTH, (PUCHAR)&m_cbKeyObject, sizeof(m_cbKeyObject), &cbData, 0))) { DEBUG("BCryptGetProperty returns 0x%x\n", status); return; } ``` * 第42到第48行,取得金鑰大小,並存放至第24行所設立之參數。 * 第50到第52行,若發生錯誤,則回傳錯誤代碼並標示錯誤"BCryptGetProperty returns",並且結束程式。 ```cpp=54 m_pbKeyObject = (PUCHAR)HeapAlloc( GetProcessHeap(), 0, m_cbKeyObject); if (NULL == m_pbKeyObject) { DEBUG("memory allocation failed\n"); return; } return; } ``` * 第54及第55行,配置金鑰。 * 第56到第61行,若發生錯誤,則回傳錯誤代碼並標示錯誤"memory allocation failed",並且結束程式。 ### 結束加密 ```cpp=64 EZAES::~EZAES() { if (m_pbIV) { HeapFree(GetProcessHeap(), 0, m_pbIV); m_pbIV = NULL; } m_cbIV = 0; if (m_pbKeyObject) { HeapFree(GetProcessHeap(), 0, m_pbKeyObject); m_pbKeyObject = NULL; } m_cbKeyObject = 0; if (m_hProv != INVALID_HANDLE_VALUE) { BCryptCloseAlgorithmProvider(m_hProv, 0); m_hProv = INVALID_HANDLE_VALUE; } if (m_hKey != INVALID_HANDLE_VALUE) { BCryptDestroyKey(m_hKey); m_hKey = INVALID_HANDLE_VALUE; } return; } ``` * 第66到第69行,釋放初始向量。 * 第70行,參數歸零。 * 第71到第74行,釋放金鑰。 * 第75行,參數歸零。 * 第78行,關閉演算法提供者。 * 第79行,參數歸零。 * 第83行,銷毀金鑰。 * 第84行,參數歸零。 ### 產生金鑰 ```cpp=89 BOOL EZAES::GenKey(PUCHAR pbKey, ULONG cbKey) { NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG cbKeyObject = 0; if (!NT_SUCCESS(status = BCryptGenerateSymmetricKey( m_hProv, &m_hKey, m_pbKeyObject, m_cbKeyObject, pbKey, cbKey, 0))) { DEBUG("BCryptGenerateSymmetricKey returns 0x%x\n", status); return FALSE; } Init(); return TRUE; } ``` * 第91及第92行,初始化參數為0; * 第94到第101行,以密碼產生對應之金鑰。 * 第103到第105行,若發生錯誤,則回傳錯誤代碼並標示錯誤"BCryptGenerateSymmetricKey returns",並且結束程式。 ### 初始化 ```cpp=111 BOOL EZAES::Init() { if (m_pbIV && m_cbIV) { ZeroMemory(m_pbIV, m_cbIV); } return TRUE; } ``` ### 加密 ```cpp=119 BOOL EZAES::Encrypt( PUCHAR pbPlain, ULONG cbPlain, PUCHAR pbCipher, ULONG cbCipher, PULONG pcbResult) { NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG cbData; if (!NT_SUCCESS(status = BCryptEncrypt( m_hKey, pbPlain, cbPlain, NULL, m_pbIV, m_cbIV, NULL, 0, &cbData, 0))) { DEBUG("AES BCryptEncrypt#1 0x%x\n", status); return NULL; } if (pcbResult) { *pcbResult = cbData; } if (cbCipher < cbData) { return FALSE; } ``` * 第129到第139行,取得加密所需空間,並儲存至第127行參數。 * 第141到第143行,若發生錯誤,則回傳錯誤代碼並標示錯誤"AES BCryptEncrypt#1",並且結束程式。 * 第148到第150行,若記憶體大小小於所需空間,則回傳錯誤。 ```cpp=151 if (!NT_SUCCESS(status = BCryptEncrypt( m_hKey, pbPlain, cbPlain, NULL, m_pbIV, m_cbIV, pbCipher, cbData, &cbData, 0))) { DEBUG("AES BCryptEncrypt#2 0x%x\n", status); return NULL; } if (pcbResult) { *pcbResult = cbData; } return TRUE; } ``` * 第152到第162行,執行加密。 * 第141到第143行,若發生錯誤,則回傳錯誤代碼並標示錯誤"AES BCryptEncrypt#2",並且結束程式。 * 第168到第170行,設置為加密結果之大小。 ### 解密 ```cpp=173 BOOL EZAES::Decrypt( PUCHAR pbCipher, ULONG cbCipher, PUCHAR pbPlain, ULONG cbPlain, PULONG pcbResult) { NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG cbData; if (!NT_SUCCESS(status = BCryptDecrypt( m_hKey, pbCipher, cbCipher, NULL, m_pbIV, m_cbIV, NULL, 0, &cbData, 0))) { DEBUG("EZAES::BCryptDecrypt#1 returns 0x%x\n", status); return NULL; } if (pcbResult) { *pcbResult = cbData; } if (cbPlain < cbData) { return FALSE; } ``` * 第183到第193行,取得解密所需空間,並儲存至第181行參數。 * 第195到第197行,若發生錯誤,則回傳錯誤代碼並標示錯誤"AES BCryptDecrypt#1",並且結束程式。 * 第202到第204行,若記憶體大小小於所需空間,則回傳錯誤。 ```cpp=205 if (!NT_SUCCESS(status = BCryptDecrypt( m_hKey, pbCipher, cbCipher, NULL, m_pbIV, m_cbIV, pbPlain, cbData, &cbData, 0))) { DEBUG("EZAES::BCryptDecrypt#2 returns 0x%x\n", status); return NULL; } return TRUE; } ``` * 第206到第216行,執行加密。 * 第218到第220行,若發生錯誤,則回傳錯誤代碼並標示錯誤"AES BCryptEncrypt#2",並且結束程式。