help with Win32API

D

David Garamond

I'm trying to do the equivalent of this C code:

long getrand()
{
HCRYPTPROV hProv = 0;
CryptAcquireContext(&hProv,
0, 0, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT);
long rnd;
CryptGenRandom(hProv,
sizeof(rnd), (BYTE*)&rnd);
CryptReleaseContext(hProv, 0);
return rnd;
}

Eexcept that I want to generate 16 bytes of random numbers. Here's my
stab so far:

require 'Win32API'
cac = Win32API.new("advapi32", "CryptAcquireContext",
['P','L','L','I','I'], 'N')
cgr = Win32API.new("advapi32", "CryptGenRandom", ['P','I','P'], 'N')
hProv = " " * 16
cac.call(hProv, 0, 0, 1, 251658240)
guid = " " * 16
cgr.call(hProv, 16, guid)
p guid

From wincrypt.h:

#define PROV_RSA_FULL 1
#define CRYPT_VERIFYCONTEXT 0xF0000000

BOOL WINAPI CryptGenRandom (HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);

BOOL WINAPI CryptAcquireContext(HCRYPTPROV *phProv, LPCSTR pszContainer,
LPCSTR pszProvider, DWORD dwProvType,
DWORD dwFlags);


No segfaults, but the output comes up still empty. Any pointer where I
did wrong? Sigh, I'm so terrible when it comes to C.
 
S

Stephen Veit

David Garamond said:
I'm trying to do the equivalent of this C code:

long getrand()
{
HCRYPTPROV hProv = 0;
CryptAcquireContext(&hProv,
0, 0, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT);
long rnd;
CryptGenRandom(hProv,
sizeof(rnd), (BYTE*)&rnd);
CryptReleaseContext(hProv, 0);
return rnd;
}

Eexcept that I want to generate 16 bytes of random numbers. Here's my
stab so far:

require 'Win32API'
cac = Win32API.new("advapi32", "CryptAcquireContext",
['P','L','L','I','I'], 'N')
cgr = Win32API.new("advapi32", "CryptGenRandom", ['P','I','P'], 'N')
hProv = " " * 16
cac.call(hProv, 0, 0, 1, 251658240)
guid = " " * 16
cgr.call(hProv, 16, guid)
p guid

From wincrypt.h:

#define PROV_RSA_FULL 1
#define CRYPT_VERIFYCONTEXT 0xF0000000

BOOL WINAPI CryptGenRandom (HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);

BOOL WINAPI CryptAcquireContext(HCRYPTPROV *phProv, LPCSTR pszContainer,
LPCSTR pszProvider, DWORD dwProvType,
DWORD dwFlags);


No segfaults, but the output comes up still empty. Any pointer where I
did wrong? Sigh, I'm so terrible when it comes to C.


Unfortunately you have two mistakes. The first simple one is that the
decimal equivalent for 0xF0000000 (CRYPT_VERIFYCONTEXT) is 4026531840
not 251658240.

The second is a little more subtle. CryptAcquireContext takes a
pointer to a HCRYPTPROV which is a 4 byte long. After this call
returns, the HCRYPTPROV value needs to be unpacked as a L:

hProvI, = hProv.unpack('L')

CryptGenRandom takes a HCRYPTPROV value (a long). So the first
parameter should be specified as a 'L':

cgr = Win32API.new("advapi32", "CryptGenRandom", ['L','I','P'], 'N')

Here is you code snippet rewritten with as few changes as possible:

#==========================================================================
require 'Win32API'
cac = Win32API.new("advapi32", "CryptAcquireContext",
['P','L','L','I','I'], 'N')
cgr = Win32API.new("advapi32", "CryptGenRandom", ['L','I','P'], 'N')
hProv = " " * 16
cac.call(hProv, 0, 0, 1, 4026531840)
guid = " " * 16
hProvI, = hProv.unpack('L')
cgr.call(hProvI, 16, guid)
p guid
#==========================================================================


Really you should check for errors and display them. Here is a
somewhat more refined implementation:

#==========================================================================
require 'Win32API'

PROV_RSA_FULL = 1
CRYPT_VERIFYCONTEXT = 0xF0000000

FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000

CryptAcquireContext = Win32API.new("advapi32", "CryptAcquireContext",
'PPPII', 'L')
CryptGenRandom = Win32API.new("advapi32", "CryptGenRandom",
'LIP', 'L')
GetLastError = Win32API.new("Kernel32", "GetLastError", '', 'L')
FormatMessageA = Win32API.new("Kernel32", "FormatMessageA",
'LPLLPLPPPPPPPP', 'L')

def lastErrorMessage
code = GetLastError.call
msg = "\0" * 1024
len = FormatMessageA.call(FORMAT_MESSAGE_IGNORE_INSERTS +
FORMAT_MESSAGE_FROM_SYSTEM, 0,
code, 0, msg, 1024, nil, nil,
nil, nil, nil, nil, nil, nil)
msg[0, len].tr("\r", '').chomp
end

def getRandGUID
hProvStr = " " * 4
if CryptAcquireContext.call(hProvStr, nil, nil, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT) == 0
raise "CryptAcquireContext failed: #{lastErrorMessage}"
end
hProv, = hProvStr.unpack('L')
guid = " " * 16
if CryptGenRandom.call(hProv, 16, guid) == 0
raise "CryptAcquireContext failed: #{lastErrorMessage}"
end
guid
end

p getRandGUID
#==========================================================================
 
D

David Garamond

Stephen said:
Unfortunately you have two mistakes. The first simple one is that the
decimal equivalent for 0xF0000000 (CRYPT_VERIFYCONTEXT) is 4026531840
not 251658240.

Ah, missed another zero there (251658240 = 0xF000000).

[snip]
Really you should check for errors and display them. Here is a
somewhat more refined implementation:

Thanks so much! I'm learning a bit more about C and Win32... I'm now
using your code; all that's left to do is adding the CryptReleaseContext
call.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top