зеркало из https://github.com/microsoft/SymCrypt.git
Adding Add/Remove Padding for PKCS7
This commit is contained in:
Родитель
6a765350ce
Коммит
2839a6d144
|
@ -3023,7 +3023,7 @@ SymCryptPaddingPkcs7Add(
|
|||
SIZE_T* pcbResult);
|
||||
//
|
||||
// Prerequisites:
|
||||
// cbBlockSize is a power of 2 and <= 256
|
||||
// cbBlockSize is a power of 2 and < 256
|
||||
// cbDst >= cbSrc - cbSrc % cbBlockSize + cbBlockSize
|
||||
//
|
||||
// Add PKCS7 block padding to a message
|
||||
|
@ -3057,7 +3057,7 @@ SymCryptPaddingPkcs7Remove(
|
|||
SIZE_T* pcbResult);
|
||||
//
|
||||
// Prerequisites:
|
||||
// - cbBlockSize is a power of 2 and <= 256
|
||||
// - cbBlockSize is a power of 2 and < 256
|
||||
// - cbSrc is a multiple of cbBlockSize
|
||||
// - cbSrc is greater than zero (at least equals to cbBlockSize)
|
||||
//
|
||||
|
@ -3078,10 +3078,6 @@ SymCryptPaddingPkcs7Remove(
|
|||
// Even if an error is returned, the pbDst buffer may or may not contain data from the message.
|
||||
// Callers should wipe the buffer even if an error is returned.
|
||||
//
|
||||
// In case that the padding is invalid and the output buffer is too small, both the
|
||||
// errors above are detected, but SYMCRYPT_INVALID_ARGUMENT gets precedence over
|
||||
// SYMCRYPT_BUFFER_TOO_SMALL and the returned value will be SYMCRYPT_INVALID_ARGUMENT.
|
||||
//
|
||||
// Note: Removal of PKCS7 padding is extremely sensitive to side channels.
|
||||
// For example, if a message is encrypted with AES-CBC and the attacker can modify
|
||||
// the ciphertext and then determine whether a padding error occurrs during decryption,
|
||||
|
|
|
@ -21,7 +21,7 @@ SymCryptPaddingPkcs7Add(
|
|||
SIZE_T cbDataLastBlock; // dwDataLastBlock is the number of bytes of data at the final block.
|
||||
SIZE_T cbResult = 0; // This variable must always have a valid value when we finish the function.
|
||||
|
||||
SYMCRYPT_ASSERT(cbBlockSize <= 256); // cbBlockSize must be <= 256
|
||||
SYMCRYPT_ASSERT(cbBlockSize < 256); // cbBlockSize must be < 256
|
||||
SYMCRYPT_ASSERT((cbBlockSize & (cbBlockSize - 1)) == 0); // cbBlockSize must be a power of 2
|
||||
|
||||
//
|
||||
|
@ -82,12 +82,18 @@ SymCryptPaddingPkcs7Remove(
|
|||
SIZE_T cbResult; // This variable must always have a valid value when we finish the function.
|
||||
|
||||
|
||||
SYMCRYPT_ASSERT(cbBlockSize <= 256); // cbBlockSize must be <= 256
|
||||
SYMCRYPT_ASSERT(cbBlockSize < 256); // cbBlockSize must be < 256
|
||||
SYMCRYPT_ASSERT((cbBlockSize & (cbBlockSize - 1)) == 0); // cbBlockSize must be a power of 2
|
||||
SYMCRYPT_ASSERT((cbSrc & (cbBlockSize - 1)) == 0); // cbSrc is a multiple of cbBlockSize
|
||||
SYMCRYPT_ASSERT(cbSrc > 0); // cbSrc is greaten than zero
|
||||
|
||||
cbPadVal = (UINT32)pbSrc[cbSrc - 1];
|
||||
|
||||
// check the Padding to make sure it is valid.
|
||||
mPaddingError |= SymCryptMask32IsZeroU31(cbPadVal) | SymCryptMask32LtU31((UINT32)cbBlockSize, cbPadVal);
|
||||
|
||||
// If cbPadVal is greater than cbSrc, SYMCRYPT_INVALID_ARGUMENT will be returned
|
||||
// and cbResult will not be the right value.
|
||||
cbResult = cbSrc - cbPadVal;
|
||||
|
||||
//
|
||||
|
@ -121,15 +127,14 @@ SymCryptPaddingPkcs7Remove(
|
|||
//
|
||||
// Validating padding
|
||||
//
|
||||
|
||||
// If cbPadVal is greater than cbBlockSize,
|
||||
// we have to limit cbPadVal to be at most equal to cbBlockSize.
|
||||
cbPadVal = 1 + ((cbPadVal - 1) & (cbBlockSize - 1));
|
||||
cbMsg32 = (UINT32)(cbBlockSize - cbPadVal);
|
||||
|
||||
//check Dst buffer length to make sure it is possible copy the whole message (not including the padding).
|
||||
mBufferSizeError |= SymCryptMask32LtU31(cbDst32, cbMsg32);
|
||||
|
||||
// check the Padding to make sure it is valid.
|
||||
mPaddingError |= SymCryptMask32IsZeroU31(cbPadVal) | SymCryptMask32LtU31((UINT32)cbBlockSize, cbPadVal);
|
||||
|
||||
//
|
||||
// Final Block processing
|
||||
//
|
||||
|
|
|
@ -364,7 +364,7 @@ SymCryptScsRotateBuffer(
|
|||
|
||||
UINT32 SYMCRYPT_CALL SymCryptMapUint32(UINT32 u32Input, UINT32 u32Default, PCSYMCRYPT_UINT32_MAP pcMap, SIZE_T nMap)
|
||||
{
|
||||
UINT32 mask = 0;
|
||||
UINT32 mask;
|
||||
UINT32 u32Output = u32Default;
|
||||
|
||||
for (SIZE_T i = 0; i < nMap; ++i)
|
||||
|
|
|
@ -1096,6 +1096,9 @@ testScsTable();
|
|||
VOID
|
||||
testScsTools();
|
||||
|
||||
VOID
|
||||
testPaddingPkcs7();
|
||||
|
||||
VOID
|
||||
testEcc();
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ set(SOURCES
|
|||
testScsTable.cpp
|
||||
testScsTools.cpp
|
||||
perf.cpp
|
||||
testPaddingPkcs7.cpp
|
||||
)
|
||||
|
||||
# Append Windows-specific sources
|
||||
|
|
|
@ -1548,7 +1548,9 @@ runFunctionalTests()
|
|||
testArithmetic();
|
||||
|
||||
testScsTable();
|
||||
|
||||
|
||||
testPaddingPkcs7();
|
||||
|
||||
testScsTools();
|
||||
|
||||
testRsaSignAlgorithms();
|
||||
|
|
|
@ -73,6 +73,7 @@ SOURCES= \
|
|||
testRsaEnc.cpp \
|
||||
testDh.cpp \
|
||||
testDsa.cpp \
|
||||
testPaddingPkcs7.cpp \
|
||||
|
||||
I386_SOURCES = \
|
||||
savexmm.asm \
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
|
||||
//
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#define MAX_BUFFER_SIZE 10000
|
||||
#define MAX_PKCS7_BLOCK_SIZE 128
|
||||
#define MAX_DEST_BUFFER_SIZE 2 * (MAX_BUFFER_SIZE + MAX_PKCS7_BLOCK_SIZE)
|
||||
|
||||
SIZE_T
|
||||
verifyAddPadding(SIZE_T cbBlockSize, PCBYTE pbSrc, UINT32 cbSrc, PBYTE pbDst, UINT32 cbDst)
|
||||
{
|
||||
SIZE_T cbResult = cbSrc;
|
||||
|
||||
// Making copy of the Dst buffer before padding for validation
|
||||
PBYTE pbDstCpy = new BYTE[cbDst];
|
||||
memcpy(pbDstCpy, pbDst, cbDst);
|
||||
|
||||
// Calculating padding parameters for validation
|
||||
UINT32 cbPadVal = (UINT32)(cbBlockSize - (cbSrc % cbBlockSize));
|
||||
UINT32 cbPredictedResult = cbSrc + cbPadVal;
|
||||
|
||||
SymCryptPaddingPkcs7Add(cbBlockSize, pbSrc, cbSrc, pbDst, cbDst, &cbResult);
|
||||
|
||||
// Verify cbResult value
|
||||
CHECK(cbResult == cbPredictedResult, "testPaddingPkcs7Add : cbResult is incorrect.");
|
||||
|
||||
// Verify pbDst data (msg, padding, unchanged data)
|
||||
for (UINT32 i = 0; i < cbDst; ++i)
|
||||
{
|
||||
if (i < cbSrc)
|
||||
{
|
||||
CHECK(pbSrc[i] == pbDst[i], "testPaddingPkcs7Add: message was not copied to destination as expected!");
|
||||
continue;
|
||||
}
|
||||
if (i < cbResult)
|
||||
{
|
||||
CHECK((BYTE)cbPadVal == pbDst[i], "testPaddingPkcs7Add: invalid padded value!");
|
||||
continue;
|
||||
}
|
||||
CHECK(pbDst[i] == pbDstCpy[i], "testPaddingPkcs7Add: data after padding was changed!");
|
||||
}
|
||||
|
||||
delete [] pbDstCpy;
|
||||
return cbResult;
|
||||
}
|
||||
|
||||
VOID
|
||||
verifyRemovePadding(SIZE_T cbBlockSize, PCBYTE pbSrc, UINT32 cbSrc, PBYTE pbDst, UINT32 cbDst)
|
||||
{
|
||||
|
||||
SIZE_T cbResult = cbSrc;
|
||||
UINT32 cbPadVal = pbSrc[cbSrc - 1];
|
||||
UINT32 cbMsg = cbSrc - (cbPadVal % (cbBlockSize + 1 ));
|
||||
|
||||
bool validPadding = (cbPadVal != 0 && cbPadVal <= cbBlockSize) ? true : false;
|
||||
bool bufferTooSmall = (cbDst < cbSrc - cbBlockSize) ? true : false;
|
||||
bool validBuffer = (cbDst < cbMsg) ? false : true;
|
||||
|
||||
// Making copy of the Dst buffer for validation
|
||||
PBYTE pbDstCpy = new BYTE[cbDst];
|
||||
memcpy(pbDstCpy, pbDst, cbDst);
|
||||
|
||||
SYMCRYPT_ERROR err = SymCryptPaddingPkcs7Remove(cbBlockSize, pbSrc, cbSrc, pbDst, cbDst, &cbResult);
|
||||
|
||||
// if cbDst is less than block size, we don't need to check the padding.
|
||||
if (!bufferTooSmall)
|
||||
{
|
||||
for (UINT32 i = cbMsg; i < cbSrc; ++i)
|
||||
{
|
||||
if (pbSrc[i] != cbPadVal)
|
||||
{
|
||||
validPadding = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!validPadding)
|
||||
{
|
||||
CHECK(((err == SYMCRYPT_BUFFER_TOO_SMALL) || (err == SYMCRYPT_INVALID_ARGUMENT)),
|
||||
"SymCryptPaddingPkcs7Remove: not the expected error was returned.");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(err == SYMCRYPT_BUFFER_TOO_SMALL, "testPaddingPkcs7Remove: not the expected error was returned.");
|
||||
}
|
||||
}
|
||||
|
||||
if (validBuffer && validPadding)
|
||||
{
|
||||
CHECK(err == SYMCRYPT_NO_ERROR,
|
||||
"SymCryptPaddingPkcs7Remove: not the expected error was returned.");
|
||||
CHECK(cbResult == cbMsg, "testPaddingPkcs7Remove: cbResult is incorrect.");
|
||||
|
||||
// validate data at pbDst
|
||||
for (UINT32 i = 0; i < cbDst; ++i)
|
||||
{
|
||||
if (!bufferTooSmall && i < cbMsg)
|
||||
{
|
||||
CHECK(pbSrc[i] == pbDst[i], "testPaddingPkcs7Remove: message was not copied to destination as expected!");
|
||||
continue;
|
||||
}
|
||||
|
||||
CHECK(pbDstCpy[i] == pbDst[i], "testPaddingPkcs7Remove: data after padding was changed!");
|
||||
}
|
||||
}
|
||||
else if (validBuffer && !validPadding)
|
||||
{
|
||||
CHECK(err == SYMCRYPT_INVALID_ARGUMENT,
|
||||
"SymCryptPaddingPkcs7Remove: not the expected error was returned.");
|
||||
}
|
||||
else if (!validBuffer && validPadding)
|
||||
{
|
||||
CHECK(err == SYMCRYPT_BUFFER_TOO_SMALL,
|
||||
"SymCryptPaddingPkcs7Remove: not the expected error was returned.");
|
||||
}
|
||||
else if (!validBuffer && !validPadding)
|
||||
{
|
||||
CHECK(((err == SYMCRYPT_BUFFER_TOO_SMALL) || (err == SYMCRYPT_INVALID_ARGUMENT)),
|
||||
"SymCryptPaddingPkcs7Remove: not the expected error was returned.");
|
||||
}
|
||||
|
||||
delete [] pbDstCpy;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
testPaddingPkcs7()
|
||||
{
|
||||
UINT32 cbMsg;
|
||||
UINT32 cbAddPad;
|
||||
UINT32 cbRemovePad;
|
||||
|
||||
// Prerequisites: cbBlockSize is a power of 2 and <= 128
|
||||
SIZE_T cbBlockSize;
|
||||
GENRANDOM(&cbBlockSize, sizeof(cbBlockSize));
|
||||
cbBlockSize = SymCryptRoundUpPow2Sizet(1 + (cbBlockSize % MAX_PKCS7_BLOCK_SIZE));
|
||||
|
||||
GENRANDOM(&cbMsg, sizeof(cbMsg));
|
||||
cbMsg = cbMsg % MAX_BUFFER_SIZE;
|
||||
|
||||
GENRANDOM(&cbRemovePad, sizeof(cbRemovePad));
|
||||
cbRemovePad = cbRemovePad % MAX_BUFFER_SIZE;
|
||||
|
||||
// Prerequisites: cbDst >= cbSrc - cbSrc % cbBlockSize + cbBlockSize
|
||||
GENRANDOM(&cbAddPad, sizeof(cbAddPad));
|
||||
cbAddPad = cbAddPad % MAX_DEST_BUFFER_SIZE;
|
||||
cbAddPad = cbAddPad + (cbMsg + (UINT32)cbBlockSize - (cbMsg % cbBlockSize));
|
||||
|
||||
|
||||
// Generating both Src and Dst random buffers
|
||||
PBYTE pbMsg = new BYTE[cbMsg];
|
||||
PBYTE pbAddPad = new BYTE[cbAddPad];
|
||||
PBYTE pbRemovePad = new BYTE[cbRemovePad];
|
||||
|
||||
GENRANDOM(pbMsg, cbMsg);
|
||||
GENRANDOM(pbAddPad, cbAddPad);
|
||||
GENRANDOM(pbRemovePad, cbRemovePad);
|
||||
|
||||
// Check Add padding process
|
||||
UINT32 cbResult = (UINT32) verifyAddPadding(cbBlockSize, pbMsg, cbMsg, pbAddPad, cbAddPad);
|
||||
|
||||
// Check Remove padding process with validated padded buffer
|
||||
verifyRemovePadding(cbBlockSize, pbAddPad, cbResult, pbRemovePad, cbRemovePad);
|
||||
|
||||
// Checking the remove padding process with manipulated padded data.
|
||||
// In this test we will generate a padding value and a position and replace one of
|
||||
// the padded bytes with this random value. Then we will validate the remove padding.
|
||||
UINT32 cbPadValDummy;
|
||||
GENRANDOM(&cbPadValDummy, sizeof(cbPadValDummy));
|
||||
if (MAX_PKCS7_BLOCK_SIZE <= cbPadValDummy)
|
||||
{
|
||||
cbPadValDummy = cbPadValDummy % MAX_PKCS7_BLOCK_SIZE;
|
||||
}
|
||||
UINT32 cbPadVal = cbResult - cbMsg;
|
||||
UINT32 rndPadPos = cbMsg;
|
||||
if (cbPadVal != 0)
|
||||
{
|
||||
rndPadPos = rndPadPos + (cbPadValDummy % cbPadVal);
|
||||
}
|
||||
UINT32 cbSrcDummy = cbResult;
|
||||
PBYTE pbSrcDummy = new BYTE[cbSrcDummy];
|
||||
memcpy(pbSrcDummy, pbAddPad, cbResult);
|
||||
memset(pbSrcDummy + rndPadPos, cbPadValDummy, 1);
|
||||
|
||||
UINT32 cbDstDummy;
|
||||
GENRANDOM(&cbDstDummy, sizeof(cbDstDummy));
|
||||
cbDstDummy = cbDstDummy % MAX_BUFFER_SIZE;
|
||||
PBYTE pbDstDummy = new BYTE[cbDstDummy];
|
||||
GENRANDOM(pbDstDummy, cbDstDummy);
|
||||
|
||||
verifyRemovePadding(cbBlockSize, pbSrcDummy, cbSrcDummy, pbDstDummy, cbDstDummy);
|
||||
|
||||
// Cleanup
|
||||
delete [] pbMsg;
|
||||
delete [] pbAddPad;
|
||||
delete [] pbRemovePad;
|
||||
delete [] pbSrcDummy;
|
||||
delete [] pbDstDummy;
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "precomp.h"
|
||||
|
||||
#define MAX_MAP_UINT32_LEN 99
|
||||
|
||||
VOID
|
||||
testScsRotateBuffer()
|
||||
|
@ -127,51 +128,105 @@ testBasicMaskFunctions()
|
|||
|
||||
}
|
||||
|
||||
VOID
|
||||
initMapUint32(PSYMCRYPT_UINT32_MAP pMap, UINT32 uMapLen)
|
||||
{
|
||||
UINT32 uDuplication;
|
||||
GENRANDOM(&uDuplication, sizeof(uDuplication));
|
||||
|
||||
// Limiting the number of duplicates of 'from' values to be at most uMapLen
|
||||
uDuplication = uDuplication % uMapLen;
|
||||
|
||||
// Generating fully random map
|
||||
for (UINT32 i = 0; i < uMapLen; ++i)
|
||||
{
|
||||
GENRANDOM(&(pMap[i].from), sizeof(pMap[i].from));
|
||||
GENRANDOM(&(pMap[i].to), sizeof(pMap[i].to));
|
||||
}
|
||||
|
||||
// forcing duplications
|
||||
for (UINT32 i = 0; i < uDuplication; ++i)
|
||||
{
|
||||
UINT32 copyFromEntry;
|
||||
UINT32 copyToEntry;
|
||||
|
||||
GENRANDOM(©FromEntry, sizeof(copyFromEntry));
|
||||
GENRANDOM(©ToEntry, sizeof(copyToEntry));
|
||||
|
||||
copyFromEntry = copyFromEntry % uMapLen;
|
||||
copyToEntry = copyToEntry % uMapLen;
|
||||
|
||||
pMap[copyToEntry].from = pMap[copyFromEntry].from;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
validateMapping(UINT32 u32Input, PCSYMCRYPT_UINT32_MAP pMap, UINT32 uMapLen)
|
||||
{
|
||||
UINT32 u32Default;
|
||||
UINT32 u32Result;
|
||||
|
||||
bool result = false;
|
||||
bool exists = false;
|
||||
|
||||
GENRANDOM(&u32Default, sizeof(u32Default));
|
||||
|
||||
u32Result = SymCryptMapUint32(u32Input, u32Default, pMap, uMapLen);
|
||||
|
||||
for (UINT32 i = 0; i < uMapLen; ++i)
|
||||
{
|
||||
if (pMap[i].from == u32Input)
|
||||
{
|
||||
exists = true;
|
||||
if (pMap[i].to == u32Result)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists && u32Result == u32Default)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VOID
|
||||
testScsMapUint32()
|
||||
{
|
||||
UINT32 u32Input;
|
||||
UINT32 u32Default;
|
||||
UINT32 u32From1;
|
||||
UINT32 u32To1;
|
||||
UINT32 u32From2;
|
||||
UINT32 u32To2;
|
||||
UINT32 u32To3;
|
||||
UINT32 uMapLen;
|
||||
GENRANDOM(&uMapLen, sizeof(uMapLen));
|
||||
|
||||
GENRANDOM(&u32Default, sizeof(u32Default));
|
||||
GENRANDOM(&u32From1, sizeof(u32From1));
|
||||
GENRANDOM(&u32From2, sizeof(u32From2));
|
||||
GENRANDOM(&u32To1, sizeof(u32To1));
|
||||
GENRANDOM(&u32To2, sizeof(u32To2));
|
||||
GENRANDOM(&u32To3, sizeof(u32To3));
|
||||
// Limiting the length of the map to be between 1 to 100.
|
||||
// We want to avoid a creation of huge map.
|
||||
uMapLen = (uMapLen % MAX_MAP_UINT32_LEN) + 1;
|
||||
|
||||
SYMCRYPT_UINT32_MAP pMap[3] = {
|
||||
{ u32From1, u32To1 },
|
||||
{ u32From2, u32To2 },
|
||||
{ u32From2, u32To3 } }; // multiple map entries may have the same 'from'
|
||||
PSYMCRYPT_UINT32_MAP pMap = new SYMCRYPT_UINT32_MAP[uMapLen];
|
||||
CHECK(pMap != NULL, "Out of memory");
|
||||
|
||||
//
|
||||
// Case 1: u32Input matches the 'from' field of only one entry
|
||||
//
|
||||
// Initiating map with random values
|
||||
initMapUint32(pMap, uMapLen);
|
||||
|
||||
CHECK(SymCryptMapUint32(u32From1, u32Default, pMap, 2) == u32To1, "SymCryptMapUint32");
|
||||
|
||||
//
|
||||
// Case 2: u32Input matches the 'from' field of multiple entries
|
||||
//
|
||||
CHECK(SymCryptMapUint32(u32From2, u32Default, pMap, 2) == u32To2, "SymCryptMapUint32");
|
||||
|
||||
//
|
||||
// Case 3: u32Input doesn't match the 'from' field of any entry
|
||||
//
|
||||
do
|
||||
// Validating SymCryptMapUint32 result for every 'from' value in map
|
||||
for (UINT32 i = 0; i < uMapLen; ++i)
|
||||
{
|
||||
GENRANDOM(&u32Input, sizeof(u32Input));
|
||||
}
|
||||
while (u32Input == u32From1 || u32Input == u32From2);
|
||||
CHECK(validateMapping(pMap[i].from, pMap, uMapLen), "SymCryptMapUint32");
|
||||
}
|
||||
|
||||
CHECK(SymCryptMapUint32(u32Input, u32Default, pMap, 2) == u32Default, "SymCryptMapUint32");
|
||||
// Validating SymCryptMapUint32 result for random inputs
|
||||
|
||||
for (UINT32 i = 0; i < MAX_MAP_UINT32_LEN; ++i)
|
||||
{
|
||||
UINT32 u32RndInput;
|
||||
GENRANDOM(&u32RndInput, sizeof(u32RndInput));
|
||||
CHECK(validateMapping(u32RndInput, pMap, uMapLen), "SymCryptMapUint32");
|
||||
}
|
||||
|
||||
//cleanup
|
||||
delete [] pMap;
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
Загрузка…
Ссылка в новой задаче