简体   繁体   English

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

[英]Pinvoking adwapi.dll - cryptDecrypt and cryptEncrypt functions, weird problem

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. 我正在观察这个函数的奇怪行为,我要加密的字符串包含14个字节,如果我使用函数发送缓冲区的长度= 14,它就会失败(“内部错误” - 非常具有描述性和最有用的错误代码) ,但它在缓冲区长度(和缓冲区本身)大128字节时有效。

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), 我通过制作128字节大小的数组克服了这个问题,并从纯文本中复制了14个字节(我希望加密),

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)). 当我解密那些字节时,我必须再次给函数提供整个128字节的数组(现在每个字节都加密,甚至是#13-#127(我猜是预期的))。 Luckily for me the first 14 bytes get decrypted as they should, the rest is gibberish. 对我来说幸运的是前14个字节应该被解密,剩下的就是胡言乱语。

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? 我想知道为什么如果传入的缓冲区不是128字节大,加密方法失败,为什么解密函数也需要一个128字节的数组,这是一些填充的东西?

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 //在这种情况下,MyKey是指向加密密钥的指针,第二个参数是null,第三个是“true”(没有更多数据),没有标志,缓冲区字节数组(128),在这种情况下,Testing.Length是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? 结果如下所示:测试?R ???? 7?q ??????????????????????????????????????????????? )电子? i?+? >[?S???}Ct?n?&??b?P!?u1??%?JQ???/?mP?5wB???? > [?Sαδ+}的Ct 2 N?&14 B 2 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. 我需要使用我的智能卡(我使用其专有CSP)和私钥来验证(解密)此文件。 As you can see, it ALMOST works. 如你所见,它几乎可以工作。

Thanks in advance. 提前致谢。

I think the reason the buffer must be 128 bytes is that a block cipher is being used. 我认为缓冲区必须是128字节的原因是正在使用块密码。 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. 在调用CryptDecrypt之后,参数pdwDataLen (代码中的locInputLength )将包含已解密的实际数据的长度。 If you take only the first locInputLength bytes of dataCopy , does it give you what you need? 如果你只需要第一locInputLength字节dataCopy ,它给你你需要什么?

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

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 ;) 其中一件你不会“看到”的东西,直到你退后一点,从略微不同的角度看待事物;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM