---
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",並且結束程式。