Pinvoking adwapi.dll - cryptDecrypt 和 cryptEncrypt 函数,奇怪的问题

发布于 2024-10-24 03:40:29 字数 2193 浏览 5 评论 0原文

我正在观察这个函数的奇怪行为,我想要加密的字符串包含 14 个字节,如果我使用该函数发送缓冲区长度 = 14,它会失败(“内部错误” - 非常具有描述性且最有帮助的错误代码) ,但当缓冲区长度(以及缓冲区本身)为 128 字节大时,它会起作用。

我通过创建一个大小为 128 字节的数组克服了这个问题,并从纯文本中复制了 14 个字节(我希望加密),

当我解密这些字节时,我必须再次为该函数提供整个 128 字节数组(现在每个字节都已加密,甚至包括 #13-#127 中的字节(我猜这是预料之中的)。对我来说幸运的是,前 14 个字节得到了应有的解密,其余的都是乱码。

我想知道为什么如果传入缓冲区不是 128 字节大,加密方法会失败,为什么解密函数还需要 128 字节数组,是一些填充的东西吗?

这就是我调用加密函数的方式:

System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();  // encoding type
byte[] buff = new byte[128];     // this is my buffer array, instantiated and initiated
string String2Encrypt = "Testing";      // this is the string I need encrypted
byte[] tempo = encoding.GetBytes(String2Encrypt);   // getting bytes from string
Buffer.BlockCopy(tempo, 0, buff, 0, tempo.Length);    // copying the small array into the large one
uint inputlength = Convert.ToUInt32(tempo.Length);   // getting the size of the small array 


bool DidIt = UnsafeNativeMethods.CryptEncrypt(MyKey, IntPtr.Zero, 1, 0, buff, ref inputlength, outputdatalength);     // calling the function

// 在这种情况下,MyKey 是指向加密密钥的指针,第二个参数为 null,第三个参数为“true”(没有更多数据),没有标志,缓冲区字节数组 (128),在本例中,Testing.Length 为 7, 128

这就是我解密的方式:

IntPtr UserKeyLocal = MyUserKey;     // taking an argument (MyUserKey) and "filling" the local variable, not really relevant
byte[] dataCopy = new byte[buff.Length];   // init and insta the datacopy array (128 byte)
Buffer.BlockCopy(buff, 0, dataCopy, 0, (int)buff.Length);   // copying the argument array into a local version (I used this for testing to go around another problem), irrelevant
uint locinputlength = inputlength;  // another argument made local
bool DidIT = UnsafeNativeMethods.CryptDecrypt(UserKeyLocal, IntPtr.Zero, true, 0, dataCopy, ref locinputlength);     // calling the function

结果如下所示: 测试?R???7?q??????$??uj??m%?b??e?a?74p?)?n9??w?R*O)E?i ?+?>[?S???}Ct?n?&??b?P!?u1??%?JQ???/?mP?5wB????

它几乎按预期工作,但我需要能够仅获得字符串的“测试”部分,而不使用子字符串等技巧。

我想做的(也许还有其他方法)是这样的;我有一个二进制文件(文件),其中包含通过从智能卡导出的证书获得的公钥加密的“测试”。 我需要使用我的智能卡(我正在使用其专有的 CSP)和私钥来验证(解密)此文件。正如您所看到的,它几乎可以工作。

提前致谢。

I am observing wierd behaviour of this function, the string that I want to encrypt contains 14 bytes, if I use the function to send lenght of buffer = 14, it fails ("an internal error" - very descriptive and most helpful error code), but it works when the buffer length (and the buffer itself) is 128 bytes large.

I overcame this problem by making a size 128 byte array and I copied the 14 bytes from the plain text (that I wish to encrypt),

When I decrypt those bytes, I must once again give the function the whole 128 byte array (which now has every byte encrypted, even the ones from #13-#127 (which I guess is to be expected)). Luckily for me the first 14 bytes get decrypted as they should, the rest is gibberish.

I would like to know why the encrypt method fails if the incoming buffer isnt 128 byte large, and also why decrypt function also requires a 128 byte array, is it some padding thing?

This is how I call the encrypt function:

System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();  // encoding type
byte[] buff = new byte[128];     // this is my buffer array, instantiated and initiated
string String2Encrypt = "Testing";      // this is the string I need encrypted
byte[] tempo = encoding.GetBytes(String2Encrypt);   // getting bytes from string
Buffer.BlockCopy(tempo, 0, buff, 0, tempo.Length);    // copying the small array into the large one
uint inputlength = Convert.ToUInt32(tempo.Length);   // getting the size of the small array 


bool DidIt = UnsafeNativeMethods.CryptEncrypt(MyKey, IntPtr.Zero, 1, 0, buff, ref inputlength, outputdatalength);     // calling the function

// in this case, the MyKey is pointer to a crypto key, 2nd argument is null, 3rd is "true" (no more data), no flags, buffer byte array (128), Testing.Length in this case it is 7, 128

This is how I decrypt it:

IntPtr UserKeyLocal = MyUserKey;     // taking an argument (MyUserKey) and "filling" the local variable, not really relevant
byte[] dataCopy = new byte[buff.Length];   // init and insta the datacopy array (128 byte)
Buffer.BlockCopy(buff, 0, dataCopy, 0, (int)buff.Length);   // copying the argument array into a local version (I used this for testing to go around another problem), irrelevant
uint locinputlength = inputlength;  // another argument made local
bool DidIT = UnsafeNativeMethods.CryptDecrypt(UserKeyLocal, IntPtr.Zero, true, 0, dataCopy, ref locinputlength);     // calling the function

The result would look like this:
Testing?R????7?q?????$??uj??m%?b??e?a?74p?)?n9??w?R*O)E?i?+?>[?S???}Ct?n?&??b?P!?u1??%?JQ???/?mP?5wB????

Its almost working as intended but I need to be able to get ONLY the "Testing" part of the string without using tricks like substringing.

What I am trying to do (maybe there is an alternative way) is this; I have a binary (file) that has in it "Testing" encrypted by a public key I got from a certificate which I exported form a SmartCard.
I need to verify (decrypt) this file by using my SmartCard (I am using its propriety CSP) with the private key. As you can see, it ALMOST works.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如何视而不见 2024-10-31 03:40:29

我认为缓冲区必须为 128 字节的原因是正在使用分组密码。在这种情况下,缓冲区长度必须是块大小的倍数。对于分组密码,缓冲区可能需要大于数据的大小,以便可以将加密或解密的数据写入其中(长度(加密)!=长度(明文))。

调用 CryptDecrypt 后,参数 pdwDataLen(代码中的 locInputLength)将包含已解密的实际数据的长度。如果您只获取 dataCopy 的前一个 locInputLength 字节,它是否能满足您的需求?

参考:
http://msdn.microsoft.com/en-us/库/aa379913(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa379924(VS.85).aspx

I think the reason the buffer must be 128 bytes is that a block cipher is being used. In that case, the buffer length must be a multiple of the block size. With a block ciper, the buffer may need to be larger than the size of the data anyway, so that the encrypted or decrypted data can be written to it (length(encrypted) != length(plaintext)).

After you call CryptDecrypt, the parameter pdwDataLen (locInputLength in your code) will contain the length of the actual data that was decrypted. If you take only the first locInputLength bytes of dataCopy, does it give you what you need?

References:
http://msdn.microsoft.com/en-us/library/aa379913(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa379924(VS.85).aspx

梦回旧景 2024-10-31 03:40:29

是的,就是这样!简单易行!

            byte[] buffer = new byte[locinputlength];
            Buffer.BlockCopy(dataCopy, 0, buffer, 0, (int)locinputlength);
            return buffer;

其中一件事你只是不会“看到”,直到你退后一点并从稍微不同的角度看待它;)

Yup, that did it! easy as pie!

            byte[] buffer = new byte[locinputlength];
            Buffer.BlockCopy(dataCopy, 0, buffer, 0, (int)locinputlength);
            return buffer;

One of those things you just dont "see" until you step back a little and look at the thing from a slightly different perspective ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文