#ifdef __MINGW32__
#ifndef __USE_MINGW_ANSI_STDIO
#define __USE_MINGW_ANSI_STDIO 1
#endif
#endif
#define PERL_NO_GET_CONTEXT 1
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <wincrypt.h> /* needed for crypt_gen_random
but not for rtl_gen_random */
void print_error(pTHX) {
dSP;
PUSHMARK(SP);
call_pv("Win32::GenRandom::_system_error", G_DISCARD|G_NOARGS);
}
void cgr(pTHX_ SV * x, ...) {
dXSARGS;
unsigned long i;
BYTE * buff;
HCRYPTPROV prov = 0;
unsigned long how_many;
DWORD len;
if(items == 1) {
how_many = 1;
len = (ULONG)SvUV(ST(0));
}
else {
if(items == 2) {
how_many = (unsigned long)SvUV(ST(0));
len = (ULONG)SvUV(ST(1));
}
else croak("cgr takes either 1 or 2 args, not %d", items);
}
if(!CryptAcquireContextA(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) {
warn("Call to CryptAcquireContextA failed\n");
print_error(aTHX); /* callback to $^E */
croak("Croaking - owing to failure of CryptAcquireContextA");
}
Newx(buff, len + 1, BYTE);
if(buff == NULL) {
warn ("Failed to allocate memory for buffer");
CryptReleaseContext(prov, 0);
croak("Croaking - owing to memory allocation failure");
}
sp = mark;
for(i = 0; i < how_many; i++) {
if(!CryptGenRandom(prov, len, buff)) {
warn("Call to CryptGenRandom failed");
Safefree(buff);
CryptReleaseContext(prov, 0);
print_error(aTHX); /* callback to $^E */
croak("Croaking - owing to failure of call to CryptGenRandom");
}
XPUSHs(sv_2mortal(newSVpv(buff, len)));
}
Safefree(buff);
CryptReleaseContext(prov, 0);
PUTBACK;
XSRETURN(how_many);
}
void cgr_custom(pTHX_ SV * x, ...) {
dXSARGS;
unsigned long i;
BYTE * buff;
HCRYPTPROV prov = 0;
unsigned long how_many;
DWORD len;
int offset = 0;
if(items == 5) {
how_many = 1;
len = (ULONG)SvUV(ST(0));
}
else {
if(items == 6) {
how_many = (unsigned long)SvUV(ST(0));
len = (ULONG)SvUV(ST(1));
offset = 1;
}
else croak("cgr_custom takes either 5 or 6 args, not %d", items);
}
if(!CryptAcquireContextA(&prov, SvPV_nolen(ST(offset + 1)), SvPV_nolen(ST(offset + 2)),
(DWORD)SvUV(ST(offset + 3)), (DWORD)SvUV(ST(offset + 4)))) {
warn("Call to CryptAcquireContextA failed\n");
print_error(aTHX); /* callback to $^E */
croak("Croaking - owing to failure of CryptAcquireContextA");
}
Newx(buff, len + 1, BYTE);
if(buff == NULL) {
warn ("Failed to allocate memory for buffer");
CryptReleaseContext(prov, 0);
croak("Croaking - owing to memory allocation failure");
}
sp = mark;
for(i = 0; i < how_many; i++) {
if(!CryptGenRandom(prov, len, buff)) {
warn("Call to CryptGenRandom failed");
Safefree(buff);
CryptReleaseContext(prov, 0);
print_error(aTHX); /* callback to $^E */
croak("Croaking - owing to failure of call to CryptGenRandom");
}
XPUSHs(sv_2mortal(newSVpv(buff, len)));
}
Safefree(buff);
CryptReleaseContext(prov, 0);
PUTBACK;
XSRETURN(how_many);
}
void rgr(pTHX_ SV * x, ...) {
#ifndef WIN2K
dXSARGS;
unsigned long i;
BYTE * buff;
unsigned long how_many;
ULONG len;
HMODULE hLib;
if(items == 1) {
how_many = 1;
len = (ULONG)SvUV(ST(0));
}
else {
if(items == 2) {
how_many = (unsigned long)SvUV(ST(0));
len = (ULONG)SvUV(ST(1));
}
else croak("rgr takes either 1 or 2 args, not %d", items);
}
Newx(buff, len + 1, BYTE);
if(buff == NULL) croak ("Failed to allocate memory for 'buff'");
hLib = LoadLibrary("ADVAPI32.DLL");
sp = mark;
if (hLib) {
BOOLEAN (APIENTRY *pfn)(void*, ULONG) =
(BOOLEAN (APIENTRY *)(void*,ULONG))GetProcAddress(hLib,"SystemFunction036");
for(i = 0; i < how_many; i++) {
if(pfn(buff,len)) {
XPUSHs(sv_2mortal(newSVpv(buff, len)));
/*
Now that we've finished with it, fill buffer with zeroes (as per MSDN recommendation).
We do this with SecureZeroMemory if its available, else we do it with ZeroMemory if
it's available, else we don't do it.
*/
#ifdef SecureZeroMemory
SecureZeroMemory(buff, len);
#else
#ifdef ZeroMemory
ZeroMemory(buff, len);
#endif
#endif
}
else {
warn("Call to 'SystemFunction036' failed");
FreeLibrary(hLib);
print_error(aTHX); /* callback to $^E */
croak("Croaking - owing to failure of call to 'SystemFunction036'");
}
}
FreeLibrary(hLib);
}
else {
print_error(aTHX); /* callback to $^E */
croak("Failed to load ADVAPI32.dll");
}
Safefree(buff);
PUTBACK;
XSRETURN(how_many);
# else
croak("RtlGenRandom not available on Windows 2000 - use CryptGenRandom instead");
#endif
}
SV * _error_test(pTHX) {
/* Solely for use of test suite */
HMODULE hLib=LoadLibrary("NO_SUCH.DLL");
if(hLib) return newSVuv(0);
else print_error(aTHX);
return newSVuv(42);
}
/* FLAGS */
SV * _CRYPT_DEFAULT_CONTAINER_OPTIONAL(pTHX) {
#ifdef CRYPT_DEFAULT_CONTAINER_OPTIONAL
return newSVuv(CRYPT_DEFAULT_CONTAINER_OPTIONAL);
#else
return &PL_sv_undef;
#endif
}
SV * _CRYPT_SILENT(pTHX) {
#ifdef CRYPT_SILENT
return newSVuv(CRYPT_SILENT);
#else
return &PL_sv_undef;
#endif
}
SV * _CRYPT_DELETEKEYSET(pTHX) {
#ifdef CRYPT_DELETEKEYSET
return newSVuv(CRYPT_DELETEKEYSET);
#else
return &PL_sv_undef;
#endif
}
SV * _CRYPT_MACHINE_KEYSET(pTHX) {
#ifdef CRYPT_MACHINE_KEYSET
return newSVuv(CRYPT_MACHINE_KEYSET);
#else
return &PL_sv_undef;
#endif
}
SV * _CRYPT_NEWKEYSET(pTHX) {
#ifdef CRYPT_NEWKEYSET
return newSVuv(CRYPT_NEWKEYSET);
#else
return &PL_sv_undef;
#endif
}
SV * _CRYPT_VERIFYCONTEXT(pTHX) {
#ifdef CRYPT_VERIFYCONTEXT
return newSVuv(CRYPT_VERIFYCONTEXT);
#else
return &PL_sv_undef;
#endif
}
/* PROVIDER TYPES */
SV * _PROV_RSA_FULL(pTHX) {
#ifdef PROV_RSA_FULL
return newSVuv(PROV_RSA_FULL);
#else
return &PL_sv_undef;
#endif
}
SV * _PROV_RSA_AES(pTHX) {
#ifdef PROV_RSA_AES
return newSVuv(PROV_RSA_AES);
#else
return &PL_sv_undef;
#endif
}
SV * _PROV_RSA_SIG(pTHX) {
#ifdef PROV_RSA_SIG
return newSVuv(PROV_RSA_SIG);
#else
return &PL_sv_undef;
#endif
}
SV * _PROV_RSA_SCHANNEL(pTHX) {
#ifdef PROV_RSA_SCHANNEL
return newSVuv(PROV_RSA_SCHANNEL);
#else
return &PL_sv_undef;
#endif
}
SV * _PROV_DSS(pTHX) {
#ifdef PROV_DSS
return newSVuv(PROV_DSS);
#else
return &PL_sv_undef;
#endif
}
SV * _PROV_DSS_DH(pTHX) {
#ifdef PROV_DSS_DH
return newSVuv(PROV_DSS_DH);
#else
return &PL_sv_undef;
#endif
}
SV * _PROV_DH_SCHANNEL(pTHX) {
#ifdef PROV_DH_SCHANNEL
return newSVuv(PROV_DH_SCHANNEL);
#else
return &PL_sv_undef;
#endif
}
SV * _PROV_FORTEZZA(pTHX) {
#ifdef PROV_FORTEZZA
return newSVuv(PROV_FORTEZZA);
#else
return &PL_sv_undef;
#endif
}
SV * _PROV_MS_EXCHANGE(pTHX) {
#ifdef PROV_MS_EXCHANGE
return newSVuv(PROV_MS_EXCHANGE);
#else
return &PL_sv_undef;
#endif
}
SV * _PROV_SSL(pTHX) {
#ifdef PROV_SSL
return newSVuv(PROV_SSL);
#else
return &PL_sv_undef;
#endif
}
SV * whw(pTHX) {
#ifdef SecureZeroMemory
return newSVpv("SecureZeroMemory", 0);
#else
#ifdef ZeroMemory
return newSVpv("ZeroMemory", 0);
#else
return newSVpv("None", 0);
#endif
#endif
}
/*
DWORD WINAPI GetLastError(void);
HRESULT HRESULT_FROM_WIN32(DWORD x);
BOOL WINAPI CryptAcquireContext(
_Out_ HCRYPTPROV *phProv,
_In_ LPCTSTR pszContainer,
_In_ LPCTSTR pszProvider,
_In_ DWORD dwProvType,
_In_ DWORD dwFlags
);
BOOL WINAPI CryptGenRandom(
_In_ HCRYPTPROV hProv,
_In_ DWORD dwLen,
_Inout_ BYTE *pbBuffer
);
BOOLEAN RtlGenRandom(
_Out_ PVOID RandomBuffer,
_In_ ULONG RandomBufferLength
);
*/
MODULE = Win32::GenRandom PACKAGE = Win32::GenRandom
PROTOTYPES: DISABLE
void
print_error ()
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
print_error(aTHX);
if (PL_markstack_ptr != temp) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = temp;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */
void
cgr (x, ...)
SV * x
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
cgr(aTHX_ x);
if (PL_markstack_ptr != temp) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = temp;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */
void
cgr_custom (x, ...)
SV * x
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
cgr_custom(aTHX_ x);
if (PL_markstack_ptr != temp) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = temp;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */
void
rgr (x, ...)
SV * x
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
rgr(aTHX_ x);
if (PL_markstack_ptr != temp) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = temp;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */
SV *
_error_test ()
CODE:
RETVAL = _error_test (aTHX);
OUTPUT: RETVAL
SV *
_CRYPT_DEFAULT_CONTAINER_OPTIONAL ()
CODE:
RETVAL = _CRYPT_DEFAULT_CONTAINER_OPTIONAL (aTHX);
OUTPUT: RETVAL
SV *
_CRYPT_SILENT ()
CODE:
RETVAL = _CRYPT_SILENT (aTHX);
OUTPUT: RETVAL
SV *
_CRYPT_DELETEKEYSET ()
CODE:
RETVAL = _CRYPT_DELETEKEYSET (aTHX);
OUTPUT: RETVAL
SV *
_CRYPT_MACHINE_KEYSET ()
CODE:
RETVAL = _CRYPT_MACHINE_KEYSET (aTHX);
OUTPUT: RETVAL
SV *
_CRYPT_NEWKEYSET ()
CODE:
RETVAL = _CRYPT_NEWKEYSET (aTHX);
OUTPUT: RETVAL
SV *
_CRYPT_VERIFYCONTEXT ()
CODE:
RETVAL = _CRYPT_VERIFYCONTEXT (aTHX);
OUTPUT: RETVAL
SV *
_PROV_RSA_FULL ()
CODE:
RETVAL = _PROV_RSA_FULL (aTHX);
OUTPUT: RETVAL
SV *
_PROV_RSA_AES ()
CODE:
RETVAL = _PROV_RSA_AES (aTHX);
OUTPUT: RETVAL
SV *
_PROV_RSA_SIG ()
CODE:
RETVAL = _PROV_RSA_SIG (aTHX);
OUTPUT: RETVAL
SV *
_PROV_RSA_SCHANNEL ()
CODE:
RETVAL = _PROV_RSA_SCHANNEL (aTHX);
OUTPUT: RETVAL
SV *
_PROV_DSS ()
CODE:
RETVAL = _PROV_DSS (aTHX);
OUTPUT: RETVAL
SV *
_PROV_DSS_DH ()
CODE:
RETVAL = _PROV_DSS_DH (aTHX);
OUTPUT: RETVAL
SV *
_PROV_DH_SCHANNEL ()
CODE:
RETVAL = _PROV_DH_SCHANNEL (aTHX);
OUTPUT: RETVAL
SV *
_PROV_FORTEZZA ()
CODE:
RETVAL = _PROV_FORTEZZA (aTHX);
OUTPUT: RETVAL
SV *
_PROV_MS_EXCHANGE ()
CODE:
RETVAL = _PROV_MS_EXCHANGE (aTHX);
OUTPUT: RETVAL
SV *
_PROV_SSL ()
CODE:
RETVAL = _PROV_SSL (aTHX);
OUTPUT: RETVAL
SV *
whw ()
CODE:
RETVAL = whw (aTHX);
OUTPUT: RETVAL