首页
社区
课程
招聘
kcrypt--windows内核加密算法库
发表于: 2023-8-4 18:23 14468

kcrypt--windows内核加密算法库

2023-8-4 18:23
14468

MD5 测试
9592

SHA1 Test
1920

use default key(0)

DES ecb test

4434

AES test

1111

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;私钥用于解密也是同理;

最终代码如下

#include <Hasher.hpp>
#include <SymCipher.hpp>
#include <ASymCipher.hpp>
#include <Hasher.hpp>
#include <SymCipher.hpp>
#include <ASymCipher.hpp>
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();
#pragma  warning(disable :4996)
    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();
#pragma  warning(disable :4996)
    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);
#define BCRYPT_RSA_ALGORITHM                    L"RSA"
#define BCRYPT_RSA_SIGN_ALGORITHM               L"RSA_SIGN"
#define BCRYPT_DH_ALGORITHM                     L"DH"
#define BCRYPT_DSA_ALGORITHM                    L"DSA"
#define BCRYPT_RC2_ALGORITHM                    L"RC2"
#define BCRYPT_RC4_ALGORITHM                    L"RC4"
#define BCRYPT_AES_ALGORITHM                    L"AES"
#define BCRYPT_DES_ALGORITHM                    L"DES"
#define BCRYPT_DESX_ALGORITHM                   L"DESX"
#define BCRYPT_3DES_ALGORITHM                   L"3DES"
#define BCRYPT_3DES_112_ALGORITHM               L"3DES_112"
#define BCRYPT_MD2_ALGORITHM                    L"MD2"
#define BCRYPT_MD4_ALGORITHM                    L"MD4"
#define BCRYPT_MD5_ALGORITHM                    L"MD5"
#define BCRYPT_SHA1_ALGORITHM                   L"SHA1"
#define BCRYPT_SHA256_ALGORITHM                 L"SHA256"
#define BCRYPT_SHA384_ALGORITHM                 L"SHA384"
#define BCRYPT_RSA_ALGORITHM                    L"RSA"
#define BCRYPT_RSA_SIGN_ALGORITHM               L"RSA_SIGN"
#define BCRYPT_DH_ALGORITHM                     L"DH"
#define BCRYPT_DSA_ALGORITHM                    L"DSA"
#define BCRYPT_RC2_ALGORITHM                    L"RC2"
#define BCRYPT_RC4_ALGORITHM                    L"RC4"
#define BCRYPT_AES_ALGORITHM                    L"AES"
#define BCRYPT_DES_ALGORITHM                    L"DES"
#define BCRYPT_DESX_ALGORITHM                   L"DESX"
#define BCRYPT_3DES_ALGORITHM                   L"3DES"
#define BCRYPT_3DES_112_ALGORITHM               L"3DES_112"
#define BCRYPT_MD2_ALGORITHM                    L"MD2"
#define BCRYPT_MD4_ALGORITHM                    L"MD4"
#define BCRYPT_MD5_ALGORITHM                    L"MD5"
#define BCRYPT_SHA1_ALGORITHM                   L"SHA1"
#define BCRYPT_SHA256_ALGORITHM                 L"SHA256"
#define BCRYPT_SHA384_ALGORITHM                 L"SHA384"
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;
        }
#pragma once
#include <fltKernel.h>
#include <bcrypt.h>
#include <ntstrsafe.h>
namespace kcrypt {
 
    //由于这个项目用了crt库 不能用内核的了 只能这样
    using fnsprintf = int(*)(char* _DstBuf,const char* _Format, ...);
#pragma warning(disable : 4996)
#define hashprintk(...)do{DbgPrintEx(77,0,__VA_ARGS__);}while(0);
 
    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]);
        }
 
    }
 
#pragma warning(default : 4996)
}
#pragma once
#include <fltKernel.h>
#include <bcrypt.h>
#include <ntstrsafe.h>
namespace kcrypt {
 
    //由于这个项目用了crt库 不能用内核的了 只能这样
    using fnsprintf = int(*)(char* _DstBuf,const char* _Format, ...);
#pragma warning(disable : 4996)
#define hashprintk(...)do{DbgPrintEx(77,0,__VA_ARGS__);}while(0);
 
    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]);
        }
 
    }
 
#pragma warning(default : 4996)
}
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
#define BCRYPT_CHAIN_MODE_NA        L"ChainingModeN/A"
#define BCRYPT_CHAIN_MODE_CBC       L"ChainingModeCBC"
#define BCRYPT_CHAIN_MODE_ECB       L"ChainingModeECB"
#define BCRYPT_CHAIN_MODE_CFB       L"ChainingModeCFB"
#define BCRYPT_CHAIN_MODE_CCM       L"ChainingModeCCM"
#define BCRYPT_CHAIN_MODE_GCM       L"ChainingModeGCM"
if(!NT_SUCCESS(status = BCryptSetProperty(
                                hAesAlg,
                                BCRYPT_CHAINING_MODE,
                                (PBYTE)BCRYPT_CHAIN_MODE_CBC,
                                sizeof(BCRYPT_CHAIN_MODE_CBC),
                                0)))
     // Property Strings
#define BCRYPT_CHAIN_MODE_NA        L"ChainingModeN/A"
#define BCRYPT_CHAIN_MODE_CBC       L"ChainingModeCBC"
#define BCRYPT_CHAIN_MODE_ECB       L"ChainingModeECB"
#define BCRYPT_CHAIN_MODE_CFB       L"ChainingModeCFB"
#define BCRYPT_CHAIN_MODE_CCM       L"ChainingModeCCM"
#define BCRYPT_CHAIN_MODE_GCM       L"ChainingModeGCM"
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;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 5
支持
分享
最新回复 (8)
雪    币: 6124
活跃值: (4716)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
2
牛逼
2023-8-5 10:32
0
雪    币: 1620
活跃值: (3502)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
好人啊
2023-8-5 14:21
0
雪    币: 219
活跃值: (161)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
好人一生平安
2023-8-8 10:21
0
雪    币: 304
活跃值: (103)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
学习啦大佬
2023-8-11 09:39
0
雪    币: 1289
活跃值: (1332)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
mark
2023-8-11 11:39
0
雪    币: 1818
活跃值: (4780)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
非常感谢,赞一个。
2023-8-12 00:50
0
雪    币: 4796
活跃值: (3339)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8

非常感谢,赞一个。

最后于 2023-8-12 15:49 被linghaien编辑 ,原因:
2023-8-12 15:42
0
雪    币: 1309
活跃值: (1249)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9
代码越复杂可能潜在的攻击点越多,一直想要一个库能一个函数实现一个加解密的,从而方便整个函数forceinline然后vmp拉满
2023-8-13 00:31
0
游客
登录 | 注册 方可回帖
返回
//