MD5 测试
SHA1 Test
use default key(0)
DES ecb test
AES test
RSA test
这个其实更多地用在文件系统的透明加密上面
我们知道,加密算法主要分为三种
数字摘要确定数据完整性,对称加密用于数据传输的时候加密,非对称加密用处主要是用于数字签名,证书认证等确认身份的;
在windows内核都实现了相关的函数进行加解密,库是cng.lib
,而头文件是bcrypt.h
这里可以简单地封装个hasher类来进行简单调用这个库,因为使用cng.lib这个库方法是很固定的。
都是先BCryptOpenAlgorithmProvider
生成一个特定加密算法的提供者句柄 ,比如
返回的就是算法句柄,但是要BCryptCloseAlgorithmProvider
来进行清理他;
这个pszAlgId其实就是加密算法的名字
windows已经预定义了,第三个第四个参数都是可选的,第三个是算法提供程序,第四个是flags
获取完这个句柄之后,我们要获取这个提供者的相关信息,分配一个加密对象 ,注意一定是非分页内存
BCryptGetProperty
获取MD5加密算法加密对象的大小,申请块非分页内存,然后使用BCryptCreateHash
创建一个加密对象,一定要注意,假如是对称加密,生成密钥就要用BCryptGenerateSymmetricKey
了;不同类型的加密算法所使用生成对象的函数是不一样的;
创建成功之后,直接使用BCryptHashData
,参数填刚才获得的hHash
即可。若要将多个缓冲区合并到哈希或 MAC 中,可以多次调用此函数,每次传递不同的缓冲区。 若要获取哈希或 MAC 值,请调用 BCryptFinishHash 函数。 为指定的句柄调用 BCryptFinishHash 函数后,无法重复使用该句柄。
这里封装个类+模板来更方便地优雅地使用hash;这里只支持MD4-MD5,SHA1-SHA256这些常用的数字摘要;
如果支持更多,可以自己添加相关的类,然后填入模板;
常见的对称加密主要是DES 3DES AES这些,而对称加密有密钥
这个概念,因此就得生成密钥了;
其实对称加密使用起来比数字摘要更简短,在使用了使用 BCryptOpenAlgorithmProvider 创建相关算法提供者句柄之后,直接调用BCryptGenerateSymmetricKey
这个函数就行了;
里面可以指定密钥,也可以不填,如果不填会由windows默认生成;
phKey
这个就是传出的加密句柄了,后续BCryptEncrypt
时候需要用到,不需要用次句柄就得调用BCryptDestoryKey
销毁了;
第三四个参数分别是一个是接受密钥对象的指针后面是密钥对象的大小,这个大小用 BCRYPT_OBJECT_LENGTH 属性获取(调用 BCryptGetProperty 函数);
第三个第四个均可以填0,这个意思是则此函数会分配并释放密钥对象的内存。
第五个第六个参数就是密钥
一切就绪之后,即可调用
这个函数进行加密,这个函数非对称加密也是通用的,对称加密使用这个函数很多填0即可;
解密调用BCryptDecrypt
;
IV主要是给分组密码用的 ,这个主要是为了防止块加密对于相同的块加密的数据是相同情况的弊端 ;
还需要注意的是,每次调用EnCrypt这个IV都会被更改,但是解密的时候和加密的时候必须用到的IV是相同的,而且一般IV大小和块的大小是相同的;因为可以考虑在类中写入get
,set
函数设置IV,来方便加解密
而flags可以填的是:如果密钥是对称密钥,则此值可以为零或以下值。
如果密钥是非对称密钥,则此值可以是下列值之一。
众所周知AES/DES有多种加密方式,ECB(电子密码本模式)、CBC(密码分组链接模式)、CFB(密码反馈模式;ECB不太安全,CBC啥的更安全,这样加密两段相同明文就不会密文一样了;
至于如何设置一个对称加密的加密模式,使用BCryptSetProperty
即可;
此外,对于对称加密有块的概念,所以可以询问块的大小,一般来说明文必须是按照块对齐的;
下面与数字摘要那个类似,封装一个类进行实现对称加密的加解密;
上面还支持了自定义IV,自定义密钥和自定义加密方式(ECB CBC CFB等);
这里用RC4做例子,流加密和块加密最大的不同就是流加密对于明文长度是不固定的;
流加密的加密原理是根据密钥(伪随机)生成一个密钥流,然后依次把伪密钥流和明文进行加密运算
举个例子,假设你的密钥流是1234567890
,你第一次调用encrypt
使用了前三个数字123
,那么第二次调用encrypt
就会使用下三个数字456
,依此类推。这就是导致连续两次调用encrypt
得到的结果不同。
同时,由于密钥流的不同,解密的时候需要重新创建一个对象,而且密钥必须是相同的;这样保证初始化的伪随机的密钥流是相同的;从而可以完成解密
最终实现如下
我们知道,非对称加密(也叫)公钥加密,也分为很多种;但是作用不同
既可以数字签名,也可以用于加密数据
仅用于数字签名
也是一种非对称加密,效率高
windows的cng.sys也提供了上述算法,同时,由于非对称加密有私钥和公钥的概念;
因此,加解密是需要调用BCryptExportKey
来获取私钥,公钥长度和真实数值的;此外,因为公钥加密的特殊性,只有密钥的位数是固定的,密钥本身应当是随机生成的;
目前cng.sys所支持的非对称加密公用这些;
分别是DH(密钥交换协议,不是用于加密或签名的,而是用于在不安全的网络环境中创建一个只有两方知道的共享密钥,具体算法不知道,猜测可能是像大数定理那样质数分解)
RSA,DSA,基于椭圆曲线的DSA,基于椭圆取消的DH;
RSA就很熟悉了,它本质上是用n=pq,pq都是质数,然后计算;
选取e(1<e<φ(n)),e 与φ(n)互素,计算d,使得ed=1(modφ(n))
公钥为(n,e),私钥为(n,d)
加密:c=m^e^mod n
解密:e=m^d^mod n
这里只使用RSA作为加解密的简单演示
注意,首先BCryptGenerateKeyPair
调用这个是生成一对公钥和私钥;此外,还应当提供一个接口,RSA加密大部分是只有公钥没有私钥,解密也是只用到私钥;
可以在类中直接简单地使用加解密函数,但是无法自定义公钥和私钥那么也没有啥意义了;所以最好写两个构造函数,分别是只有私钥和只有公钥的情况;分别对应加解密;
而这样的还是先BCryptOpenAlgorithmProvider
然后调用
来把公钥变成一个密钥句柄 ,只有这样才能调用BCryptEncypt
;私钥用于解密也是同理;
最终代码如下
unsigned char plainText[
2
]
=
{
'a'
,
'\0'
};
/
/
MD5 Test
kcrypt::Md5Creator md5test;
unsigned char md5Hash[
20
]{
0
};
md5test.crypt(plainText,
1
, md5Hash, kcrypt::MD5::GetHashLength());
char md5Str[
40
]{
0
};
kcrypt::hexToStr(md5Str, sizeof (md5Str), md5Hash, kcrypt::MD5::GetHashLength());
printk(
"md5 crypt->%s\r\n"
, md5Str);
unsigned char plainText[
2
]
=
{
'a'
,
'\0'
};
/
/
MD5 Test
kcrypt::Md5Creator md5test;
unsigned char md5Hash[
20
]{
0
};
md5test.crypt(plainText,
1
, md5Hash, kcrypt::MD5::GetHashLength());
char md5Str[
40
]{
0
};
kcrypt::hexToStr(md5Str, sizeof (md5Str), md5Hash, kcrypt::MD5::GetHashLength());
printk(
"md5 crypt->%s\r\n"
, md5Str);
/
/
SHA1 TEST
kcrypt::SHA1Creator sha1test;
unsigned char sha1Hash[
20
]{
0
};
sha1test.crypt(plainText,
1
, sha1Hash, kcrypt::SHA1::GetHashLength());
char sha1Str[
40
]{
0
};
kcrypt::hexToStr(sha1Str, sizeof sha1Str, sha1Hash, kcrypt::SHA1::GetHashLength());
printk(
"sha1 crypt->%s\r\n"
, sha1Str);
/
/
SHA1 TEST
kcrypt::SHA1Creator sha1test;
unsigned char sha1Hash[
20
]{
0
};
sha1test.crypt(plainText,
1
, sha1Hash, kcrypt::SHA1::GetHashLength());
char sha1Str[
40
]{
0
};
kcrypt::hexToStr(sha1Str, sizeof sha1Str, sha1Hash, kcrypt::SHA1::GetHashLength());
printk(
"sha1 crypt->%s\r\n"
, sha1Str);
/
/
DES test ecb
unsigned char desPlainText[
8
]
=
{
0
};
memset(desPlainText,
7
,
8
);
kcrypt::DESCreator desTest;
unsigned char desBuf[
20
] {
0
};
auto result
=
desTest.encrypt(desPlainText, sizeof desPlainText, desBuf,sizeof desBuf);
char desStr[
20
]{
0
};
kcrypt::hexToStr(desStr, sizeof desStr, desBuf,
8
);
printk(
"des ecb str->%s\r\n"
, desStr);
/
/
decrypt test
unsigned char decryptCode[
8
]{
0
};
desTest.decrypt(decryptCode, sizeof decryptCode, desBuf, result);
/
/
DES test ecb
unsigned char desPlainText[
8
]
=
{
0
};
memset(desPlainText,
7
,
8
);
kcrypt::DESCreator desTest;
unsigned char desBuf[
20
] {
0
};
auto result
=
desTest.encrypt(desPlainText, sizeof desPlainText, desBuf,sizeof desBuf);
char desStr[
20
]{
0
};
kcrypt::hexToStr(desStr, sizeof desStr, desBuf,
8
);
printk(
"des ecb str->%s\r\n"
, desStr);
/
/
decrypt test
unsigned char decryptCode[
8
]{
0
};
desTest.decrypt(decryptCode, sizeof decryptCode, desBuf, result);
unsigned char rsaPlainText[
1
]
=
{
7
};
unsigned char rsaBuf[
500
]
=
{
0
};
char rsaStr[
40
]{
0
};
unsigned char rsadecryptCode[
1
]
=
{
0
};
kcrypt::RSACreator rsatest;
auto [pubkey, pubkeysize]
=
rsatest.getPubKey();
auto [prikey, prikeysize]
=
rsatest.getPriKey();
auto pubKeyStr
=
(char
*
)ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE,
'tmp'
);
auto priKeyStr
=
(char
*
)ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE,
'tmp'
);
memset(pubKeyStr,
0
, PAGE_SIZE);
memset(priKeyStr,
0
, PAGE_SIZE);
kcrypt::hexToStr(priKeyStr, PAGE_SIZE, prikey, prikeysize);
kcrypt::hexToStr(pubKeyStr, PAGE_SIZE, pubkey, pubkeysize);
printk(
"pub key ->%s\r\n pri key ->%s\r\n"
, pubKeyStr,priKeyStr);
/
/
You can leave arg5
and
arg6 blank,
/
/
as this will use the default public key
for
encryption
/
/
and
the private key
for
decryption.
result
=
rsatest.encrypt(rsaPlainText, sizeof rsaPlainText, rsaBuf, sizeof rsaBuf);
kcrypt::hexToStr(rsaStr, sizeof rsaStr, rsaBuf, result);
printk(
"rsa str->%s\r\n"
, rsaStr);
/
/
rsatest.decrypt(rsadecryptCode, sizeof rsadecryptCode, rsaBuf, result);
/
/
and
you can fill
any
pubkey
or
private key to encrypt
and
decrypt
result
=
rsatest.encrypt(rsaPlainText, sizeof rsaPlainText,
rsaBuf, sizeof rsaBuf, pubkey, pubkeysize);
rsatest.decrypt(rsadecryptCode, sizeof rsadecryptCode, rsaBuf, result);
ExFreePool(pubKeyStr);
unsigned char rsaPlainText[
1
]
=
{
7
};
unsigned char rsaBuf[
500
]
=
{
0
};
char rsaStr[
40
]{
0
};
unsigned char rsadecryptCode[
1
]
=
{
0
};
kcrypt::RSACreator rsatest;
auto [pubkey, pubkeysize]
=
rsatest.getPubKey();
auto [prikey, prikeysize]
=
rsatest.getPriKey();
auto pubKeyStr
=
(char
*
)ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE,
'tmp'
);
auto priKeyStr
=
(char
*
)ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE,
'tmp'
);
memset(pubKeyStr,
0
, PAGE_SIZE);
memset(priKeyStr,
0
, PAGE_SIZE);
kcrypt::hexToStr(priKeyStr, PAGE_SIZE, prikey, prikeysize);
kcrypt::hexToStr(pubKeyStr, PAGE_SIZE, pubkey, pubkeysize);
printk(
"pub key ->%s\r\n pri key ->%s\r\n"
, pubKeyStr,priKeyStr);
/
/
You can leave arg5
and
arg6 blank,
/
/
as this will use the default public key
for
encryption
/
/
and
the private key
for
decryption.
result
=
rsatest.encrypt(rsaPlainText, sizeof rsaPlainText, rsaBuf, sizeof rsaBuf);
kcrypt::hexToStr(rsaStr, sizeof rsaStr, rsaBuf, result);
printk(
"rsa str->%s\r\n"
, rsaStr);
/
/
rsatest.decrypt(rsadecryptCode, sizeof rsadecryptCode, rsaBuf, result);
/
/
and
you can fill
any
pubkey
or
private key to encrypt
and
decrypt
result
=
rsatest.encrypt(rsaPlainText, sizeof rsaPlainText,
rsaBuf, sizeof rsaBuf, pubkey, pubkeysize);
rsatest.decrypt(rsadecryptCode, sizeof rsadecryptCode, rsaBuf, result);
ExFreePool(pubKeyStr);
NTSTATUS
WINAPI
BCryptOpenAlgorithmProvider(
_Out_ BCRYPT_ALG_HANDLE
*
phAlgorithm,
_In_z_ LPCWSTR pszAlgId,
_In_opt_z_ LPCWSTR pszImplementation,
_In_ ULONG dwFlags);
NTSTATUS
WINAPI
BCryptOpenAlgorithmProvider(
_Out_ BCRYPT_ALG_HANDLE
*
phAlgorithm,
_In_z_ LPCWSTR pszAlgId,
_In_opt_z_ LPCWSTR pszImplementation,
_In_ ULONG dwFlags);
alue
含义
BCRYPT_ALG_HANDLE_HMAC_FLAG
提供程序将使用指定的哈希算法执行 基于哈希的消息身份验证代码 (HMAC) 算法。 此标志仅供哈希算法提供程序使用。
BCRYPT_PROV_DISPATCH
将提供程序加载到非分页内存池中。 如果此标志不存在,则提供程序将加载到分页内存池中。 指定此标志后,在释放所有依赖对象之前,不得关闭返回的句柄。注意 此标志仅在内核模式下受支持,并允许在 Dispatch 级别处理提供程序上的后续操作。 如果提供程序不支持在调度级别调用,则使用此标志打开时,它将返回错误。 Windows Server 2008 和 Windows Vista: 此标志仅受 Microsoft 算法提供程序支持,仅适用于 哈希算法 和 对称密钥 加密算法 。
BCRYPT_HASH_REUSABLE_FLAG
创建可重用哈希对象。 该对象可在调用 BCryptFinishHash 后立即用于新的哈希操作。 有关详细信息,请参阅 使用 CNG 创建哈希 。Windows Server 2008 R2、Windows 7、Windows Server 2008 和 Windows Vista: 不支持此标志。
status
=
BCryptGetProperty(hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hashObjectSize, sizeof(ULONG), &resultSize,
0
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"BCryptGetProperty failed with %x\n"
, status);
goto Cleanup;
}
hashObject
=
(PUCHAR)ExAllocatePoolWithTag(NonPagedPool, hashObjectSize,
'md5h'
);
if
(hashObject
=
=
nullptr)
{
DbgPrint(
"Memory allocation failed\n"
);
status
=
STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
status
=
BCryptCreateHash(hAlgorithm, &hHash, hashObject, hashObjectSize, nullptr,
0
,
0
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"BCryptCreateHash failed with %x\n"
, status);
goto Cleanup;
}
status
=
BCryptHashData(hHash, data, dataLength,
0
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"BCryptHashData failed with %x\n"
, status);
goto Cleanup;
}
status
=
BCryptFinishHash(hHash,
hash
, hashLength,
0
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"BCryptFinishHash failed with %x\n"
, status);
goto Cleanup;
}
status
=
BCryptGetProperty(hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hashObjectSize, sizeof(ULONG), &resultSize,
0
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"BCryptGetProperty failed with %x\n"
, status);
goto Cleanup;
}
hashObject
=
(PUCHAR)ExAllocatePoolWithTag(NonPagedPool, hashObjectSize,
'md5h'
);
if
(hashObject
=
=
nullptr)
{
DbgPrint(
"Memory allocation failed\n"
);
status
=
STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
status
=
BCryptCreateHash(hAlgorithm, &hHash, hashObject, hashObjectSize, nullptr,
0
,
0
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"BCryptCreateHash failed with %x\n"
, status);
goto Cleanup;
}
status
=
BCryptHashData(hHash, data, dataLength,
0
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"BCryptHashData failed with %x\n"
, status);
goto Cleanup;
}
status
=
BCryptFinishHash(hHash,
hash
, hashLength,
0
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"BCryptFinishHash failed with %x\n"
, status);
goto Cleanup;
}
namespace kcrypt {
/
/
由于这个项目用了crt库 不能用内核的了 只能这样
using fnsprintf
=
int
(
*
)(char
*
_DstBuf,const char
*
_Format, ...);
template <typename Algorithm>
class
Hasher {
public:
Hasher();
~Hasher();
bool
crypt(PUCHAR data, ULONG size, PUCHAR
hash
, ULONG hash_len);
Hasher(const Hasher&)
=
delete;
Hasher(Hasher&&)
=
delete;
Hasher& operator
=
(Hasher&)
=
delete;
private:
BCRYPT_ALG_HANDLE hAlgorithm_;
/
/
算法提供者句柄
BCRYPT_HASH_HANDLE hHash_;
/
/
hash
对象句柄
unsigned
long
hashObjSize_;
void
*
hashObj_;
/
/
哈希对象
};
template <typename Algorithm>
Hasher<Algorithm>::Hasher() {
auto status
=
STATUS_UNSUCCESSFUL;
do {
status
=
BCryptOpenAlgorithmProvider(&hAlgorithm_, Algorithm::GetAlgorithmName(), nullptr,
0
);
if
(!NT_SUCCESS(status))
break
;
unsigned
long
resultSize
=
0
;
/
/
询问属性
status
=
BCryptGetProperty(hAlgorithm_, BCRYPT_OBJECT_LENGTH,
(PUCHAR)&hashObjSize_, sizeof hashObjSize_, &resultSize,
0
);
if
(!NT_SUCCESS(status)) {
break
;
}
hashObj_
=
ExAllocatePoolWithTag(NonPagedPool, hashObjSize_,
'hash'
);
if
(hashObj_
=
=
nullptr)
break
;
/
/
创建
hash
对象
status
=
BCryptCreateHash(hAlgorithm_, &hHash_,(PUCHAR)hashObj_, hashObjSize_,
0
,
0
,
0
);
if
(!NT_SUCCESS(status)) {
break
;
}
return
;
/
/
成功
}
while
(
0
);
/
/
走到这是不成功
if
(hashObj_) {
ExFreePool(hashObj_);
}
if
(hAlgorithm_) {
BCryptCloseAlgorithmProvider(hAlgorithm_,
0
);
}
if
(hHash_) {
BCryptDestroyHash(hHash_);
}
hashprintk(
"failed to ctor!\r\n"
);
}
template <typename Algorithm>
Hasher<Algorithm>::~Hasher() {
if
(hashObj_) {
ExFreePool(hashObj_);
hashObj_
=
0
;
}
if
(hAlgorithm_) {
BCryptCloseAlgorithmProvider(hAlgorithm_,
0
);
hAlgorithm_
=
0
;
}
if
(hHash_) {
BCryptDestroyHash(hHash_);
hHash_
=
0
;
}
}
template <typename Algorithm>
bool
Hasher<Algorithm>::crypt(PUCHAR data, ULONG size, PUCHAR
hash
, ULONG hash_len) {
if
(hHash_ && hashObj_ && hAlgorithm_) {
/
/
先验证
hash
的长度是否正确
/
/
BCryptFinsihHash 很邪门,必须长度等同于
hash
值长度
if
(Algorithm::GetHashLength() > hash_len)
return
false;
auto status
=
STATUS_UNSUCCESSFUL;
status
=
BCryptHashData(hHash_, data, size,
0
);
if
(!NT_SUCCESS(status))
return
false;
status
=
BCryptFinishHash(hHash_,
hash
, Algorithm::GetHashLength(),
0
);
if
(!NT_SUCCESS(status))
return
false;
return
true;
}
return
false;
}
class
SHA1 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_SHA1_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
20
;
/
/
SHA
-
1
的哈希值长度为
160
位,即
20
字节
}
};
class
SHA256 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_SHA256_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
32
;
/
/
SHA
-
256
的哈希值长度为
256
位,即
32
字节
}
};
class
SHA384 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_SHA384_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
48
;
/
/
SHA
-
384
的哈希值长度为
384
位,即
48
字节
}
};
class
SHA512 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_SHA512_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
64
;
/
/
SHA
-
512
的哈希值长度为
512
位,即
64
字节
}
};
class
MD4 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_MD4_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
16
;
/
/
MD4的哈希值长度为
128
位,即
16
字节
}
};
class
MD5 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_MD5_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
16
;
}
};
using Md4Creator
=
Hasher<MD4>;
using Md5Creator
=
Hasher<MD5>;
using SHA1Creator
=
Hasher<SHA1>;
using SHA256Creator
=
Hasher<SHA256>;
using SHA384Creator
=
Hasher<SHA384>;
using SHA512Creator
=
Hasher<SHA512>;
/
/
16
进制转换成
str
void hexToStr(char
*
hexStr, ULONG
len
, PUCHAR hexArry, ULONG hexLen) {
if
(
len
< hexLen
*
2
)
return
;
UNICODE_STRING uFuncName{
0
};
RtlInitUnicodeString(&uFuncName, L
"sprintf"
);
auto ___sprintf
=
(fnsprintf)MmGetSystemRoutineAddress(&uFuncName);
for
(unsigned
int
i
=
0
; i < hexLen; i
+
+
) {
/
/
只能从ntoskrnl.exe导出了 因为被stdio这个坑填了
___sprintf(hexStr
+
i
*
2
,
"%02x"
, hexArry[i]);
}
}
}
namespace kcrypt {
/
/
由于这个项目用了crt库 不能用内核的了 只能这样
using fnsprintf
=
int
(
*
)(char
*
_DstBuf,const char
*
_Format, ...);
template <typename Algorithm>
class
Hasher {
public:
Hasher();
~Hasher();
bool
crypt(PUCHAR data, ULONG size, PUCHAR
hash
, ULONG hash_len);
Hasher(const Hasher&)
=
delete;
Hasher(Hasher&&)
=
delete;
Hasher& operator
=
(Hasher&)
=
delete;
private:
BCRYPT_ALG_HANDLE hAlgorithm_;
/
/
算法提供者句柄
BCRYPT_HASH_HANDLE hHash_;
/
/
hash
对象句柄
unsigned
long
hashObjSize_;
void
*
hashObj_;
/
/
哈希对象
};
template <typename Algorithm>
Hasher<Algorithm>::Hasher() {
auto status
=
STATUS_UNSUCCESSFUL;
do {
status
=
BCryptOpenAlgorithmProvider(&hAlgorithm_, Algorithm::GetAlgorithmName(), nullptr,
0
);
if
(!NT_SUCCESS(status))
break
;
unsigned
long
resultSize
=
0
;
/
/
询问属性
status
=
BCryptGetProperty(hAlgorithm_, BCRYPT_OBJECT_LENGTH,
(PUCHAR)&hashObjSize_, sizeof hashObjSize_, &resultSize,
0
);
if
(!NT_SUCCESS(status)) {
break
;
}
hashObj_
=
ExAllocatePoolWithTag(NonPagedPool, hashObjSize_,
'hash'
);
if
(hashObj_
=
=
nullptr)
break
;
/
/
创建
hash
对象
status
=
BCryptCreateHash(hAlgorithm_, &hHash_,(PUCHAR)hashObj_, hashObjSize_,
0
,
0
,
0
);
if
(!NT_SUCCESS(status)) {
break
;
}
return
;
/
/
成功
}
while
(
0
);
/
/
走到这是不成功
if
(hashObj_) {
ExFreePool(hashObj_);
}
if
(hAlgorithm_) {
BCryptCloseAlgorithmProvider(hAlgorithm_,
0
);
}
if
(hHash_) {
BCryptDestroyHash(hHash_);
}
hashprintk(
"failed to ctor!\r\n"
);
}
template <typename Algorithm>
Hasher<Algorithm>::~Hasher() {
if
(hashObj_) {
ExFreePool(hashObj_);
hashObj_
=
0
;
}
if
(hAlgorithm_) {
BCryptCloseAlgorithmProvider(hAlgorithm_,
0
);
hAlgorithm_
=
0
;
}
if
(hHash_) {
BCryptDestroyHash(hHash_);
hHash_
=
0
;
}
}
template <typename Algorithm>
bool
Hasher<Algorithm>::crypt(PUCHAR data, ULONG size, PUCHAR
hash
, ULONG hash_len) {
if
(hHash_ && hashObj_ && hAlgorithm_) {
/
/
先验证
hash
的长度是否正确
/
/
BCryptFinsihHash 很邪门,必须长度等同于
hash
值长度
if
(Algorithm::GetHashLength() > hash_len)
return
false;
auto status
=
STATUS_UNSUCCESSFUL;
status
=
BCryptHashData(hHash_, data, size,
0
);
if
(!NT_SUCCESS(status))
return
false;
status
=
BCryptFinishHash(hHash_,
hash
, Algorithm::GetHashLength(),
0
);
if
(!NT_SUCCESS(status))
return
false;
return
true;
}
return
false;
}
class
SHA1 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_SHA1_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
20
;
/
/
SHA
-
1
的哈希值长度为
160
位,即
20
字节
}
};
class
SHA256 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_SHA256_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
32
;
/
/
SHA
-
256
的哈希值长度为
256
位,即
32
字节
}
};
class
SHA384 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_SHA384_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
48
;
/
/
SHA
-
384
的哈希值长度为
384
位,即
48
字节
}
};
class
SHA512 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_SHA512_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
64
;
/
/
SHA
-
512
的哈希值长度为
512
位,即
64
字节
}
};
class
MD4 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_MD4_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
16
;
/
/
MD4的哈希值长度为
128
位,即
16
字节
}
};
class
MD5 {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_MD5_ALGORITHM;
}
static constexpr ULONG GetHashLength() {
return
16
;
}
};
using Md4Creator
=
Hasher<MD4>;
using Md5Creator
=
Hasher<MD5>;
using SHA1Creator
=
Hasher<SHA1>;
using SHA256Creator
=
Hasher<SHA256>;
using SHA384Creator
=
Hasher<SHA384>;
using SHA512Creator
=
Hasher<SHA512>;
/
/
16
进制转换成
str
void hexToStr(char
*
hexStr, ULONG
len
, PUCHAR hexArry, ULONG hexLen) {
if
(
len
< hexLen
*
2
)
return
;
UNICODE_STRING uFuncName{
0
};
RtlInitUnicodeString(&uFuncName, L
"sprintf"
);
auto ___sprintf
=
(fnsprintf)MmGetSystemRoutineAddress(&uFuncName);
for
(unsigned
int
i
=
0
; i < hexLen; i
+
+
) {
/
/
只能从ntoskrnl.exe导出了 因为被stdio这个坑填了
___sprintf(hexStr
+
i
*
2
,
"%02x"
, hexArry[i]);
}
}
}
NTSTATUS BCryptGenerateSymmetricKey(
[
in
, out] BCRYPT_ALG_HANDLE hAlgorithm,
[out] BCRYPT_KEY_HANDLE
*
phKey,
[out, optional] PUCHAR pbKeyObject,
[
in
] ULONG cbKeyObject,
[
in
] PUCHAR pbSecret,
[
in
] ULONG cbSecret,
[
in
] ULONG dwFlags
);
NTSTATUS BCryptGenerateSymmetricKey(
[
in
, out] BCRYPT_ALG_HANDLE hAlgorithm,
[out] BCRYPT_KEY_HANDLE
*
phKey,
[out, optional] PUCHAR pbKeyObject,
[
in
] ULONG cbKeyObject,
[
in
] PUCHAR pbSecret,
[
in
] ULONG cbSecret,
[
in
] ULONG dwFlags
);
NTSTATUS BCryptEncrypt(
[
in
, out] BCRYPT_KEY_HANDLE hKey,
[
in
] PUCHAR pbInput,
[
in
] ULONG cbInput,
[
in
, optional] VOID
*
pPaddingInfo,
[
in
, out, optional] PUCHAR pbIV,
[
in
] ULONG cbIV,
[out, optional] PUCHAR pbOutput,
[
in
] ULONG cbOutput,
[out] ULONG
*
pcbResult,
[
in
] ULONG dwFlags
);
NTSTATUS BCryptEncrypt(
[
in
, out] BCRYPT_KEY_HANDLE hKey,
[
in
] PUCHAR pbInput,
[
in
] ULONG cbInput,
[
in
, optional] VOID
*
pPaddingInfo,
[
in
, out, optional] PUCHAR pbIV,
[
in
] ULONG cbIV,
[out, optional] PUCHAR pbOutput,
[
in
] ULONG cbOutput,
[out] ULONG
*
pcbResult,
[
in
] ULONG dwFlags
);
Value
含义
BCRYPT_BLOCK_PADDING
允许加密算法将数据填充到下一个块大小。 如果未指定此标志, 则 cbInput 参数中指定的纯文本的大小必须是算法块大小的倍数。可以通过调用 BCryptGetProperty 函数来获取该密钥 的BCRYPT_BLOCK_LENGTH 属性来获取块大小。 这将为算法提供块的大小。此标志不得与经过身份验证的加密模式一起使用, (AES-CCM 和 AES-GCM) 。
Value
含义
BCRYPT_PAD_NONE
请勿使用任何填充。 不使用 pPaddingInfo 参数。 cbInput 参数中指定的纯文本的大小必须是算法块大小的倍数。
BCRYPT_PAD_OAEP
使用最佳非对称加密填充 (OAEP) 方案。 pPaddingInfo 参数是指向BCRYPT_OAEP_PADDING_INFO 结构的指针。
BCRYPT_PAD_PKCS1
数据将填充一个随机数字,以舍入块大小。 不使用 pPaddingInfo 参数。
if
(!NT_SUCCESS(status
=
BCryptSetProperty(
hAesAlg,
BCRYPT_CHAINING_MODE,
(PBYTE)BCRYPT_CHAIN_MODE_CBC,
sizeof(BCRYPT_CHAIN_MODE_CBC),
0
)))
/
/
Property
Strings
if
(!NT_SUCCESS(status
=
BCryptSetProperty(
hAesAlg,
BCRYPT_CHAINING_MODE,
(PBYTE)BCRYPT_CHAIN_MODE_CBC,
sizeof(BCRYPT_CHAIN_MODE_CBC),
0
)))
/
/
Property
Strings
if
(!NT_SUCCESS(status
=
BCryptGetProperty(
hAesAlg,
BCRYPT_BLOCK_LENGTH,
(PBYTE)&cbBlockLen,
sizeof(DWORD),
&cbData,
0
)))
if
(!NT_SUCCESS(status
=
BCryptGetProperty(
hAesAlg,
BCRYPT_BLOCK_LENGTH,
(PBYTE)&cbBlockLen,
sizeof(DWORD),
&cbData,
0
)))
enum
class
Mode {
ecb,
cbc,
cfb,
ccm,
gcm
};
template<typename Algorithm>
class
BlockCipher {
public:
/
/
密钥 IV随机向量 还有加密模式
BlockCipher(PUCHAR key
=
nullptr, Mode mod
=
Mode::ecb,PUCHAR iv
=
nullptr);
~BlockCipher();
ULONG encrypt(PUCHAR data,ULONG dataSize,PUCHAR cryptData,ULONG cryptSize);
ULONG decrypt(PUCHAR data, ULONG dataSize, PUCHAR cryptData, ULONG cryptSize);
PUCHAR constexpr getcuriv() {
return
_iv; }
PUCHAR constexpr getlastiv(){
return
_preIv}
PUCHAR constexpr getkey() {
return
_key; }
private:
PUCHAR _key;
/
/
密钥
BCRYPT_ALG_HANDLE _hAlg;
/
/
算法提供句柄
BCRYPT_KEY_HANDLE _hKey;
/
/
对称加密的密钥对象句柄 必须用这个加解密
PUCHAR _keyObj;
Mode _mod;
PUCHAR _iv;
PUCHAR _preIv;
ULONG _ivSize;
};
template<typename Algorithm>
BlockCipher<Algorithm>::BlockCipher(PUCHAR key, Mode mod,PUCHAR iv):_key(key),_mod(mod),_iv(iv) {
do {
/
/
创建提供者
auto status
=
BCryptOpenAlgorithmProvider(&_hAlg,
Algorithm::GetAlgorithmName(),
0
,
0
);
if
(!NT_SUCCESS(status))
break
;
/
/
询问密钥对象大小
ULONG keyObjSize
=
0
,result
=
0
;
status
=
BCryptGetProperty(_hAlg, BCRYPT_OBJECT_LENGTH, (PUCHAR)&keyObjSize, sizeof ULONG, &result,
0
);
if
(!NT_SUCCESS(status))
break
;
_keyObj
=
(PUCHAR)ExAllocatePoolWithTag(NonPagedPool,keyObjSize,
'sym'
);
if
(_keyObj
=
=
nullptr)
break
;
/
/
设置IV随机向量 用于加密 如果是ECB方式则不需要
if
(_key
=
=
nullptr) _key
=
Algorithm::GetDefaultKey();
else
{
/
/
需要申请
_key
=
(PUCHAR)ExAllocatePoolWithTag(PagedPool, Algorithm::GetBlockSize(),
'sym'
);
if
(_key
=
=
nullptr)
break
;
memcpy(_key, key, Algorithm::GetBlockSize());
}
if
(mod !
=
Mode::ecb) {
/
/
询问获取_ivSize
if
(!NT_SUCCESS(BCryptGetProperty(
_hAlg,
BCRYPT_BLOCK_LENGTH,
(PUCHAR)&_ivSize,
sizeof(ULONG),
&result,
0
)))
break
;
/
/
如果不是ECB加密 需要随机向量
if
(_iv
=
=
nullptr) {
iv
=
Algorithm::GetDefaultIV();
}
/
/
申请内存 防止传入的是局部变量
_iv
=
(PUCHAR)ExAllocatePoolWithTag(NonPagedPool, _ivSize,
'sym'
);
_preIv
=
(PUCHAR)ExAllocatePoolWithTag(NonPagedPool, _ivSize,
'sym'
);
if
(_iv
=
=
nullptr || !_preIv)
break
;
memcpy(_iv, iv, _ivSize);
memset(_preIv,
0
, _ivSize);
}
else
{ _iv
=
nullptr, _ivSize
=
0
,_preIv
=
nullptr; }
/
/
设置加密方式
switch (_mod)
{
case kcrypt::Mode::ecb:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_ECB,
sizeof(BCRYPT_CHAIN_MODE_ECB),
0
);
break
;
case kcrypt::Mode::cbc:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_CBC,
sizeof(BCRYPT_CHAIN_MODE_CBC),
0
);
break
;
case kcrypt::Mode::cfb:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_CFB,
sizeof(BCRYPT_CHAIN_MODE_CFB),
0
);
break
;
case kcrypt::Mode::ccm:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_CCM,
sizeof(BCRYPT_CHAIN_MODE_CCM),
0
);
break
;
case kcrypt::Mode::gcm:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_GCM,
sizeof(BCRYPT_CHAIN_MODE_GCM),
0
);
break
;
default:
status
=
STATUS_INVALID_PARAMETER;
break
;
}
if
(!NT_SUCCESS(status))
break
;
/
/
生成密钥句柄 用于后续加密
status
=
BCryptGenerateSymmetricKey(_hAlg, &_hKey, _keyObj,keyObjSize, _key, Algorithm::GetBlockSize(),
0
);
if
(!NT_SUCCESS(status)) {
symprintk(
"failed to generate key!\r\n"
);
break
;
}
return
;
}
while
(
0
);
/
/
对称加密可以省略密钥对象 由windows自己管理
if
(_hAlg) {
BCryptCloseAlgorithmProvider(_hAlg,
0
);
_hAlg
=
0
;
}
if
(_hKey) {
BCryptDestroyKey(_hKey);
_hKey
=
0
;
}
if
(_keyObj) {
ExFreePool(_keyObj);
_keyObj
=
0
;
}
if
(_iv !
=
nullptr) {
ExFreePool(_iv);
_iv
=
0
;
}
if
(_preIv) {
ExFreePool(_preIv);
_preIv
=
0
;
}
if
(_key !
=
Algorithm::GetDefaultKey() && key) {
ExFreePool(_key);
_key
=
nullptr;
}
symprintk(
"failed to ctor!\r\n"
);
}
template <typename Algorithm>
BlockCipher<Algorithm>::~BlockCipher() {
if
(_keyObj) {
ExFreePool(_keyObj);
_keyObj
=
0
;
}
/
/
对称加密可以省略密钥对象 由windows自己管理
if
(_hAlg) {
BCryptCloseAlgorithmProvider(_hAlg,
0
);
_hAlg
=
0
;
}
if
(_hKey) {
BCryptDestroyKey(_hKey);
_hKey
=
0
;
}
if
(_iv !
=
nullptr) {
ExFreePool(_iv);
_iv
=
0
;
}
if
(_preIv) {
ExFreePool(_preIv);
_preIv
=
0
;
}
if
(_key !
=
Algorithm::GetDefaultKey() && _key) {
ExFreePool(_key);
_key
=
nullptr;
}
}
template <typename Algorithm>
ULONG BlockCipher<Algorithm>::encrypt(PUCHAR data, ULONG dataSize, PUCHAR cryptData, ULONG cryptSize) {
if
(!_hKey || !_hAlg ||!_keyObj) {
return
0
;
}
ULONG result
=
0
;
NTSTATUS status
=
STATUS_UNSUCCESSFUL;
unsigned char saveIv[
8
]{
0
};
if
(_iv!
=
nullptr)
memcpy(saveIv, _iv,
8
);
/
/
自动填充到一个块
if
(!NT_SUCCESS(status
=
BCryptEncrypt(_hKey, data, dataSize,
0
, _iv,_ivSize,
cryptData, cryptSize, &result,
0
))) {
symprintk(
"fialed to encrypt,errcode->08%x\r\n"
, status);
return
0
;
}
else
{
if
(_iv !
=
nullptr)
memcpy(_preIv, saveIv,
8
);
return
result;
}
}
template<typename Algorithm>
ULONG BlockCipher<Algorithm>::decrypt(PUCHAR data, ULONG dataSize,PUCHAR cryptData, ULONG cryptSize) {
/
/
解密
if
(!_hKey || !_hAlg || !_keyObj) {
return
0
;
}
ULONG result
=
0
;
NTSTATUS status
=
STATUS_UNSUCCESSFUL;
if
(!NT_SUCCESS(status
=
BCryptDecrypt(_hKey,cryptData,cryptSize,
0
,_preIv
,_ivSize,data,dataSize,&result,
0
))) {
symprintk(
"failed to decrypt,errcode->08%x\r\n"
, status);
return
0
;
}
else
return
result;
}
class
DES {
public:
static constexpr LPCWSTR GetAlgorithmName() {
return
BCRYPT_DES_ALGORITHM;
}
static constexpr ULONG GetBlockSize() {
return
8
;
}
static PUCHAR GetDefaultKey(){
/
/
DES的密钥是
7
字节
static UCHAR key[
8
]
=
{
0
};
return
key;
}
static PUCHAR GetDefaultIV() {
/
/
DES block size
is
8
bytes.
static UCHAR iv[
8
]
=
{
0
};
return
iv;
}
};
class
TripleDES {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_3DES_ALGORITHM;
}
static constexpr ULONG GetBlockSize() {
return
24
;
}
static UCHAR
*
GetDefaultKey() {
/
/
3DES
supports key sizes of
21
bytes.
static UCHAR key[
24
]
=
{
0
};
return
key;
}
static PUCHAR GetDefaultIV() {
/
/
3DES
block size
is
8
bytes.
static UCHAR iv[
8
]
=
{
0
};
return
iv;
}
};
class
AES {
public:
static constexpr PCWSTR GetAlgorithmName() {
return
BCRYPT_AES_ALGORITHM;
}
static constexpr ULONG GetBlockSize() {
return
16
;
}
static UCHAR
*
GetDefaultKey() {
/
/
AES supports key sizes of
16
,
24
,
or
32
bytes.
static UCHAR key[
16
]
=
{
0
};
return
key;
}
static UCHAR
*
GetDefaultIV() {
/
/
AES block size
is
16
bytes.
static UCHAR iv[
16
]
=
{
0
};
return
iv;
}
};
using DESCreator
=
BlockCipher<DES>;
using TripleDESCreator
=
BlockCipher<TripleDES>;
using AESCreator
=
BlockCipher<AES>;
enum
class
Mode {
ecb,
cbc,
cfb,
ccm,
gcm
};
template<typename Algorithm>
class
BlockCipher {
public:
/
/
密钥 IV随机向量 还有加密模式
BlockCipher(PUCHAR key
=
nullptr, Mode mod
=
Mode::ecb,PUCHAR iv
=
nullptr);
~BlockCipher();
ULONG encrypt(PUCHAR data,ULONG dataSize,PUCHAR cryptData,ULONG cryptSize);
ULONG decrypt(PUCHAR data, ULONG dataSize, PUCHAR cryptData, ULONG cryptSize);
PUCHAR constexpr getcuriv() {
return
_iv; }
PUCHAR constexpr getlastiv(){
return
_preIv}
PUCHAR constexpr getkey() {
return
_key; }
private:
PUCHAR _key;
/
/
密钥
BCRYPT_ALG_HANDLE _hAlg;
/
/
算法提供句柄
BCRYPT_KEY_HANDLE _hKey;
/
/
对称加密的密钥对象句柄 必须用这个加解密
PUCHAR _keyObj;
Mode _mod;
PUCHAR _iv;
PUCHAR _preIv;
ULONG _ivSize;
};
template<typename Algorithm>
BlockCipher<Algorithm>::BlockCipher(PUCHAR key, Mode mod,PUCHAR iv):_key(key),_mod(mod),_iv(iv) {
do {
/
/
创建提供者
auto status
=
BCryptOpenAlgorithmProvider(&_hAlg,
Algorithm::GetAlgorithmName(),
0
,
0
);
if
(!NT_SUCCESS(status))
break
;
/
/
询问密钥对象大小
ULONG keyObjSize
=
0
,result
=
0
;
status
=
BCryptGetProperty(_hAlg, BCRYPT_OBJECT_LENGTH, (PUCHAR)&keyObjSize, sizeof ULONG, &result,
0
);
if
(!NT_SUCCESS(status))
break
;
_keyObj
=
(PUCHAR)ExAllocatePoolWithTag(NonPagedPool,keyObjSize,
'sym'
);
if
(_keyObj
=
=
nullptr)
break
;
/
/
设置IV随机向量 用于加密 如果是ECB方式则不需要
if
(_key
=
=
nullptr) _key
=
Algorithm::GetDefaultKey();
else
{
/
/
需要申请
_key
=
(PUCHAR)ExAllocatePoolWithTag(PagedPool, Algorithm::GetBlockSize(),
'sym'
);
if
(_key
=
=
nullptr)
break
;
memcpy(_key, key, Algorithm::GetBlockSize());
}
if
(mod !
=
Mode::ecb) {
/
/
询问获取_ivSize
if
(!NT_SUCCESS(BCryptGetProperty(
_hAlg,
BCRYPT_BLOCK_LENGTH,
(PUCHAR)&_ivSize,
sizeof(ULONG),
&result,
0
)))
break
;
/
/
如果不是ECB加密 需要随机向量
if
(_iv
=
=
nullptr) {
iv
=
Algorithm::GetDefaultIV();
}
/
/
申请内存 防止传入的是局部变量
_iv
=
(PUCHAR)ExAllocatePoolWithTag(NonPagedPool, _ivSize,
'sym'
);
_preIv
=
(PUCHAR)ExAllocatePoolWithTag(NonPagedPool, _ivSize,
'sym'
);
if
(_iv
=
=
nullptr || !_preIv)
break
;
memcpy(_iv, iv, _ivSize);
memset(_preIv,
0
, _ivSize);
}
else
{ _iv
=
nullptr, _ivSize
=
0
,_preIv
=
nullptr; }
/
/
设置加密方式
switch (_mod)
{
case kcrypt::Mode::ecb:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_ECB,
sizeof(BCRYPT_CHAIN_MODE_ECB),
0
);
break
;
case kcrypt::Mode::cbc:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_CBC,
sizeof(BCRYPT_CHAIN_MODE_CBC),
0
);
break
;
case kcrypt::Mode::cfb:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_CFB,
sizeof(BCRYPT_CHAIN_MODE_CFB),
0
);
break
;
case kcrypt::Mode::ccm:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_CCM,
sizeof(BCRYPT_CHAIN_MODE_CCM),
0
);
break
;
case kcrypt::Mode::gcm:
status
=
BCryptSetProperty(_hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_GCM,
sizeof(BCRYPT_CHAIN_MODE_GCM),
0
);
break
;
default:
status
=
STATUS_INVALID_PARAMETER;
break
;
}
if
(!NT_SUCCESS(status))
break
;
/
/
生成密钥句柄 用于后续加密
status
=
BCryptGenerateSymmetricKey(_hAlg, &_hKey, _keyObj,keyObjSize, _key, Algorithm::GetBlockSize(),
0
);
if
(!NT_SUCCESS(status)) {
symprintk(
"failed to generate key!\r\n"
);
break
;
}
return
;
}
while
(
0
);
/
/
对称加密可以省略密钥对象 由windows自己管理
if
(_hAlg) {
BCryptCloseAlgorithmProvider(_hAlg,
0
);
_hAlg
=
0
;
}
if
(_hKey) {
BCryptDestroyKey(_hKey);
_hKey
=
0
;
}
if
(_keyObj) {
ExFreePool(_keyObj);
_keyObj
=
0
;
}
if
(_iv !
=
nullptr) {
ExFreePool(_iv);
_iv
=
0
;
}
if
(_preIv) {
ExFreePool(_preIv);
_preIv
=
0
;
}
if
(_key !
=
Algorithm::GetDefaultKey() && key) {
ExFreePool(_key);
_key
=
nullptr;
}
symprintk(
"failed to ctor!\r\n"
);
}
template <typename Algorithm>
BlockCipher<Algorithm>::~BlockCipher() {
if
(_keyObj) {
ExFreePool(_keyObj);
_keyObj
=
0
;
}
/
/
对称加密可以省略密钥对象 由windows自己管理
if
(_hAlg) {
BCryptCloseAlgorithmProvider(_hAlg,
0
);
_hAlg
=
0
;
}
if
(_hKey) {
BCryptDestroyKey(_hKey);
_hKey
=
0
;
}
if
(_iv !
=
nullptr) {
ExFreePool(_iv);
_iv
=
0
;
}
if
(_preIv) {
ExFreePool(_preIv);
_preIv
=
0
;
}
if
(_key !
=
Algorithm::GetDefaultKey() && _key) {
ExFreePool(_key);
_key
=
nullptr;
}
}
template <typename Algorithm>
ULONG BlockCipher<Algorithm>::encrypt(PUCHAR data, ULONG dataSize, PUCHAR cryptData, ULONG cryptSize) {
if
(!_hKey || !_hAlg ||!_keyObj) {
return
0
;
}
ULONG result
=
0
;
NTSTATUS status
=
STATUS_UNSUCCESSFUL;
unsigned char saveIv[
8
]{
0
};
if
(_iv!
=
nullptr)
memcpy(saveIv, _iv,
8
);
/
/
自动填充到一个块
if
(!NT_SUCCESS(status
=
BCryptEncrypt(_hKey, data, dataSize,
0
, _iv,_ivSize,
cryptData, cryptSize, &result,
0
))) {
symprintk(
"fialed to encrypt,errcode->08%x\r\n"
, status);
return
0
;
}
else
{
if
(_iv !
=
nullptr)
memcpy(_preIv, saveIv,
8
);
return
result;
}
}
template<typename Algorithm>
ULONG BlockCipher<Algorithm>::decrypt(PUCHAR data, ULONG dataSize,PUCHAR cryptData, ULONG cryptSize) {
/
/
解密
if
(!_hKey || !_hAlg || !_keyObj) {
return
0
;
}
ULONG result
=
0
;
NTSTATUS status
=
STATUS_UNSUCCESSFUL;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!