David Garamond <lists / zara.6.isreserved.com> wrote in message news:<400FF2F2.7080800 / zara.6.isreserved.com>... > 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 #==========================================================================