Skip to content

Commit

Permalink
Merged PR 8176148: Linux RNG perf testing and improvements
Browse files Browse the repository at this point in the history
+ Enable measurements of Linux RNG system
+ Make various performance improvements to defer costly calls into JitterEntropy until they are strictly required,
and reduce cost of calls when they are made.

Related work items: #42441472, #42441492
  • Loading branch information
samuel-lee-msft committed Dec 2, 2022
1 parent 2ef5a91 commit 07a5bf9
Show file tree
Hide file tree
Showing 15 changed files with 335 additions and 127 deletions.
44 changes: 22 additions & 22 deletions inc/symcrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ SymCryptHashResult(
SIZE_T cbResult );
//
// SymCryptHashResult
//
//
// Finalizes the hash computation by calling the resultFunc member
// of pHash.
// The hash result is produced to an internal buffer and
Expand Down Expand Up @@ -4130,21 +4130,21 @@ SymCryptSshKdfExpandKey(
// Process the key using the specified hash function and store the result in
// SYMCRYPT_SSHKDF_EXPANDED_KEY structure. Once the key is expanded,
// SymCryptSshKdfDerive can be called multiple times to generate keys for
// different uses/labels.
//
// different uses/labels.
//
// After all the keys are derived from a particular "shared secret" key,
// SYMCRYPT_SSHKDF_EXPANDED_KEY structure must be wiped.
//
//
// Parameters:
// - pExpandedKey : Pointer to a SYMCRYPT_SSHKDF_EXPANDED_KEY structure that
// will contain the expanded key after the function returns.
// - pHashFunc : Hash function that will be used in the key derivation.
// This function is saved in SYMCRYPT_SSHKDF_EXPANDED_KEY
// so that it is also used by the SymCryptSshKdfDerive function.
// - pbKey, cbKey : Buffer contatining the secret key for the KDF.
//
//
// Returns SYMCRYPT_NO_ERROR
//
//


SYMCRYPT_ERROR
Expand All @@ -4162,7 +4162,7 @@ SymCryptSshKdfDerive(
// Derive keys using the expanded key that was initialized with SymCryptSshKdfExpandKey
// along with other inputs. This function can be called consecutively with varying label
// values to generate keys for different purposes as defined in the RFC.
//
//
// Parameters:
// - pExpandedKey : Pointer to a SYMCRYPT_SSHKDF_EXPANDED_KEY structure that is
// initialized by a prior call to SymCryptSshKdfExpandKey.
Expand All @@ -4174,7 +4174,7 @@ SymCryptSshKdfDerive(
// - pbSessionId, cbSessionId : Buffer pointing to the session identifier. cbSessionId must be equal
// to the output size of the hash function passed to SymCryptSshKdfExpandKey.
// - pbOutput, cbOutput : Buffer to store the derived key. Exactly cbOutput bytes of output will be generated.
//
//
// Returns SYMCRYPT_NO_ERROR
//

Expand All @@ -4192,7 +4192,7 @@ SymCryptSshKdf(
SIZE_T cbSessionId,
_Out_writes_(cbOutput) PBYTE pbOutput,
SIZE_T cbOutput);
//
//
// This function is a wrapper for using SymCryptSshKdfExpandKey followed by SymCryptSshKdfDerive
// in order to produce SSH-KDF output.
//
Expand Down Expand Up @@ -4231,23 +4231,23 @@ SymCryptSrtpKdfExpandKey(
_In_reads_(cbKey) PCBYTE pbKey,
SIZE_T cbKey);
//
// Process the key and store the result in SYMCRYPT_SRTPKDF_EXPANDED_KEY structure.
// Once the key is expanded, SymCryptSrtpKdfDerive can be called multiple times to
// generate keys for different uses/labels.
//
// Process the key and store the result in SYMCRYPT_SRTPKDF_EXPANDED_KEY structure.
// Once the key is expanded, SymCryptSrtpKdfDerive can be called multiple times to
// generate keys for different uses/labels.
//
// After all the keys are derived from a particular "shared secret" key,
// SYMCRYPT_SRTPKDF_EXPANDED_KEY structure must be wiped.
//
//
// Parameters:
// - pExpandedKey : Pointer to a SYMCRYPT_SRTPKDF_EXPANDED_KEY structure that
// will contain the expanded key after the function returns.
// - pbKey, cbKey : Buffer contatining the secret key for the KDF. cbKey must be
// a valid AES key size (16-, 24-, or 32-bytes).
//
//
// Returns:
// SYMCRYPT_WRONG_KEY_SIZE : If cbKey is not a valid AES key size
// SYMCRYPT_NO_ERROR : On success
//
//

SYMCRYPT_ERROR
SYMCRYPT_CALL
Expand All @@ -4265,7 +4265,7 @@ SymCryptSrtpKdfDerive(
// Derive keys using the expanded key that was initialized with SymCryptSrtpKdfExpandKey
// along with other inputs. This function can be called consecutively with varying label
// values to generate keys for different purposes as defined in the RFC.
//
//
// Parameters:
// - pExpandedKey : Pointer to a SYMCRYPT_SRTPKDF_EXPANDED_KEY structure that is
// initialized by a prior call to SymCryptSrtpKdfExpandKey.
Expand All @@ -4281,9 +4281,9 @@ SymCryptSrtpKdfDerive(
// to be 48-bits by Errata ID 3712. SRTP index values are defined to be 48-bits.
// - label : Label value used to indicate the type of the derived key.
// - pbOutput, cbOutput : Buffer to store the derived key. Exactly cbOutput bytes of output will be generated.
//
//
// Returns:
// SYMCRYPT_INVALID_ARGUMENT : If cbSalt is not 14-bytes, or uKeyDerivationRate in invalid.
// SYMCRYPT_INVALID_ARGUMENT : If cbSalt is not 14-bytes, or uKeyDerivationRate in invalid.
// SYMCRYPT_NO_ERROR : On success.
//

Expand All @@ -4301,7 +4301,7 @@ SymCryptSrtpKdf(
BYTE label,
_Out_writes_(cbOutput) PBYTE pbOutput,
SIZE_T cbOutput);
//
//
// This function is a wrapper for using SymCryptSrtpKdfExpandKey followed by SymCryptSrtpKdfDerive
// in order to produce SRTP-KDF output.
//
Expand Down Expand Up @@ -4428,7 +4428,7 @@ SymCryptRngAesInstantiate(
// Initialize a new SYMCRYPT_RNG_AES_STATE, and seed it with the seed material.
//
// 'Instantiate' is the SP800-90 terminology.
// The seed material must be at least SYMCRYPT_RNG_AES_MIN_SEED_SIZE bytes,
// The seed material must be at least SYMCRYPT_RNG_AES_MIN_INSTANTIATE_SIZE bytes,
// and at most SYMCRYPT_RNG_AES_MAX_SEED_SIZE bytes.
//
// This implementation always uses 256-bit security strength, and
Expand All @@ -4446,7 +4446,7 @@ SymCryptRngAesInstantiate(
// Nonce: must either be a random value with 128-bits of entropy, or a value that does not
// repeat with a probability of more than 2^{-128}.
// Together these requirements imply that cbSeedMaterial should be at least
// SYMCRYPT_RNG_AES_MIN_SEED_SIZE
// SYMCRYPT_RNG_AES_MIN_INSTANTIATE_SIZE
//
// This function only returns an error if the cbSeedMaterial value is out of range.
//
Expand Down
33 changes: 31 additions & 2 deletions inc/symcrypt_low_level.h
Original file line number Diff line number Diff line change
Expand Up @@ -2654,6 +2654,35 @@ SymCryptEcpointMultiScalarMul(
// - cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_MULTI_SCALAR_ECURVE_OPERATIONS( pCurve, nPoints ).
//


////////////////////////////////////////////////////////////////////////////
// AES-CTR-DRBG
//

#define SYMCRYPT_RNG_AES_INTERNAL_SEED_SIZE (32 + 16)

SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptRngAesGenerateSmall(
_Inout_ PSYMCRYPT_RNG_AES_STATE pRngState,
_Out_writes_( cbRandom ) PBYTE pbRandom,
SIZE_T cbRandom,
_In_reads_opt_( cbAdditionalInput ) PCBYTE pbAdditionalInput,
SIZE_T cbAdditionalInput );
//
// Generate random output from the state per SP 800-90.
// Callers should almost always use SymCryptRngAesGenerate from symcrypt.h instead.
//
// This is the core generation function that produces up to 64 kB at a time
// This function returns an error code so that we can test the
// error handling of having done more than 2^48 requests between reseeds,
// as required by SP 800-90.
// This is also the Generate function of our SP800-90 compliant implementation.
// If pRngState->fips140-2Check is true, this function runs the continuous self test
// required by FIPS 140-2 (but not by FIPS 140-3 as far as we know).
// pbAdditionalInput is optional.
//

//=====================================================
// ECDSA-EX
//
Expand Down Expand Up @@ -2806,7 +2835,7 @@ SymCrypt802_11SaeCustomCreatePTGeneric(
_Out_writes_( cbPT ) PBYTE pbPT,
SIZE_T cbPT );
//
// Generic version of the SymCrypt802_11SaeCustomCreatePT() function that allows elliptic curve
// Generic version of the SymCrypt802_11SaeCustomCreatePT() function that allows elliptic curve
// group selection.
// Generate the PT secret element for use with the SAE Hash-to-Element algorithm, as described in
// section 12.4.4.2.3 of the 802.11 spec ("Hash-to-curve generation of the password element with
Expand Down Expand Up @@ -2856,7 +2885,7 @@ SymCrypt802_11SaeCustomInitH2EGeneric(
_Inout_updates_opt_( cbMask ) PBYTE pbMask,
SIZE_T cbMask );
//
// Generic version of the SymCrypt802_11SaeCustomInitH2E() function that allows elliptic curve
// Generic version of the SymCrypt802_11SaeCustomInitH2E() function that allows elliptic curve
// group selection.
// Initialize the state object using the Hash-to-Element algorithm, using the PT value calculated
// by SymCrypt802_11SaeCustomCreatePT.
Expand Down
60 changes: 33 additions & 27 deletions lib/aesCtrDrbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include "precomp.h"

#define SYMCRYPT_RNG_AES_KEY_SIZE (32)
#define SYMCRYPT_RNG_AES_INTERNAL_SEED_SIZE (32 + 16)
#define SYMCRYPT_RNG_AES_KEY_AND_V_SIZE (32 + 16)
#define SYMCRYPT_RNG_AES_MAX_REQUEST_SIZE (1<<16)
#define SYMCRYPT_RNG_AES_MAX_REQUESTS_PER_RESEED ((UINT64)1<<48)
Expand Down Expand Up @@ -380,7 +379,7 @@ VOID
SYMCRYPT_CALL
SymCryptRngAesUpdate(
_Inout_ PSYMCRYPT_RNG_AES_STATE pState,
_In_reads_opt_( SYMCRYPT_RNG_AES_INTERNAL_SEED_SIZE ) PBYTE pbProvidedData,
_In_reads_opt_( SYMCRYPT_RNG_AES_INTERNAL_SEED_SIZE ) PCBYTE pbProvidedData,
_In_opt_ PSYMCRYPT_AES_EXPANDED_KEY pAesKey)
//
// Implement the CTR_DRBG Update function.
Expand Down Expand Up @@ -435,26 +434,19 @@ SymCryptRngAesUpdate(
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptRngAesGenerateSmall(
_Inout_ PSYMCRYPT_RNG_AES_STATE pRngState,
_Out_writes_(cbRandom) PBYTE pbRandom,
SIZE_T cbRandom )
_Inout_ PSYMCRYPT_RNG_AES_STATE pRngState,
_Out_writes_( cbRandom ) PBYTE pbRandom,
SIZE_T cbRandom,
_In_reads_opt_( cbAdditionalInput ) PCBYTE pbAdditionalInput,
SIZE_T cbAdditionalInput )
//
// The core generation function that produces upto 64 kB at a time
// This function returns an error code so that we can test the
// error handling of having done more than 2^48 requests between reseeds,
// as required by SP 800-90.
// This is also the Generate function of our SP800-90 compliant implementation.
// If fips140-2Check is true, this function runs the continuous self test required
// by FIPS 140-2 (but not by FIPS 140-3 as far as we know).
// This is the Generate function of our SP800-90 compliant implementation.
// It follows the method specified in SP800-90A 10.2.1.5.2
//
{
SYMCRYPT_AES_EXPANDED_KEY aesKey;
SYMCRYPT_ALIGN BYTE buf[SYMCRYPT_AES_BLOCK_SIZE];

if( cbRandom == 0 )
{
return SYMCRYPT_NO_ERROR;
}
SYMCRYPT_ALIGN BYTE abSeed[SYMCRYPT_RNG_AES_INTERNAL_SEED_SIZE];

//
// SP 800-90 9.3.1 requires a check on the length of the request.
Expand All @@ -466,14 +458,24 @@ SymCryptRngAesGenerateSmall(
//
// The requestCounter test is useless as it can never happen. (It would require
// 2^48 calls to this function to trigger this error.)
// Unfortunatly, SP800-90 section 11 requires a test of this error, so we have
// to impelement the error.
// Unfortunately, SP800-90 section 11 requires a test of this error, so we have
// to implement the error.
//
if( pRngState->requestCounter > SYMCRYPT_RNG_AES_MAX_REQUESTS_PER_RESEED )
{
return SYMCRYPT_FIPS_FAILURE;
}

if( pbAdditionalInput != NULL )
{
// Update additional input using Derivation function
SymCryptRngAesDf( pbAdditionalInput, cbAdditionalInput, abSeed );
pbAdditionalInput = &abSeed[0];

// Update state with modified additional input
SymCryptRngAesUpdate( pRngState, pbAdditionalInput, NULL );
}

SymCryptAesExpandKeyEncryptOnly( &aesKey, pRngState->keyAndV, SYMCRYPT_RNG_AES_KEY_SIZE );

if( cbRandom >= SYMCRYPT_AES_BLOCK_SIZE )
Expand Down Expand Up @@ -507,11 +509,12 @@ SymCryptRngAesGenerateSmall(
SymCryptWipeKnownSize( buf, sizeof( buf ) );
}

SymCryptRngAesUpdate( pRngState, NULL, &aesKey );
SymCryptRngAesUpdate( pRngState, pbAdditionalInput, &aesKey );

++pRngState->requestCounter;

SymCryptWipeKnownSize( &aesKey, sizeof( aesKey ) );
SymCryptWipeKnownSize( abSeed, sizeof( abSeed ) );

return SYMCRYPT_NO_ERROR;
}
Expand Down Expand Up @@ -574,7 +577,7 @@ SymCryptRngAesGenerate( PSYMCRYPT_RNG_AES_STATE pRngState,
while( cbRandom > SYMCRYPT_RNG_AES_MAX_REQUEST_SIZE )
{

scError = SymCryptRngAesGenerateSmall( pRngState, pbRandom, SYMCRYPT_RNG_AES_MAX_REQUEST_SIZE );
scError = SymCryptRngAesGenerateSmall( pRngState, pbRandom, SYMCRYPT_RNG_AES_MAX_REQUEST_SIZE, NULL, 0 );
if( scError != SYMCRYPT_NO_ERROR )
{
SymCryptFatal( 'acdx' );
Expand All @@ -583,10 +586,13 @@ SymCryptRngAesGenerate( PSYMCRYPT_RNG_AES_STATE pRngState,
cbRandom -= SYMCRYPT_RNG_AES_MAX_REQUEST_SIZE;
}

scError = SymCryptRngAesGenerateSmall( pRngState, pbRandom, cbRandom );
if( scError != SYMCRYPT_NO_ERROR )
if( cbRandom > 0 )
{
SymCryptFatal( 'acdx' );
scError = SymCryptRngAesGenerateSmall( pRngState, pbRandom, cbRandom, NULL, 0 );
if( scError != SYMCRYPT_NO_ERROR )
{
SymCryptFatal( 'acdx' );
}
}
}

Expand Down Expand Up @@ -811,7 +817,7 @@ SymCryptRngAesTestGenerate( PSYMCRYPT_RNG_AES_STATE pRngState )
//

pRngState->requestCounter = SYMCRYPT_RNG_AES_MAX_REQUESTS_PER_RESEED + 1;
scError = SymCryptRngAesGenerateSmall( pRngState, abOutput, sizeof( g_abOutput1 ) );
scError = SymCryptRngAesGenerateSmall( pRngState, abOutput, sizeof( g_abOutput1 ), NULL, 0 );

if( scError == SYMCRYPT_NO_ERROR )
{
Expand All @@ -820,7 +826,7 @@ SymCryptRngAesTestGenerate( PSYMCRYPT_RNG_AES_STATE pRngState )
pRngState->requestCounter = 7;

#pragma prefast( suppress: 6202 26000, "buffer size of cbOutput is purposely incorrect");
scError = SymCryptRngAesGenerateSmall( pRngState, abOutput, SYMCRYPT_RNG_AES_MAX_REQUEST_SIZE + 1);
scError = SymCryptRngAesGenerateSmall( pRngState, abOutput, SYMCRYPT_RNG_AES_MAX_REQUEST_SIZE + 1, NULL, 0 );

if( scError == SYMCRYPT_NO_ERROR )
{
Expand All @@ -830,7 +836,7 @@ SymCryptRngAesTestGenerate( PSYMCRYPT_RNG_AES_STATE pRngState )
//
// Now test for correct output data.
//
scError = SymCryptRngAesGenerateSmall( pRngState, abOutput, sizeof( g_abOutput1 ) );
scError = SymCryptRngAesGenerateSmall( pRngState, abOutput, sizeof( g_abOutput1 ), NULL, 0 );

SymCryptInjectError( abOutput, sizeof( abOutput ) );

Expand Down
2 changes: 1 addition & 1 deletion modules_linux/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ include_directories(${CMAKE_SOURCE_DIR}/inc)

add_library(symcrypt_module_linux_common STATIC ${SOURCES})

set(jitter_cflags "${CMAKE_C_FLAGS} -fwrapv -fvisibility=hidden")
set(jitter_cflags "${CMAKE_C_FLAGS} -fwrapv -fvisibility=hidden -DCONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY")
set(jitter_ldflags "")

if(SYMCRYPT_TARGET_ARCH MATCHES "X86")
Expand Down
36 changes: 36 additions & 0 deletions modules_linux/common/optional/rngforkdetection.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// rngforkdetection.c
// Defines fork detection functions using getpid system call and a global variable.
//
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
//

#include "precomp.h"
#include <unistd.h>

pid_t g_pid = 0;

// Sets the initial pid
VOID
SYMCRYPT_CALL
SymCryptRngForkDetectionInit()
{
g_pid = getpid();
}

// Returns true if pid has changed since init or last call
BOOLEAN
SYMCRYPT_CALL
SymCryptRngForkDetect()
{
BOOLEAN forkDetected = FALSE;
pid_t currPid = getpid();

if( currPid != g_pid )
{
forkDetected = TRUE;
g_pid = currPid;
}

return forkDetected;
}
Loading

0 comments on commit 07a5bf9

Please sign in to comment.