📄 os_spec.c
字号:
#define MB_OK 0x00000000L
#define MB_ICONQUESTION 0x00000020L
int WINAPI MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption,
UINT uType );
#pragma comment( linker, "/export:DllRegisterServer=_DllRegisterServer@0,PRIVATE" )
STDAPI DllRegisterServer( void )
{
MessageBoxA( NULL, "Why are you trying to register the cryptlib DLL?\n"
"It's just a standard Windows DLL, there's nothing\nto be "
"registered.", "ESO Error",
MB_ICONQUESTION | MB_OK );
return( E_NOINTERFACE );
}
#elif defined( __WIN16__ )
/* WinMain() and WEP() under Win16 are intended for DLL initialisation,
however it isn't possible to reliably do anything terribly useful in these
routines. The reason for this is that the WinMain/WEP functions are
called by the windows module loader, which has a very limited workspace
and can cause peculiar behaviour for some functions (allocating/freeing
memory and loading other modules from these routines is unreliable), the
order in which WinMain() and WEP() will be called for a set of DLL's is
unpredictable (sometimes WEP doesn't seem to be called at all), and they
can't be tracked by a standard debugger. This is why MS have
xxxRegisterxxx() and xxxUnregisterxxx() functions in their DLL's.
Under Win16 on a Win32 system this isn't a problem because the module
loader has been rewritten to work properly, but it isn't possible to get
reliable performance under pure Win16, so the DLL entry/exit routines here
do almost nothing, with the real work being done in cryptInit()/
cryptEnd() */
HWND hInst;
int CALLBACK LibMain( HINSTANCE hInstance, WORD wDataSeg, WORD wHeapSize, \
LPSTR lpszCmdLine )
{
/* Remember the proc instance for later */
hInst = hInstance;
return( TRUE );
}
int CALLBACK WEP( int nSystemExit )
{
switch( nSystemExit )
{
case WEP_SYSTEM_EXIT:
/* System is shutting down */
break;
case WEP_FREE_DLL:
/* DLL reference count = 0, DLL-only shutdown */
break;
}
return( TRUE );
}
/****************************************************************************
* *
* Windows CE *
* *
****************************************************************************/
#elif defined( __WINCE__ )
/* Windows CE doesn't provide ANSI standard time functions (although it'd be
relatively easy to do so, and they are in fact provided in MFC), so we
have to provide our own */
static LARGE_INTEGER *getTimeOffset( void )
{
static LARGE_INTEGER timeOffset = { 0 };
/* Get the difference between the ANSI/ISO C time epoch and the Windows
time epoch if we haven't already done so (we could also hardcode this
in as 116444736000000000LL) */
if( timeOffset.QuadPart == 0 )
{
SYSTEMTIME ofsSystemTime;
FILETIME ofsFileTime;
memset( &ofsSystemTime, 0, sizeof( SYSTEMTIME ) );
ofsSystemTime.wYear = 1970;
ofsSystemTime.wMonth = 1;
ofsSystemTime.wDay = 1;
SystemTimeToFileTime( &ofsSystemTime, &ofsFileTime );
timeOffset.HighPart = ofsFileTime.dwHighDateTime;
timeOffset.LowPart = ofsFileTime.dwLowDateTime;
}
return( &timeOffset );
}
static time_t fileTimeToTimeT( const FILETIME *fileTime )
{
const LARGE_INTEGER *timeOffset = getTimeOffset();
LARGE_INTEGER largeInteger;
/* Convert a Windows FILETIME to a time_t by dividing by
10,000,000 (to go from 100ns ticks to 1s ticks) */
largeInteger.HighPart = fileTime->dwHighDateTime;
largeInteger.LowPart = fileTime->dwLowDateTime;
largeInteger.QuadPart = ( largeInteger.QuadPart - \
timeOffset->QuadPart ) / 10000000L;
if( sizeof( time_t ) == 4 && \
largeInteger.QuadPart > 0x80000000UL )
/* time_t is 32 bits but the converted time is larger than a 32-bit
signed value, indicate that we couldn't convert it. In theory
we could check for largeInteger.HighPart == 0 and perform a
second check to see if time_t is unsigned, but it's unlikely that
this change would be made to the VC++ runtime time_t since it'd
break too many existing apps */
return( -1 );
return( ( time_t ) largeInteger.QuadPart );
}
static void timeTToFileTime( FILETIME *fileTime, const time_t timeT )
{
const LARGE_INTEGER *timeOffset = getTimeOffset();
LARGE_INTEGER largeInteger = { timeT };
/* Convert a time_t to a Windows FILETIME by multiplying by
10,000,000 (to go from 1s ticks to 100ns ticks) */
largeInteger.QuadPart = ( largeInteger.QuadPart * 10000000L ) + \
timeOffset->QuadPart;
fileTime->dwHighDateTime = largeInteger.HighPart;
fileTime->dwLowDateTime = largeInteger.LowPart;
}
time_t time( time_t *timePtr )
{
FILETIME fileTime;
#ifdef __WINCE__
SYSTEMTIME systemTime;
#endif /* __WINCE__ */
assert( timePtr == NULL );
/* Get the time via GetSystemTimeAsFileTime(). Windows CE doesn't have
the unified call so we have to assemble it from discrete calls */
#ifdef __WINCE__
GetSystemTime( &systemTime );
SystemTimeToFileTime( &systemTime, &fileTime );
#else
GetSystemTimeAsFileTime( &fileTime );
#endif /* Win32 vs. WinCE */
return( fileTimeToTimeT( &fileTime ) );
}
time_t mktime( struct tm *tmStruct )
{
SYSTEMTIME systemTime;
FILETIME fileTime;
assert( isWritePtr( tmStruct, sizeof( struct tm ) ) );
/* Use SystemTimeToFileTime() as a mktime() substitute. The input time
seems to be treated as local time, so we have to convert it to GMT
before we return it */
memset( &systemTime, 0, sizeof( SYSTEMTIME ) );
systemTime.wYear = tmStruct->tm_year + 1900;
systemTime.wMonth = tmStruct->tm_mon + 1;
systemTime.wDay = tmStruct->tm_mday;
systemTime.wHour = tmStruct->tm_hour;
systemTime.wMinute = tmStruct->tm_min;
systemTime.wSecond = tmStruct->tm_sec;
SystemTimeToFileTime( &systemTime, &fileTime );
LocalFileTimeToFileTime( &fileTime, &fileTime );
return( fileTimeToTimeT( &fileTime ) );
}
struct tm *gmtime( const time_t *timePtr )
{
static struct tm tmStruct;
SYSTEMTIME systemTime;
FILETIME fileTime;
assert( isReadPtr( timePtr, sizeof( time_t ) ) );
/* Use FileTimeToSystemTime() as a gmtime() substitute. Note that this
function, like its original ANSI/ISO C counterpart, is not thread-
safe */
timeTToFileTime( &fileTime, *timePtr );
FileTimeToSystemTime( &fileTime, &systemTime );
memset( &tmStruct, 0, sizeof( struct tm ) );
tmStruct.tm_year = systemTime.wYear - 1900;
tmStruct.tm_mon = systemTime.wMonth - 1;
tmStruct.tm_mday = systemTime.wDay;
tmStruct.tm_hour = systemTime.wHour;
tmStruct.tm_min = systemTime.wMinute;
tmStruct.tm_sec = systemTime.wSecond;
return( &tmStruct );
}
/* Windows CE systems need to convert characters from ASCII <-> Unicode
before/after they're read/written to external formats, the following
functions perform the necessary conversion.
winnls.h was already included via the global include of windows.h, however
it isn't needed for any other part of cryptlib so it was disabled via
NONLS. Since winnls.h is now locked out, we have to un-define the guards
used earlier to get it included */
#undef _WINNLS_
#undef NONLS
#include <winnls.h>
int asciiToUnicode( wchar_t *dest, const char *src, const int length )
{
int status;
assert( isReadPtr( src, length ) );
status = MultiByteToWideChar( GetACP(), 0, src, length, dest, length );
return( status <= 0 ? CRYPT_ERROR_BADDATA : status * sizeof( wchar_t ) );
}
int unicodeToAscii( char *dest, const wchar_t *src, const int length )
{
int status;
assert( isReadPtr( src, length ) );
/* Convert the string, overriding the system default char '?', which
causes problems if the output is used as a filename. This function
has stupid semantics in that instead of returning the number of bytes
written to the output, it returns the number of bytes specified as
available in the output buffer, zero-filling the rest. Because
there's no way to tell how long the resulting string actually is, we
use wcstombs() instead */
#if 0
status = WideCharToMultiByte( GetACP(), 0, src, length, dest,
length * sizeof( wchar_t ), "_", NULL );
return( ( status <= 0 ) ? CRYPT_ERROR_BADDATA : wcslen( dest ) );
#else
status = wcstombs( dest, src, length * sizeof( wchar_t ) );
return( ( status <= 0 ) ? CRYPT_ERROR_BADDATA : status );
#endif
}
BOOL WINAPI DllMain( HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved )
{
UNUSED( hinstDLL );
UNUSED( lpvReserved );
switch( dwReason )
{
case DLL_PROCESS_ATTACH:
/* Disable thread-attach notifications, which we don't do
anything with and therefore don't need */
DisableThreadLibraryCalls( hinstDLL );
/* Set up the initialisation lock in the kernel */
preInit();
break;
case DLL_PROCESS_DETACH:
/* Delete the initialisation lock in the kernel */
postShutdown();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return( TRUE );
}
#endif /* OS-specific support */
/****************************************************************************
* *
* SysCaps Support *
* *
****************************************************************************/
#if defined( __WIN32__ )
int getSysCaps( void )
{
static BOOLEAN sysCapsSet = FALSE;
static int sysCaps = 0;
BOOLEAN hasAdvFeatures = 0;
char vendorID[ 12 ];
#if 0 /* Not needed for now */
unsigned long processorID, featureFlags;
#endif /* 0 */
/* If we've already established the system hardware capabilities,
return the cached result of the lookup */
if( sysCapsSet )
return( sysCaps );
/* Check whether the CPU supports extended features like CPUID and
RDTSC, and get any info we need related to this. There is an
IsProcessorFeaturePresent() function, but all that this provides is
an indication of the availability of rdtsc (alongside some stuff we
don't care about, like MMX and 3DNow). Since we still need to check
for the presence of other features, we do the whole thing ourselves */
_asm {
/* Detect the CPU type */
pushfd
pop eax /* Get EFLAGS in eax */
mov ebx, eax /* Save a copy for later */
xor eax, 0x200000 /* Toggle the CPUID bit */
push eax
popfd /* Update EFLAGS */
pushfd
pop eax /* Get updated EFLAGS back in eax */
push ebx
popfd /* Restore original EFLAGS */
xor eax, ebx /* Check if we could toggle CPUID bit */
jz noCPUID /* Nope, we can't do anything further */
mov [hasAdvFeatures], 1 /* Remember that we have CPUID */
or [sysCaps], SYSCAP_FLAG_RDTSC /* Remember that we have RDTSC */
/* We have CPUID, see what we've got */
xor ecx, ecx
xor edx, edx /* Tell VC++ that ECX, EDX will be trashed */
xor eax, eax /* CPUID function 0: Get vendor ID */
cpuid
mov dword ptr [vendorID], ebx
mov dword ptr [vendorID+4], edx
mov dword ptr [vendorID+8], ecx /* Save vendor ID string */
#if 0
mov eax, 1 /* CPUID function 1: Get processor info */
cpuid
mov [processorID], eax /* Save processor ID */
mov [featureFlags], edx /* Save processor feature info */
#endif /* 0 */
noCPUID:
}
/* If there's no CPUID support, there are no special HW capabilities
available */
if( !hasAdvFeatures )
return( SYSCAP_FLAG_NONE );
/* If there's a vendor ID present, check for vendor-specific special
features */
if( hasAdvFeatures && !memcmp( vendorID, "CentaurHauls", 12 ) )
{
_asm {
xor ebx, ebx
xor ecx, ecx /* Tell VC++ that EBX, ECX will be trashed */
mov eax, 0xC0000000 /* Centaur extended CPUID info */
cpuid
cmp eax, 0xC0000001 /* Need at least release 2 ext.feature set */
jb endCheck /* No extended info available */
mov eax, 0xC0000001 /* Centaur extended feature flags */
cpuid
mov eax, edx /* Save a copy of the feature flags */
and edx, 01100b
cmp edx, 01100b /* Check for RNG present + enabled flags */
jz noRNG /* No, RNG not present or enabled */
or [sysCaps], SYSCAP_FLAG_XSTORE /* Remember that we have a HW RNG */
noRNG:
and eax, 011000000b
cmp eax, 011000000b /* Check for ACE present + enabled flags */
jz endCheck /* No, ACE not present or enabled */
or [sysCaps], SYSCAP_FLAG_XCRYPT /* Remember that we have HW crypto */
endCheck:
}
}
return( sysCaps );
}
#else
int getSysCaps( void )
{
return( SYSCAP_FLAG_NONE );
}
#endif /* OS-specific support */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -