зеркало из https://github.com/microsoft/SymCrypt.git
740 строки
24 KiB
C++
740 строки
24 KiB
C++
//
|
|
// Test Hash-based Signatures
|
|
//
|
|
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
|
|
//
|
|
|
|
#include "precomp.h"
|
|
|
|
extern
|
|
"C"
|
|
{
|
|
VOID
|
|
SYMCRYPT_CALL
|
|
SymCryptHbsGetWinternitzLengths(
|
|
UINT32 n, // blob size in bytes
|
|
UINT32 w, // digit length in bits (Winternitz coefficient)
|
|
_Out_ PUINT32 puLen1, // number of w-bit digits in n
|
|
_Out_ PUINT32 puLen2 // number of w-bit digits to store the checksum <= len1 * (2^w - 1)
|
|
);
|
|
|
|
UINT32
|
|
SymCryptCountLeadingZeros32( UINT32 value );
|
|
}
|
|
|
|
typedef struct _SYMCRYPT_WINTERNITZ_LENGTHS
|
|
{
|
|
UINT32 n;
|
|
UINT32 w;
|
|
UINT32 len1;
|
|
UINT32 len2;
|
|
} SYMCRYPT_WINTERNITZ_LENGTHS, * PSYMCRYPT_WINTERNITZ_LENGTHS;
|
|
|
|
//
|
|
// Precomputed digit counts in Excel
|
|
//
|
|
// len1 = CEILING.MATH(8 * n / w)
|
|
// len2 = FLOOR.MATH(LOG(len1 * (POWER(2, w) - 1), 2) / w) + 1
|
|
//
|
|
static const SYMCRYPT_WINTERNITZ_LENGTHS _SymCryptWinternitzLengths[] = {
|
|
|
|
// n w len1 len2
|
|
{ 24, 1, 192, 8 },
|
|
{ 24, 2, 96, 5 },
|
|
{ 24, 3, 64, 3 },
|
|
{ 24, 4, 48, 3 },
|
|
{ 24, 5, 39, 3 },
|
|
{ 24, 6, 32, 2 },
|
|
{ 24, 7, 28, 2 },
|
|
{ 24, 8, 24, 2 },
|
|
|
|
{ 32, 1, 256, 9 },
|
|
{ 32, 2, 128, 5 },
|
|
{ 32, 3, 86, 4 },
|
|
{ 32, 4, 64, 3 },
|
|
{ 32, 5, 52, 3 },
|
|
{ 32, 6, 43, 2 },
|
|
{ 32, 7, 37, 2 },
|
|
{ 32, 8, 32, 2 },
|
|
|
|
{ 64, 1, 512, 10 },
|
|
{ 64, 2, 256, 5 },
|
|
{ 64, 3, 171, 4 },
|
|
{ 64, 4, 128, 3 },
|
|
{ 64, 5, 103, 3 },
|
|
{ 64, 6, 86, 3 },
|
|
{ 64, 7, 74, 2 },
|
|
{ 64, 8, 64, 2 },
|
|
};
|
|
|
|
VOID
|
|
testWinternitzLengths()
|
|
{
|
|
for (UINT32 i = 0; i < sizeof(_SymCryptWinternitzLengths) / sizeof(_SymCryptWinternitzLengths[0]); i++)
|
|
{
|
|
UINT32 len1, len2;
|
|
|
|
SymCryptHbsGetWinternitzLengths(
|
|
_SymCryptWinternitzLengths[i].n,
|
|
_SymCryptWinternitzLengths[i].w,
|
|
&len1,
|
|
&len2);
|
|
|
|
CHECK4( len1 == _SymCryptWinternitzLengths[i].len1,
|
|
"Incorrect Winternitz digit count for len1: expecting %d got %d",
|
|
_SymCryptWinternitzLengths[i].len1,
|
|
len1);
|
|
|
|
CHECK4( len2 == _SymCryptWinternitzLengths[i].len2,
|
|
"Incorrect Winternitz digit count for len2: expecting %d got %d",
|
|
_SymCryptWinternitzLengths[i].len2,
|
|
len2);
|
|
}
|
|
}
|
|
|
|
|
|
class HbsMultiImp : public HbsImplementation
|
|
{
|
|
public:
|
|
HbsMultiImp( String algName );
|
|
virtual ~HbsMultiImp();
|
|
|
|
private:
|
|
HbsMultiImp(const HbsMultiImp&);
|
|
VOID operator=(const HbsMultiImp&);
|
|
|
|
public:
|
|
|
|
typedef std::vector<HbsImplementation*> HbsImpPtrVector;
|
|
|
|
HbsImpPtrVector m_imps; // Implementations we use
|
|
|
|
HbsImpPtrVector m_comps; // Subset of m_imps; set of ongoing computations
|
|
|
|
VOID addImplementation(HbsImplementation* pImp );
|
|
VOID setImpName();
|
|
|
|
virtual NTSTATUS setKey(UINT32, BOOL, PCBYTE, SIZE_T, BOOL);
|
|
virtual NTSTATUS sign(PCBYTE, SIZE_T, PBYTE, SIZE_T);
|
|
virtual NTSTATUS verify(PCBYTE, SIZE_T, PCBYTE, SIZE_T);
|
|
};
|
|
|
|
VOID
|
|
HbsMultiImp::setImpName()
|
|
{
|
|
String sumAlgName;
|
|
char* sepStr = "<";
|
|
|
|
for (HbsImpPtrVector::const_iterator i = m_imps.begin(); i != m_imps.end(); ++i)
|
|
{
|
|
sumAlgName += sepStr + (*i)->m_algorithmName;
|
|
sepStr = "+";
|
|
}
|
|
m_implementationName = sumAlgName + ">";
|
|
}
|
|
|
|
HbsMultiImp::HbsMultiImp(String algName)
|
|
{
|
|
m_algorithmName = algName;
|
|
|
|
getAllImplementations<HbsImplementation>(algName, &m_imps);
|
|
}
|
|
|
|
VOID
|
|
HbsMultiImp::addImplementation(HbsImplementation* pImp)
|
|
{
|
|
m_imps.push_back(pImp);
|
|
setImpName();
|
|
}
|
|
|
|
|
|
HbsMultiImp::~HbsMultiImp()
|
|
{
|
|
//
|
|
// Propagate the # KAT failures to the individual algorithms.
|
|
//
|
|
for (HbsImpPtrVector::iterator i = m_imps.begin(); i != m_imps.end(); ++i)
|
|
{
|
|
(*i)->m_nErrorKatFailure += m_nErrorKatFailure;
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HbsMultiImp::setKey(
|
|
UINT32 uAlgId,
|
|
BOOL fMultitree,
|
|
PCBYTE pbSrc,
|
|
SIZE_T cbSrc,
|
|
BOOL fVerify )
|
|
{
|
|
m_comps.clear();
|
|
|
|
for (HbsImpPtrVector::const_iterator i = m_imps.begin(); i != m_imps.end(); ++i)
|
|
{
|
|
if ((*i)->setKey(uAlgId, fMultitree, pbSrc, cbSrc, fVerify) == STATUS_SUCCESS)
|
|
{
|
|
m_comps.push_back(*i);
|
|
}
|
|
}
|
|
|
|
return m_comps.size() == 0 ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
HbsMultiImp::sign(
|
|
PCBYTE pbMsg,
|
|
SIZE_T cbMsg,
|
|
PBYTE pbSignature,
|
|
SIZE_T cbSignature )
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ResultMerge res;
|
|
PBYTE pbBuffer = NULL;
|
|
|
|
pbBuffer = new BYTE[cbSignature];
|
|
|
|
CHECK(pbBuffer != nullptr, "Memory allocation error");
|
|
|
|
for (HbsImpPtrVector::const_iterator i = m_comps.begin(); i != m_comps.end(); ++i)
|
|
{
|
|
SymCryptWipe(pbBuffer, cbSignature);
|
|
if ((*i)->sign(pbMsg, cbMsg, pbBuffer, cbSignature) != STATUS_SUCCESS)
|
|
{
|
|
CHECK(FALSE, "Signature generation error");
|
|
continue;
|
|
}
|
|
res.addResult((*i), pbBuffer, cbSignature);
|
|
}
|
|
|
|
res.getResult(pbSignature, cbSignature);
|
|
|
|
delete[] pbBuffer;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HbsMultiImp::verify(
|
|
PCBYTE pbMsg,
|
|
SIZE_T cbMsg,
|
|
PCBYTE pbSignature,
|
|
SIZE_T cbSignature )
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ResultMerge res;
|
|
BYTE b[4];
|
|
|
|
for (HbsImpPtrVector::const_iterator i = m_comps.begin(); i != m_comps.end(); ++i)
|
|
{
|
|
status = (*i)->verify(pbMsg, cbMsg, pbSignature, cbSignature);
|
|
SYMCRYPT_STORE_MSBFIRST32(b, status);
|
|
res.addResult((*i), b, 4);
|
|
}
|
|
|
|
res.getResult(b, 4);
|
|
status = SYMCRYPT_LOAD_MSBFIRST32(b);
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
testHbsVerify(
|
|
HbsImplementation* pHbs,
|
|
UINT32 AlgId,
|
|
BOOL fMultitree,
|
|
_In_reads_(cbMsg) PCBYTE pbMsg,
|
|
SIZE_T cbMsg,
|
|
_In_reads_(cbPubkey) PCBYTE pbPubkey,
|
|
SIZE_T cbPubkey,
|
|
_In_reads_(cbSig) PCBYTE pbSig,
|
|
SIZE_T cbSig,
|
|
LONGLONG line )
|
|
{
|
|
NTSTATUS status;
|
|
|
|
UNREFERENCED_PARAMETER(line);
|
|
|
|
status = pHbs->setKey(AlgId, fMultitree, pbPubkey, cbPubkey, FALSE);
|
|
CHECK3(status == STATUS_SUCCESS, "Hbs setKey failed for algid = %u", AlgId);
|
|
|
|
status = pHbs->verify(pbMsg, cbMsg, pbSig, cbSig);
|
|
CHECK3(status == STATUS_SUCCESS, "Hbs verify failed for algid = %u", AlgId);
|
|
|
|
CHECK( pHbs->setKey( 0, FALSE, NULL, 0, FALSE ) == STATUS_SUCCESS, "Failed to clear key" );
|
|
}
|
|
|
|
VOID
|
|
testHbsSign(
|
|
HbsImplementation* pHbs,
|
|
UINT32 AlgId,
|
|
BOOL fMultitree,
|
|
_In_reads_(cbMsg) PCBYTE pbMsg,
|
|
SIZE_T cbMsg,
|
|
_In_reads_(cbPrvkey) PCBYTE pbPrvkey,
|
|
SIZE_T cbPrvkey,
|
|
_In_reads_(cbSig) PCBYTE pbSig,
|
|
SIZE_T cbSig,
|
|
LONGLONG line )
|
|
{
|
|
NTSTATUS status;
|
|
PBYTE pbSig2 = nullptr;
|
|
|
|
UNREFERENCED_PARAMETER(line);
|
|
|
|
pbSig2 = new BYTE[cbSig];
|
|
CHECK3(pbSig2 != nullptr, "Memory allocation failed for %u bytes", cbSig);
|
|
|
|
status = pHbs->setKey(AlgId, fMultitree, pbPrvkey, cbPrvkey, FALSE);
|
|
CHECK3(status == STATUS_SUCCESS, "Hbs setKey failed for algid = %u", AlgId);
|
|
|
|
status = pHbs->sign(pbMsg, cbMsg, pbSig2, cbSig);
|
|
CHECK3(status == STATUS_SUCCESS, "Hbs sign failed for algid = %u", AlgId);
|
|
|
|
int bMatch = memcmp(pbSig, pbSig2, cbSig) == 0;
|
|
CHECK3(bMatch == TRUE, "generated signature does not match the given one for alg id %d", AlgId);
|
|
|
|
CHECK( pHbs->setKey( 0, FALSE, NULL, 0, FALSE ) == STATUS_SUCCESS, "Failed to clear key" );
|
|
|
|
delete[] pbSig2;
|
|
}
|
|
|
|
VOID
|
|
testHbsKeygen(
|
|
HbsImplementation* pHbs,
|
|
UINT32 AlgId,
|
|
BOOL fMultitree,
|
|
_In_reads_(cbPrvkey) PCBYTE pbPrvkey,
|
|
SIZE_T cbPrvkey,
|
|
LONGLONG line )
|
|
{
|
|
NTSTATUS status;
|
|
|
|
UNREFERENCED_PARAMETER(line);
|
|
|
|
status = pHbs->setKey(AlgId, fMultitree, pbPrvkey, cbPrvkey, TRUE);
|
|
CHECK3(status == STATUS_SUCCESS, "Hbs setKey failed for algid = %u", AlgId);
|
|
|
|
CHECK( pHbs->setKey( 0, FALSE, NULL, 0, FALSE ) == STATUS_SUCCESS, "Failed to clear key" );
|
|
}
|
|
|
|
VOID
|
|
testHbsKats()
|
|
{
|
|
KatData* katHbs = getCustomResource("kat_hbs.dat", "KAT_HBS");
|
|
KAT_ITEM katItem;
|
|
|
|
static String g_currentCategory;
|
|
BOOL skipData = TRUE;
|
|
String sep = " ";
|
|
BOOL doneAnything = FALSE;
|
|
|
|
std::unique_ptr<HbsMultiImp> pHbsMultiImp;
|
|
|
|
while (1)
|
|
{
|
|
katHbs->getKatItem(&katItem);
|
|
|
|
if (katItem.type == KAT_TYPE_END)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (katItem.type == KAT_TYPE_CATEGORY)
|
|
{
|
|
g_currentCategory = katItem.categoryName;
|
|
|
|
pHbsMultiImp.reset(new HbsMultiImp(g_currentCategory));
|
|
|
|
skipData = (pHbsMultiImp->m_imps.size() == 0);
|
|
|
|
if (!skipData)
|
|
{
|
|
iprint("%s%s", sep.c_str(), g_currentCategory.c_str());
|
|
sep = ", ";
|
|
doneAnything = TRUE;
|
|
}
|
|
}
|
|
|
|
if (skipData)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (katItem.type == KAT_TYPE_DATASET)
|
|
{
|
|
if (katIsFieldPresent(katItem, "pubkey"))
|
|
{
|
|
//
|
|
// Signature verification test
|
|
//
|
|
BOOL fMultitree = FALSE;
|
|
UINT32 nExpectedItems = 4;
|
|
|
|
if (katIsFieldPresent(katItem, "multitree"))
|
|
{
|
|
fMultitree = katParseInteger(katItem, "multitree") > 0;
|
|
nExpectedItems++;
|
|
}
|
|
|
|
CHECK3(katItem.dataItems.size() == nExpectedItems, "Incorrect number of items in Hbs signature verification record ending at line %lld", katHbs->m_line);
|
|
|
|
UINT32 algId = (UINT32)katParseInteger(katItem, "algid");
|
|
BString katMsg = katParseData(katItem, "msg");
|
|
BString katPubkey = katParseData(katItem, "pubkey");
|
|
BString katSig = katParseData(katItem, "sig");
|
|
|
|
testHbsVerify(
|
|
pHbsMultiImp.get(),
|
|
algId,
|
|
fMultitree,
|
|
(PCBYTE)katMsg.data(),
|
|
katMsg.size(),
|
|
(PCBYTE)katPubkey.data(),
|
|
katPubkey.size(),
|
|
(PCBYTE)katSig.data(),
|
|
katSig.size(),
|
|
katHbs->m_line);
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
if (katIsFieldPresent(katItem, "prvkey"))
|
|
{
|
|
if (katIsFieldPresent(katItem, "msg"))
|
|
{
|
|
//
|
|
// Signature generation test
|
|
//
|
|
BOOL fMultitree = FALSE;
|
|
UINT32 nExpectedItems = 4;
|
|
|
|
if (katIsFieldPresent(katItem, "multitree"))
|
|
{
|
|
fMultitree = katParseInteger(katItem, "multitree") > 0;
|
|
nExpectedItems++;
|
|
}
|
|
|
|
CHECK3(katItem.dataItems.size() == nExpectedItems, "Incorrect number of items in Hbs signature verification record ending at line %lld", katHbs->m_line);
|
|
|
|
UINT32 algId = (UINT32)katParseInteger(katItem, "algid");
|
|
BString katMsg = katParseData(katItem, "msg");
|
|
BString katPrvkey = katParseData(katItem, "prvkey");
|
|
BString katSig = katParseData(katItem, "sig");
|
|
|
|
testHbsSign(
|
|
pHbsMultiImp.get(),
|
|
algId,
|
|
fMultitree,
|
|
(PCBYTE)katMsg.data(),
|
|
katMsg.size(),
|
|
(PCBYTE)katPrvkey.data(),
|
|
katPrvkey.size(),
|
|
(PCBYTE)katSig.data(),
|
|
katSig.size(),
|
|
katHbs->m_line);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Key generation test
|
|
//
|
|
BOOL fMultitree = FALSE;
|
|
UINT32 nExpectedItems = 2;
|
|
|
|
if (katIsFieldPresent(katItem, "multitree"))
|
|
{
|
|
fMultitree = katParseInteger(katItem, "multitree") > 0;
|
|
nExpectedItems++;
|
|
}
|
|
|
|
CHECK3(katItem.dataItems.size() == nExpectedItems, "Incorrect number of items in Hbs signature verification record ending at line %lld", katHbs->m_line);
|
|
|
|
UINT32 algId = (UINT32)katParseInteger(katItem, "algid");
|
|
BString katPrvkey = katParseData(katItem, "prvkey");
|
|
|
|
testHbsKeygen(
|
|
pHbsMultiImp.get(),
|
|
algId,
|
|
fMultitree,
|
|
(PCBYTE)katPrvkey.data(),
|
|
katPrvkey.size(),
|
|
katHbs->m_line);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
FATAL2("Unknown data record ending at line %lld", katHbs->m_line);
|
|
}
|
|
}
|
|
|
|
if (doneAnything)
|
|
{
|
|
iprint("\n");
|
|
}
|
|
|
|
delete katHbs;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
testXmssCustomParameters()
|
|
{
|
|
SYMCRYPT_XMSS_PARAMS params;
|
|
PSYMCRYPT_XMSS_KEY pKey;
|
|
PBYTE pbSignature;
|
|
SYMCRYPT_ERROR scError;
|
|
SIZE_T cbSignature;
|
|
BYTE msg[] = { 0x00, 0x01, 0x03, 0x04 };
|
|
PCSYMCRYPT_HASH pHash = SymCryptSha256Algorithm;
|
|
|
|
//
|
|
// Test varying Winternitz lengths with custom tree heights
|
|
//
|
|
for (UINT8 w = 1; w <= 8; w <<= 1)
|
|
{
|
|
for (UINT8 h = 1; h <= 4; h++)
|
|
{
|
|
ScDispatchSymCryptWipe(¶ms, sizeof(SYMCRYPT_XMSS_PARAMS));
|
|
|
|
scError = ScDispatchSymCryptXmssSetParams(
|
|
¶ms,
|
|
0, // alg id
|
|
pHash, // hash alg.
|
|
(UINT8)pHash->resultSize, // n
|
|
w, // w
|
|
h, // h
|
|
(UINT8)1, // d
|
|
(UINT8)pHash->resultSize); // cbPrefix
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
pKey = ScDispatchSymCryptXmsskeyAllocate(¶ms, 0);
|
|
CHECK(pKey != nullptr, "?");
|
|
|
|
scError = ScDispatchSymCryptXmsskeyGenerate(pKey, 0);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
cbSignature = ScDispatchSymCryptXmssSizeofSignatureFromParams(¶ms);
|
|
pbSignature = new BYTE[cbSignature];
|
|
CHECK(pbSignature != nullptr, "?");
|
|
|
|
// Sign and Verify with each WOTSP key
|
|
for (UINT32 idx = 0; idx < (1UL << h); idx++)
|
|
{
|
|
scError = ScDispatchSymCryptXmssSign(pKey, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
scError = ScDispatchSymCryptXmssVerify(pKey, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
// Modify the signature and expect verification failure
|
|
UINT32 nModifyPos = g_rng.uint32() % cbSignature;
|
|
pbSignature[nModifyPos] ^= 1;
|
|
|
|
scError = ScDispatchSymCryptXmssVerify(pKey, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError != SYMCRYPT_NO_ERROR, "?");
|
|
}
|
|
|
|
// All one-time signatures are consumed above, we shouldn't be able to sign anymore
|
|
scError = ScDispatchSymCryptXmssSign(pKey, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError == SYMCRYPT_HBS_NO_OTS_KEYS_LEFT, "?");
|
|
|
|
delete[] pbSignature;
|
|
|
|
ScDispatchSymCryptXmsskeyFree(pKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
testXmssImportExport()
|
|
{
|
|
SYMCRYPT_XMSS_PARAMS params;
|
|
PSYMCRYPT_XMSS_KEY pKeyPrivate;
|
|
PSYMCRYPT_XMSS_KEY pKeyPublic;
|
|
SYMCRYPT_ERROR scError;
|
|
PBYTE pbPrivateKeyBlob;
|
|
PBYTE pbPublicKeyBlob;
|
|
SIZE_T cbPrivateKey;
|
|
SIZE_T cbPublicKey;
|
|
PBYTE pbSignature;
|
|
PBYTE pbSignature2;
|
|
SIZE_T cbSignature;
|
|
BYTE msg[] = { 0x01 };
|
|
|
|
scError = ScDispatchSymCryptXmssParamsFromAlgId(SYMCRYPT_XMSS_SHA2_10_256, ¶ms);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
// Create a private key
|
|
pKeyPrivate = ScDispatchSymCryptXmsskeyAllocate(¶ms, 0);
|
|
CHECK(pKeyPrivate != nullptr, "?");
|
|
scError = ScDispatchSymCryptXmsskeyGenerate(pKeyPrivate, 0);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
scError = ScDispatchSymCryptXmssSizeofKeyBlobFromParams(¶ms, SYMCRYPT_XMSSKEY_TYPE_PUBLIC, &cbPublicKey);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
scError = ScDispatchSymCryptXmssSizeofKeyBlobFromParams(¶ms, SYMCRYPT_XMSSKEY_TYPE_PRIVATE, &cbPrivateKey);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
// Export private key
|
|
pbPrivateKeyBlob = new BYTE[cbPrivateKey];
|
|
CHECK(pbPrivateKeyBlob != nullptr, "?");
|
|
scError = ScDispatchSymCryptXmsskeyGetValue(pKeyPrivate, SYMCRYPT_XMSSKEY_TYPE_PRIVATE, 0, pbPrivateKeyBlob, cbPrivateKey);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
// Export public key
|
|
pbPublicKeyBlob = new BYTE[cbPublicKey];
|
|
CHECK(pbPublicKeyBlob != nullptr, "?");
|
|
scError = ScDispatchSymCryptXmsskeyGetValue(pKeyPrivate, SYMCRYPT_XMSSKEY_TYPE_PUBLIC, 0, pbPublicKeyBlob, cbPublicKey);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
// Sign and verify a message
|
|
cbSignature = ScDispatchSymCryptXmssSizeofSignatureFromParams(¶ms);
|
|
pbSignature = new BYTE[cbSignature];
|
|
CHECK(pbSignature != nullptr, "?");
|
|
|
|
scError = ScDispatchSymCryptXmssSign(pKeyPrivate, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
scError = ScDispatchSymCryptXmssVerify(pKeyPrivate, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
// Done with the original private key
|
|
ScDispatchSymCryptXmsskeyFree(pKeyPrivate);
|
|
|
|
// Import the private key from the key blob
|
|
pKeyPrivate = ScDispatchSymCryptXmsskeyAllocate(¶ms, 0);
|
|
CHECK(pKeyPrivate != nullptr, "?");
|
|
scError = ScDispatchSymCryptXmsskeySetValue(pbPrivateKeyBlob, cbPrivateKey, SYMCRYPT_XMSSKEY_TYPE_PRIVATE, 0, pKeyPrivate);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
// Sign the message again with the imported private key and check if the same signature is produced
|
|
pbSignature2 = new BYTE[cbSignature];
|
|
CHECK(pbSignature2 != nullptr, "?");
|
|
|
|
scError = ScDispatchSymCryptXmssSign(pKeyPrivate, msg, sizeof(msg), 0, pbSignature2, cbSignature);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
CHECK(memcmp(pbSignature, pbSignature2, cbSignature) == 0, "?");
|
|
|
|
ScDispatchSymCryptXmsskeyFree(pKeyPrivate);
|
|
|
|
// Import the public key and verify the signature
|
|
pKeyPublic = ScDispatchSymCryptXmsskeyAllocate(¶ms, 0);
|
|
CHECK(pKeyPublic != nullptr, "?");
|
|
scError = ScDispatchSymCryptXmsskeySetValue(pbPublicKeyBlob, cbPublicKey, SYMCRYPT_XMSSKEY_TYPE_PUBLIC, 0, pKeyPublic);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
scError = ScDispatchSymCryptXmssVerify(pKeyPublic, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
ScDispatchSymCryptXmsskeyFree(pKeyPublic);
|
|
|
|
delete[] pbSignature2;
|
|
delete[] pbSignature;
|
|
delete[] pbPublicKeyBlob;
|
|
delete[] pbPrivateKeyBlob;
|
|
}
|
|
|
|
|
|
VOID
|
|
testXmssMultitree()
|
|
{
|
|
SYMCRYPT_XMSS_PARAMS params;
|
|
PSYMCRYPT_XMSS_KEY pKey;
|
|
PBYTE pbSignature;
|
|
SYMCRYPT_ERROR scError;
|
|
SIZE_T cbSignature;
|
|
BYTE msg[] = { 0x00, 0x01, 0x03, 0x04 };
|
|
PCSYMCRYPT_HASH pHash = SymCryptSha256Algorithm;
|
|
const UINT8 H = 6;
|
|
const UINT8 LayerHeights[] = { 1, 2, 3 };
|
|
|
|
//
|
|
// Total tree height is 6
|
|
//
|
|
// Test all possible layer heights 1, 2, 3, corresponding to
|
|
// number of layers 6, 3, 2.
|
|
//
|
|
|
|
for (UINT32 i = 0; i < sizeof(LayerHeights); i++)
|
|
{
|
|
scError = ScDispatchSymCryptXmssSetParams(
|
|
¶ms,
|
|
0,
|
|
pHash,
|
|
(UINT8)pHash->resultSize,
|
|
(UINT8)4,
|
|
H,
|
|
(UINT8)(H / LayerHeights[i]),
|
|
(UINT8)pHash->resultSize);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
pKey = ScDispatchSymCryptXmsskeyAllocate(¶ms, 0);
|
|
CHECK(pKey != nullptr, "?");
|
|
|
|
scError = ScDispatchSymCryptXmsskeyGenerate(pKey, 0);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
cbSignature = ScDispatchSymCryptXmssSizeofSignatureFromParams(¶ms);
|
|
pbSignature = new BYTE[cbSignature];
|
|
CHECK(pbSignature != nullptr, "?");
|
|
|
|
// Sign and Verify with each WOTSP key
|
|
for (UINT32 idx = 0; idx < (1UL << H); idx++)
|
|
{
|
|
scError = ScDispatchSymCryptXmssSign(pKey, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
scError = ScDispatchSymCryptXmssVerify(pKey, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError == SYMCRYPT_NO_ERROR, "?");
|
|
|
|
// Modify the signature and expect verification failure
|
|
UINT32 nModifyPos = g_rng.uint32() % cbSignature;
|
|
pbSignature[nModifyPos] ^= 1;
|
|
|
|
scError = ScDispatchSymCryptXmssVerify(pKey, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError != SYMCRYPT_NO_ERROR, "?");
|
|
}
|
|
|
|
// All one-time signatures are consumed above, we shouldn't be able to sign anymore
|
|
scError = ScDispatchSymCryptXmssSign(pKey, msg, sizeof(msg), 0, pbSignature, cbSignature);
|
|
CHECK(scError == SYMCRYPT_HBS_NO_OTS_KEYS_LEFT , "?");
|
|
|
|
ScDispatchSymCryptXmsskeyFree(pKey);
|
|
|
|
delete[] pbSignature;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
testXmss()
|
|
{
|
|
testWinternitzLengths();
|
|
|
|
testXmssCustomParameters();
|
|
|
|
testXmssMultitree();
|
|
|
|
testXmssImportExport();
|
|
}
|
|
|
|
|
|
VOID
|
|
testHbs()
|
|
{
|
|
INT64 nOutstandingAllocs = 0;
|
|
|
|
testXmss();
|
|
|
|
nOutstandingAllocs = SYMCRYPT_INTERNAL_VOLATILE_READ64(&g_nOutstandingCheckedAllocs);
|
|
CHECK3( nOutstandingAllocs == 0, "Memory leak %d outstanding", nOutstandingAllocs );
|
|
|
|
testHbsKats();
|
|
|
|
nOutstandingAllocs = SYMCRYPT_INTERNAL_VOLATILE_READ64(&g_nOutstandingCheckedAllocs);
|
|
CHECK3( nOutstandingAllocs == 0, "Memory leak %d outstanding", nOutstandingAllocs );
|
|
} |