无法使用 C# 中的 CryptEncrypt/CryptDecrypt 进行解密

2024-03-08

我制作了一个小应用程序来加密和解密一些文本。只要我直接使用加密中的字节数组,一切都很好。但是,一旦我复制了数组来模拟将加密文本作为文件发送的过程,解密就不会运行。

为什么我无法使用复制的数组运行解密?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;

using System.Runtime.InteropServices.WindowsRuntime;
using System.Runtime.InteropServices;
using System.IO;


namespace EncryptDecryptApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            //Text to encrypt
            string plaintext = "Text to encrypt and decrypt!";

            // Password
            const string password = "password";

            // Constants used in cryptography functions
            const string MS_ENH_RSA_AES_PROV = "Microsoft Enhanced RSA and AES Cryptographic Provider"; //Name of provider. Same as "Microsoft AES Cryptographic Provider".
            const byte PROV_RSA_AES = 24;         //Type of provider
            const string KeyContainer = null;     //Name of the key container to be used, if NULL then a default key container name is used. Must be a null-terminated string.
            const uint ALG_CLASS_HASH = (4 << 13); //32768 = 4*2^13; //Samma tror jag för alla hashalgoritmer
            const uint ALG_TYPE_ANY = (0);       //Samma tror jag för alla hashalgoritmer
            const uint ALG_SID_SHA_256 = 12;    //ALG_SID_MD5 = 3, ALG_SID_SHA = 4, ALG_SID_SHA_256 = 12, ALG_SID_SHA_384 = 13, ALG_SID_SHA_512 = 14
            const uint CALG_SHA_256 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256);
            const int ALG_CLASS_DATA_ENCRYPT = 24576;
            const int ALG_TYPE_BLOCK = 1536;       //used in all types of AES, and in RC2
            const int ALG_SID_AES_256 = 16; //ALG_SID_AES_128 = 14, ALG_SID_AES_192 = 15, ALG_SID_AES_256 = 16
            const int CALG_AES_256 = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256);
            const int ENCRYPT_ALGORITHM = CALG_AES_256;

            // Obtain handle to Cryptographic Service Provider (CSP)
            string ProviderCSP = MS_ENH_RSA_AES_PROV + null;     //name of the CSP to be used. Must be a null-terminated string.
            IntPtr CSPhandle = new IntPtr();
            Crypt32.CryptAcquireContext(ref CSPhandle, KeyContainer, ProviderCSP, PROV_RSA_AES, 0);

            //Create hash object
            IntPtr handleHashObj = new IntPtr();
            Crypt32.CryptCreateHash(CSPhandle, CALG_SHA_256, IntPtr.Zero, 0, ref handleHashObj);

            //Hash password
            byte[] pwByteArray = Encoding.Unicode.GetBytes(password);
            uint pwByteAmt = (uint)ASCIIEncoding.Unicode.GetByteCount(password);
            Crypt32.CryptHashData(handleHashObj, pwByteArray, pwByteAmt, 0);

            //Dervie session key from the hashed password
            IntPtr handleSessionKey = new IntPtr();
            Crypt32.CryptDeriveKey(CSPhandle, ENCRYPT_ALGORITHM, handleHashObj, 0, ref handleSessionKey);

            //CryptEncrypt iteration no 1 - Obtain buffer size (output ByteAmt_Itr1)
            byte[] byteArray = new byte[plaintext.Length * sizeof(char)];
            System.Buffer.BlockCopy(plaintext.ToCharArray(), 0, byteArray, 0, byteArray.Length);

            uint byteAmt_Itr1 = (uint)byteArray.Length; //No of bytes, i.e. the size, of the plaintext.
            uint bufferSize_Itr1 = byteAmt_Itr1; //Set buffer size to input data size for now

            Crypt32.CryptEncrypt(handleSessionKey, IntPtr.Zero, 1, 0, null, ref byteAmt_Itr1, 0);

            //CryptEncrypt iteration no 2 - Encryption
            uint byteAmt_Itr2 = (uint)byteArray.Length; //No of bytes, i.e. the size, of the plaintext.
            uint bufferSize_Itr2 = byteAmt_Itr1; //Output from iteration no 1 - size of output data, i.e. correct buffer size

            Crypt32.CryptEncrypt(handleSessionKey, IntPtr.Zero, 1, 0, byteArray, ref byteAmt_Itr2, bufferSize_Itr2);

            Console.WriteLine("Encrypted: " + Encoding.Default.GetString(byteArray));

            // Text encrypted as byteArray, try to decrypt it! //

            //CryptDecrypt - with input from CryptEncrypt".
            Console.WriteLine(Crypt32.CryptDecrypt(handleSessionKey, IntPtr.Zero, 1, 0, byteArray, ref byteAmt_Itr2));

            //Convert decrypted byte array to string
            char[] chars = new char[byteArray.Length / sizeof(char)];
            System.Buffer.BlockCopy(byteArray, 0, chars, 0, byteArray.Length);
            string decryptedText = new string(chars);
            Console.WriteLine("Decrypted: " + decryptedText);
        }
    }

    public class Crypt32
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptAcquireContext(
            ref IntPtr hProv,
            string pszContainer,
            string pszProvider,
            uint dwProvType,
            uint dwFlags);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptCreateHash(
            IntPtr hProv,
            uint algId,
            IntPtr hKey,
            uint dwFlags,
            ref IntPtr phHash);

        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptHashData(
            IntPtr hHash,
            byte[] pbData,
            uint dataLen,
            uint flags);

        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptDeriveKey(
            IntPtr hProv,
            int Algid,
            IntPtr hBaseData,
            int flags,
            ref IntPtr phKey);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptEncrypt(
            IntPtr hKey,
            IntPtr hHash,
            int Final,
            uint dwFlags,
            byte[] pbData,
            ref uint pdwDataLen,
            uint dwBufLen);

        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptDecrypt(
            IntPtr hKey,
            IntPtr hHash,
            int Final,
            uint dwFlags,
            byte[] pbData,
            ref uint pdwDataLen);
    }
}

Output:

Encrypted:
B'♦tt'sô?*ý¢┼àò⌂9Z▼?£'$'¥«çæOÆà[/ë?·UÛÙªÄ2?┼[É{&IâínaÇe
True
Decrypted: Text to encrypt and decrypt!

我已经整理了 CryptDecrypt 的其他输入(制作了另一个 handleSessionKey 和另一个变量而不是 byteAtm_Itr2),它们不是问题的根源。问题似乎出在字节数组上。

如果我使用此代码(或 Buffer.BlockCopy)复制数组,解密将失败:

byte[] byteArray2 = new byte[byteArray.Length];
byteArray.CopyTo(byteArray2, 0);

数组是相同的,但当然不是同一个对象。无法弄清楚为什么这行不通。如果我使用复制的数组运行代码,则输出如下:

Encrypted:
B'♦tt'sô?*ý¢┼àò⌂9Z▼?£'$'¥«çæOÆà[/ë?·UÛÙªÄ2?┼[É{&IâínaÇe
False
Decrypted: Text to encrypt and decr????

因为您使用的是 Unicode,每个字符使用两个字节,所以您没有为原始字符保留足够的空间byteArray。您需要分配当前空间两倍的空间:

  byte[] byteArray = new byte[2*plaintext.Length*sizeof (char)];

更改此代码后,您可以安全地复制数组并解密复制的数组。似乎可以解密原始数组,因为编组库正确识别了数组长度(它首先创建的)。但是,当使用 Array.Copy 时,.NET 代码不会传输这些额外的字节。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;

using System.Runtime.InteropServices.WindowsRuntime;
using System.Runtime.InteropServices;
using System.IO;


namespace EncryptDecryptApplication
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            //Text to encrypt
            string plaintext = "Text to encrypt and decrypt!";

            // Password
            const string password = "password";

            // Constants used in cryptography functions
            const string MS_ENH_RSA_AES_PROV = "Microsoft Enhanced RSA and AES Cryptographic Provider";
                //Name of provider. Same as "Microsoft AES Cryptographic Provider".
            const byte PROV_RSA_AES = 24; //Type of provider
            const string KeyContainer = null;
                //Name of the key container to be used, if NULL then a default key container name is used. Must be a null-terminated string.
            const uint ALG_CLASS_HASH = (4 << 13); //32768 = 4*2^13; //Samma tror jag för alla hashalgoritmer
            const uint ALG_TYPE_ANY = (0); //Samma tror jag för alla hashalgoritmer
            const uint ALG_SID_SHA_256 = 12;
                //ALG_SID_MD5 = 3, ALG_SID_SHA = 4, ALG_SID_SHA_256 = 12, ALG_SID_SHA_384 = 13, ALG_SID_SHA_512 = 14
            const uint CALG_SHA_256 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256);
            const int ALG_CLASS_DATA_ENCRYPT = 24576;
            const int ALG_TYPE_BLOCK = 1536; //used in all types of AES, and in RC2
            const int ALG_SID_AES_256 = 16; //ALG_SID_AES_128 = 14, ALG_SID_AES_192 = 15, ALG_SID_AES_256 = 16
            const int CALG_AES_256 = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256);
            const int ENCRYPT_ALGORITHM = CALG_AES_256;

            // Obtain handle to Cryptographic Service Provider (CSP)
            string ProviderCSP = MS_ENH_RSA_AES_PROV + null;
                //name of the CSP to be used. Must be a null-terminated string.
            IntPtr CSPhandle = new IntPtr();
            Crypt32.CryptAcquireContext(ref CSPhandle, KeyContainer, ProviderCSP, PROV_RSA_AES, 0);

            //Create hash object
            IntPtr handleHashObj = new IntPtr();
            Crypt32.CryptCreateHash(CSPhandle, CALG_SHA_256, IntPtr.Zero, 0, ref handleHashObj);

            //Hash password
            byte[] pwByteArray = Encoding.Unicode.GetBytes(password);
            uint pwByteAmt = (uint) ASCIIEncoding.Unicode.GetByteCount(password);
            Crypt32.CryptHashData(handleHashObj, pwByteArray, pwByteAmt, 0);

            //Dervie session key from the hashed password
            IntPtr handleSessionKey = new IntPtr();
            Crypt32.CryptDeriveKey(CSPhandle, ENCRYPT_ALGORITHM, handleHashObj, 0, ref handleSessionKey);

            //CryptEncrypt iteration no 1 - Obtain buffer size (output ByteAmt_Itr1)
            byte[] byteArray = new byte[2*plaintext.Length*sizeof (char)];
            System.Buffer.BlockCopy(plaintext.ToCharArray(), 0, byteArray, 0, byteArray.Length/2);

            uint byteAmt_Itr1 = (uint) byteArray.Length; //No of bytes, i.e. the size, of the plaintext.
            uint bufferSize_Itr1 = byteAmt_Itr1; //Set buffer size to input data size for now

            Crypt32.CryptEncrypt(handleSessionKey, IntPtr.Zero, 1, 0, null, ref byteAmt_Itr1, 0);

            //CryptEncrypt iteration no 2 - Encryption
            uint byteAmt_Itr2 = (uint) byteArray.Length; //No of bytes, i.e. the size, of the plaintext.
            uint bufferSize_Itr2 = byteAmt_Itr1;
                //Output from iteration no 1 - size of output data, i.e. correct buffer size

            Crypt32.CryptEncrypt(handleSessionKey, IntPtr.Zero, 1, 0, byteArray, ref byteAmt_Itr2, bufferSize_Itr2);

            Console.WriteLine("Encrypted: " + Encoding.Default.GetString(byteArray));

            // Text encrypted as byteArray, try to decrypt it! //

            byte[] byteArray2 = new byte[byteArray.Length];
            byteArray.CopyTo(byteArray2, 0);

            //CryptDecrypt - with input from CryptEncrypt".
            Console.WriteLine(Crypt32.CryptDecrypt(handleSessionKey, IntPtr.Zero, 1, 0, byteArray2, ref byteAmt_Itr2));

            //Convert decrypted byte array to string
            string decryptedText = Encoding.Unicode.GetString(byteArray2).Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries)[0];
            //char[] chars = new char[byteArray.Length / sizeof(char)];
            //System.Buffer.BlockCopy(byteArray, 0, chars, 0, byteArray.Length);
            //string decryptedText = new string(chars);
            Console.WriteLine("Decrypted: " + decryptedText);
        }
    }

    public class Crypt32
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptAcquireContext(
            ref IntPtr hProv,
            string pszContainer,
            string pszProvider,
            uint dwProvType,
            uint dwFlags);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptCreateHash(
            IntPtr hProv,
            uint algId,
            IntPtr hKey,
            uint dwFlags,
            ref IntPtr phHash);

        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptHashData(
            IntPtr hHash,
            byte[] pbData,
            uint dataLen,
            uint flags);

        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptDeriveKey(
            IntPtr hProv,
            int Algid,
            IntPtr hBaseData,
            int flags,
            ref IntPtr phKey);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptEncrypt(
            IntPtr hKey,
            IntPtr hHash,
            int Final,
            uint dwFlags,
            byte[] pbData,
            ref uint pdwDataLen,
            uint dwBufLen);

        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptDecrypt(
            IntPtr hKey,
            IntPtr hHash,
            int Final,
            uint dwFlags,
            byte[] pbData,
            ref uint pdwDataLen);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无法使用 C# 中的 CryptEncrypt/CryptDecrypt 进行解密 的相关文章

随机推荐

  • 我应该使用什么重定向 uri (OAuth 2.0)?

    我为 google API Console 注册了我的应用程序 我得到了我的客户秘密 客户 ID 以及两个重定向 uri urn xxxxxxx oob http localhostxxxxxx 当然 我使用这些项目并成功向谷歌请求令牌 但
  • MySQL 并发性,它是如何工作的以及我是否需要在我的应用程序中处理它

    我目前正在运行 MySQL 数据库 我的所有表都使用表引擎 InnoDB 每个登录我的应用程序的人都可以查看记录 我担心在某些时候两个用户可能会同时更新或插入记录 MySQL 是否能够优雅地处理这种类型的并发问题 还是我必须将其编程到我的代
  • PCRE 正则表达式反向引用有效,但子例程无效

    我正在尝试匹配文本 1 嘿嘿嘿嘿 2 嘿嘿嘿嘿 与正则表达式 a w 1 w b w w w c w 1 w Regex a火柴1完全 并且2完全 但最后一个 y Regex b完全匹配1 and 2 Regex c不匹配1 or 2 下列
  • WordPress 博客分页不起作用

    我仍然卡在这个问题上 我的 WordPress 博客上的分页无法正常工作 http www example com news http www example com news 当您单击不同的页码时 它会正确更新 URL 和页面标题 但不会
  • Swift Couple - Publishers.CombineLatest 在多个线程上

    当将 Publishers CombineLatest 与运行除 Main 的 sink 以外的线程的 Publishers 一起使用时Publishers CombineLatest并不总是被调用 这个问题并不是每次都会出现 这就是为什么
  • 在 Facebook 见解上找不到我的应用程序?

    我正在使用社交插件运行一个网站 所以我创建了一个 Facebook 应用程序 然后我想使用 facebook inform 来连接我的网站和应用程序 ps 我还在标题中添加了app id或meta 但我在连接列表中找不到我创建的应用程序 有
  • 如何在 Android 中将 getview() 与 SimpleAdapter 一起使用?

    我正在生成一个ListView用一个SimpleAdapter My SimpleAdapter代码如下 ListAdapter k new SimpleAdapter this val1 R layout mytask new Strin
  • QTextEdit 中的水平线

    我试图在一个水平线QTextDocument 我使用 HTML 进行格式化 为了画出我想要的线条 我自然地使用了 hr 标签 但这条线是灰色的 我想把它的颜色改为黑色 这些样式似乎不适用于hr元素 那么有没有一个简单的解决方法可以在我的文档
  • 如何在Python中使用“with open”打开多个文件?

    我想一次更改几个文件 iff我可以写信给他们所有人 我想知道是否可以以某种方式将多个开放调用与with陈述 try with open a w as a and open b w as b do something except IOErr
  • Flask 应用程序“使用 stat 重新启动”

    我已经构建了一些 Flask 应用程序 但在我最新的项目中 我注意到开发模式有些奇怪 终端中常见消息的第二行始终显示 Running on http 127 0 0 1 5000 Restarting with reloader 已被替换为
  • git bisect skip 如何选择下一个提交来尝试?

    使用时git bisect 一个人可以跑git bisect skip将当前提交标记为不可构建 不可测试的提交 尝试让 Git 选择其他提交进行测试 Git 如何决定在某个提交之后尝试哪个提交git bisect skip 实验表明这不仅仅
  • Backbone.js 查看实例变量?

    我正在学习 Backbone js 并试图弄清楚是否可以在 Backbone 视图中包含实例变量 我的目标是在实例化视图时从外部文件加载视图的模板 目前 我将它们存储在 Backbone 应用程序的全局命名空间中的全局变量中 但将模板存储在
  • 动态获取变量

    我正在使用 Go 模板来管理 Helm 的部署 我有这样的values yaml 文件 env dev config dev myname Hi live myname Bye 现在我想根据环境 开发 实时 获取值 喜欢 Values co
  • dlopen 是否创建多个库实例?

    在网上搜索后 我似乎找不到答案 当我第一次使用 dlopen 时 它似乎比此后的任何时间都花费更长的时间 包括如果我从程序的多个实例运行它 dlopen 是否将 so 加载到内存中一次并让操作系统保存它 以便任何后续调用 甚至来自程序的另一
  • 在 Cassandra 中选择两个表

    I use Cassandra一个项目 这是我的第一个项目 我试图对两个表执行一个简单的请求 但这不起作用 我想做类似的事情 Select from table1 table2 where table1 test test and tabl
  • 无法打开选定的 VM 调试端口 (8700)。确保您没有运行 DDMS 或 eclipse 插件的另一个实例

    我正在尝试在 eclipse kepler 中执行 android 程序 但是 每次执行时我都会收到此消息 我按照大家对这个问题所说的做了 Making sure there is a line on windows Host file t
  • Xcode:“无法保存文档。您没有权限。”

    尝试在 Xcode 4 中保存文件时出现此错误 无法保存文档 您没有权限 要查看或更改权限 请在 Finder 中选择该项目 然后选择 文件 gt 获取信息 当然 将文件保存在 TextMate 中效果很好 权限 rw r r 与上次工作时
  • 使用 Ionic 框架将 html 文件的内容嵌入到另一个 html 页面?

    我目前正在创建一个网站使用离子框架 http ionicframework com左侧有一个侧边栏 用户可以单击某个项目转到网站的另一个页面 现在我必须将侧边栏的代码复制到每个页面 这是没有用的 也不是可行的方法 所以我的问题是是否可以将
  • 定期重置嵌入式 H2 数据库

    我正在演示服务器中设置应用程序的新版本 并且希望找到一种每天重置数据库的方法 我想我总是可以有一个 cron 作业执行删除和创建查询 但我正在寻找一种更干净的方法 我尝试使用带有删除创建方法的特殊持久性单元 但它不起作用 因为系统频繁地 按
  • 无法使用 C# 中的 CryptEncrypt/CryptDecrypt 进行解密

    我制作了一个小应用程序来加密和解密一些文本 只要我直接使用加密中的字节数组 一切都很好 但是 一旦我复制了数组来模拟将加密文本作为文件发送的过程 解密就不会运行 为什么我无法使用复制的数组运行解密 using System using Sy