Merged PR 7551174: Rejig CPUID logic for VAES and AVX*

+ Make VAES CPU feature depend only on VAES and VPCLMULQDQ
+ Make features for VAES_256 code depend on AVX2 feature and VAES (so
  disabling AVX2 will disable VAES_256)
+ Similarly make features for VAES_512 code depend on AVX512 feature
+ Check xgetbv correctly to enable/disable AVX512 appropriately based on
  OS support
+ Remove GetEnabledXStateFeatures logic from linux env file. For Windows
 unittest env, check if xgetbv result is different to GetEnabledXStateFeatures, as
that indicates an OS bug
  + This enables all AVX2 on Linux which can support it, rather than
    only supporting VAES_256 on Linux which supports AVX2 (the prior
    situation)
+ Reintroduce reduced Xmm save/restore testing on Windows AMD64 user
mode, to check that Xmm6-Xmm15 are correctly saved/restored in SymCrypt code
+ Introduce optional Ymm save/restore testing which can be run on Linux
successfully today using runtime options for telling glibc to not use AVX. This allows
us to test the SymCrypt[Save|Restore]Ymm logic (relevant to Windows kernel mode)
accurately in the SymCrypt ADO pipeline.

Related work items: #32997124
This commit is contained in:
Samuel Lee 2022-07-12 11:50:20 +00:00
Родитель e875f1f957
Коммит cc2148e4d0
33 изменённых файлов: 1239 добавлений и 1288 удалений

Просмотреть файл

@ -132,6 +132,14 @@ steps:
./symcryptunittest
displayName: 'Execute unit tests'
name: '${{parameters.env}}UnitTest_${{parameters.buildType}}'
- ${{ if eq(parameters.arch, 'AMD64') }}:
# Run unit tests in a mode where the Ymm registers must not be modified by the functional tests
# Set GLIBC to not use AVX using GLIBC_TUNABLES
- script: |
cd bin/exe/${{parameters.arch}}/${{parameters.env}}
GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX_Usable,-AVX_Fast_Unaligned_Load,-AVX2_Usable ./symcryptunittest testSaveYmm
displayName: 'Execute unit tests (Test Ymm Save/Restore)'
name: '${{parameters.env}}UnitTest_TestYmm_${{parameters.buildType}}'
- ${{ if ne(parameters.buildType, 'Sanitize') }}:
# Only run oe module test if rdseed is present on the CPU
- script: |

Просмотреть файл

@ -590,7 +590,7 @@ createIfxTpmWeakKeyTable()
fclose( f );
}
int __cdecl
int SYMCRYPT_CDECL
main( int argc, _In_reads_( argc ) char * argv[] )
{
printf( "SymCrypt constants generation program\n" );

Просмотреть файл

@ -390,7 +390,7 @@ C_ASSERT( (SYMCRYPT_ALIGN_VALUE & (SYMCRYPT_ALIGN_VALUE - 1 )) == 0 );
#define SYMCRYPT_CPU_FEATURE_SSSE3 0x0002 // includes SSE, SSE2, SSE3, SSSE3
#define SYMCRYPT_CPU_FEATURE_AESNI 0x0004
#define SYMCRYPT_CPU_FEATURE_PCLMULQDQ 0x0008
#define SYMCRYPT_CPU_FEATURE_AVX2 0x0010 // includes AVX, AVX2
#define SYMCRYPT_CPU_FEATURE_AVX2 0x0010 // includes AVX, AVX2 - also indicates support for saving/restoring Ymm registers
#define SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL 0x0020 // if SymCryptSaveXmm() will never fail
#define SYMCRYPT_CPU_FEATURE_SHANI 0x0040
#define SYMCRYPT_CPU_FEATURE_BMI2 0x0080 // MULX, RORX, SARX, SHLX, SHRX
@ -398,8 +398,9 @@ C_ASSERT( (SYMCRYPT_ALIGN_VALUE & (SYMCRYPT_ALIGN_VALUE - 1 )) == 0 );
#define SYMCRYPT_CPU_FEATURE_ADX 0x0100 // ADCX, ADOX
#define SYMCRYPT_CPU_FEATURE_RDRAND 0x0200
#define SYMCRYPT_CPU_FEATURE_RDSEED 0x0400
#define SYMCRYPT_CPU_FEATURE_VAES_256 0x0800
#define SYMCRYPT_CPU_FEATURE_VAES_512 0x1000
#define SYMCRYPT_CPU_FEATURE_VAES 0x0800 // support for VAES and VPCLMULQDQ (may only be supported on Ymm registers (i.e. Zen3))
#define SYMCRYPT_CPU_FEATURE_AVX512 0x1000 // includes F, VL, DQ, BW (VL allows AVX-512 instructions to be used on Xmm and Ymm registers)
// also indicates support for saving/restoring additional AVX-512 state
#define SYMCRYPT_CPU_FEATURE_CMPXCHG16B 0x2000 // Compare and Swap 128b value

Просмотреть файл

@ -69,19 +69,19 @@ CPUID_BIT_INFO cpuidBitInfo[] = {
{1, WORD_EDX, CPUID_1_EDX_SSE2_BIT, SYMCRYPT_CPU_FEATURE_SSE2 | SYMCRYPT_CPU_FEATURE_SSSE3 },
{1, WORD_ECX, CPUID_1_ECX_SSE3_BIT, SYMCRYPT_CPU_FEATURE_SSSE3 },
{1, WORD_ECX, CPUID_1_ECX_SSSE3_BIT, SYMCRYPT_CPU_FEATURE_SSSE3 },
{1, WORD_ECX, CPUID_1_ECX_AVX_BIT, SYMCRYPT_CPU_FEATURE_AVX2 | SYMCRYPT_CPU_FEATURE_VAES_256 },
{1, WORD_ECX, CPUID_1_ECX_AVX_BIT, SYMCRYPT_CPU_FEATURE_AVX2 },
{1, WORD_ECX, CPUID_1_ECX_CMPXCHG16B_BIT, SYMCRYPT_CPU_FEATURE_CMPXCHG16B },
{7, WORD_EBX, CPUID_70_EBX_AVX2_BIT, SYMCRYPT_CPU_FEATURE_AVX2 | SYMCRYPT_CPU_FEATURE_VAES_256 },
{7, WORD_EBX, CPUID_70_EBX_AVX2_BIT, SYMCRYPT_CPU_FEATURE_AVX2 },
{7, WORD_EBX, CPUID_70_EBX_RDSEED_BIT, SYMCRYPT_CPU_FEATURE_RDSEED },
{7, WORD_EBX, CPUID_70_EBX_SHANI_BIT, SYMCRYPT_CPU_FEATURE_SHANI },
{7, WORD_EBX, CPUID_70_EBX_ADX_BIT, SYMCRYPT_CPU_FEATURE_ADX },
{7, WORD_EBX, CPUID_70_EBX_BMI2_BIT, SYMCRYPT_CPU_FEATURE_BMI2 },
{7, WORD_EBX, CPUID_70_EBX_AVX512F_BIT, SYMCRYPT_CPU_FEATURE_VAES_512 },
{7, WORD_EBX, CPUID_70_EBX_AVX512VL_BIT, SYMCRYPT_CPU_FEATURE_VAES_512 },
{7, WORD_EBX, CPUID_70_EBX_AVX512BW_BIT, SYMCRYPT_CPU_FEATURE_VAES_512 },
{7, WORD_EBX, CPUID_70_EBX_AVX512DQ_BIT, SYMCRYPT_CPU_FEATURE_VAES_512 },
{7, WORD_ECX, CPUID_70_ECX_VAES_BIT, SYMCRYPT_CPU_FEATURE_VAES_512 | SYMCRYPT_CPU_FEATURE_VAES_256 },
{7, WORD_ECX, CPUID_70_ECX_VPCLMULQDQ_BIT, SYMCRYPT_CPU_FEATURE_VAES_512 | SYMCRYPT_CPU_FEATURE_VAES_256 },
{7, WORD_EBX, CPUID_70_EBX_AVX512F_BIT, SYMCRYPT_CPU_FEATURE_AVX512 },
{7, WORD_EBX, CPUID_70_EBX_AVX512VL_BIT, SYMCRYPT_CPU_FEATURE_AVX512 },
{7, WORD_EBX, CPUID_70_EBX_AVX512BW_BIT, SYMCRYPT_CPU_FEATURE_AVX512 },
{7, WORD_EBX, CPUID_70_EBX_AVX512DQ_BIT, SYMCRYPT_CPU_FEATURE_AVX512 },
{7, WORD_ECX, CPUID_70_ECX_VAES_BIT, SYMCRYPT_CPU_FEATURE_VAES },
{7, WORD_ECX, CPUID_70_ECX_VPCLMULQDQ_BIT, SYMCRYPT_CPU_FEATURE_VAES },
};
extern void __cpuid( _Out_writes_(4) int a[4], int b); // Add SAL annotation to intrinsic declaration to keep Prefast happy.
@ -95,7 +95,7 @@ SymCryptDetectCpuFeaturesByCpuid( UINT32 flags )
int InfoType;
int maxInfoType;
int i;
BOOLEAN allowYmm;
BOOLEAN allowYmm, allowZmm;
INT64 xGetBvResult;
//
@ -112,8 +112,8 @@ SymCryptDetectCpuFeaturesByCpuid( UINT32 flags )
SYMCRYPT_CPU_FEATURE_ADX |
SYMCRYPT_CPU_FEATURE_RDRAND |
SYMCRYPT_CPU_FEATURE_RDSEED |
// SYMCRYPT_CPU_FEATURE_VAES_512 |
SYMCRYPT_CPU_FEATURE_VAES_256 |
SYMCRYPT_CPU_FEATURE_AVX512 |
SYMCRYPT_CPU_FEATURE_VAES |
SYMCRYPT_CPU_FEATURE_CMPXCHG16B
);
@ -150,6 +150,7 @@ SymCryptDetectCpuFeaturesByCpuid( UINT32 flags )
// all our (known) OSes have it.
//
allowYmm = FALSE;
allowZmm = FALSE;
SymCryptCpuidExFunc( CPUInfo, 1, 0 );
if( (CPUInfo[WORD_ECX] & (1 << CPUID_1_ECX_OSXSAVE_BIT)) != 0 )
@ -161,13 +162,40 @@ SymCryptDetectCpuFeaturesByCpuid( UINT32 flags )
if( (xGetBvResult & 0x6) == 0x6)
{
allowYmm = TRUE;
//
// For AVX-512, also check that bits 5, 6, and 7 are set, corresponding to the
// opmask, ZMM (0-15), and ZMM (16-31) register states
// This follows the recommendation in the Intel 64 and IA-32 Architectures Software
// Developer's Manual, Volume 1, 15.3 / 15.4.
//
// It seems plausible that on some system the OS would not support save/restore of
// AVX-512 state, but use of AVX-512VL instructions on Ymm or Xmm registers would be
// OK, however Intel explicitly suggests that we should only use AVX512-VL if the
// support is indicated by xgetbv, so we use the same logic as for AVX2 (our
// SymCrypt feature indicates both CPU support, and OS support for saving/restoring
// the extended state)
//
if( (xGetBvResult & 0xe0) == 0xe0)
{
allowZmm = TRUE;
}
}
}
if( !allowYmm )
{
// Disallow the AVX2-dependent code because we don't have OS YMM support.
result |= SYMCRYPT_CPU_FEATURE_AVX2 | SYMCRYPT_CPU_FEATURE_VAES_512 | SYMCRYPT_CPU_FEATURE_VAES_256;
result |= SYMCRYPT_CPU_FEATURE_AVX2;
}
if( !allowZmm )
{
// Disallow any AVX512-dependent code because we don't have OS ZMM support.
// Note that not all AVX-512 dependent code will need to save/restore ZMM state, but we
// do not support AVX-512 instructions (even acting on YMM or XMM registers), unless the
// OS indicates support via XCR0
result |= SYMCRYPT_CPU_FEATURE_AVX512;
}
}

Просмотреть файл

@ -25,19 +25,6 @@ SymCryptInitEnvLinuxUsermode( UINT32 version )
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
SymCryptDetectCpuFeaturesByCpuid( SYMCRYPT_CPUID_DETECT_FLAG_CHECK_OS_SUPPORT_FOR_YMM );
//
// Don't use Ymm registers if the OS doesn't report them as available.
// We assume Ymm register swapping isn't supported unless we can verify that it is.
//
g_SymCryptCpuFeaturesNotPresent |= SYMCRYPT_CPU_FEATURE_AVX2;
#if SYMCRYPT_MS_VC
if( (GetEnabledXStateFeatures() & XSTATE_MASK_AVX) != 0 )
{
g_SymCryptCpuFeaturesNotPresent &= ~SYMCRYPT_CPU_FEATURE_AVX2;
}
#endif
//
// Our SaveXmm function never fails because it doesn't have to do anything in User mode.
//

Просмотреть файл

@ -249,8 +249,8 @@ SymCryptCheckLibraryInitialized()
#define SYMCRYPT_CPU_FEATURES_FOR_AESNI_CODE (SYMCRYPT_CPU_FEATURE_SSSE3 | SYMCRYPT_CPU_FEATURE_AESNI)
#define SYMCRYPT_CPU_FEATURES_FOR_AESNI_PCLMULQDQ_CODE (SYMCRYPT_CPU_FEATURES_FOR_AESNI_CODE | SYMCRYPT_CPU_FEATURES_FOR_PCLMULQDQ_CODE)
#define SYMCRYPT_CPU_FEATURES_FOR_VAES_256_CODE (SYMCRYPT_CPU_FEATURES_FOR_AESNI_CODE | SYMCRYPT_CPU_FEATURE_VAES_256)
#define SYMCRYPT_CPU_FEATURES_FOR_VAES_512_CODE (SYMCRYPT_CPU_FEATURES_FOR_AESNI_CODE | SYMCRYPT_CPU_FEATURE_VAES_512)
#define SYMCRYPT_CPU_FEATURES_FOR_VAES_256_CODE (SYMCRYPT_CPU_FEATURES_FOR_AESNI_CODE | SYMCRYPT_CPU_FEATURE_AVX2 | SYMCRYPT_CPU_FEATURE_VAES)
#define SYMCRYPT_CPU_FEATURES_FOR_VAES_512_CODE (SYMCRYPT_CPU_FEATURES_FOR_AESNI_CODE | SYMCRYPT_CPU_FEATURE_AVX512 | SYMCRYPT_CPU_FEATURE_VAES)
#define SYMCRYPT_CPU_FEATURES_FOR_SHANI_CODE (SYMCRYPT_CPU_FEATURE_SSSE3 | SYMCRYPT_CPU_FEATURE_SHANI)

Просмотреть файл

@ -102,7 +102,7 @@ void printPerfNumbers()
}
int __cdecl
int SYMCRYPT_CDECL
main( int argc, _In_reads_( argc ) LPSTR * argv[] )
{
UNREFERENCED_PARAMETER( argv );

Просмотреть файл

@ -9,31 +9,4 @@
SYMCRYPT_ENVIRONMENT_WINDOWS_USERMODE_WIN7_N_LATER;
#include "main_exe_common.cpp"
int __cdecl
main( int argc, _In_reads_( argc ) char * argv[] )
{
initTestInfrastructure( argc, argv );
addAllAlgs();
if (g_profile)
{
runProfiling();
}
else
{
runFunctionalTests();
testMultiThread();
runPerfTests();
}
exitTestInfrastructure();
return 0;
}
#include "main_exe_common_windows.cpp"

Просмотреть файл

@ -9,31 +9,4 @@
SYMCRYPT_ENVIRONMENT_WINDOWS_USERMODE_WIN8_1_N_LATER;
#include "main_exe_common.cpp"
int __cdecl
main( int argc, _In_reads_( argc ) char * argv[] )
{
initTestInfrastructure( argc, argv );
addAllAlgs();
if (g_profile)
{
runProfiling();
}
else
{
runFunctionalTests();
testMultiThread();
runPerfTests();
}
exitTestInfrastructure();
return 0;
}
#include "main_exe_common_windows.cpp"

Просмотреть файл

@ -9,31 +9,4 @@
SYMCRYPT_ENVIRONMENT_WINDOWS_USERMODE_LEGACY;
#include "main_exe_common.cpp"
int __cdecl
main( int argc, _In_reads_( argc ) char * argv[] )
{
initTestInfrastructure( argc, argv );
addAllAlgs();
if (g_profile)
{
runProfiling();
}
else
{
runFunctionalTests();
testMultiThread();
runPerfTests();
}
exitTestInfrastructure();
return 0;
}
#include "main_exe_common_windows.cpp"

Просмотреть файл

@ -9,59 +9,81 @@
SYMCRYPT_ENVIRONMENT_DEFS( Unittest );
const char * g_implementationNames[] =
#if SYMCRYPT_CPU_AMD64
/////////////////////////////////////////////////////////////
//
// Code to set up the YMM registers for testing in SAVE_YMM mode
__m256i g_ymmStartState[16];
__m256i g_ymmTestState[16];
VOID
verifyVectorRegisters()
{
ImpSc::name,
// ImpRsa32::name,
// ImpRsa32b::name,
// ImpCapi::name,
// ImpCng::name,
// ImpMsBignum::name,
ImpRef::name,
NULL,
};
// #include "main_exe_common.cpp"
int
main( int argc, _In_reads_( argc ) char * argv[] )
{
initTestInfrastructure( argc, argv );
TestSaveXmmEnabled = TRUE;
TestSaveYmmEnabled = TRUE;
// addCapiAlgs();
// addRsa32Algs();
// addCngAlgs();
// addMsBignumAlgs();
addSymCryptAlgs();
addRefAlgs();
if (!g_profile)
if( !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_AVX2 ) )
{
runFunctionalTests();
return;
}
TestSaveXmmEnabled = FALSE;
TestSaveYmmEnabled = FALSE;
if (g_profile)
//
// We know that AVX2 is present from here on
//
if( TestSaveYmmEnabled )
{
runProfiling();
SymCryptEnvUmSaveYmmRegistersAsm( g_ymmTestState );
//
// It is perfectly fine for the XMM register values to have been modified.
// We just test that the top half of the Ymm registers have been preserved.
//
for( int i=0; i<sizeof( g_ymmStartState ); i++ )
{
if( ((volatile BYTE * )&g_ymmStartState[0])[i] != ((volatile BYTE * )&g_ymmTestState[0])[i] &&
((i & 16) == 16 )
)
{
FATAL3( "Ymm registers modified without proper save/restore Ymm%d[%d]", i>>5, i&31);
}
}
}
else
{
runPerfTests();
// testMultiThread();
testSelftest();
}
exitTestInfrastructure();
return 0;
}
VOID
initVectorRegisters()
{
if( !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_AVX2 ) )
{
return;
}
if( TestSaveYmmEnabled )
{
//
// Do the memsets outside the save area as it might use vector registers
// Set the initial Ymm registers to a non-trivial value. It is likely (for performance
// reasons) that the upper halves are already zero-ed and will be re-zeroed by any function
// we call.
//
memset( g_ymmTestState, 17, sizeof( g_ymmTestState ) );
memset( g_ymmStartState, (__rdtsc() & 255) ^ 0x42, sizeof( g_ymmStartState ) );
SymCryptEnvUmRestoreYmmRegistersAsm( g_ymmStartState );
verifyVectorRegisters();
}
}
#else
VOID verifyVectorRegisters()
{
}
VOID initVectorRegisters()
{
}
#endif
VOID testMultiThread()
{
}
#include "main_exe_common.cpp"

Просмотреть файл

@ -9,48 +9,4 @@
SYMCRYPT_ENVIRONMENT_DEFS( Unittest );
#include "main_exe_common.cpp"
int __cdecl
main( int argc, _In_reads_( argc ) char * argv[] )
{
initTestInfrastructure( argc, argv );
// As of January 2020, we can't test XMM register saving and restoring because basic CRT
// functions like memcpy and memcmp use the XMM registers. This causes the test to fail on
// x86, but there's no point in testing this on AMD64 either because it effectively ignores
// the modified XMM values, meaning it's not actually testing anything.
TestSaveXmmEnabled = FALSE;
TestSaveYmmEnabled = TRUE;
addAllAlgs();
if (!g_profile && !g_measure_specific_sizes)
{
runFunctionalTests();
}
TestSaveYmmEnabled = FALSE;
if (g_profile)
{
runProfiling();
}
else
{
runPerfTests();
if (!g_measure_specific_sizes)
{
testMultiThread();
testSelftest();
}
}
exitTestInfrastructure();
return 0;
}
#include "main_exe_common_windows.cpp"

Просмотреть файл

@ -1076,7 +1076,6 @@ std::unique_ptr<std::vector<AlgType *>> getAlgorithmsOfOneType( );
extern BOOLEAN TestSelftestsEnabled;
extern BOOLEAN TestSaveXmmEnabled;
extern BOOLEAN TestSaveYmmEnabled;
extern BOOLEAN TestSaveYmmFallback;
extern ULONGLONG TestFatalCount;
extern ULONGLONG TestErrorInjectionCount;
@ -1085,21 +1084,14 @@ extern ULONG TestErrorInjectionProb;
extern BYTE TestErrorInjectionSeed[ SYMCRYPT_SHA1_RESULT_SIZE ];
#if SYMCRYPT_CPU_X86
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
//
// These Save/Restore functions are used by user mode SaveXmm code, plus the testing code.
// These Save/Restore functions are used by user mode SaveXmm and Ymm code, plus the testing code.
//
extern "C" {
VOID SYMCRYPT_CALL SymCryptEnvUmSaveXmmRegistersAsm( __m128i * buffer );
VOID SYMCRYPT_CALL SymCryptEnvUmRestoreXmmRegistersAsm( __m128i * buffer );
}
#endif
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
//
// These Save/Restore functions are used by user mode SaveXmm code, plus the testing code.
//
extern "C" {
VOID SYMCRYPT_CALL SymCryptEnvUmSaveYmmRegistersAsm( __m256i * buffer );
VOID SYMCRYPT_CALL SymCryptEnvUmRestoreYmmRegistersAsm( __m256i * buffer );
}
@ -1202,16 +1194,10 @@ CHAR charToLower( CHAR c );
extern double g_wipePerf[PERF_WIPE_MAX_SIZE+1][PERF_WIPE_N_OFFSETS];
VOID
initXmmRegisters();
initVectorRegisters();
VOID
verifyXmmRegisters();
VOID
initYmmRegisters();
VOID
verifyYmmRegisters();
verifyVectorRegisters();
VOID

Просмотреть файл

@ -19,7 +19,6 @@ set(SOURCES
testutil.cpp
testKdf.cpp
testTlsCbcHmac.cpp
env_SymCryptUnittest.cpp
testMultiThread.cpp
rndDriver.cpp
testArithmetic.cpp
@ -39,6 +38,7 @@ set(SOURCES
# Append Windows-specific sources
if(WIN32)
list(APPEND SOURCES
env_windowsSymCryptUnittest.cpp
rsa32_implementations.cpp
capi_implementations.cpp
cng_implementations.cpp
@ -54,15 +54,19 @@ if(WIN32)
# testDl_msbignum.cpp
# testDl_cng.cpp
)
else()
list(APPEND SOURCES
env_linuxSymCryptUnittest.cpp
)
endif()
if(WIN32 AND NOT SYMCRYPT_TARGET_ENV MATCHES "Generic")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64")
list(APPEND SOURCES amd64/saveymm.asm)
set_source_files_properties(amd64/saveymm.asm PROPERTY LANGUAGE ASM_MASM)
list(APPEND SOURCES amd64/savevectors.asm)
set_source_files_properties(amd64/savevectors.asm PROPERTY LANGUAGE ASM_MASM)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "X86")
list(APPEND SOURCES i386/savexmm.asm)
set_source_files_properties(i386/savexmm.asm PROPERTY LANGUAGE ASM_MASM)
list(APPEND SOURCES i386/savevectors.asm)
set_source_files_properties(i386/savevectors.asm PROPERTY LANGUAGE ASM_MASM)
endif()
elseif(NOT SYMCRYPT_TARGET_ENV MATCHES "Generic")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64")

Просмотреть файл

@ -1,68 +1,121 @@
;
; saveymm.asm
;
; Copyright (c) Microsoft Corporation. Licensed under the MIT license.
;
include ksamd64.inc
TITLE saveymm.asm
;VOID SYMCRYPT_CALL SymCryptEnvUmSaveYmmRegistersAsm( __m256i * buffer );
;VOID SYMCRYPT_CALL SymCryptEnvUmRestoreYmmRegistersAsm( __m256i * buffer );
LEAF_ENTRY SymCryptEnvUmSaveYmmRegistersAsm, _TEXT
add rcx, 31
and rcx, NOT 31
vmovaps [rcx+ 0 * 32 ], ymm0
vmovaps [rcx+ 1 * 32 ], ymm1
vmovaps [rcx+ 2 * 32 ], ymm2
vmovaps [rcx+ 3 * 32 ], ymm3
vmovaps [rcx+ 4 * 32 ], ymm4
vmovaps [rcx+ 5 * 32 ], ymm5
vmovaps [rcx+ 6 * 32 ], ymm6
vmovaps [rcx+ 7 * 32 ], ymm7
vmovaps [rcx+ 8 * 32 ], ymm8
vmovaps [rcx+ 9 * 32 ], ymm9
vmovaps [rcx+ 10 * 32 ], ymm10
vmovaps [rcx+ 11 * 32 ], ymm11
vmovaps [rcx+ 12 * 32 ], ymm12
vmovaps [rcx+ 13 * 32 ], ymm13
vmovaps [rcx+ 14 * 32 ], ymm14
vmovaps [rcx+ 15 * 32 ], ymm15
ret
LEAF_END SymCryptEnvUmSaveYmmRegistersAsm, _TEXT
LEAF_ENTRY SymCryptEnvUmRestoreYmmRegistersAsm, _TEXT
add rcx, 31
and rcx, NOT 31
vmovaps ymm0 , [rcx+ 0 * 32 ]
vmovaps ymm1 , [rcx+ 1 * 32 ]
vmovaps ymm2 , [rcx+ 2 * 32 ]
vmovaps ymm3 , [rcx+ 3 * 32 ]
vmovaps ymm4 , [rcx+ 4 * 32 ]
vmovaps ymm5 , [rcx+ 5 * 32 ]
vmovaps ymm6 , [rcx+ 6 * 32 ]
vmovaps ymm7 , [rcx+ 7 * 32 ]
vmovaps ymm8 , [rcx+ 8 * 32 ]
vmovaps ymm9 , [rcx+ 9 * 32 ]
vmovaps ymm10, [rcx+ 10 * 32 ]
vmovaps ymm11, [rcx+ 11 * 32 ]
vmovaps ymm12, [rcx+ 12 * 32 ]
vmovaps ymm13, [rcx+ 13 * 32 ]
vmovaps ymm14, [rcx+ 14 * 32 ]
vmovaps ymm15, [rcx+ 15 * 32 ]
ret
LEAF_END SymCryptEnvUmRestoreYmmRegistersAsm, _TEXT
END
;
; savevectors.asm
;
; Copyright (c) Microsoft Corporation. Licensed under the MIT license.
;
include ksamd64.inc
TITLE savevectors.asm
;VOID SYMCRYPT_CALL SymCryptEnvUmSaveXmmRegistersAsm( __m128i * buffer );
;VOID SYMCRYPT_CALL SymCryptEnvUmRestoreXmmRegistersAsm( __m128i * buffer );
LEAF_ENTRY SymCryptEnvUmSaveXmmRegistersAsm, _TEXT
add rcx, 15
and rcx, NOT 15
movaps [rcx+ 0 * 16 ], xmm0
movaps [rcx+ 1 * 16 ], xmm1
movaps [rcx+ 2 * 16 ], xmm2
movaps [rcx+ 3 * 16 ], xmm3
movaps [rcx+ 4 * 16 ], xmm4
movaps [rcx+ 5 * 16 ], xmm5
movaps [rcx+ 6 * 16 ], xmm6
movaps [rcx+ 7 * 16 ], xmm7
movaps [rcx+ 8 * 16 ], xmm8
movaps [rcx+ 9 * 16 ], xmm9
movaps [rcx+ 10 * 16 ], xmm10
movaps [rcx+ 11 * 16 ], xmm11
movaps [rcx+ 12 * 16 ], xmm12
movaps [rcx+ 13 * 16 ], xmm13
movaps [rcx+ 14 * 16 ], xmm14
movaps [rcx+ 15 * 16 ], xmm15
ret
LEAF_END SymCryptEnvUmSaveXmmRegistersAsm, _TEXT
LEAF_ENTRY SymCryptEnvUmRestoreXmmRegistersAsm, _TEXT
add rcx, 15
and rcx, NOT 15
movaps xmm0 , [rcx+ 0 * 16 ]
movaps xmm1 , [rcx+ 1 * 16 ]
movaps xmm2 , [rcx+ 2 * 16 ]
movaps xmm3 , [rcx+ 3 * 16 ]
movaps xmm4 , [rcx+ 4 * 16 ]
movaps xmm5 , [rcx+ 5 * 16 ]
movaps xmm6 , [rcx+ 6 * 16 ]
movaps xmm7 , [rcx+ 7 * 16 ]
movaps xmm8 , [rcx+ 8 * 16 ]
movaps xmm9 , [rcx+ 9 * 16 ]
movaps xmm10, [rcx+ 10 * 16 ]
movaps xmm11, [rcx+ 11 * 16 ]
movaps xmm12, [rcx+ 12 * 16 ]
movaps xmm13, [rcx+ 13 * 16 ]
movaps xmm14, [rcx+ 14 * 16 ]
movaps xmm15, [rcx+ 15 * 16 ]
ret
LEAF_END SymCryptEnvUmRestoreXmmRegistersAsm, _TEXT
;VOID SYMCRYPT_CALL SymCryptEnvUmSaveYmmRegistersAsm( __m256i * buffer );
;VOID SYMCRYPT_CALL SymCryptEnvUmRestoreYmmRegistersAsm( __m256i * buffer );
LEAF_ENTRY SymCryptEnvUmSaveYmmRegistersAsm, _TEXT
add rcx, 31
and rcx, NOT 31
vmovaps [rcx+ 0 * 32 ], ymm0
vmovaps [rcx+ 1 * 32 ], ymm1
vmovaps [rcx+ 2 * 32 ], ymm2
vmovaps [rcx+ 3 * 32 ], ymm3
vmovaps [rcx+ 4 * 32 ], ymm4
vmovaps [rcx+ 5 * 32 ], ymm5
vmovaps [rcx+ 6 * 32 ], ymm6
vmovaps [rcx+ 7 * 32 ], ymm7
vmovaps [rcx+ 8 * 32 ], ymm8
vmovaps [rcx+ 9 * 32 ], ymm9
vmovaps [rcx+ 10 * 32 ], ymm10
vmovaps [rcx+ 11 * 32 ], ymm11
vmovaps [rcx+ 12 * 32 ], ymm12
vmovaps [rcx+ 13 * 32 ], ymm13
vmovaps [rcx+ 14 * 32 ], ymm14
vmovaps [rcx+ 15 * 32 ], ymm15
ret
LEAF_END SymCryptEnvUmSaveYmmRegistersAsm, _TEXT
LEAF_ENTRY SymCryptEnvUmRestoreYmmRegistersAsm, _TEXT
add rcx, 31
and rcx, NOT 31
vmovaps ymm0 , [rcx+ 0 * 32 ]
vmovaps ymm1 , [rcx+ 1 * 32 ]
vmovaps ymm2 , [rcx+ 2 * 32 ]
vmovaps ymm3 , [rcx+ 3 * 32 ]
vmovaps ymm4 , [rcx+ 4 * 32 ]
vmovaps ymm5 , [rcx+ 5 * 32 ]
vmovaps ymm6 , [rcx+ 6 * 32 ]
vmovaps ymm7 , [rcx+ 7 * 32 ]
vmovaps ymm8 , [rcx+ 8 * 32 ]
vmovaps ymm9 , [rcx+ 9 * 32 ]
vmovaps ymm10, [rcx+ 10 * 32 ]
vmovaps ymm11, [rcx+ 11 * 32 ]
vmovaps ymm12, [rcx+ 12 * 32 ]
vmovaps ymm13, [rcx+ 13 * 32 ]
vmovaps ymm14, [rcx+ 14 * 32 ]
vmovaps ymm15, [rcx+ 15 * 32 ]
ret
LEAF_END SymCryptEnvUmRestoreYmmRegistersAsm, _TEXT
END

Просмотреть файл

@ -5,8 +5,6 @@
#
.intel_syntax noprefix
# TITLE saveymm.asm
.text
#VOID SYMCRYPT_CALL SymCryptEnvUmSaveYmmRegistersAsm( __m256i * buffer );

Просмотреть файл

@ -1,412 +1,352 @@
//
// env_SymCryptUnitTest
// Non-standard environment to support the unit test
//
#include "precomp.h"
//
// Some test hooks to allow the unit test to have its own environment.
//
extern "C" {
#if SYMCRYPT_APPLE_CC
#include "sc_lib-testhooks.h"
#else
#include "sc_lib-testhooks.h"
#endif
}
//
// We hack and create a NEW environment for our unit test.
//
BOOLEAN TestSelftestsEnabled = FALSE;
BOOLEAN TestSaveXmmEnabled = FALSE;
BOOLEAN TestSaveYmmEnabled = FALSE;
// Set to TRUE when unit tests artificially fail to save Ymm registers
BOOLEAN TestSaveYmmFallback = FALSE;
ULONGLONG TestFatalCount = 0;
ULONGLONG TestErrorInjectionCount = 0;
ULONGLONG TestErrorInjectionCalls = 0;
ULONG TestErrorInjectionProb = 0;
BYTE TestErrorInjectionSeed[ SYMCRYPT_SHA1_RESULT_SIZE ] = {0};
extern "C" {
;
///////////////////////////////////////////////////////
// Start of the actual fake environment code
SYMCRYPT_CPU_FEATURES SYMCRYPT_CALL SymCryptCpuFeaturesNeverPresentEnvUnittest()
{
return 0;
}
VOID
SYMCRYPT_CALL
SymCryptInitEnvUnittest( UINT32 version )
{
if( g_SymCryptFlags & SYMCRYPT_FLAG_LIB_INITIALIZED )
{
return;
}
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
SymCryptDetectCpuFeaturesByCpuid( SYMCRYPT_CPUID_DETECT_FLAG_CHECK_OS_SUPPORT_FOR_YMM );
//
// Don't use Ymm registers if the OS doesn't report them as available.
// We assume Ymm register swapping isn't supported unless we can verify that it is.
//
g_SymCryptCpuFeaturesNotPresent |= SYMCRYPT_CPU_FEATURE_AVX2;
#if SYMCRYPT_MS_VC
if( (GetEnabledXStateFeatures() & XSTATE_MASK_AVX) != 0 )
{
g_SymCryptCpuFeaturesNotPresent &= ~SYMCRYPT_CPU_FEATURE_AVX2;
}
#endif
//
// By default we don't fail XMM so that we get proper performance for GCM.
// We allow the nofail to be disabled by command-line option.
//
g_SymCryptCpuFeaturesNotPresent &= ~SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL;
#elif SYMCRYPT_CPU_ARM
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) ~SYMCRYPT_CPU_FEATURE_NEON;
#elif SYMCRYPT_CPU_ARM64
SymCryptDetectCpuFeaturesFromIsProcessorFeaturePresent();
#endif
SymCryptInitEnvCommon( version );
}
_Analysis_noreturn_
VOID
SYMCRYPT_CALL
SymCryptFatalEnvUnittest( ULONG fatalCode )
{
if( TestSelftestsEnabled )
{
TestFatalCount++;
return;
}
FATAL5( "*\n\nSymCrypt fatal error '%c%c%c%c' ", (fatalCode >> 24) & 0xff, (fatalCode >> 16) & 0xff, (fatalCode >> 8) & 0xff, fatalCode & 0xff );
}
VOID SYMCRYPT_CALL SymCryptTestInjectErrorEnvUnittest( PBYTE pbBuf, SIZE_T cbBuf )
{
if( TestSelftestsEnabled )
{
++TestErrorInjectionCalls;
if( TestErrorInjectionSeed[10]% TestErrorInjectionProb == 1 )
{
SIZE_T bitNo = (*(ULONGLONG *)TestErrorInjectionSeed) % (8*cbBuf);
pbBuf[ bitNo/8 ] ^= ( 1 << (bitNo % 8) );
++TestErrorInjectionCount;
}
SymCryptSha1( TestErrorInjectionSeed, sizeof( TestErrorInjectionSeed ), TestErrorInjectionSeed );
}
}
PVOID malloc_align32( SIZE_T size )
{
PVOID pBase = malloc( size + 8 + 31 );
if( pBase == NULL )
{
return pBase;
}
PBYTE pAligned = (PBYTE)((((ULONG_PTR) pBase) + 8 + 31) & ~31);
*(PVOID *) (pAligned - 8) = pBase;
return pAligned;
}
VOID free_align32( PVOID p )
{
CHECK( ((ULONG_PTR)p & 31) == 0, "?" );
free( *(PVOID *) ((PBYTE)p - 8) );
}
#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86
char g_saveInProgressType = 0;
PVOID g_savePtr = NULL;
extern "C" {
ULONG g_nSaves = 0;
}
#endif
#if SYMCRYPT_CPU_X86
//
// We have XMM save/restore logic even in Windows user mode so that we can test the library in user mode
// This makes it much easier to do thorough testing.
// We can disable these tests through a flag to get reasonable performance measurements on the same code.
//
#pragma warning(push)
#pragma warning(disable:4359)
typedef SYMCRYPT_ALIGN_STRUCT _SYMCRYPT_ENV_XMM_SAVE_DATA_REGS {
//
// The alignment on x86 is only 4, so we can't align the __m128i fields properly.
// We add some padding and let the assembler code adjust the alignmetn of the actual data.
// This is all transperant to the C code
//
__m128i xmm[8]; // 8 for the XMM registers.
SYMCRYPT_MAGIC_FIELD
} SYMCRYPT_ENV_XMM_SAVE_DATA_REGS, *PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS;
#pragma warning(pop)
typedef struct _SYMCRYPT_ENV_XMM_SAVE_DATA {
PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS pRegs;
SYMCRYPT_MAGIC_FIELD
} SYMCRYPT_ENV_XMM_SAVE_DATA, *PSYMCRYPT_ENV_XMM_SAVE_DATA;
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptSaveXmmEnvUnittest( _Out_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
PSYMCRYPT_ENV_XMM_SAVE_DATA p = (PSYMCRYPT_ENV_XMM_SAVE_DATA) pSaveData;
PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS pRegs;
__m128i regs[8];
if( TestSaveXmmEnabled )
{
//
// To test the fallback from the failure of the savexmm function we introduce occasional errors
//
if( !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL ) && __rdtsc() % 101 == 0 )
{
return SYMCRYPT_EXTERNAL_FAILURE;
}
//
// Malloc & Free can modify the XMM registers, so we save them first in a temp
// so that we call them inside the save/restore area.
//
SymCryptEnvUmSaveXmmRegistersAsm( &regs[0] );
pRegs = (PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS) malloc_align32( sizeof( *pRegs ) );
if( pRegs == NULL )
{
return SYMCRYPT_EXTERNAL_FAILURE;
}
memcpy( &pRegs->xmm[0], &regs[0], sizeof( regs ) );
SYMCRYPT_SET_MAGIC( pRegs );
p->pRegs = pRegs;
SYMCRYPT_SET_MAGIC( p );
CHECK( g_saveInProgressType == 0, "Nested register saves are not supported at IRQL=DISPATCH_LEVEL" );
g_savePtr = pSaveData;
g_saveInProgressType = 'X';
}
return SYMCRYPT_NO_ERROR;
}
VOID
SYMCRYPT_CALL
SymCryptRestoreXmmEnvUnittest( _Inout_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
PSYMCRYPT_ENV_XMM_SAVE_DATA p = (PSYMCRYPT_ENV_XMM_SAVE_DATA) pSaveData;
PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS pRegs;
__m128i regs[8];
if( TestSaveXmmEnabled )
{
SYMCRYPT_CHECK_MAGIC( p );
pRegs = p->pRegs;
SYMCRYPT_CHECK_MAGIC( pRegs );
CHECK( g_saveInProgressType == 'X', "XMM not saved" );
CHECK( g_savePtr == pSaveData, "?" );
memcpy( &regs[0], &pRegs->xmm[0], sizeof( regs ) );
SYMCRYPT_WIPE_MAGIC( pRegs );
free_align32( pRegs );
p->pRegs = NULL;
SYMCRYPT_WIPE_MAGIC( p );
SymCryptEnvUmRestoreXmmRegistersAsm( &regs[0] );
g_saveInProgressType = 0;
}
}
#elif SYMCRYPT_CPU_AMD64
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptSaveXmmEnvUnittest( _Out_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
UNREFERENCED_PARAMETER( pSaveData );
return SYMCRYPT_NO_ERROR;
}
VOID
SYMCRYPT_CALL
SymCryptRestoreXmmEnvUnittest( _Inout_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
UNREFERENCED_PARAMETER( pSaveData );
}
#endif
#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86
//
// We have YMM save/restore logic even in Windows user mode so that we can test the library in user mode
// This makes it much easier to do thorough testing.
// We can disable these tests through a flag to get reasonable performance measurements on the same code.
//
typedef SYMCRYPT_ALIGN_AT(32) struct _SYMCRYPT_ENV_YMM_SAVE_DATA_REGS {
__m256i ymm[16]; // 16 for the XMM registers
SYMCRYPT_MAGIC_FIELD
} SYMCRYPT_ENV_YMM_SAVE_DATA_REGS, *PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS;
typedef struct _SYMCRYPT_ENV_YMM_SAVE_DATA {
PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS pRegs;
SYMCRYPT_MAGIC_FIELD
} SYMCRYPT_ENV_YMM_SAVE_DATA, *PSYMCRYPT_ENV_YMM_SAVE_DATA;
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptSaveYmmEnvUnittest( _Out_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
PSYMCRYPT_ENV_YMM_SAVE_DATA p = (PSYMCRYPT_ENV_YMM_SAVE_DATA) pSaveData;
PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS pRegs;
__m256i regs[16];
CHECK( SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_AVX2 ), "?" );
if( TestSaveYmmEnabled )
{
//
// To test the fallback from the failure of the saveYmm function we introduce occasional errors
//
if( __rdtsc() % 101 == 0 )
{
// If we are testing the fallback path, we want to record this so test for presence of
// Ymm save/restore logic is not triggered. If fallback code calls memcpy (for instance)
// the CRT may (correctly) use Ymm registers without saving/restoring in user mode.
// This is the case for our Parallel SHA implementations.
TestSaveYmmFallback = TRUE;
return SYMCRYPT_EXTERNAL_FAILURE;
}
//
// Alloc can modify the regs, so save them first so that the modification happens
// inside the save block
//
SymCryptEnvUmSaveYmmRegistersAsm( regs );
pRegs = (PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS) malloc_align32( sizeof( *pRegs ) );
if( pRegs == NULL )
{
return SYMCRYPT_EXTERNAL_FAILURE;
}
memcpy( pRegs->ymm, regs, sizeof( regs ) );
SYMCRYPT_SET_MAGIC( pRegs );
SYMCRYPT_CHECK_MAGIC( pRegs );
p->pRegs = pRegs;
SYMCRYPT_SET_MAGIC( p );
CHECK( g_saveInProgressType == 0, "Nested register saves are not supported at IRQL=DISPATCH_LEVEL" );
g_savePtr = pSaveData;
g_saveInProgressType = 'Y';
}
return SYMCRYPT_NO_ERROR;
}
VOID
SYMCRYPT_CALL
SymCryptRestoreYmmEnvUnittest( _Inout_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
PSYMCRYPT_ENV_YMM_SAVE_DATA p = (PSYMCRYPT_ENV_YMM_SAVE_DATA) pSaveData;
PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS pRegs;
__m256i regs[16];
CHECK( SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_AVX2 ), "?" );
if( TestSaveYmmEnabled )
{
SYMCRYPT_CHECK_MAGIC( p );
pRegs = p->pRegs;
SYMCRYPT_CHECK_MAGIC( pRegs );
CHECK( g_saveInProgressType == 'Y', "YMM not saved" );
CHECK( g_savePtr == pSaveData, "?" );
memcpy( regs, pRegs->ymm, sizeof( regs ) );
SYMCRYPT_WIPE_MAGIC( pRegs );
free_align32( pRegs );
p->pRegs = NULL;
SYMCRYPT_WIPE_MAGIC( p );
SymCryptEnvUmRestoreYmmRegistersAsm( regs );
g_saveInProgressType = 0;
}
}
#endif
VOID
SYMCRYPT_CALL
SymCryptEnvUnittestDetectCpuFeatures( ULONG flags )
{
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
SymCryptDetectCpuFeaturesByCpuid( flags );
#elif SYMCRYPT_CPU_ARM | SYMCRYPT_CPU_ARM64
UNREFERENCED_PARAMETER( flags );
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) ~SYMCRYPT_CPU_FEATURE_NEON;
#else
UNREFERENCED_PARAMETER( flags );
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) (-1);
#endif
}
#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86
VOID
SYMCRYPT_CALL
SymCryptCpuidExFuncEnvUnittest( int cpuInfo[4], int function_id, int subfunction_id )
{
__cpuidex( cpuInfo, function_id, subfunction_id );
}
#endif
} // extern "C"
//
// env_commonSymCryptUnitTest
// Common parts of non-standard environment to support the unit test
//
//
// Some test hooks to allow the unit test to have its own environment.
//
extern "C" {
#include "sc_lib-testhooks.h"
}
//
// We hack and create a NEW environment for our unit test.
//
BOOLEAN TestSelftestsEnabled = FALSE;
ULONGLONG TestFatalCount = 0;
ULONGLONG TestErrorInjectionCount = 0;
ULONGLONG TestErrorInjectionCalls = 0;
ULONG TestErrorInjectionProb = 0;
BYTE TestErrorInjectionSeed[ SYMCRYPT_SHA1_RESULT_SIZE ] = {0};
extern "C" {
;
///////////////////////////////////////////////////////
// Start of the actual fake environment code
SYMCRYPT_CPU_FEATURES SYMCRYPT_CALL SymCryptCpuFeaturesNeverPresentEnvUnittest()
{
return 0;
}
_Analysis_noreturn_
VOID
SYMCRYPT_CALL
SymCryptFatalEnvUnittest( ULONG fatalCode )
{
if( TestSelftestsEnabled )
{
TestFatalCount++;
return;
}
FATAL5( "*\n\nSymCrypt fatal error '%c%c%c%c' ", (fatalCode >> 24) & 0xff, (fatalCode >> 16) & 0xff, (fatalCode >> 8) & 0xff, fatalCode & 0xff );
}
VOID SYMCRYPT_CALL SymCryptTestInjectErrorEnvUnittest( PBYTE pbBuf, SIZE_T cbBuf )
{
if( TestSelftestsEnabled )
{
++TestErrorInjectionCalls;
if( TestErrorInjectionSeed[10]% TestErrorInjectionProb == 1 )
{
SIZE_T bitNo = (*(ULONGLONG *)TestErrorInjectionSeed) % (8*cbBuf);
pbBuf[ bitNo/8 ] ^= ( 1 << (bitNo % 8) );
++TestErrorInjectionCount;
}
SymCryptSha1( TestErrorInjectionSeed, sizeof( TestErrorInjectionSeed ), TestErrorInjectionSeed );
}
}
PVOID malloc_align32( SIZE_T size )
{
PVOID pBase = malloc( size + 8 + 31 );
if( pBase == NULL )
{
return pBase;
}
PBYTE pAligned = (PBYTE)((((ULONG_PTR) pBase) + 8 + 31) & ~31);
*(PVOID *) (pAligned - 8) = pBase;
return pAligned;
}
VOID free_align32( PVOID p )
{
CHECK( ((ULONG_PTR)p & 31) == 0, "?" );
free( *(PVOID *) ((PBYTE)p - 8) );
}
#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86
char g_saveInProgressType = 0;
PVOID g_savePtr = NULL;
extern "C" {
ULONG g_nSaves = 0;
}
#endif
#if SYMCRYPT_CPU_X86
//
// We have XMM save/restore logic even in Windows user mode so that we can test the library in user mode
// This makes it much easier to do thorough testing.
// We can disable these tests through a flag to get reasonable performance measurements on the same code.
//
#pragma warning(push)
#pragma warning(disable:4359)
typedef SYMCRYPT_ALIGN_STRUCT _SYMCRYPT_ENV_XMM_SAVE_DATA_REGS {
//
// The alignment on x86 is only 4, so we can't align the __m128i fields properly.
// We add some padding and let the assembler code adjust the alignmetn of the actual data.
// This is all transperant to the C code
//
__m128i xmm[8]; // 8 for the XMM registers.
SYMCRYPT_MAGIC_FIELD
} SYMCRYPT_ENV_XMM_SAVE_DATA_REGS, *PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS;
#pragma warning(pop)
typedef struct _SYMCRYPT_ENV_XMM_SAVE_DATA {
PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS pRegs;
SYMCRYPT_MAGIC_FIELD
} SYMCRYPT_ENV_XMM_SAVE_DATA, *PSYMCRYPT_ENV_XMM_SAVE_DATA;
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptSaveXmmEnvUnittest( _Out_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
PSYMCRYPT_ENV_XMM_SAVE_DATA p = (PSYMCRYPT_ENV_XMM_SAVE_DATA) pSaveData;
PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS pRegs;
__m128i regs[8];
if( TestSaveXmmEnabled )
{
//
// To test the fallback from the failure of the savexmm function we introduce occasional errors
//
if( !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL ) && __rdtsc() % 101 == 0 )
{
return SYMCRYPT_EXTERNAL_FAILURE;
}
//
// Malloc & Free can modify the XMM registers, so we save them first in a temp
// so that we call them inside the save/restore area.
//
SymCryptEnvUmSaveXmmRegistersAsm( &regs[0] );
pRegs = (PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS) malloc_align32( sizeof( *pRegs ) );
if( pRegs == NULL )
{
return SYMCRYPT_EXTERNAL_FAILURE;
}
memcpy( &pRegs->xmm[0], &regs[0], sizeof( regs ) );
SYMCRYPT_SET_MAGIC( pRegs );
p->pRegs = pRegs;
SYMCRYPT_SET_MAGIC( p );
CHECK( g_saveInProgressType == 0, "Nested register saves are not supported at IRQL=DISPATCH_LEVEL" );
g_savePtr = pSaveData;
g_saveInProgressType = 'X';
}
return SYMCRYPT_NO_ERROR;
}
VOID
SYMCRYPT_CALL
SymCryptRestoreXmmEnvUnittest( _Inout_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
PSYMCRYPT_ENV_XMM_SAVE_DATA p = (PSYMCRYPT_ENV_XMM_SAVE_DATA) pSaveData;
PSYMCRYPT_ENV_XMM_SAVE_DATA_REGS pRegs;
__m128i regs[8];
if( TestSaveXmmEnabled )
{
SYMCRYPT_CHECK_MAGIC( p );
pRegs = p->pRegs;
SYMCRYPT_CHECK_MAGIC( pRegs );
CHECK( g_saveInProgressType == 'X', "XMM not saved" );
CHECK( g_savePtr == pSaveData, "?" );
memcpy( &regs[0], &pRegs->xmm[0], sizeof( regs ) );
SYMCRYPT_WIPE_MAGIC( pRegs );
free_align32( pRegs );
p->pRegs = NULL;
SYMCRYPT_WIPE_MAGIC( p );
SymCryptEnvUmRestoreXmmRegistersAsm( &regs[0] );
g_saveInProgressType = 0;
}
}
#elif SYMCRYPT_CPU_AMD64
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptSaveXmmEnvUnittest( _Out_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
UNREFERENCED_PARAMETER( pSaveData );
return SYMCRYPT_NO_ERROR;
}
VOID
SYMCRYPT_CALL
SymCryptRestoreXmmEnvUnittest( _Inout_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
UNREFERENCED_PARAMETER( pSaveData );
}
#endif
#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86
//
// We have YMM save/restore logic even in Windows user mode so that we can test the library in user mode
// This makes it much easier to do thorough testing.
// We can disable these tests through a flag to get reasonable performance measurements on the same code.
//
typedef SYMCRYPT_ALIGN_AT(32) struct _SYMCRYPT_ENV_YMM_SAVE_DATA_REGS {
__m256i ymm[16]; // 16 for the XMM registers
SYMCRYPT_MAGIC_FIELD
} SYMCRYPT_ENV_YMM_SAVE_DATA_REGS, *PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS;
typedef struct _SYMCRYPT_ENV_YMM_SAVE_DATA {
PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS pRegs;
SYMCRYPT_MAGIC_FIELD
} SYMCRYPT_ENV_YMM_SAVE_DATA, *PSYMCRYPT_ENV_YMM_SAVE_DATA;
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptSaveYmmEnvUnittest( _Out_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
PSYMCRYPT_ENV_YMM_SAVE_DATA p = (PSYMCRYPT_ENV_YMM_SAVE_DATA) pSaveData;
PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS pRegs;
__m256i regs[16];
CHECK( SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_AVX2 ), "?" );
if( TestSaveYmmEnabled )
{
//
// To test the fallback from the failure of the saveYmm function we introduce occasional errors
//
if( __rdtsc() % 101 == 0 )
{
return SYMCRYPT_EXTERNAL_FAILURE;
}
//
// Alloc can modify the regs, so save them first so that the modification happens
// inside the save block
//
SymCryptEnvUmSaveYmmRegistersAsm( regs );
pRegs = (PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS) malloc_align32( sizeof( *pRegs ) );
if( pRegs == NULL )
{
return SYMCRYPT_EXTERNAL_FAILURE;
}
memcpy( pRegs->ymm, regs, sizeof( regs ) );
SYMCRYPT_SET_MAGIC( pRegs );
SYMCRYPT_CHECK_MAGIC( pRegs );
p->pRegs = pRegs;
SYMCRYPT_SET_MAGIC( p );
CHECK( g_saveInProgressType == 0, "Nested register saves are not supported at IRQL=DISPATCH_LEVEL" );
g_savePtr = pSaveData;
g_saveInProgressType = 'Y';
}
return SYMCRYPT_NO_ERROR;
}
VOID
SYMCRYPT_CALL
SymCryptRestoreYmmEnvUnittest( _Inout_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
PSYMCRYPT_ENV_YMM_SAVE_DATA p = (PSYMCRYPT_ENV_YMM_SAVE_DATA) pSaveData;
PSYMCRYPT_ENV_YMM_SAVE_DATA_REGS pRegs;
__m256i regs[16];
CHECK( SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_AVX2 ), "?" );
if( TestSaveYmmEnabled )
{
SYMCRYPT_CHECK_MAGIC( p );
pRegs = p->pRegs;
SYMCRYPT_CHECK_MAGIC( pRegs );
CHECK( g_saveInProgressType == 'Y', "YMM not saved" );
CHECK( g_savePtr == pSaveData, "?" );
memcpy( regs, pRegs->ymm, sizeof( regs ) );
SYMCRYPT_WIPE_MAGIC( pRegs );
free_align32( pRegs );
p->pRegs = NULL;
SYMCRYPT_WIPE_MAGIC( p );
SymCryptEnvUmRestoreYmmRegistersAsm( regs );
g_saveInProgressType = 0;
}
}
#endif
VOID
SYMCRYPT_CALL
SymCryptEnvUnittestDetectCpuFeatures( ULONG flags )
{
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
SymCryptDetectCpuFeaturesByCpuid( flags );
#elif SYMCRYPT_CPU_ARM | SYMCRYPT_CPU_ARM64
UNREFERENCED_PARAMETER( flags );
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) ~SYMCRYPT_CPU_FEATURE_NEON;
#else
UNREFERENCED_PARAMETER( flags );
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) (-1);
#endif
}
#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86
VOID
SYMCRYPT_CALL
SymCryptCpuidExFuncEnvUnittest( int cpuInfo[4], int function_id, int subfunction_id )
{
__cpuidex( cpuInfo, function_id, subfunction_id );
}
#endif
} // extern "C"

Просмотреть файл

@ -0,0 +1,45 @@
//
// env_linuxSymCryptUnitTest
// Non-standard environment to support the unit test
//
#include "precomp.h"
#include "env_commonSymCryptUnittest.cpp"
BOOLEAN TestSaveXmmEnabled = FALSE;
BOOLEAN TestSaveYmmEnabled = FALSE;
extern "C" {
VOID
SYMCRYPT_CALL
SymCryptInitEnvUnittest( UINT32 version )
{
if( g_SymCryptFlags & SYMCRYPT_FLAG_LIB_INITIALIZED )
{
return;
}
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
SymCryptDetectCpuFeaturesByCpuid( SYMCRYPT_CPUID_DETECT_FLAG_CHECK_OS_SUPPORT_FOR_YMM );
//
// By default we don't fail XMM so that we get proper performance for GCM.
// We allow the nofail to be disabled by command-line option.
//
g_SymCryptCpuFeaturesNotPresent &= ~SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL;
#elif SYMCRYPT_CPU_ARM
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) ~SYMCRYPT_CPU_FEATURE_NEON;
#elif SYMCRYPT_CPU_ARM64
SymCryptDetectCpuFeaturesFromIsProcessorFeaturePresent();
#endif
SymCryptInitEnvCommon( version );
}
} // extern "C"

Просмотреть файл

@ -0,0 +1,68 @@
//
// env_windowsSymCryptUnitTest
// Non-standard environment to support the unit test
//
#include "precomp.h"
#include "env_commonSymCryptUnittest.cpp"
#if SYMCRYPT_CPU_AMD64
BOOLEAN TestSaveXmmEnabled = TRUE; // For AMD64 we always test Xmm6-Xmm15 are preserved
#else
BOOLEAN TestSaveXmmEnabled = FALSE;
#endif
BOOLEAN TestSaveYmmEnabled = FALSE;
extern "C" {
VOID
SYMCRYPT_CALL
SymCryptInitEnvUnittest( UINT32 version )
{
if( g_SymCryptFlags & SYMCRYPT_FLAG_LIB_INITIALIZED )
{
return;
}
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
SymCryptDetectCpuFeaturesByCpuid( SYMCRYPT_CPUID_DETECT_FLAG_CHECK_OS_SUPPORT_FOR_YMM );
//
// Check OS reports the same AVX2 availability through GetEnabledXStateFeatures and _xgetbv
//
if (((GetEnabledXStateFeatures() & XSTATE_MASK_AVX) != 0) ^
((g_SymCryptCpuFeaturesNotPresent & SYMCRYPT_CPU_FEATURE_AVX2) == 0) )
{
FATAL3("GetEnabledXStateFeatures (%d) and g_SymCryptCpuFeaturesNotPresent (%d) set by _xgetbv disagree on whether AVX2 should be enabled!",
GetEnabledXStateFeatures() & XSTATE_MASK_AVX, g_SymCryptCpuFeaturesNotPresent & SYMCRYPT_CPU_FEATURE_AVX2);
}
//
// Check OS reports the same AVX512 availability through GetEnabledXStateFeatures and _xgetbv
//
if (((GetEnabledXStateFeatures() & XSTATE_MASK_AVX512) != 0) ^
((g_SymCryptCpuFeaturesNotPresent & SYMCRYPT_CPU_FEATURE_AVX512) == 0) )
{
FATAL3("GetEnabledXStateFeatures (%d) and g_SymCryptCpuFeaturesNotPresent (%d) set by _xgetbv disagree on whether AVX512 should be enabled!",
GetEnabledXStateFeatures() & XSTATE_MASK_AVX512, g_SymCryptCpuFeaturesNotPresent & SYMCRYPT_CPU_FEATURE_AVX512);
}
//
// By default we don't fail XMM so that we get proper performance for GCM.
// We allow the nofail to be disabled by command-line option.
//
g_SymCryptCpuFeaturesNotPresent &= ~SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL;
#elif SYMCRYPT_CPU_ARM
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) ~SYMCRYPT_CPU_FEATURE_NEON;
#elif SYMCRYPT_CPU_ARM64
SymCryptDetectCpuFeaturesFromIsProcessorFeaturePresent();
#endif
SymCryptInitEnvCommon( version );
}
} // extern "C"

Просмотреть файл

@ -1,184 +1,184 @@
;
; savexmm.asm
;
; Copyright (c) Microsoft Corporation. Licensed under the MIT license.
;
; Routines for saving and restoring XMM registers.
;
TITLE savexmm.asm
.686
.xmm
_TEXT SEGMENT PARA PUBLIC USE32 'CODE'
ASSUME CS:_TEXT, DS:FLAT, SS:FLAT
PUBLIC @SymCryptEnvUmSaveXmmRegistersAsm@4
PUBLIC @SymCryptEnvUmRestoreXmmRegistersAsm@4
PUBLIC @SymCryptEnvUmSaveYmmRegistersAsm@4
PUBLIC @SymCryptEnvUmRestoreYmmRegistersAsm@4
;VOID SYMCRYPT_CALL SymCryptEnvUmSaveXmmRegistersAsm( __m128i * buffer );
;VOID SYMCRYPT_CALL SymCryptEnvUmRestoreXmmRegistersAsm( __m128i * buffer );
;VOID SYMCRYPT_CALL SymCryptEnvUmSaveYmmRegistersAsm( __m256i * buffer );
;VOID SYMCRYPT_CALL SymCryptEnvUmRestoreYmmRegistersAsm( __m256i * buffer );
@SymCryptEnvUmSaveXmmRegistersAsm@4 PROC
;
; The .FPO provides debugging information for stack frames that do not use
; ebp as a base pointer.
; This stuff not well documented,
; but here is the information I've gathered about the arguments to .FPO
;
; In order:
; cdwLocals: Size of local variables, in DWords
; cdwParams: Size of parameters, in DWords. Given that this is all about
; stack stuff, I'm assuming this is only about parameters passed
; on the stack.
; cbProlog : Number of bytes in the prolog code. We sometimes interleaved the
; prolog code with work for better performance. Most uses of
; .FPO seem to set this value to 0.
; The debugger seems to work if the prolog defined by this value
; contains all the stack adjustments.
; cbRegs : # registers saved in the prolog. 4 in our case
; fUseBP : 0 if EBP is not used as base pointer, 1 if EBP is used as base pointer
; cbFrame : Type of frame.
; 0 = FPO frame (no frame pointer)
; 1 = Trap frame (result of a CPU trap event)
; 2 = TSS frame
;
; Having looked at various occurrences of .FPO in the Windows code it
; seems to be used fairly sloppy, with lots of arguments left 0 even when
; they probably shouldn't be according to the spec.
;
.FPO(0,0,0,0,0,0)
; ecx = buffer
;
; First we align ecx to the next multiple of 16. The buffer is defined to have 16*9 bytes so we have enough room
;
add ecx, 15
and ecx, NOT 15
movaps [ecx ], xmm0
movaps [ecx+ 16], xmm1
movaps [ecx+ 32], xmm2
movaps [ecx+ 48], xmm3
movaps [ecx+ 64], xmm4
movaps [ecx+ 80], xmm5
movaps [ecx+ 96], xmm6
movaps [ecx+112], xmm7
ret
@SymCryptEnvUmSaveXmmRegistersAsm@4 ENDP
@SymCryptEnvUmRestoreXmmRegistersAsm@4 PROC
; ecx = buffer
;
; First we align ecx to the next multiple of 16. The buffer is defined to have 16*9 bytes so we have enough room
;
add ecx, 15
and ecx, NOT 15
movaps xmm0, [ecx ]
movaps xmm1, [ecx+ 16]
movaps xmm2, [ecx+ 32]
movaps xmm3, [ecx+ 48]
movaps xmm4, [ecx+ 64]
movaps xmm5, [ecx+ 80]
movaps xmm6, [ecx+ 96]
movaps xmm7, [ecx+112]
ret
@SymCryptEnvUmRestoreXmmRegistersAsm@4 ENDP
@SymCryptEnvUmSaveYmmRegistersAsm@4 PROC
;
; The .FPO provides debugging information for stack frames that do not use
; ebp as a base pointer.
; This stuff not well documented,
; but here is the information I've gathered about the arguments to .FPO
;
; In order:
; cdwLocals: Size of local variables, in DWords
; cdwParams: Size of parameters, in DWords. Given that this is all about
; stack stuff, I'm assuming this is only about parameters passed
; on the stack.
; cbProlog : Number of bytes in the prolog code. We sometimes interleaved the
; prolog code with work for better performance. Most uses of
; .FPO seem to set this value to 0.
; The debugger seems to work if the prolog defined by this value
; contains all the stack adjustments.
; cbRegs : # registers saved in the prolog. 4 in our case
; fUseBP : 0 if EBP is not used as base pointer, 1 if EBP is used as base pointer
; cbFrame : Type of frame.
; 0 = FPO frame (no frame pointer)
; 1 = Trap frame (result of a CPU trap event)
; 2 = TSS frame
;
; Having looked at various occurrences of .FPO in the Windows code it
; seems to be used fairly sloppy, with lots of arguments left 0 even when
; they probably shouldn't be according to the spec.
;
.FPO(0,0,0,0,0,0)
; ecx = buffer
;
; First we align ecx to the next multiple of 16. The buffer is defined to have 16*9 bytes so we have enough room
;
add ecx, 31
and ecx, NOT 31
vmovaps [ecx+ 0 * 32 ], ymm0
vmovaps [ecx+ 1 * 32 ], ymm1
vmovaps [ecx+ 2 * 32 ], ymm2
vmovaps [ecx+ 3 * 32 ], ymm3
vmovaps [ecx+ 4 * 32 ], ymm4
vmovaps [ecx+ 5 * 32 ], ymm5
vmovaps [ecx+ 6 * 32 ], ymm6
vmovaps [ecx+ 7 * 32 ], ymm7
ret
@SymCryptEnvUmSaveYmmRegistersAsm@4 ENDP
@SymCryptEnvUmRestoreYmmRegistersAsm@4 PROC
; ecx = buffer
;
; First we align ecx to the next multiple of 16. The buffer is defined to have 16*9 bytes so we have enough room
;
add ecx, 31
and ecx, NOT 31
vmovaps ymm0, [ecx + 0 * 32 ]
vmovaps ymm1, [ecx + 1 * 32 ]
vmovaps ymm2, [ecx + 2 * 32 ]
vmovaps ymm3, [ecx + 3 * 32 ]
vmovaps ymm4, [ecx + 4 * 32 ]
vmovaps ymm5, [ecx + 5 * 32 ]
vmovaps ymm6, [ecx + 6 * 32 ]
vmovaps ymm7, [ecx + 7 * 32 ]
ret
@SymCryptEnvUmRestoreYmmRegistersAsm@4 ENDP
_TEXT ENDS
END
;
; savevectors.asm
;
; Copyright (c) Microsoft Corporation. Licensed under the MIT license.
;
; Routines for saving and restoring XMM and YMM registers.
;
TITLE savevectors.asm
.686
.xmm
_TEXT SEGMENT PARA PUBLIC USE32 'CODE'
ASSUME CS:_TEXT, DS:FLAT, SS:FLAT
PUBLIC @SymCryptEnvUmSaveXmmRegistersAsm@4
PUBLIC @SymCryptEnvUmRestoreXmmRegistersAsm@4
PUBLIC @SymCryptEnvUmSaveYmmRegistersAsm@4
PUBLIC @SymCryptEnvUmRestoreYmmRegistersAsm@4
;VOID SYMCRYPT_CALL SymCryptEnvUmSaveXmmRegistersAsm( __m128i * buffer );
;VOID SYMCRYPT_CALL SymCryptEnvUmRestoreXmmRegistersAsm( __m128i * buffer );
;VOID SYMCRYPT_CALL SymCryptEnvUmSaveYmmRegistersAsm( __m256i * buffer );
;VOID SYMCRYPT_CALL SymCryptEnvUmRestoreYmmRegistersAsm( __m256i * buffer );
@SymCryptEnvUmSaveXmmRegistersAsm@4 PROC
;
; The .FPO provides debugging information for stack frames that do not use
; ebp as a base pointer.
; This stuff not well documented,
; but here is the information I've gathered about the arguments to .FPO
;
; In order:
; cdwLocals: Size of local variables, in DWords
; cdwParams: Size of parameters, in DWords. Given that this is all about
; stack stuff, I'm assuming this is only about parameters passed
; on the stack.
; cbProlog : Number of bytes in the prolog code. We sometimes interleaved the
; prolog code with work for better performance. Most uses of
; .FPO seem to set this value to 0.
; The debugger seems to work if the prolog defined by this value
; contains all the stack adjustments.
; cbRegs : # registers saved in the prolog. 4 in our case
; fUseBP : 0 if EBP is not used as base pointer, 1 if EBP is used as base pointer
; cbFrame : Type of frame.
; 0 = FPO frame (no frame pointer)
; 1 = Trap frame (result of a CPU trap event)
; 2 = TSS frame
;
; Having looked at various occurrences of .FPO in the Windows code it
; seems to be used fairly sloppy, with lots of arguments left 0 even when
; they probably shouldn't be according to the spec.
;
.FPO(0,0,0,0,0,0)
; ecx = buffer
;
; First we align ecx to the next multiple of 16. The buffer is defined to have 16*9 bytes so we have enough room
;
add ecx, 15
and ecx, NOT 15
movaps [ecx ], xmm0
movaps [ecx+ 16], xmm1
movaps [ecx+ 32], xmm2
movaps [ecx+ 48], xmm3
movaps [ecx+ 64], xmm4
movaps [ecx+ 80], xmm5
movaps [ecx+ 96], xmm6
movaps [ecx+112], xmm7
ret
@SymCryptEnvUmSaveXmmRegistersAsm@4 ENDP
@SymCryptEnvUmRestoreXmmRegistersAsm@4 PROC
; ecx = buffer
;
; First we align ecx to the next multiple of 16. The buffer is defined to have 16*9 bytes so we have enough room
;
add ecx, 15
and ecx, NOT 15
movaps xmm0, [ecx ]
movaps xmm1, [ecx+ 16]
movaps xmm2, [ecx+ 32]
movaps xmm3, [ecx+ 48]
movaps xmm4, [ecx+ 64]
movaps xmm5, [ecx+ 80]
movaps xmm6, [ecx+ 96]
movaps xmm7, [ecx+112]
ret
@SymCryptEnvUmRestoreXmmRegistersAsm@4 ENDP
@SymCryptEnvUmSaveYmmRegistersAsm@4 PROC
;
; The .FPO provides debugging information for stack frames that do not use
; ebp as a base pointer.
; This stuff not well documented,
; but here is the information I've gathered about the arguments to .FPO
;
; In order:
; cdwLocals: Size of local variables, in DWords
; cdwParams: Size of parameters, in DWords. Given that this is all about
; stack stuff, I'm assuming this is only about parameters passed
; on the stack.
; cbProlog : Number of bytes in the prolog code. We sometimes interleaved the
; prolog code with work for better performance. Most uses of
; .FPO seem to set this value to 0.
; The debugger seems to work if the prolog defined by this value
; contains all the stack adjustments.
; cbRegs : # registers saved in the prolog. 4 in our case
; fUseBP : 0 if EBP is not used as base pointer, 1 if EBP is used as base pointer
; cbFrame : Type of frame.
; 0 = FPO frame (no frame pointer)
; 1 = Trap frame (result of a CPU trap event)
; 2 = TSS frame
;
; Having looked at various occurrences of .FPO in the Windows code it
; seems to be used fairly sloppy, with lots of arguments left 0 even when
; they probably shouldn't be according to the spec.
;
.FPO(0,0,0,0,0,0)
; ecx = buffer
;
; First we align ecx to the next multiple of 16. The buffer is defined to have 16*9 bytes so we have enough room
;
add ecx, 31
and ecx, NOT 31
vmovaps [ecx+ 0 * 32 ], ymm0
vmovaps [ecx+ 1 * 32 ], ymm1
vmovaps [ecx+ 2 * 32 ], ymm2
vmovaps [ecx+ 3 * 32 ], ymm3
vmovaps [ecx+ 4 * 32 ], ymm4
vmovaps [ecx+ 5 * 32 ], ymm5
vmovaps [ecx+ 6 * 32 ], ymm6
vmovaps [ecx+ 7 * 32 ], ymm7
ret
@SymCryptEnvUmSaveYmmRegistersAsm@4 ENDP
@SymCryptEnvUmRestoreYmmRegistersAsm@4 PROC
; ecx = buffer
;
; First we align ecx to the next multiple of 16. The buffer is defined to have 16*9 bytes so we have enough room
;
add ecx, 31
and ecx, NOT 31
vmovaps ymm0, [ecx + 0 * 32 ]
vmovaps ymm1, [ecx + 1 * 32 ]
vmovaps ymm2, [ecx + 2 * 32 ]
vmovaps ymm3, [ecx + 3 * 32 ]
vmovaps ymm4, [ecx + 4 * 32 ]
vmovaps ymm5, [ecx + 5 * 32 ]
vmovaps ymm6, [ecx + 6 * 32 ]
vmovaps ymm7, [ecx + 7 * 32 ]
ret
@SymCryptEnvUmRestoreYmmRegistersAsm@4 ENDP
_TEXT ENDS
END

Просмотреть файл

@ -596,7 +596,7 @@ usage()
" sizeprefix:<prefix> Only applies when sizes: parameter is also specified. Prefixes\n"
" output of test command with a specific string. This can enable\n"
" easier concatenation of many test runs on differing platforms into\n"
" a single .csv for postprocessing."
" a single .csv for postprocessing.\n"
" kernel Run the kernel-mode tests \n"
" verbose Print detailed information for some algorithms\n"
" noperftests Skip running the performance tests - only run functional tests\n"
@ -609,6 +609,9 @@ usage()
" rsakgp Run perf measurement of RSA key generation.\n"
" sgx Run CNG and symcrypt test implementations against BCrypt in SGX enclave.\n"
" This option is only valid for win8_1 version and newer of the tests.\n"
" testSaveYmm This option enables the unit tests to test the save/restore logic for\n"
" Ymm registers. Normally the C runtime may overwrite Ymm registers and\n"
" these tests will fail, so the test is disabled by default.\n"
"\n"
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
" CPU feature: aesni, pclmulqdq, sse2, sse3, ssse3, avx2,\n"
@ -677,8 +680,8 @@ const CPU_FEATURE_DATA g_cpuFeatureData[] =
{ "shani", SYMCRYPT_CPU_FEATURE_SHANI },
{ "adx", SYMCRYPT_CPU_FEATURE_ADX },
{ "bmi2", SYMCRYPT_CPU_FEATURE_BMI2 },
{ "vaes512", SYMCRYPT_CPU_FEATURE_VAES_512 },
{ "vaes256", SYMCRYPT_CPU_FEATURE_VAES_256 },
{ "vaes", SYMCRYPT_CPU_FEATURE_VAES },
{ "avx512", SYMCRYPT_CPU_FEATURE_AVX512 },
{ "cmpxchg16b", SYMCRYPT_CPU_FEATURE_CMPXCHG16B },
#elif SYMCRYPT_CPU_ARM64
{ "neon", SYMCRYPT_CPU_FEATURE_NEON },
@ -707,6 +710,25 @@ VOID printSymCryptCpuInfo( PCSTR text, SYMCRYPT_CPU_FEATURES notPresent )
print( "\n" );
}
VOID printTestVectorSaveOptions()
{
CHAR sep = ' ';
print("\nTest Vector Save/Restore options:");
if (TestSaveXmmEnabled)
{
print("%cTestSaveXmmEnabled", sep);
sep = ',';
}
if (TestSaveYmmEnabled)
{
print("%cTestSaveYmmEnabled", sep);
sep = ',';
}
if (sep == ' ')
{
print(" None");
}
}
VOID
processSingleOption( _In_ PSTR option )
@ -858,6 +880,11 @@ processSingleOption( _In_ PSTR option )
g_sgx = TRUE;
optionHandled = TRUE;
}
if (STRICMP(&option[0], "testSaveYmm") == 0)
{
TestSaveYmmEnabled = TRUE;
optionHandled = TRUE;
}
}
if( !optionHandled )
{
@ -1244,6 +1271,8 @@ initTestInfrastructure( int argc, _In_reads_( argc ) char * argv[] )
printSymCryptCpuInfo( "Modified CPU features for this test", g_SymCryptCpuFeaturesNotPresent );
}
printTestVectorSaveOptions();
if( g_rngSeed == 0 )
{
CHECK( NT_SUCCESS( GENRANDOM(&g_rngSeed, sizeof( g_rngSeed )) ), "Failed to get random seed" );
@ -1762,204 +1791,6 @@ rdrandTest()
#endif
}
//
// Below some of the code used to test the XMM registers.
// This is Unittest code, so outside the extern "C" block.
//
#if SYMCRYPT_CPU_X86
/////////////////////////////////////////////////////////////
//
// Code to set up the XMM registers for testing in SAVE_XMM mode
__m128i g_xmmStartState[8];
__m128i g_xmmTestState[8];
//
// The save/restore functions work on an aligned subset of the structure.
// We don't care which part is used, we copy the start structure, store the
// XMM registers in it, and check that it is the same.
//
VOID
verifyXmmRegisters()
{
BOOL difference = FALSE;
if( TestSaveXmmEnabled && SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_SSE2 ) && !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL ) )
{
memset( g_xmmTestState, 0, sizeof( g_xmmTestState ) );
SymCryptEnvUmSaveXmmRegistersAsm( g_xmmTestState );
difference = memcmp( g_xmmTestState, g_xmmStartState, sizeof( g_xmmStartState ) ) != 0;
if( difference )
{
//
// Starting late 2018 our compiler & CRT are now using XMM registers for transient things.
// In particular, the compiler calls memset() on a large local struct to wipe the memory.
// (Part of the security mitigations against leaking data from uninitialized stack variables.)
// The CRT in turn uses XMM0 to wipe more efficiently.
// This is indistinguishable from a SymCrypt bug where we use XMM registers in X86 code without
// proper save/restore logic.
// In short: we cannot test this anymore in user mode. We'd have to compile for Win7 kernel mode
// to even run this test.
// For now we will relax this test to not be triggered by the compiler/CRT. This means that we
// no longer test this property, but we can at least detect some violations, which is better
// than none.
//
if( (g_xmmTestState[0].m128i_u64[0] | g_xmmTestState[0].m128i_u64[1]) == 0 &&
memcmp( &g_xmmTestState[1], &g_xmmStartState[1], 7 * sizeof( g_xmmStartState[0] ) ) == 0 )
{
difference = FALSE;
}
}
if( difference )
{
print( "\n" );
print( "Registers different: " );
for( int i=0; i<8; i++ )
{
if( memcmp( &g_xmmTestState[i], &g_xmmStartState[i], 16 ) != 0 )
{
print( "xmm%d ", i );
}
}
print( "\nStartState:\n" );
printHexArray( (PCBYTE) g_xmmStartState, 8, 16 );
print( "TestState:\n");
printHexArray( (PCBYTE) g_xmmTestState, 8, 16 );
ULONGLONG checksum;
SymCryptMarvin32( SymCryptMarvin32DefaultSeed, (PCBYTE) g_xmmStartState, 8*16, (PBYTE) &checksum );
print( "%04x\n", (ULONG) checksum & 0xffff );
SymCryptMarvin32( SymCryptMarvin32DefaultSeed, (PCBYTE) g_xmmTestState, 8*16, (PBYTE) &checksum );
print( "%04x\n", (ULONG) checksum & 0xffff );
FATAL( "Xmm registers modified without proper save/restore" );
}
}
}
VOID
initXmmRegisters()
{
/*
#pragma prefast(push)
#pragma prefast(disable:6031)
BCryptGenRandom( NULL, (PBYTE) g_xmmStartState, sizeof( g_xmmStartState ), BCRYPT_USE_SYSTEM_PREFERRED_RNG );
#pragma prefast(pop)
memcpy( g_xmmTestState, g_xmmStartState, sizeof( g_xmmStartState ) );
SymCryptEnvUmRestoreXmmRegistersAsm( g_xmmStartState );
*/
if( TestSaveXmmEnabled && SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_SSE2 ) && !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL ) )
{
SymCryptEnvUmSaveXmmRegistersAsm( g_xmmStartState );
verifyXmmRegisters();
}
}
#else
VOID verifyXmmRegisters()
{
}
VOID initXmmRegisters()
{
}
#endif
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
/////////////////////////////////////////////////////////////
//
// Code to set up the YMM registers for testing in SAVE_YMM mode
#if SYMCRYPT_CPU_AMD64
__m256i g_ymmStartState[16];
__m256i g_ymmTestState[16];
#else
__m256i g_ymmStartState[8];
__m256i g_ymmTestState[8];
#endif
VOID
verifyYmmRegisters()
{
if( !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_AVX2 ) )
{
verifyXmmRegisters();
return;
}
//
// We know that AVX2 is present from here on
//
if( TestSaveYmmEnabled && (SYMCRYPT_CPU_X86 || !TestSaveYmmFallback) )
{
SymCryptEnvUmSaveYmmRegistersAsm( g_ymmTestState );
//
// On AMD64 it is perfectly fine for the XMM register values to have been modified.
// Similarly, on x86 C runtime functions which SymCrypt uses may now use XMM registers and
// fail to preserve them.
// We just test that the top half of the Ymm registers have been preserved.
//
for( int i=0; i<sizeof( g_ymmStartState ); i++ )
{
if( ((volatile BYTE * )&g_ymmStartState[0])[i] != ((volatile BYTE * )&g_ymmTestState[0])[i] &&
((i & 16) == 16 )
)
{
FATAL3( "Ymm registers modified without proper save/restore Ymm%d[%d]", i>>5, i&31);
}
}
}
}
VOID
initYmmRegisters()
{
if( !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_AVX2 ) )
{
initXmmRegisters();
return;
}
if( TestSaveYmmEnabled )
{
//
// Do the memsets outside the save area as it might use XMM registers on x86
// Set the initial Ymm registers to a non-trivial value. It is likely (for performance
// reasons) that the upper halves are already zero-ed and will be re-zeroed by any function
// we call.
//
memset( g_ymmTestState, 17, sizeof( g_ymmTestState ) );
memset( g_ymmStartState, (__rdtsc() & 255) ^ 0x42, sizeof( g_ymmStartState ) );
// Reset TestSaveYmmFallback (set to TRUE when unit-test artificially fails save Ymm, in
// which case user mode code can clobber volatile Ymm registers on AMD64)
TestSaveYmmFallback = FALSE;
SymCryptEnvUmRestoreYmmRegistersAsm( g_ymmStartState );
verifyYmmRegisters();
}
}
#else
VOID verifyYmmRegisters()
{
}
VOID initYmmRegisters()
{
}
#endif
VOID
printHexArray( PCBYTE pData, SIZE_T nElements, SIZE_T elementSize )
{

Просмотреть файл

@ -2,9 +2,6 @@
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
//
PSTR testDriverName = TESTDRIVER_NAME;
const char * g_implementationNames[] =
{
ImpSc::name,
@ -56,49 +53,55 @@ addAllAlgs()
#endif
}
DWORD WINAPI umThreadFunc( LPVOID param )
int SYMCRYPT_CDECL
main( int argc, _In_reads_( argc ) char * argv[] )
{
runTestThread( param );
initTestInfrastructure( argc, argv );
// Set up vector registers to be in a state that should not be modified by unit tests
// This may do nothing if TestSaveXXXEnabled is FALSE, but it can also:
// On Windows AMD64 set Xmm6-Xmm15 to random values
// these values are non-volatile in Window x64 ABI, so should be preserved. If they are not
// preserved it indicates a problem with our assembly not adhering to the Windows ABI
// On Linux AMD64 set Ymm0-Ymm15 to random values
// these values are naturally volatile on Linux, but symcryptunittest callers may specify the
// following environment variable:
// GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX_Usable,-AVX_Fast_Unaligned_Load,-AVX2_Usable
// to avoid use of AVX in glibc. This means we can test the Ymm save/restore logic that is
// used in Windows kernel using Linux user mode.
initVectorRegisters();
addAllAlgs();
if (!g_profile && !g_measure_specific_sizes)
{
runFunctionalTests();
}
// Check that all uses of vector registers in the functional unit tests correctly saved/restored
verifyVectorRegisters();
if (g_profile)
{
runProfiling();
}
else
{
runPerfTests();
if (!g_measure_specific_sizes)
{
testSelftest();
// Disable Vector save tests for multithreaded tests
TestSaveXmmEnabled = FALSE;
TestSaveYmmEnabled = FALSE;
testMultiThread();
}
}
exitTestInfrastructure();
return 0;
}
VOID
scheduleAsyncTest( SelfTestFn f )
{
//
// No async testing in user mode, just run the test in-line.
//
f();
}
VOID
testMultiThread()
{
HANDLE threads[64];
int i;
g_fExitMultithreadTest = FALSE;
g_nMultithreadTestsRun = 0;
iprint( "\nMulti-thread test..." );
for( i=0; i<ARRAY_SIZE( threads ); i++ )
{
threads[i] = CreateThread( NULL, 0, &umThreadFunc, (LPVOID) g_rng.sizet( (SIZE_T)-1 ), 0, NULL );
CHECK3( threads[i] != NULL, "Failed to start thread i", i)
}
Sleep( 1000 * 5 );
g_fExitMultithreadTest = TRUE;
for( i=0; i<ARRAY_SIZE( threads ); i++ )
{
// Timeout increased from 15 seconds to 2 minutes. In Entropy Validation test, we run several SymCryptUnitTests in parallel, and
// the timeout wasn't enough in that case.
CHECK( WaitForSingleObject( threads[i], 120000 ) == 0, "Thread did not exit in time" );
CloseHandle( threads[i] );
}
iprint( " done. %lld tests run.\n", g_nMultithreadTestsRun );
}

Просмотреть файл

@ -0,0 +1,163 @@
//
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
//
PSTR testDriverName = TESTDRIVER_NAME;
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
/////////////////////////////////////////////////////////////
//
// Code to set up the Vector registers for testing when TestSaveXmmEnabled or TestSaveYmmEnabled
#if SYMCRYPT_CPU_AMD64
__m128i g_xmmStartState[16];
__m128i g_xmmTestState[16];
__m256i g_ymmStartState[16];
__m256i g_ymmTestState[16];
#else
__m256i g_ymmStartState[8];
__m256i g_ymmTestState[8];
#endif
VOID
verifyVectorRegisters()
{
if (TestSaveYmmEnabled && SYMCRYPT_CPU_FEATURES_PRESENT(SYMCRYPT_CPU_FEATURE_AVX2))
{
SymCryptEnvUmSaveYmmRegistersAsm( g_ymmTestState );
//
// We want to test that the top half of the Ymm registers have been preserved.
// For MSFT x64 ABI Xmm6-Xmm15 are non-volatile so should be preserved. We also check this
// is done, which gives us confidence none of our assembly breaks the ABI. This check also
// applies to x86.
//
for( int i=0; i<sizeof( g_ymmStartState ); i++ )
{
if( ((volatile BYTE * )&g_ymmStartState[0])[i] != ((volatile BYTE * )&g_ymmTestState[0])[i] &&
(((i & 16) == 16 ) || (i > 6*sizeof( g_ymmStartState[0] )))
)
{
FATAL3( "Ymm registers modified without proper save/restore Ymm%d[%d]", i>>5, i&31);
}
}
}
#if SYMCRYPT_CPU_AMD64
//
// For x86 all vector registers Xmm0-Xmm7 are volatile by default - so we cannot test that
// they are not modified. E.g. In the unit tests we call BCrypt to generate random numbers
// and BCrypt can trash the full Xmm state, as this is how our AES intrinsics are compiled
// (using all registers and no save/restore in prologue/epilogue).
// The CRT is also free to trash the state semi-arbitrarily (observationally the CRT tends to
// only trash Xmm0 - Xmm5, same as AMD64, but it is free to use all Xmm registers)
//
if (TestSaveXmmEnabled && SYMCRYPT_CPU_FEATURES_PRESENT(SYMCRYPT_CPU_FEATURE_SSE2) && !SYMCRYPT_CPU_FEATURES_PRESENT(SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL))
{
memset( g_xmmTestState, 0, sizeof( g_xmmTestState ) );
SymCryptEnvUmSaveXmmRegistersAsm(g_xmmTestState);
//
// For MSFT x64 ABI Xmm6-Xmm15 are non-volatile so should be preserved. We just check this
// is done, which gives us confidence none of our assembly breaks the ABI.
//
for( int i = 6 * sizeof(g_xmmStartState[0]); i < sizeof(g_xmmStartState); i++ )
{
if( ((volatile BYTE * )&g_xmmStartState[0])[i] != ((volatile BYTE * )&g_xmmTestState[0])[i] )
{
FATAL3( "Xmm registers modified without proper save/restore Xmm%d[%d]", i>>4, i&15);
}
}
}
#endif
}
VOID
initVectorRegisters()
{
if (TestSaveYmmEnabled && SYMCRYPT_CPU_FEATURES_PRESENT(SYMCRYPT_CPU_FEATURE_AVX2))
{
//
// Do the memsets outside the save area as it might use vector registers
// Set the initial Ymm registers to a non-trivial value. It is likely (for performance
// reasons) that the upper halves are already zero-ed and will be re-zeroed by any function
// we call.
//
memset( g_ymmTestState, 17, sizeof( g_ymmTestState ) );
memset( g_ymmStartState, (__rdtsc() & 255) ^ 0x42, sizeof( g_ymmStartState ) );
SymCryptEnvUmRestoreYmmRegistersAsm( g_ymmStartState );
verifyVectorRegisters();
}
#if SYMCRYPT_CPU_AMD64
if (TestSaveXmmEnabled && SYMCRYPT_CPU_FEATURES_PRESENT(SYMCRYPT_CPU_FEATURE_SSE2) && !SYMCRYPT_CPU_FEATURES_PRESENT(SYMCRYPT_CPU_FEATURE_SAVEXMM_NOFAIL))
{
//
// Do the memsets outside the save area as it might use Xmm registers
// Set the initial Xmm registers to a non-trivial value.
//
memset( g_xmmTestState, 17, sizeof( g_xmmTestState ) );
memset( g_xmmStartState, (__rdtsc() & 255) ^ 0x42, sizeof( g_xmmStartState ) );
SymCryptEnvUmRestoreXmmRegistersAsm( g_xmmStartState );
verifyVectorRegisters();
}
#endif
}
#else
VOID verifyVectorRegisters()
{
}
VOID initVectorRegisters()
{
}
#endif
DWORD WINAPI umThreadFunc( LPVOID param )
{
runTestThread( param );
return 0;
}
VOID
scheduleAsyncTest( SelfTestFn f )
{
//
// No async testing in user mode, just run the test in-line.
//
f();
}
VOID
testMultiThread()
{
HANDLE threads[64];
int i;
g_fExitMultithreadTest = FALSE;
g_nMultithreadTestsRun = 0;
iprint( "\nMulti-thread test..." );
for( i=0; i<ARRAY_SIZE( threads ); i++ )
{
threads[i] = CreateThread( NULL, 0, &umThreadFunc, (LPVOID) g_rng.sizet( (SIZE_T)-1 ), 0, NULL );
CHECK3( threads[i] != NULL, "Failed to start thread i", i)
}
Sleep( 1000 * 5 );
g_fExitMultithreadTest = TRUE;
for( i=0; i<ARRAY_SIZE( threads ); i++ )
{
// Timeout increased from 15 seconds to 2 minutes. In Entropy Validation test, we run several SymCryptUnitTests in parallel, and
// the timeout wasn't enough in that case.
CHECK( WaitForSingleObject( threads[i], 120000 ) == 0, "Thread did not exit in time" );
CloseHandle( threads[i] );
}
iprint( " done. %lld tests run.\n", g_nMultithreadTestsRun );
}
#include "main_exe_common.cpp"

Просмотреть файл

@ -68,9 +68,8 @@ BlockCipherImp<ImpXxx, AlgXxx, ModeXxx>::setKey( PCBYTE pbKey, SIZE_T cbKey )
{
SYMCRYPT_ERROR e;
initXmmRegisters();
e = SYMCRYPT_XxxExpandKey( &state.key, pbKey, cbKey );
verifyXmmRegisters();
verifyVectorRegisters();
if( e != SYMCRYPT_NO_ERROR )
{
@ -88,9 +87,8 @@ BlockCipherImp<ImpXxx, AlgXxx, ModeXxx>::encrypt( PBYTE pbChain, SIZE_T cbChain,
CHECK( cbData % msgBlockLen() == 0, "Wrong data length" );
CHECK( cbChain == chainBlockLen(), "Wrong chain len" );
initXmmRegisters();
SYMCRYPT_XxxXxxEncrypt( &state.key, pbChain, pbSrc, pbDst, cbData );
verifyXmmRegisters();
verifyVectorRegisters();
}
template<>
@ -101,8 +99,7 @@ BlockCipherImp<ImpXxx, AlgXxx, ModeXxx>::decrypt( PBYTE pbChain, SIZE_T cbChain,
CHECK( cbData % msgBlockLen() == 0, "Wrong data length" );
CHECK( cbChain == chainBlockLen(), "Wrong chain len" );
initXmmRegisters();
SYMCRYPT_XxxXxxDecrypt( &state.key, pbChain, pbSrc, pbDst, cbData );
verifyXmmRegisters();
verifyVectorRegisters();
}

Просмотреть файл

@ -25,7 +25,6 @@ HashImp< ImpXxx, AlgXxx >::HashImp()
SYMCRYPT_XXX_STATE hashState;
BYTE exportBlob[SYMCRYPT_XXX_STATE_EXPORT_SIZE];
initXmmRegisters();
SYMCRYPT_XxxInit( &hashState );
for( int i=0; i<200; i++ )
{
@ -44,7 +43,7 @@ HashImp< ImpXxx, AlgXxx >::HashImp()
CHECK( SymCryptHashStateSize( SYMCRYPT_XxxAlgorithm ) == sizeof( SYMCRYPT_XXX_STATE ), "State size mismatch" );
state.isReset = FALSE;
verifyXmmRegisters();
verifyVectorRegisters();
}
//
@ -90,15 +89,13 @@ VOID HashImp<ImpXxx,AlgXxx>::hash(
SYMCRYPT_XXX_STATE state2;
SIZE_T halfSize = cbData >> 1;
initXmmRegisters();
CHECK( cbResult == SYMCRYPT_XXX_RESULT_SIZE, "Result len error in SymCrypt" STRING( ALG_Name ) );
SYMCRYPT_Xxx( pbData, cbData, pbResult );
verifyXmmRegisters();
verifyVectorRegisters();
initXmmRegisters();
SymCryptHash( SYMCRYPT_XxxAlgorithm, pbData, cbData, splitResult, cbResult );
CHECK( memcmp( splitResult, pbResult, SYMCRYPT_XXX_RESULT_SIZE ) == 0, "Generic hash error in SymCrypt" STRING( ALG_Name ) );
verifyXmmRegisters();
verifyVectorRegisters();
SYMCRYPT_XxxInit( &state1 );
SYMCRYPT_XxxAppend( &state1, pbData, halfSize );
@ -106,7 +103,7 @@ VOID HashImp<ImpXxx,AlgXxx>::hash(
SYMCRYPT_XxxAppend( &state2, pbData+halfSize, cbData-halfSize );
SYMCRYPT_XxxResult( &state2, splitResult );
CHECK( memcmp( splitResult, pbResult, SYMCRYPT_XXX_RESULT_SIZE ) == 0, "State copy error in SymCrypt" STRING( ALG_Name ) );
verifyXmmRegisters();
verifyVectorRegisters();
SYMCRYPT_XxxInit( &state1 );
SYMCRYPT_XxxAppend( &state1, pbData, halfSize );
@ -117,7 +114,7 @@ VOID HashImp<ImpXxx,AlgXxx>::hash(
SYMCRYPT_XxxAppend( &state2, pbData+halfSize, cbData-halfSize );
SYMCRYPT_XxxResult( &state2, splitResult );
CHECK( memcmp( splitResult, pbResult, SYMCRYPT_XXX_RESULT_SIZE ) == 0, "Import/Export error in SymCrypt" STRING( ALG_Name ) );
verifyXmmRegisters();
verifyVectorRegisters();
}
@ -129,24 +126,22 @@ VOID HashImp<ImpXxx,AlgXxx>::hash(
template<>
VOID HashImp<ImpXxx,AlgXxx>::init()
{
initXmmRegisters();
if( !state.isReset || (g_rng.byte() & 1) == 0 )
{
SYMCRYPT_XxxInit( &state.sc );
SymCryptHashInit( SYMCRYPT_XxxAlgorithm, &state.scHash );
}
state.isReset = TRUE;
verifyXmmRegisters();
verifyVectorRegisters();
}
template<>
VOID HashImp<ImpXxx,AlgXxx>::append( _In_reads_( cbData ) PCBYTE pbData, SIZE_T cbData )
{
initXmmRegisters();
SYMCRYPT_XxxAppend( &state.sc, pbData, cbData );
SymCryptHashAppend( SYMCRYPT_XxxAlgorithm, &state.scHash, pbData, cbData );
state.isReset = FALSE;
verifyXmmRegisters();
verifyVectorRegisters();
}
template<>
@ -155,12 +150,11 @@ VOID HashImp<ImpXxx,AlgXxx>::result( _Out_writes_( cbResult ) PBYTE pbResult, SI
BYTE buf[SYMCRYPT_HASH_MAX_RESULT_SIZE];
CHECK( cbResult == SYMCRYPT_XXX_RESULT_SIZE, "Result len error in SymCrypt " STRING( ALG_Name ) );
initXmmRegisters();
SYMCRYPT_XxxResult( &state.sc, pbResult );
SymCryptHashResult( SYMCRYPT_XxxAlgorithm, &state.scHash, buf, sizeof( buf ) );
CHECK( memcmp( pbResult, buf, cbResult ) == 0, "Inconsistent result" );
state.isReset = TRUE;
verifyXmmRegisters();
verifyVectorRegisters();
}
template<>
@ -171,12 +165,11 @@ NTSTATUS HashImp<ImpXxx,AlgXxx>::exportSymCryptFormat(
{
CHECK( cbResultBufferSize >= SYMCRYPT_XXX_STATE_EXPORT_SIZE, "Export buffer too small" );
initXmmRegisters();
SYMCRYPT_XxxStateExport( &state.sc, pbResult );
*pcbResult = SYMCRYPT_XXX_STATE_EXPORT_SIZE;
SymCryptWipeKnownSize( &state.sc, sizeof( state.sc ) );
SYMCRYPT_XxxStateImport( &state.sc, pbResult );
verifyXmmRegisters();
verifyVectorRegisters();
return STATUS_SUCCESS;
}

Просмотреть файл

@ -86,14 +86,13 @@ KdfImp<ImpSc, AlgHkdf, BaseAlgXxx>::derive(
}
// 1) Full HKDF
initXmmRegisters();
scError = SymCryptHkdf(
SYMCRYPT_BaseXxxAlgorithm,
pbKey, cbKey,
pbSalt, cbSalt,
pbInfo, cbInfo,
&buf1[0], cbDst);
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt HKDF");
@ -102,7 +101,7 @@ KdfImp<ImpSc, AlgHkdf, BaseAlgXxx>::derive(
SYMCRYPT_BaseXxxAlgorithm,
pbKey, cbKey,
pbSalt, cbSalt );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt HKDF");
SymCryptMarvin32(SymCryptMarvin32DefaultSeed, (PCBYTE)&expandedKey, sizeof(expandedKey), expandedKeyChecksum);
@ -110,7 +109,7 @@ KdfImp<ImpSc, AlgHkdf, BaseAlgXxx>::derive(
scError = SymCryptHkdfDerive( &expandedKey,
pbInfo, cbInfo,
&buf2[0], cbDst);
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt HKDF");
CHECK(memcmp(buf1, buf2, cbDst) == 0, "SymCrypt HKDF calling versions disagree");
@ -123,13 +122,13 @@ KdfImp<ImpSc, AlgHkdf, BaseAlgXxx>::derive(
pbKey, cbKey,
pbSalt, cbSalt,
rbPrk, SYMCRYPT_BaseXxxAlgorithm->resultSize );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt HKDF");
scError = SymCryptHkdfPrkExpandKey( &expandedKey,
SYMCRYPT_BaseXxxAlgorithm,
rbPrk, SYMCRYPT_BaseXxxAlgorithm->resultSize );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt HKDF");
SymCryptMarvin32(SymCryptMarvin32DefaultSeed, (PCBYTE)&expandedKey, sizeof(expandedKey), expandedKeyChecksum);
@ -137,7 +136,7 @@ KdfImp<ImpSc, AlgHkdf, BaseAlgXxx>::derive(
scError = SymCryptHkdfDerive( &expandedKey,
pbInfo, cbInfo,
&buf2[0], cbDst);
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt HKDF");
CHECK(memcmp(buf1, buf2, cbDst) == 0, "SymCrypt HKDF calling versions disagree");

Просмотреть файл

@ -64,13 +64,11 @@ NTSTATUS MacImp<ImpXxx, AlgXxx>::mac(
CHECK( cbResult == SYMCRYPT_XXX_RESULT_SIZE, "Result len error in SymCrypt" STRING( MAC_Name ) );
initXmmRegisters();
SYMCRYPT_XxxExpandKey( &state.key, pbKey, cbKey );
verifyXmmRegisters();
verifyVectorRegisters();
SYMCRYPT_Xxx( &state.key, pbData, cbData, pbResult );
verifyXmmRegisters();
verifyVectorRegisters();
//
// Test the key & state duplication functions
@ -78,7 +76,7 @@ NTSTATUS MacImp<ImpXxx, AlgXxx>::mac(
SYMCRYPT_XxxExpandKey( &key1, pbKey, cbKey );
SYMCRYPT_XxxKeyCopy( &key1, &key2 );
SymCryptWipe( &key1, sizeof( key1 ) );
verifyXmmRegisters();
verifyVectorRegisters();
SYMCRYPT_XxxInit( &state1, &key2 );
SYMCRYPT_XxxAppend( &state1, pbData, halfSize );
@ -86,13 +84,13 @@ NTSTATUS MacImp<ImpXxx, AlgXxx>::mac(
SYMCRYPT_XxxAppend( &state2, pbData+halfSize, cbData-halfSize );
SYMCRYPT_XxxResult( &state2, splitResult );
CHECK( memcmp( splitResult, pbResult, SYMCRYPT_XXX_RESULT_SIZE ) == 0, "State copy error in SymCrypt" STRING( ALG_Name ) );
verifyXmmRegisters();
verifyVectorRegisters();
SYMCRYPT_XxxStateCopy( &state1, &state.key, &state2 );
SYMCRYPT_XxxAppend( &state2, pbData+halfSize, cbData-halfSize );
SYMCRYPT_XxxResult( &state2, splitResult );
CHECK( memcmp( splitResult, pbResult, SYMCRYPT_XXX_RESULT_SIZE ) == 0, "State copy error in SymCrypt" STRING( ALG_Name ) );
verifyXmmRegisters();
verifyVectorRegisters();
SymCryptWipeKnownSize( &state.key, sizeof( state.key ) );
SymCryptWipeKnownSize( &state1, sizeof( state1 ) );
@ -110,10 +108,9 @@ NTSTATUS MacImp<ImpXxx, AlgXxx>::mac(
template<>
NTSTATUS MacImp<ImpXxx, AlgXxx>::init( _In_reads_( cbKey ) PCBYTE pbKey, SIZE_T cbKey )
{
initXmmRegisters();
SYMCRYPT_XxxExpandKey( &state.key, pbKey, cbKey );
SYMCRYPT_XxxInit( &state.state, &state.key );
verifyXmmRegisters();
verifyVectorRegisters();
return STATUS_SUCCESS;
}
@ -121,9 +118,8 @@ NTSTATUS MacImp<ImpXxx, AlgXxx>::init( _In_reads_( cbKey ) PCBYTE pbKey, SIZE_T
template<>
VOID MacImp<ImpXxx, AlgXxx>::append( _In_reads_( cbData ) PCBYTE pbData, SIZE_T cbData )
{
initXmmRegisters();
SYMCRYPT_XxxAppend( &state.state, pbData, cbData );
verifyXmmRegisters();
verifyVectorRegisters();
}
template<>
@ -131,9 +127,8 @@ VOID MacImp<ImpXxx, AlgXxx>::result( _Out_writes_( cbResult ) PBYTE pbResult, SI
{
CHECK( cbResult == SYMCRYPT_XXX_RESULT_SIZE, "Result len error in SymCrypt " STRING( MAC_Name ) );
initXmmRegisters();
SYMCRYPT_XxxResult( &state.state, pbResult );
verifyXmmRegisters();
verifyVectorRegisters();
}
template<>

Просмотреть файл

@ -43,21 +43,20 @@ KdfImp<ImpSc,AlgPbkdf2,BaseAlgXxx>::derive(
CHECK( cbDst <= sizeof( buf1 ), "PBKDF2 output too large" );
initXmmRegisters();
scError = SymCryptPbkdf2(
SYMCRYPT_BaseXxxAlgorithm,
pbKey, cbKey,
pbSalt, cbSalt,
iterationCnt,
&buf1[0], cbDst );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt PBKDF2" );
scError = SymCryptPbkdf2ExpandKey( &expandedKey,
SYMCRYPT_BaseXxxAlgorithm,
pbKey, cbKey );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt PBKDF2" );
SymCryptMarvin32( SymCryptMarvin32DefaultSeed, (PCBYTE) &expandedKey, sizeof( expandedKey ), expandedKeyChecksum );
@ -66,7 +65,7 @@ KdfImp<ImpSc,AlgPbkdf2,BaseAlgXxx>::derive(
pbSalt, cbSalt,
iterationCnt,
&buf2[0], cbDst );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt PBKDF2" );
CHECK( memcmp( buf1, buf2, cbDst ) == 0, "SymCrypt PBKDF2 calling versions disagree" );

Просмотреть файл

@ -47,21 +47,20 @@ KdfImp<ImpSc,AlgSp800_108,BaseAlgXxx>::derive(
return;
}
initXmmRegisters();
scError = SymCryptSp800_108(
SYMCRYPT_BaseXxxAlgorithm,
pbKey, cbKey,
pbLabel, cbLabel,
pbContext, cbContext,
&buf1[0], cbDst );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt SP800_108" );
scError = SymCryptSp800_108ExpandKey( &expandedKey,
SYMCRYPT_BaseXxxAlgorithm,
pbKey, cbKey );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt SP800_108" );
SymCryptMarvin32( SymCryptMarvin32DefaultSeed, (PCBYTE) &expandedKey, sizeof( expandedKey ), expandedKeyChecksum );
@ -70,7 +69,7 @@ KdfImp<ImpSc,AlgSp800_108,BaseAlgXxx>::derive(
pbLabel, cbLabel,
pbContext, cbContext,
&buf2[0], cbDst );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt SP800_108" );
CHECK( memcmp( buf1, buf2, cbDst ) == 0, "SymCrypt SP800_108 calling versions disagree" );

Просмотреть файл

@ -85,19 +85,18 @@ KdfImp<ImpSc, AlgTlsPrf1_1, BaseAlgXxx>::derive(
return;
}
initXmmRegisters();
scError = SymCryptTlsPrf1_1(
pbKey, cbKey,
pbLabel, cbLabel,
pbSeed, cbSeed,
&buf1[0], cbDst);
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt TLS PRF 1.1");
scError = SymCryptTlsPrf1_1ExpandKey(&expandedKey,
pbKey, cbKey);
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt TLS PRF 1.1");
SymCryptMarvin32(SymCryptMarvin32DefaultSeed, (PCBYTE)&expandedKey, sizeof(expandedKey), expandedKeyChecksum);
@ -106,7 +105,7 @@ KdfImp<ImpSc, AlgTlsPrf1_1, BaseAlgXxx>::derive(
pbLabel, cbLabel,
pbSeed, cbSeed,
&buf2[0], cbDst);
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt TLS PRF 1.1");
CHECK(memcmp(buf1, buf2, cbDst) == 0, "SymCrypt TLS PRF 1.1 calling versions disagree");

Просмотреть файл

@ -40,21 +40,20 @@ KdfImp<ImpSc, AlgTlsPrf1_2, BaseAlgXxx>::derive(
return;
}
initXmmRegisters();
scError = SymCryptTlsPrf1_2(
SYMCRYPT_BaseXxxAlgorithm,
pbKey, cbKey,
pbLabel, cbLabel,
pbSeed, cbSeed,
&buf1[0], cbDst);
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt TLS PRF 1.2");
scError = SymCryptTlsPrf1_2ExpandKey( &expandedKey,
SYMCRYPT_BaseXxxAlgorithm,
pbKey, cbKey);
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt TLS PRF 1.2");
SymCryptMarvin32(SymCryptMarvin32DefaultSeed, (PCBYTE)&expandedKey, sizeof(expandedKey), expandedKeyChecksum);
@ -63,7 +62,7 @@ KdfImp<ImpSc, AlgTlsPrf1_2, BaseAlgXxx>::derive(
pbLabel, cbLabel,
pbSeed, cbSeed,
&buf2[0], cbDst);
verifyXmmRegisters();
verifyVectorRegisters();
CHECK(scError == SYMCRYPT_NO_ERROR, "Error in SymCrypt TLS PRF 1.2");
CHECK(memcmp(buf1, buf2, cbDst) == 0, "SymCrypt TLS PRF 1.2 calling versions disagree");

Просмотреть файл

@ -970,9 +970,8 @@ NTSTATUS
AuthEncImp<ImpSc, AlgAes, ModeCcm>::setKey( PCBYTE pbKey, SIZE_T cbKey )
{
CHECK( cbKey == 16 || cbKey == 24 || cbKey == 32, "?" );
initXmmRegisters();
SymCryptAesExpandKey( &state.key, pbKey, cbKey );
verifyXmmRegisters();
verifyVectorRegisters();
state.inComputation = FALSE;
return STATUS_SUCCESS;
@ -1008,19 +1007,18 @@ AuthEncImp<ImpSc, AlgAes, ModeCcm>::encrypt(
if( (flags & AUTHENC_FLAG_PARTIAL) == 0 )
{
// simple straight CCM computation.
initXmmRegisters();
CHECK( SymCryptCcmValidateParameters( SymCryptAesBlockCipher,
cbNonce,
cbAuthData,
cbData,
cbTag ) == SYMCRYPT_NO_ERROR, "?" );
verifyXmmRegisters();
verifyVectorRegisters();
SymCryptCcmEncrypt( SymCryptAesBlockCipher, &state.key,
pbNonce, cbNonce, pbAuthData, cbAuthData,
pbSrc, pbDst, cbData,
pbTag, cbTag );
verifyXmmRegisters();
verifyVectorRegisters();
// Done
goto cleanup;
@ -1030,23 +1028,20 @@ AuthEncImp<ImpSc, AlgAes, ModeCcm>::encrypt(
{
CHECK( (flags & AUTHENC_FLAG_PARTIAL) != 0, "?" );
// total cbData is passed in the cbTag parameter in the first partial call
initXmmRegisters();
SymCryptCcmInit( &state.ccmState, SymCryptAesBlockCipher, &state.key, pbNonce, cbNonce, pbAuthData, cbAuthData, state.totalCbData, cbTag );
verifyXmmRegisters();
verifyVectorRegisters();
state.inComputation = TRUE;
}
// We can process the next part before we decide whether to produce the tag.
initXmmRegisters();
SymCryptCcmEncryptPart( &state.ccmState, pbSrc, pbDst, cbData );
verifyXmmRegisters();
verifyVectorRegisters();
if( pbTag != NULL )
{
initXmmRegisters();
SymCryptCcmEncryptFinal( &state.ccmState, pbTag, cbTag );
verifyXmmRegisters();
verifyVectorRegisters();
state.inComputation = FALSE;
}
@ -1081,19 +1076,18 @@ AuthEncImp<ImpSc, AlgAes, ModeCcm>::decrypt(
if( (flags & AUTHENC_FLAG_PARTIAL) == 0 )
{
// simple straight CCM computation.
initXmmRegisters();
CHECK( SymCryptCcmValidateParameters( SymCryptAesBlockCipher,
cbNonce,
cbAuthData,
cbData,
cbTag ) == SYMCRYPT_NO_ERROR, "?" );
verifyXmmRegisters();
verifyVectorRegisters();
scError = SymCryptCcmDecrypt( SymCryptAesBlockCipher, &state.key,
pbNonce, cbNonce, pbAuthData, cbAuthData,
pbSrc, pbDst, cbData,
pbTag, cbTag );
verifyXmmRegisters();
verifyVectorRegisters();
if( scError == SYMCRYPT_AUTHENTICATION_FAILURE )
{
@ -1109,21 +1103,18 @@ AuthEncImp<ImpSc, AlgAes, ModeCcm>::decrypt(
if( !state.inComputation )
{
// First call of a partial computation.
initXmmRegisters();
SymCryptCcmInit( &state.ccmState, SymCryptAesBlockCipher, &state.key, pbNonce, cbNonce, pbAuthData, cbAuthData, state.totalCbData, cbTag );
verifyXmmRegisters();
verifyVectorRegisters();
state.inComputation = TRUE;
}
// We can process the next part before we decide whether to produce the tag.
initXmmRegisters();
SymCryptCcmDecryptPart( &state.ccmState, pbSrc, pbDst, cbData );
verifyXmmRegisters();
verifyVectorRegisters();
if( pbTag != NULL )
{
initXmmRegisters();
scError = SymCryptCcmDecryptFinal( &state.ccmState, pbTag, cbTag );
if( scError == SYMCRYPT_AUTHENTICATION_FAILURE )
{
@ -1131,7 +1122,7 @@ AuthEncImp<ImpSc, AlgAes, ModeCcm>::decrypt(
} else {
CHECK( scError == SYMCRYPT_NO_ERROR, "?" );
}
verifyXmmRegisters();
verifyVectorRegisters();
state.inComputation = FALSE;
}
@ -1252,9 +1243,8 @@ AuthEncImp<ImpSc, AlgAes, ModeGcm>::setKey( PCBYTE pbKey, SIZE_T cbKey )
{
CHECK( cbKey == 16 || cbKey == 24 || cbKey == 32, "?" );
initXmmRegisters();
SymCryptGcmExpandKey( &state.key, SymCryptAesBlockCipher, pbKey, cbKey );
verifyXmmRegisters();
verifyVectorRegisters();
state.inComputation = FALSE;
return STATUS_SUCCESS;
@ -1288,20 +1278,18 @@ AuthEncImp<ImpSc, AlgAes, ModeGcm>::encrypt(
if( (flags & AUTHENC_FLAG_PARTIAL) == 0 )
{
// simple straight GCM computation.
initXmmRegisters();
CHECK( SymCryptGcmValidateParameters( SymCryptAesBlockCipher,
cbNonce,
cbAuthData,
cbData,
cbTag ) == SYMCRYPT_NO_ERROR, "?" );
verifyXmmRegisters();
verifyVectorRegisters();
initYmmRegisters();
SymCryptGcmEncrypt( &state.key,
pbNonce, cbNonce, pbAuthData, cbAuthData,
pbSrc, pbDst, cbData,
pbTag, cbTag );
verifyYmmRegisters();
verifyVectorRegisters();
// Done
goto cleanup;
@ -1317,37 +1305,32 @@ AuthEncImp<ImpSc, AlgAes, ModeGcm>::encrypt(
{
CHECK( (flags & AUTHENC_FLAG_PARTIAL) != 0, "?" );
// total cbData is passed in the cbTag parameter in the first partial call
initXmmRegisters();
SymCryptGcmInit( &gcmState1, (g_rng.byte() & 1) ? &state.key : &gcmKey2, pbNonce, cbNonce );
verifyXmmRegisters();
verifyVectorRegisters();
SIZE_T bytesDone = 0;
while( bytesDone != cbAuthData )
{
SIZE_T bytesThisLoop = g_rng.sizet( cbAuthData - bytesDone + 1);
initXmmRegisters();
SymCryptGcmAuthPart( &gcmState1, &pbAuthData[bytesDone], bytesThisLoop );
verifyXmmRegisters();
verifyVectorRegisters();
bytesDone += bytesThisLoop;
}
state.inComputation = TRUE;
} else {
initXmmRegisters();
SymCryptGcmStateCopy( &state.gcmState, (g_rng.byte() & 1) ? &gcmKey2 : NULL , &gcmState1 );
verifyXmmRegisters();
verifyVectorRegisters();
}
// Using gcmState1 which is using gcmKey2 or state.key.
initYmmRegisters();
SymCryptGcmEncryptPart( &gcmState1, pbSrc, pbDst, cbData );
verifyYmmRegisters();
verifyVectorRegisters();
if( pbTag != NULL )
{
initXmmRegisters();
SymCryptGcmEncryptFinal( &gcmState1, pbTag, cbTag );
verifyXmmRegisters();
verifyVectorRegisters();
state.inComputation = FALSE;
} else {
@ -1381,20 +1364,18 @@ AuthEncImp<ImpSc, AlgAes, ModeGcm>::decrypt(
if( (flags & AUTHENC_FLAG_PARTIAL) == 0 )
{
// simple straight GCM computation.
initXmmRegisters();
CHECK( SymCryptGcmValidateParameters( SymCryptAesBlockCipher,
cbNonce,
cbAuthData,
cbData,
cbTag ) == SYMCRYPT_NO_ERROR, "?" );
verifyXmmRegisters();
verifyVectorRegisters();
initYmmRegisters();
scError = SymCryptGcmDecrypt( &state.key,
pbNonce, cbNonce, pbAuthData, cbAuthData,
pbSrc, pbDst, cbData,
pbTag, cbTag );
verifyYmmRegisters();
verifyVectorRegisters();
// Done
goto cleanup;
@ -1410,37 +1391,32 @@ AuthEncImp<ImpSc, AlgAes, ModeGcm>::decrypt(
{
CHECK( (flags & AUTHENC_FLAG_PARTIAL) != 0, "?" );
// total cbData is passed in the cbTag parameter in the first partial call
initXmmRegisters();
SymCryptGcmInit( &gcmState1, (g_rng.byte() & 1) ? &state.key : &gcmKey2, pbNonce, cbNonce );
verifyXmmRegisters();
verifyVectorRegisters();
SIZE_T bytesDone = 0;
while( bytesDone != cbAuthData )
{
SIZE_T bytesThisLoop = g_rng.sizet( cbAuthData - bytesDone + 1);
initXmmRegisters();
SymCryptGcmAuthPart( &gcmState1, &pbAuthData[bytesDone], bytesThisLoop );
verifyXmmRegisters();
verifyVectorRegisters();
bytesDone += bytesThisLoop;
}
state.inComputation = TRUE;
} else {
initXmmRegisters();
SymCryptGcmStateCopy( &state.gcmState, (g_rng.byte() & 1) ? &gcmKey2 : NULL , &gcmState1 );
verifyXmmRegisters();
verifyVectorRegisters();
}
// Using gcmState1 which is using gcmKey2 or state.key.
initYmmRegisters();
SymCryptGcmDecryptPart( &gcmState1, pbSrc, pbDst, cbData );
verifyYmmRegisters();
verifyVectorRegisters();
if( pbTag != NULL )
{
initXmmRegisters();
scError = SymCryptGcmDecryptFinal( &gcmState1, pbTag, cbTag );
verifyXmmRegisters();
verifyVectorRegisters();
state.inComputation = FALSE;
} else {
@ -1982,9 +1958,8 @@ RngSp800_90Imp<ImpSc, AlgAesCtrDrbg>::instantiate( _In_reads_( cbEntropy ) PCBYT
{
SYMCRYPT_ERROR scError;
initXmmRegisters();
scError = SymCryptRngAesInstantiate( &state.state, pbEntropy, cbEntropy );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Error during instantiation" );
@ -1997,9 +1972,8 @@ RngSp800_90Imp<ImpSc, AlgAesCtrDrbg>::reseed( _In_reads_( cbEntropy ) PCBYTE pbE
{
SYMCRYPT_ERROR scError;
initXmmRegisters();
scError = SymCryptRngAesReseed( &state.state, pbEntropy, cbEntropy );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK3( scError == SYMCRYPT_NO_ERROR, "Error during reseed, len=%lld", (ULONGLONG) cbEntropy );
@ -2010,10 +1984,8 @@ template<>
VOID
RngSp800_90Imp<ImpSc, AlgAesCtrDrbg>::generate( _Out_writes_( cbData ) PBYTE pbData, SIZE_T cbData )
{
initXmmRegisters();
SymCryptRngAesGenerate( &state.state, pbData, cbData );
verifyXmmRegisters();
verifyVectorRegisters();
}
@ -2067,9 +2039,8 @@ RngSp800_90Imp<ImpSc, AlgAesCtrF142>::instantiate( _In_reads_( cbEntropy ) PCBYT
{
SYMCRYPT_ERROR scError;
initXmmRegisters();
scError = SymCryptRngAesFips140_2Instantiate( &state.state, pbEntropy, cbEntropy );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Error during instantiation" );
@ -2082,9 +2053,8 @@ RngSp800_90Imp<ImpSc, AlgAesCtrF142>::reseed( _In_reads_( cbEntropy ) PCBYTE pbE
{
SYMCRYPT_ERROR scError;
initXmmRegisters();
scError = SymCryptRngAesFips140_2Reseed( &state.state, pbEntropy, cbEntropy );
verifyXmmRegisters();
verifyVectorRegisters();
CHECK3( scError == SYMCRYPT_NO_ERROR, "Error during reseed, len=%lld", (ULONGLONG) cbEntropy );
@ -2095,10 +2065,8 @@ template<>
VOID
RngSp800_90Imp<ImpSc, AlgAesCtrF142>::generate( _Out_writes_( cbData ) PBYTE pbData, SIZE_T cbData )
{
initXmmRegisters();
SymCryptRngAesFips140_2Generate( &state.state, pbData, cbData );
verifyXmmRegisters();
verifyVectorRegisters();
}
@ -2201,9 +2169,8 @@ ParallelHashImp<ImpSc, AlgParallelSha256>::init( SIZE_T nHashes )
CHECK( nHashes <= MAX_PARALLEL_HASH_STATES, "Too many hash states requested" );
state.nHashes = nHashes;
initYmmRegisters();
SymCryptParallelSha256Init( &state.sc[0], nHashes );
verifyYmmRegisters();
verifyVectorRegisters();
}
template<>
@ -2237,14 +2204,13 @@ ParallelHashImp<ImpSc, AlgParallelSha256>::process(
scratch[scratchOffset + nScratch] = sentinel;
SYMCRYPT_ASSERT( state.nHashes <= MAX_PARALLEL_HASH_STATES );
initYmmRegisters();
scError = SymCryptParallelSha256Process( &state.sc[0],
state.nHashes,
&op[0],
nOperations,
&scratch[scratchOffset],
nScratch );
verifyYmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Parallel SHA256 returned an error" );
CHECK( scratch[scratchOffset + nScratch] == sentinel, "Parallel SHA256 used too much scratch space" );
}
@ -2360,9 +2326,8 @@ ParallelHashImp<ImpSc, AlgParallelSha384>::init( SIZE_T nHashes )
{
CHECK( nHashes <= MAX_PARALLEL_HASH_STATES, "Too many hash states requested" );
state.nHashes = nHashes;
initYmmRegisters();
SymCryptParallelSha384Init( &state.sc[0], nHashes );
verifyYmmRegisters();
verifyVectorRegisters();
}
template<>
@ -2396,14 +2361,13 @@ ParallelHashImp<ImpSc, AlgParallelSha384>::process(
scratch[scratchOffset + nScratch] = sentinel;
SYMCRYPT_ASSERT( state.nHashes <= MAX_PARALLEL_HASH_STATES );
initYmmRegisters();
scError = SymCryptParallelSha384Process( &state.sc[0],
state.nHashes,
&op[0],
nOperations,
&scratch[scratchOffset],
nScratch );
verifyYmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Parallel SHA384 returned an error" );
CHECK( scratch[scratchOffset + nScratch] == sentinel, "Parallel SHA384 used too much scratch space" );
}
@ -2519,9 +2483,8 @@ ParallelHashImp<ImpSc, AlgParallelSha512>::init( SIZE_T nHashes )
{
CHECK( nHashes <= MAX_PARALLEL_HASH_STATES, "Too many hash states requested" );
state.nHashes = nHashes;
initYmmRegisters();
SymCryptParallelSha512Init( &state.sc[0], nHashes );
verifyYmmRegisters();
verifyVectorRegisters();
}
template<>
@ -2555,14 +2518,13 @@ ParallelHashImp<ImpSc, AlgParallelSha512>::process(
scratch[scratchOffset + nScratch] = sentinel;
SYMCRYPT_ASSERT( state.nHashes <= MAX_PARALLEL_HASH_STATES );
initYmmRegisters();
scError = SymCryptParallelSha512Process( &state.sc[0],
state.nHashes,
&op[0],
nOperations,
&scratch[scratchOffset],
nScratch );
verifyYmmRegisters();
verifyVectorRegisters();
CHECK( scError == SYMCRYPT_NO_ERROR, "Parallel SHA512 returned an error" );
CHECK( scratch[scratchOffset + nScratch] == sentinel, "Parallel SHA512 used too much scratch space" );
}
@ -2656,9 +2618,8 @@ XtsImp<ImpSc, AlgXtsAes>::setKey( PCBYTE pbKey, SIZE_T cbKey )
{
SYMCRYPT_ERROR scError;
initXmmRegisters();
scError = SymCryptXtsAesExpandKey( &state.key, pbKey, cbKey );
verifyXmmRegisters();
verifyVectorRegisters();
return scError == SYMCRYPT_NO_ERROR ? 0 : STATUS_NOT_SUPPORTED;
}
@ -2672,14 +2633,13 @@ XtsImp<ImpSc, AlgXtsAes>::encrypt(
_Out_writes_( cbData ) PBYTE pbDst,
SIZE_T cbData )
{
initYmmRegisters();
SymCryptXtsAesEncrypt( &state.key,
cbDataUnit,
tweak,
pbSrc,
pbDst,
cbData );
verifyYmmRegisters();
verifyVectorRegisters();
}
template<>
@ -2691,14 +2651,13 @@ XtsImp<ImpSc, AlgXtsAes>::decrypt(
_Out_writes_( cbData ) PBYTE pbDst,
SIZE_T cbData )
{
initYmmRegisters();
SymCryptXtsAesDecrypt( &state.key,
cbDataUnit,
tweak,
pbSrc,
pbDst,
cbData );
verifyYmmRegisters();
verifyVectorRegisters();
}

Просмотреть файл

@ -50,7 +50,7 @@ SOURCES= \
testUtil.cpp \
testKdf.cpp \
testTlsCbcHmac.cpp \
env_symcryptunittest.cpp \
env_windowssymcryptunittest.cpp \
testMultiThread.cpp \
rndDriver.cpp \
testArithmetic.cpp \
@ -76,10 +76,10 @@ SOURCES= \
testPaddingPkcs7.cpp \
I386_SOURCES = \
savexmm.asm \
savevectors.asm \
AMD64_SOURCES = \
saveymm.asm
savevectors.asm
TARGETLIBS= \
# $(DS_LIB_PATH)\rsa32.lib \