Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++ implementation of CryptDeriveKey

1,302 views
Skip to first unread message

Boris

unread,
Oct 1, 2006, 11:03:36 AM10/1/06
to
I have to decrypt on UNIX what has been encrypted with 3DES on Windows. As
CryptDeriveKey is used on Windows (with a SHA1 hashed password and
CALG_NOSALT) I try to emulate this function on UNIX. According to
http://msdn.microsoft.com/library/en-us/seccrypto/security/cryptderivekey.asp?frame=true
CryptDeriveKey should look like this I think:

std::basic_string<unsigned char>
mscrypt_derive_key_sha1(std::basic_string<unsigned char> password)
{
unsigned char buf1[64];
unsigned char buf2[64];

std::fill_n(buf1, 0x36, sizeof(buf1));
std::fill_n(buf2, 0x5C, sizeof(buf2));

std::basic_string<unsigned char> hash = hash_sha1(password);
for (std::size_t i = 0; i < hash.size(); ++i)
{
buf1[i] ^= hash[i];
buf2[i] ^= hash[i];
}

return hash_sha1(buf1) + hash_sha1(buf2).substr(0, 4);
}

I only try to emulate CryptDeriveKey for 3DES with SHA1. That's why I simply
return 192 bits for the key. The function hash_sha1 has been implemented and
tested separately.

Can anyone confirm if my implementation is correct? Or is it possible to
output the key which is generated by CryptDeriveKey on Windows? Then I could
make some tests at least and compare the generated keys to be sure that my
implementation works.

Thanks in advance,
Boris


tlviewer

unread,
Oct 1, 2006, 3:09:23 PM10/1/06
to

"Boris" <bo...@gtemail.net> wrote in message
news:OaKjKrW5...@TK2MSFTNGP05.phx.gbl...

Boris,

here is a test vector made on windows using a python version of the above
algo:

string input : 124-Kelp
derived key (hex): 5ab48b8def0bdca77f16f8c4f4781823e92ecc1c4d40f762

hth,
tlviewer


Boris

unread,
Oct 1, 2006, 7:21:37 PM10/1/06
to
tlviewer wrote:
> [...] here is a test vector made on windows using a python version of the

> above algo:
>
> string input : 124-Kelp
> derived key (hex): 5ab48b8def0bdca77f16f8c4f4781823e92ecc1c4d40f762

Thanks, there must be something wrong then. When I derive the key from your
string input with the .NET class PasswordDeriveBytes I get this key:
5bb58a8cef0bdca77f16f8c4f4791923e92fcd1c4c40f762

The C++ algorithm comes pretty close but it's not yet the same. Here's the
.NET code I used:
PasswordDeriveBytes pdb = new PasswordDeriveBytes("124-Kelp", null);
byte[] pwIV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] desKey = pdb.CryptDeriveKey("TripleDES", "SHA1", 192, pwIV);

I'll read the description at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/cryptderivekey.asp
some more times to understand hopefully what Microsoft means ...

Boris


Boris

unread,
Oct 1, 2006, 7:44:47 PM10/1/06
to
tlviewer wrote:
> [...] here is a test vector made on windows using a python version of the

> above algo:
>
> string input : 124-Kelp
> derived key (hex): 5ab48b8def0bdca77f16f8c4f4781823e92ecc1c4d40f762

I tested now 124-Kelp with my C++ implementation and get a completely wrong
key. Can you show me your Python version? There must be something different
as otherwise I would expect that we get the same keys at least (even though
they are still different from what PasswordDeriveBytes returns).

Boris


tlviewer

unread,
Oct 1, 2006, 11:54:46 PM10/1/06
to

"Boris" <bo...@gtemail.net> wrote in message
news:OAbidBb5...@TK2MSFTNGP02.phx.gbl...

> tlviewer wrote:
>> [...] here is a test vector made on windows using a python version of the
>> above algo:
>>
>> string input : 124-Kelp
>> derived key (hex): 5ab48b8def0bdca77f16f8c4f4781823e92ecc1c4d40f762
>
> Thanks, there must be something wrong then. When I derive the key from
> your string input with the .NET class PasswordDeriveBytes I get this key:
> 5bb58a8cef0bdca77f16f8c4f4791923e92fcd1c4c40f762

yes this is my result corrected for parity.
5bb58a8cef0bdca77f16f8c4f4791923e92fcd1c4c40f762

you will find that exported session keys (via simpleblob) will not be
corrected for
parity that's why I didn't add that. Only when calling CryptEncrypt or
CryptHashSessionKey will
you see this correction. It's transparent -- you don't have to think about
it when using the
CryptoAPI. I don't bother with the .NET stuff.

I gave you a derived key which will match the value exported from CryptoAPI
as a
PlainTextBlob in Winxp or higher.

hth,
tlviewer


Boris

unread,
Oct 2, 2006, 6:57:20 AM10/2/06
to

There were two bugs in mscrypt_derive_key_sha1. After correcting them
everything works as expected. As I couldn't find any source code at all
which shows how CryptDeriveKey works I post a small C++ program for Windows
which might help others in the future.

Boris


Boris

unread,
Oct 2, 2006, 7:00:56 AM10/2/06
to
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <iostream>

std::basic_string<unsigned char> hash_sha1(std::basic_string<unsigned char>
data)
{
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0))
std::exit(EXIT_FAILURE);
if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
std::exit(EXIT_FAILURE);
if (!CryptHashData(hHash, data.c_str(), static_cast<DWORD>(data.size()),
0))
std::exit(EXIT_FAILURE);

DWORD dwHashLen;
DWORD dwCount = sizeof(DWORD);
if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&dwHashLen, &dwCount, 0))
std::exit(EXIT_FAILURE);

unsigned char *pbHash = new unsigned char[dwHashLen];
if (!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, 0))
std::exit(EXIT_FAILURE);
std::basic_string<unsigned char> hash = std::basic_string<unsigned
char>(pbHash, dwHashLen);
delete[] pbHash;

if (hHash)
CryptDestroyHash(hHash);
if (hProv)
CryptReleaseContext(hProv, 0);

return hash;
}

std::basic_string<unsigned char>
mscrypt_derive_key_sha1(std::basic_string<unsigned char> password)
{
unsigned char buf1[64];
unsigned char buf2[64];

std::fill_n(buf1, sizeof(buf1), 0x36);
std::fill_n(buf2, sizeof(buf2), 0x5C);

std::basic_string<unsigned char> hash = hash_sha1(password);
for (std::size_t i = 0; i < hash.size(); ++i)
{
buf1[i] ^= hash[i];
buf2[i] ^= hash[i];
}

return hash_sha1(std::basic_string<unsigned char>(buf1, sizeof(buf1))) +
hash_sha1(std::basic_string<unsigned char>(buf2, sizeof(buf2))).substr(0,
4);
}

int main(int argc, char* argv[])
{
if (argc < 2)
return EXIT_FAILURE;
std::cout << "Password: " << argv[1] << std::endl;
std::basic_string<unsigned char> password = reinterpret_cast<const unsigned
char*>(argv[1]);
std::basic_string<unsigned char> hash = mscrypt_derive_key_sha1(password);
std::string hex;


for (std::size_t i = 0; i < hash.size(); ++i)
{

hex += "0123456789ABCDEF"[hash[i] / 16];
hex += "0123456789ABCDEF"[hash[i] % 16];
}
std::cout << "Key: " << hex << std::endl;
}


Mitch Gallant

unread,
Oct 2, 2006, 9:03:44 AM10/2/06
to
"tlviewer" <tlvi...@yahoo.com> wrote in message
news:eGKbCad5...@TK2MSFTNGP04.phx.gbl...

The exported session key (for 3DES) in a simple blob is the indentical key
that generates the same cipher text in all of .NET, Java and capi as
discussed here::
http://www.jensign.com/JavaScience/dotnet/NetDESEncrypt/
So I gather that if you supply the 24 bytes 3DES binary key for interop, you
supply the non-corrected (for parity) key value.
Seems strange that PaswordDeriveBytes would output the parity-corrected
value as this will create issues in .NET when using that Pswd derivation fn.

- Mitch Gallant
MVP Security


Boris

unread,
Oct 2, 2006, 4:46:02 PM10/2/06
to
Mitch Gallant wrote:
> [...] The exported session key (for 3DES) in a simple blob is the

> indentical key that generates the same cipher text in all of .NET,
> Java and capi as discussed here::
> http://www.jensign.com/JavaScience/dotnet/NetDESEncrypt/
> So I gather that if you supply the 24 bytes 3DES binary key for
> interop, you supply the non-corrected (for parity) key value.
> Seems strange that PaswordDeriveBytes would output the
> parity-corrected value as this will create issues in .NET when using
> that Pswd derivation fn.

I had no interop problems so far: Encrypting on .NET and decrypting with
Crypto API (only 3DES though). From what I understand the parity bits are
not used for 3DES anyway thus they shouldn't matter?

Boris


Mitch Gallant

unread,
Oct 2, 2006, 6:22:23 PM10/2/06
to
Yes you are right. As long as the initial 24 byte 3DES key was initially
derived correctly, it doesn't matter if the parity corrected or uncorrected
key data is used since those LSB are discarded.
Similar discussion is at:
http://groups.google.com/group/microsoft.public.security.crypto/browse_frm/thread/75cb3d0675f63810/52f4a9951fde0b86

Talking about .NET, the recommended pbkf function is now (in .NET 2) PBKD2
Rfc2898DeriveBytes(..)

- Mitch

"Boris" <bo...@gtemail.net> wrote in message

news:%23K7gKPm...@TK2MSFTNGP05.phx.gbl...

pww19...@gmail.com

unread,
Apr 21, 2015, 9:29:59 PM4/21/15
to
在 2006年10月1日星期日 UTC+8下午11:03:36,Boris写道:
Title: The core of the core of the big data solutions -- Map
Author: pengwenwei
Email: wenwei19710430
Language: c++
Platform: Windows, linux
Technology: Perfect hash algorithm
Level: Advanced
Description: Map algorithm with high performance
Section MFC c++ map stl
SubSection c++ algorithm
License: (GPLv3)

Download demo project - 1070 Kb
Download source - 1070 Kb

Introduction:
For the c++ program, map is used everywhere.And bottleneck of program performance is often the performance of map.Especially in the case of large data,and the business association closely and unable to realize the data distribution and parallel processing condition.So the performance of map becomes the key technology.

In the work experience with telecommunications industry and the information security industry, I was dealing with the big bottom data,especially the most complex information security industry data,all can’t do without map.

For example, IP table, MAC table, telephone number list, domain name resolution table, ID number table query, the Trojan horse virus characteristic code of cloud killing etc..

The map of STL library using binary chop, its has the worst performance.Google Hash map has the optimal performance and memory at present, but it has repeated collision probability.Now the big data rarely use a collision probability map,especially relating to fees, can’t be wrong.

Now I put my algorithms out here,there are three kinds of map,after the build is Hash map.We can test the comparison,my algorithm has the zero probability of collision,but its performance is also better than the hash algorithm, even its ordinary performance has no much difference with Google.

My algorithm is perfect hash algorithm,its key index and the principle of compression algorithm is out of the ordinary,the most important is a completely different structure,so the key index compression is fundamentally different.The most direct benefit for program is that for the original map need ten servers for solutions but now I only need one server.
Declare: the code can not be used for commercial purposes, if for commercial applications,you can contact me with QQ 75293192.
Download:
https://sourceforge.net/projects/pwwhashmap/files

Applications:
First,modern warfare can’t be without the mass of information query, if the query of enemy target information slows down a second, it could lead to the delaying fighter, leading to failure of the entire war. Information retrieval is inseparable from the map, if military products use pwwhashMap instead of the traditional map,you must be the winner.

Scond,the performance of the router determines the surfing speed, just replace open source router code map for pwwHashMap, its speed can increase ten times.
There are many tables to query and set in the router DHCP ptotocol,such as IP,Mac ,and all these are completed by map.But until now,all map are using STL liabrary,its performance is very low,and using the Hash map has error probability,so it can only use multi router packet dispersion treatment.If using pwwHashMap, you can save at least ten sets of equipment.

Third,Hadoop is recognized as the big data solutions at present,and its most fundamental thing is super heavy use of the map,instead of SQL and table.Hadoop assumes the huge amounts of data so that the data is completely unable to move, people must carry on the data analysis in the local.But as long as the open source Hadoop code of the map changes into pwwHashMap, the performance will increase hundredfold without any problems.


Background to this article that may be useful such as an introduction to the basic ideas presented:
http://blog.csdn.net/chixinmuzi/article/details/1727195

0 new messages