|
|
// fipsalgt.cpp - written and placed in the public domain by Wei Dai
// This file implements the various algorithm tests needed to pass FIPS 140 validation.
// They're preserved here (commented out) in case Crypto++ needs to be revalidated.
#if 0
#ifndef CRYPTOPP_IMPORTS
#define CRYPTOPP_DEFAULT_NO_DLL
#endif
#include "dll.h"
#include "oids.h"
USING_NAMESPACE(CryptoPP) USING_NAMESPACE(std)
class LineBreakParser : public AutoSignaling<Bufferless<Filter> > { public: LineBreakParser(BufferedTransformation *attachment=NULL, byte lineEnd='\n') : m_lineEnd(lineEnd) {Detach(attachment);}
size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking) { if (!blocking) throw BlockingInputOnly("LineBreakParser"); unsigned int i, last = 0; for (i=0; i<length; i++) { if (begin[i] == m_lineEnd) { AttachedTransformation()->Put2(begin+last, i-last, GetAutoSignalPropagation(), blocking); last = i+1; } } if (last != i) AttachedTransformation()->Put2(begin+last, i-last, 0, blocking);
if (messageEnd && GetAutoSignalPropagation()) { AttachedTransformation()->MessageEnd(GetAutoSignalPropagation()-1, blocking); AttachedTransformation()->MessageSeriesEnd(GetAutoSignalPropagation()-1, blocking); }
return 0; }
private: byte m_lineEnd; };
class TestDataParser : public Unflushable<FilterWithInputQueue> { public: enum DataType {OTHER, COUNT, KEY_T, IV, INPUT, OUTPUT};
TestDataParser(std::string algorithm, std::string test, std::string mode, unsigned int feedbackSize, bool encrypt, BufferedTransformation *attachment) : m_algorithm(algorithm), m_test(test), m_mode(mode), m_feedbackSize(feedbackSize) , m_firstLine(true), m_blankLineTransition(0) { Detach(attachment);
m_typeToName[COUNT] = "COUNT";
m_nameToType["COUNT"] = COUNT; m_nameToType["KEY"] = KEY_T; m_nameToType["KEYs"] = KEY_T; m_nameToType["key"] = KEY_T; m_nameToType["Key"] = KEY_T; m_nameToType["IV"] = IV; m_nameToType["IV1"] = IV; m_nameToType["CV"] = IV; m_nameToType["CV1"] = IV; m_nameToType["IB"] = IV; m_nameToType["TEXT"] = INPUT; m_nameToType["RESULT"] = OUTPUT; m_nameToType["Msg"] = INPUT; m_nameToType["Seed"] = INPUT; m_nameToType["V"] = INPUT; m_nameToType["DT"] = IV; SetEncrypt(encrypt);
if (m_algorithm == "DSA" || m_algorithm == "ECDSA") { if (m_test == "PKV") m_trigger = "Qy"; else if (m_test == "KeyPair") m_trigger = "N"; else if (m_test == "SigGen") m_trigger = "Msg"; else if (m_test == "SigVer") m_trigger = "S"; else if (m_test == "PQGGen") m_trigger = "N"; else if (m_test == "PQGVer") m_trigger = "H"; } else if (m_algorithm == "HMAC") m_trigger = "Msg"; else if (m_algorithm == "SHA") m_trigger = (m_test == "MONTE") ? "Seed" : "Msg"; else if (m_algorithm == "RNG") m_trigger = "V"; else if (m_algorithm == "RSA") m_trigger = (m_test == "Ver") ? "S" : "Msg"; }
void SetEncrypt(bool encrypt) { m_encrypt = encrypt; if (encrypt) { m_nameToType["PLAINTEXT"] = INPUT; m_nameToType["CIPHERTEXT"] = OUTPUT; m_nameToType["PT"] = INPUT; m_nameToType["CT"] = OUTPUT; } else { m_nameToType["PLAINTEXT"] = OUTPUT; m_nameToType["CIPHERTEXT"] = INPUT; m_nameToType["PT"] = OUTPUT; m_nameToType["CT"] = INPUT; }
if (m_algorithm == "AES" || m_algorithm == "TDES") { if (encrypt) { m_trigger = "PLAINTEXT"; m_typeToName[OUTPUT] = "CIPHERTEXT"; } else { m_trigger = "CIPHERTEXT"; m_typeToName[OUTPUT] = "PLAINTEXT"; } m_count = 0; } }
protected: void OutputData(std::string &output, const std::string &key, const std::string &data) { output += key; output += "= "; output += data; output += "\n"; }
void OutputData(std::string &output, const std::string &key, int data) { OutputData(output, key, IntToString(data)); }
void OutputData(std::string &output, const std::string &key, const SecByteBlock &data) { output += key; output += "= "; HexEncoder(new StringSink(output), false).Put(data, data.size()); output += "\n"; }
void OutputData(std::string &output, const std::string &key, const Integer &data, int size=-1) { SecByteBlock s(size < 0 ? data.MinEncodedSize() : size); data.Encode(s, s.size()); OutputData(output, key, s); }
void OutputData(std::string &output, const std::string &key, const PolynomialMod2 &data, int size=-1) { SecByteBlock s(size < 0 ? data.MinEncodedSize() : size); data.Encode(s, s.size()); OutputData(output, key, s); }
void OutputData(std::string &output, DataType t, const std::string &data) { if (m_algorithm == "SKIPJACK") { if (m_test == "KAT") { if (t == OUTPUT) output = m_line + data + "\n"; } else { if (t != COUNT) { output += m_typeToName[t]; output += "="; } output += data; output += t == OUTPUT ? "\n" : " "; } } else if (m_algorithm == "TDES" && t == KEY_T && m_typeToName[KEY_T].empty()) { output += "KEY1 = "; output += data.substr(0, 16); output += "\nKEY2 = "; output += data.size() > 16 ? data.substr(16, 16) : data.substr(0, 16); output += "\nKEY3 = "; output += data.size() > 32 ? data.substr(32, 16) : data.substr(0, 16); output += "\n"; } else { output += m_typeToName[t]; output += " = "; output += data; output += "\n"; } }
void OutputData(std::string &output, DataType t, int i) { OutputData(output, t, IntToString(i)); }
void OutputData(std::string &output, DataType t, const SecByteBlock &data) { std::string hexData; StringSource(data.begin(), data.size(), true, new HexEncoder(new StringSink(hexData), false)); OutputData(output, t, hexData); }
void OutputGivenData(std::string &output, DataType t, bool optional = false) { if (m_data.find(m_typeToName[t]) == m_data.end()) { if (optional) return; throw Exception(Exception::OTHER_ERROR, "TestDataParser: key not found: " + m_typeToName[t]); }
OutputData(output, t, m_data[m_typeToName[t]]); }
template <class T> BlockCipher * NewBT(T *) { if (!m_encrypt && (m_mode == "ECB" || m_mode == "CBC")) return new typename T::Decryption; else return new typename T::Encryption; }
template <class T> SymmetricCipher * NewMode(T *, BlockCipher &bt, const byte *iv) { if (!m_encrypt) return new typename T::Decryption(bt, iv, m_feedbackSize/8); else return new typename T::Encryption(bt, iv, m_feedbackSize/8); }
static inline void Xor(SecByteBlock &z, const SecByteBlock &x, const SecByteBlock &y) { assert(x.size() == y.size()); z.resize(x.size()); xorbuf(z, x, y, x.size()); }
SecByteBlock UpdateKey(SecByteBlock key, const SecByteBlock *text) { unsigned int innerCount = (m_algorithm == "AES") ? 1000 : 10000; int keySize = key.size(), blockSize = text[0].size(); SecByteBlock x(keySize); for (int k=0; k<keySize;) { int pos = innerCount * blockSize - keySize + k; memcpy(x + k, text[pos / blockSize] + pos % blockSize, blockSize - pos % blockSize); k += blockSize - pos % blockSize; }
if (m_algorithm == "TDES" || m_algorithm == "DES") { for (int i=0; i<keySize; i+=8) { xorbuf(key+i, x+keySize-8-i, 8); DES::CorrectKeyParityBits(key+i); } } else xorbuf(key, x, keySize);
return key; }
static inline void AssignLeftMostBits(SecByteBlock &z, const SecByteBlock &x, unsigned int K) { z.Assign(x, K/8); }
template <class EC> void EC_KeyPair(string &output, int n, const OID &oid) { DL_GroupParameters_EC<EC> params(oid); for (int i=0; i<n; i++) { DL_PrivateKey_EC<EC> priv; DL_PublicKey_EC<EC> pub; priv.Initialize(m_rng, params); priv.MakePublicKey(pub);
OutputData(output, "d ", priv.GetPrivateExponent()); OutputData(output, "Qx ", pub.GetPublicElement().x, params.GetCurve().GetField().MaxElementByteLength()); OutputData(output, "Qy ", pub.GetPublicElement().y, params.GetCurve().GetField().MaxElementByteLength()); } }
template <class EC> void EC_SigGen(string &output, const OID &oid) { DL_GroupParameters_EC<EC> params(oid); typename ECDSA<EC, SHA1>::PrivateKey priv; typename ECDSA<EC, SHA1>::PublicKey pub; priv.Initialize(m_rng, params); priv.MakePublicKey(pub);
typename ECDSA<EC, SHA1>::Signer signer(priv); SecByteBlock sig(signer.SignatureLength()); StringSource(m_data["Msg"], true, new HexDecoder(new SignerFilter(m_rng, signer, new ArraySink(sig, sig.size())))); SecByteBlock R(sig, sig.size()/2), S(sig+sig.size()/2, sig.size()/2);
OutputData(output, "Qx ", pub.GetPublicElement().x, params.GetCurve().GetField().MaxElementByteLength()); OutputData(output, "Qy ", pub.GetPublicElement().y, params.GetCurve().GetField().MaxElementByteLength()); OutputData(output, "R ", R); OutputData(output, "S ", S); }
template <class EC> void EC_SigVer(string &output, const OID &oid) { SecByteBlock x(DecodeHex(m_data["Qx"])); SecByteBlock y(DecodeHex(m_data["Qy"])); Integer r((m_data["R"]+"h").c_str()); Integer s((m_data["S"]+"h").c_str());
typename EC::FieldElement Qx(x, x.size()); typename EC::FieldElement Qy(y, y.size()); typename EC::Element Q(Qx, Qy);
DL_GroupParameters_EC<EC> params(oid); typename ECDSA<EC, SHA1>::PublicKey pub; pub.Initialize(params, Q); typename ECDSA<EC, SHA1>::Verifier verifier(pub);
SecByteBlock sig(verifier.SignatureLength()); r.Encode(sig, sig.size()/2); s.Encode(sig+sig.size()/2, sig.size()/2);
SignatureVerificationFilter filter(verifier); filter.Put(sig, sig.size()); StringSource(m_data["Msg"], true, new HexDecoder(new Redirector(filter, Redirector::DATA_ONLY))); filter.MessageEnd(); byte b; filter.Get(b); OutputData(output, "Result ", b ? "P" : "F"); }
template <class EC> static bool EC_PKV(RandomNumberGenerator &rng, const SecByteBlock &x, const SecByteBlock &y, const OID &oid) { typename EC::FieldElement Qx(x, x.size()); typename EC::FieldElement Qy(y, y.size()); typename EC::Element Q(Qx, Qy);
DL_GroupParameters_EC<EC> params(oid); typename ECDSA<EC, SHA1>::PublicKey pub; pub.Initialize(params, Q); return pub.Validate(rng, 3); }
template <class H, class Result> Result * CreateRSA2(const std::string &standard) { if (typeid(Result) == typeid(PK_Verifier)) { if (standard == "R") return (Result *) new typename RSASS_ISO<H>::Verifier; else if (standard == "P") return (Result *) new typename RSASS<PSS, H>::Verifier; else if (standard == "1") return (Result *) new typename RSASS<PKCS1v15, H>::Verifier; } else if (typeid(Result) == typeid(PK_Signer)) { if (standard == "R") return (Result *) new typename RSASS_ISO<H>::Signer; else if (standard == "P") return (Result *) new typename RSASS<PSS, H>::Signer; else if (standard == "1") return (Result *) new typename RSASS<PKCS1v15, H>::Signer; }
return NULL; }
template <class Result> Result * CreateRSA(const std::string &standard, const std::string &hash) { if (hash == "1") return CreateRSA2<SHA1, Result>(standard); else if (hash == "224") return CreateRSA2<SHA224, Result>(standard); else if (hash == "256") return CreateRSA2<SHA256, Result>(standard); else if (hash == "384") return CreateRSA2<SHA384, Result>(standard); else if (hash == "512") return CreateRSA2<SHA512, Result>(standard); else return NULL; }
virtual void DoTest() { std::string output;
if (m_algorithm == "DSA") { if (m_test == "KeyPair") { DL_GroupParameters_DSA pqg; int modLen = atol(m_bracketString.substr(6).c_str()); pqg.GenerateRandomWithKeySize(m_rng, modLen);
OutputData(output, "P ", pqg.GetModulus()); OutputData(output, "Q ", pqg.GetSubgroupOrder()); OutputData(output, "G ", pqg.GetSubgroupGenerator());
int n = atol(m_data["N"].c_str()); for (int i=0; i<n; i++) { DSA::Signer priv; priv.AccessKey().GenerateRandom(m_rng, pqg); DSA::Verifier pub(priv);
OutputData(output, "X ", priv.GetKey().GetPrivateExponent()); OutputData(output, "Y ", pub.GetKey().GetPublicElement()); AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); } } else if (m_test == "PQGGen") { int n = atol(m_data["N"].c_str()); for (int i=0; i<n; i++) { Integer p, q, h, g; int counter; SecByteBlock seed(SHA::DIGESTSIZE); do { m_rng.GenerateBlock(seed, seed.size()); } while (!DSA::GeneratePrimes(seed, seed.size()*8, counter, p, 1024, q)); h.Randomize(m_rng, 2, p-2); g = a_exp_b_mod_c(h, (p-1)/q, p);
OutputData(output, "P ", p); OutputData(output, "Q ", q); OutputData(output, "G ", g); OutputData(output, "Seed ", seed); OutputData(output, "c ", counter); OutputData(output, "H ", h, p.ByteCount()); AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); } } else if (m_test == "SigGen") { std::string &encodedKey = m_data["PrivKey"]; int modLen = atol(m_bracketString.substr(6).c_str()); DSA::PrivateKey priv;
if (!encodedKey.empty()) { StringStore s(encodedKey); priv.BERDecode(s); if (priv.GetGroupParameters().GetModulus().BitCount() != modLen) encodedKey.clear(); }
if (encodedKey.empty()) { priv.Initialize(m_rng, modLen); StringSink s(encodedKey); priv.DEREncode(s); OutputData(output, "P ", priv.GetGroupParameters().GetModulus()); OutputData(output, "Q ", priv.GetGroupParameters().GetSubgroupOrder()); OutputData(output, "G ", priv.GetGroupParameters().GetSubgroupGenerator()); }
DSA::Signer signer(priv); DSA::Verifier pub(signer); OutputData(output, "Msg ", m_data["Msg"]); OutputData(output, "Y ", pub.GetKey().GetPublicElement());
SecByteBlock sig(signer.SignatureLength()); StringSource(m_data["Msg"], true, new HexDecoder(new SignerFilter(m_rng, signer, new ArraySink(sig, sig.size())))); SecByteBlock R(sig, sig.size()/2), S(sig+sig.size()/2, sig.size()/2); OutputData(output, "R ", R); OutputData(output, "S ", S); AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); } else if (m_test == "SigVer") { Integer p((m_data["P"] + "h").c_str()); Integer q((m_data["Q"] + "h").c_str()); Integer g((m_data["G"] + "h").c_str()); Integer y((m_data["Y"] + "h").c_str()); DSA::Verifier verifier(p, q, g, y);
HexDecoder filter(new SignatureVerificationFilter(verifier)); StringSource(m_data["R"], true, new Redirector(filter, Redirector::DATA_ONLY)); StringSource(m_data["S"], true, new Redirector(filter, Redirector::DATA_ONLY)); StringSource(m_data["Msg"], true, new Redirector(filter, Redirector::DATA_ONLY)); filter.MessageEnd(); byte b; filter.Get(b); OutputData(output, "Result ", b ? "P" : "F"); AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); } else if (m_test == "PQGVer") { Integer p((m_data["P"] + "h").c_str()); Integer q((m_data["Q"] + "h").c_str()); Integer g((m_data["G"] + "h").c_str()); Integer h((m_data["H"] + "h").c_str()); int c = atol(m_data["c"].c_str()); SecByteBlock seed(m_data["Seed"].size()/2); StringSource(m_data["Seed"], true, new HexDecoder(new ArraySink(seed, seed.size())));
Integer p1, q1; bool result = DSA::GeneratePrimes(seed, seed.size()*8, c, p1, 1024, q1, true); result = result && (p1 == p && q1 == q); result = result && g == a_exp_b_mod_c(h, (p-1)/q, p);
OutputData(output, "Result ", result ? "P" : "F"); AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); }
return; }
if (m_algorithm == "ECDSA") { std::map<std::string, OID> name2oid; name2oid["P-192"] = ASN1::secp192r1(); name2oid["P-224"] = ASN1::secp224r1(); name2oid["P-256"] = ASN1::secp256r1(); name2oid["P-384"] = ASN1::secp384r1(); name2oid["P-521"] = ASN1::secp521r1(); name2oid["K-163"] = ASN1::sect163k1(); name2oid["K-233"] = ASN1::sect233k1(); name2oid["K-283"] = ASN1::sect283k1(); name2oid["K-409"] = ASN1::sect409k1(); name2oid["K-571"] = ASN1::sect571k1(); name2oid["B-163"] = ASN1::sect163r2(); name2oid["B-233"] = ASN1::sect233r1(); name2oid["B-283"] = ASN1::sect283r1(); name2oid["B-409"] = ASN1::sect409r1(); name2oid["B-571"] = ASN1::sect571r1();
if (m_test == "PKV") { bool pass; if (m_bracketString[0] == 'P') pass = EC_PKV<ECP>(m_rng, DecodeHex(m_data["Qx"]), DecodeHex(m_data["Qy"]), name2oid[m_bracketString]); else pass = EC_PKV<EC2N>(m_rng, DecodeHex(m_data["Qx"]), DecodeHex(m_data["Qy"]), name2oid[m_bracketString]);
OutputData(output, "Result ", pass ? "P" : "F"); } else if (m_test == "KeyPair") { if (m_bracketString[0] == 'P') EC_KeyPair<ECP>(output, atol(m_data["N"].c_str()), name2oid[m_bracketString]); else EC_KeyPair<EC2N>(output, atol(m_data["N"].c_str()), name2oid[m_bracketString]); } else if (m_test == "SigGen") { if (m_bracketString[0] == 'P') EC_SigGen<ECP>(output, name2oid[m_bracketString]); else EC_SigGen<EC2N>(output, name2oid[m_bracketString]); } else if (m_test == "SigVer") { if (m_bracketString[0] == 'P') EC_SigVer<ECP>(output, name2oid[m_bracketString]); else EC_SigVer<EC2N>(output, name2oid[m_bracketString]); }
AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); return; }
if (m_algorithm == "RSA") { std::string shaAlg = m_data["SHAAlg"].substr(3);
if (m_test == "Ver") { Integer n((m_data["n"] + "h").c_str()); Integer e((m_data["e"] + "h").c_str()); RSA::PublicKey pub; pub.Initialize(n, e);
member_ptr<PK_Verifier> pV(CreateRSA<PK_Verifier>(m_mode, shaAlg)); pV->AccessMaterial().AssignFrom(pub);
HexDecoder filter(new SignatureVerificationFilter(*pV)); for (unsigned int i=m_data["S"].size(); i<pV->SignatureLength()*2; i++) filter.Put('0'); StringSource(m_data["S"], true, new Redirector(filter, Redirector::DATA_ONLY)); StringSource(m_data["Msg"], true, new Redirector(filter, Redirector::DATA_ONLY)); filter.MessageEnd(); byte b; filter.Get(b); OutputData(output, "Result ", b ? "P" : "F"); } else { assert(m_test == "Gen"); int modLen = atol(m_bracketString.substr(6).c_str()); std::string &encodedKey = m_data["PrivKey"]; RSA::PrivateKey priv;
if (!encodedKey.empty()) { StringStore s(encodedKey); priv.BERDecode(s); if (priv.GetModulus().BitCount() != modLen) encodedKey.clear(); }
if (encodedKey.empty()) { priv.Initialize(m_rng, modLen); StringSink s(encodedKey); priv.DEREncode(s); OutputData(output, "n ", priv.GetModulus()); OutputData(output, "e ", priv.GetPublicExponent(), modLen/8); }
member_ptr<PK_Signer> pS(CreateRSA<PK_Signer>(m_mode, shaAlg)); pS->AccessMaterial().AssignFrom(priv);
SecByteBlock sig(pS->SignatureLength()); StringSource(m_data["Msg"], true, new HexDecoder(new SignerFilter(m_rng, *pS, new ArraySink(sig, sig.size())))); OutputData(output, "SHAAlg ", m_data["SHAAlg"]); OutputData(output, "Msg ", m_data["Msg"]); OutputData(output, "S ", sig); }
AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); return; }
if (m_algorithm == "SHA") { member_ptr<HashFunction> pHF;
if (m_mode == "1") pHF.reset(new SHA1); else if (m_mode == "224") pHF.reset(new SHA224); else if (m_mode == "256") pHF.reset(new SHA256); else if (m_mode == "384") pHF.reset(new SHA384); else if (m_mode == "512") pHF.reset(new SHA512);
if (m_test == "MONTE") { SecByteBlock seed = m_data2[INPUT]; SecByteBlock MD[1003]; int i,j;
for (j=0; j<100; j++) { MD[0] = MD[1] = MD[2] = seed; for (i=3; i<1003; i++) { SecByteBlock Mi = MD[i-3] + MD[i-2] + MD[i-1]; MD[i].resize(pHF->DigestSize()); pHF->CalculateDigest(MD[i], Mi, Mi.size()); } seed = MD[1002]; OutputData(output, "COUNT ", j); OutputData(output, "MD ", seed); AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); } } else { SecByteBlock tag(pHF->DigestSize()); SecByteBlock &msg(m_data2[INPUT]); int len = atol(m_data["Len"].c_str()); StringSource(msg.begin(), len/8, true, new HashFilter(*pHF, new ArraySink(tag, tag.size()))); OutputData(output, "MD ", tag); AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); } return; }
SecByteBlock &key = m_data2[KEY_T];
if (m_algorithm == "TDES") { if (!m_data["KEY1"].empty()) { const std::string keys[3] = {m_data["KEY1"], m_data["KEY2"], m_data["KEY3"]}; key.resize(24); HexDecoder hexDec(new ArraySink(key, key.size())); for (int i=0; i<3; i++) hexDec.Put((byte *)keys[i].data(), keys[i].size());
if (keys[0] == keys[2]) { if (keys[0] == keys[1]) key.resize(8); else key.resize(16); } else key.resize(24); } }
if (m_algorithm == "RNG") { key.resize(24); StringSource(m_data["Key1"] + m_data["Key2"] + m_data["Key3"], true, new HexDecoder(new ArraySink(key, key.size())));
SecByteBlock seed(m_data2[INPUT]), dt(m_data2[IV]), r(8); X917RNG rng(new DES_EDE3::Encryption(key, key.size()), seed, dt);
if (m_test == "MCT") { for (int i=0; i<10000; i++) rng.GenerateBlock(r, r.size()); } else { rng.GenerateBlock(r, r.size()); }
OutputData(output, "R ", r); AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); return; }
if (m_algorithm == "HMAC") { member_ptr<MessageAuthenticationCode> pMAC;
if (m_bracketString == "L=20") pMAC.reset(new HMAC<SHA1>); else if (m_bracketString == "L=28") pMAC.reset(new HMAC<SHA224>); else if (m_bracketString == "L=32") pMAC.reset(new HMAC<SHA256>); else if (m_bracketString == "L=48") pMAC.reset(new HMAC<SHA384>); else if (m_bracketString == "L=64") pMAC.reset(new HMAC<SHA512>); else throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected HMAC bracket string: " + m_bracketString);
pMAC->SetKey(key, key.size()); int Tlen = atol(m_data["Tlen"].c_str()); SecByteBlock tag(Tlen); StringSource(m_data["Msg"], true, new HexDecoder(new HashFilter(*pMAC, new ArraySink(tag, Tlen), false, Tlen))); OutputData(output, "Mac ", tag); AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); return; }
member_ptr<BlockCipher> pBT; if (m_algorithm == "DES") pBT.reset(NewBT((DES*)0)); else if (m_algorithm == "TDES") { if (key.size() == 8) pBT.reset(NewBT((DES*)0)); else if (key.size() == 16) pBT.reset(NewBT((DES_EDE2*)0)); else pBT.reset(NewBT((DES_EDE3*)0)); } else if (m_algorithm == "SKIPJACK") pBT.reset(NewBT((SKIPJACK*)0)); else if (m_algorithm == "AES") pBT.reset(NewBT((AES*)0)); else throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected algorithm: " + m_algorithm);
if (!pBT->IsValidKeyLength(key.size())) key.CleanNew(pBT->DefaultKeyLength()); // for Scbcvrct
pBT->SetKey(key.data(), key.size());
SecByteBlock &iv = m_data2[IV]; if (iv.empty()) iv.CleanNew(pBT->BlockSize());
member_ptr<SymmetricCipher> pCipher; unsigned int K = m_feedbackSize;
if (m_mode == "ECB") pCipher.reset(NewMode((ECB_Mode_ExternalCipher*)0, *pBT, iv)); else if (m_mode == "CBC") pCipher.reset(NewMode((CBC_Mode_ExternalCipher*)0, *pBT, iv)); else if (m_mode == "CFB") pCipher.reset(NewMode((CFB_Mode_ExternalCipher*)0, *pBT, iv)); else if (m_mode == "OFB") pCipher.reset(NewMode((OFB_Mode_ExternalCipher*)0, *pBT, iv)); else throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected mode: " + m_mode);
bool encrypt = m_encrypt;
if (m_test == "MONTE") { SecByteBlock KEY[401]; KEY[0] = key; int keySize = key.size(); int blockSize = pBT->BlockSize();
std::vector<SecByteBlock> IB(10001), OB(10001), PT(10001), CT(10001), RESULT(10001), TXT(10001), CV(10001); PT[0] = GetData("PLAINTEXT"); CT[0] = GetData("CIPHERTEXT"); CV[0] = IB[0] = iv; TXT[0] = GetData("TEXT");
int outerCount = (m_algorithm == "AES") ? 100 : 400; int innerCount = (m_algorithm == "AES") ? 1000 : 10000;
for (int i=0; i<outerCount; i++) { pBT->SetKey(KEY[i], keySize);
for (int j=0; j<innerCount; j++) { if (m_mode == "ECB") { if (encrypt) { IB[j] = PT[j]; CT[j].resize(blockSize); pBT->ProcessBlock(IB[j], CT[j]); PT[j+1] = CT[j]; } else { IB[j] = CT[j]; PT[j].resize(blockSize); pBT->ProcessBlock(IB[j], PT[j]); CT[j+1] = PT[j]; } } else if (m_mode == "OFB") { OB[j].resize(blockSize); pBT->ProcessBlock(IB[j], OB[j]); Xor(RESULT[j], OB[j], TXT[j]); TXT[j+1] = IB[j]; IB[j+1] = OB[j]; } else if (m_mode == "CBC") { if (encrypt) { Xor(IB[j], PT[j], CV[j]); CT[j].resize(blockSize); pBT->ProcessBlock(IB[j], CT[j]); PT[j+1] = CV[j]; CV[j+1] = CT[j]; } else { IB[j] = CT[j]; OB[j].resize(blockSize); pBT->ProcessBlock(IB[j], OB[j]); Xor(PT[j], OB[j], CV[j]); CV[j+1] = CT[j]; CT[j+1] = PT[j]; } } else if (m_mode == "CFB") { if (encrypt) { OB[j].resize(blockSize); pBT->ProcessBlock(IB[j], OB[j]); AssignLeftMostBits(CT[j], OB[j], K); Xor(CT[j], CT[j], PT[j]); AssignLeftMostBits(PT[j+1], IB[j], K); IB[j+1].resize(blockSize); memcpy(IB[j+1], IB[j]+K/8, blockSize-K/8); memcpy(IB[j+1]+blockSize-K/8, CT[j], K/8); } else { OB[j].resize(blockSize); pBT->ProcessBlock(IB[j], OB[j]); AssignLeftMostBits(PT[j], OB[j], K); Xor(PT[j], PT[j], CT[j]); IB[j+1].resize(blockSize); memcpy(IB[j+1], IB[j]+K/8, blockSize-K/8); memcpy(IB[j+1]+blockSize-K/8, CT[j], K/8); AssignLeftMostBits(CT[j+1], OB[j], K); } } else throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected mode: " + m_mode); }
OutputData(output, COUNT, IntToString(i)); OutputData(output, KEY_T, KEY[i]); if (m_mode == "CBC") OutputData(output, IV, CV[0]); if (m_mode == "OFB" || m_mode == "CFB") OutputData(output, IV, IB[0]); if (m_mode == "ECB" || m_mode == "CBC" || m_mode == "CFB") { if (encrypt) { OutputData(output, INPUT, PT[0]); OutputData(output, OUTPUT, CT[innerCount-1]); KEY[i+1] = UpdateKey(KEY[i], &CT[0]); } else { OutputData(output, INPUT, CT[0]); OutputData(output, OUTPUT, PT[innerCount-1]); KEY[i+1] = UpdateKey(KEY[i], &PT[0]); } PT[0] = PT[innerCount]; IB[0] = IB[innerCount]; CV[0] = CV[innerCount]; CT[0] = CT[innerCount]; } else if (m_mode == "OFB") { OutputData(output, INPUT, TXT[0]); OutputData(output, OUTPUT, RESULT[innerCount-1]); KEY[i+1] = UpdateKey(KEY[i], &RESULT[0]); Xor(TXT[0], TXT[0], IB[innerCount-1]); IB[0] = OB[innerCount-1]; } output += "\n"; AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0); } } else if (m_test == "MCT") { SecByteBlock KEY[101]; KEY[0] = key; int keySize = key.size(); int blockSize = pBT->BlockSize();
SecByteBlock ivs[101], inputs[1001], outputs[1001]; ivs[0] = iv; inputs[0] = m_data2[INPUT];
for (int i=0; i<100; i++) { pCipher->SetKey(KEY[i], keySize, MakeParameters(Name::IV(), (const byte *)ivs[i])(Name::FeedbackSize(), (int)K/8, false));
for (int j=0; j<1000; j++) { outputs[j] = inputs[j]; pCipher->ProcessString(outputs[j], outputs[j].size()); if (K==8 && m_mode == "CFB") { if (j<16) inputs[j+1].Assign(ivs[i]+j, 1); else inputs[j+1] = outputs[j-16]; } else if (m_mode == "ECB") inputs[j+1] = outputs[j]; else if (j == 0) inputs[j+1] = ivs[i]; else inputs[j+1] = outputs[j-1]; }
if (m_algorithm == "AES") OutputData(output, COUNT, m_count++); OutputData(output, KEY_T, KEY[i]); if (m_mode != "ECB") OutputData(output, IV, ivs[i]); OutputData(output, INPUT, inputs[0]); OutputData(output, OUTPUT, outputs[999]); output += "\n"; AttachedTransformation()->Put((byte *)output.data(), output.size()); output.resize(0);
KEY[i+1] = UpdateKey(KEY[i], outputs); ivs[i+1].CleanNew(pCipher->IVSize()); ivs[i+1] = UpdateKey(ivs[i+1], outputs); if (K==8 && m_mode == "CFB") inputs[0] = outputs[999-16]; else if (m_mode == "ECB") inputs[0] = outputs[999]; else inputs[0] = outputs[998]; } } else { assert(m_test == "KAT");
SecByteBlock &input = m_data2[INPUT]; SecByteBlock result(input.size()); member_ptr<Filter> pFilter(new StreamTransformationFilter(*pCipher, new ArraySink(result, result.size()), StreamTransformationFilter::NO_PADDING)); StringSource(input.data(), input.size(), true, pFilter.release());
OutputGivenData(output, COUNT, true); OutputData(output, KEY_T, key); OutputGivenData(output, IV, true); OutputGivenData(output, INPUT); OutputData(output, OUTPUT, result); output += "\n"; AttachedTransformation()->Put((byte *)output.data(), output.size()); } }
std::vector<std::string> Tokenize(const std::string &line) { std::vector<std::string> result; std::string s; for (unsigned int i=0; i<line.size(); i++) { if (isalnum(line[i]) || line[i] == '^') s += line[i]; else if (!s.empty()) { result.push_back(s); s = ""; } if (line[i] == '=') result.push_back("="); } if (!s.empty()) result.push_back(s); return result; }
bool IsolatedMessageEnd(bool blocking) { if (!blocking) throw BlockingInputOnly("TestDataParser");
m_line.resize(0); m_inQueue.TransferTo(StringSink(m_line).Ref());
if (m_line[0] == '#') return false;
bool copyLine = false;
if (m_line[0] == '[') { m_bracketString = m_line.substr(1, m_line.size()-2); if (m_bracketString == "ENCRYPT") SetEncrypt(true); if (m_bracketString == "DECRYPT") SetEncrypt(false); copyLine = true; }
if (m_line.substr(0, 2) == "H>") { assert(m_test == "sha"); m_bracketString = m_line.substr(2, m_line.size()-4); m_line = m_line.substr(0, 13) + "Hashes<H"; copyLine = true; }
if (m_line == "D>") copyLine = true;
if (m_line == "<D") { m_line += "\n"; copyLine = true; }
if (copyLine) { m_line += '\n'; AttachedTransformation()->Put((byte *)m_line.data(), m_line.size(), blocking); return false; }
std::vector<std::string> tokens = Tokenize(m_line);
if (m_algorithm == "DSA" && m_test == "sha") { for (unsigned int i = 0; i < tokens.size(); i++) { if (tokens[i] == "^") DoTest(); else if (tokens[i] != "") m_compactString.push_back(atol(tokens[i].c_str())); } } else { if (!m_line.empty() && ((m_algorithm == "RSA" && m_test != "Gen") || m_algorithm == "RNG" || m_algorithm == "HMAC" || m_algorithm == "SHA" || (m_algorithm == "ECDSA" && m_test != "KeyPair") || (m_algorithm == "DSA" && (m_test == "PQGVer" || m_test == "SigVer")))) { // copy input to output
std::string output = m_line + '\n'; AttachedTransformation()->Put((byte *)output.data(), output.size()); }
for (unsigned int i = 0; i < tokens.size(); i++) { if (m_firstLine && m_algorithm != "DSA") { if (tokens[i] == "Encrypt" || tokens[i] == "OFB") SetEncrypt(true); else if (tokens[i] == "Decrypt") SetEncrypt(false); else if (tokens[i] == "Modes") m_test = "MONTE"; } else { if (tokens[i] != "=") continue;
if (i == 0) throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected data: " + m_line);
const std::string &key = tokens[i-1]; std::string &data = m_data[key]; data = (tokens.size() > i+1) ? tokens[i+1] : ""; DataType t = m_nameToType[key]; m_typeToName[t] = key; m_data2[t] = DecodeHex(data);
if (key == m_trigger || (t == OUTPUT && !m_data2[INPUT].empty() && !isspace(m_line[0]))) DoTest(); } } }
m_firstLine = false;
return false; }
inline const SecByteBlock & GetData(const std::string &key) { return m_data2[m_nameToType[key]]; }
static SecByteBlock DecodeHex(const std::string &data) { SecByteBlock data2(data.size() / 2); StringSource(data, true, new HexDecoder(new ArraySink(data2, data2.size()))); return data2; }
std::string m_algorithm, m_test, m_mode, m_line, m_bracketString, m_trigger; unsigned int m_feedbackSize, m_blankLineTransition; bool m_encrypt, m_firstLine;
typedef std::map<std::string, DataType> NameToTypeMap; NameToTypeMap m_nameToType; typedef std::map<DataType, std::string> TypeToNameMap; TypeToNameMap m_typeToName;
typedef std::map<std::string, std::string> Map; Map m_data; // raw data
typedef std::map<DataType, SecByteBlock> Map2; Map2 m_data2; int m_count;
AutoSeededX917RNG<AES> m_rng; std::vector<unsigned int> m_compactString; };
int FIPS_140_AlgorithmTest(int argc, char **argv) { argc--; argv++;
std::string algorithm = argv[1]; std::string pathname = argv[2]; unsigned int i = pathname.find_last_of("\\/"); std::string filename = pathname.substr(i == std::string::npos ? 0 : i+1); std::string dirname = pathname.substr(0, i);
if (algorithm == "auto") { string algTable[] = {"AES", "ECDSA", "DSA", "HMAC", "RNG", "RSA", "TDES", "SKIPJACK", "SHA"}; // order is important here
for (i=0; i<sizeof(algTable)/sizeof(algTable[0]); i++) { if (dirname.find(algTable[i]) != std::string::npos) { algorithm = algTable[i]; break; } } }
try { std::string mode; if (algorithm == "SHA") mode = IntToString(atol(filename.substr(3, 3).c_str())); else if (algorithm == "RSA") mode = filename.substr(6, 1); else if (filename[0] == 'S' || filename[0] == 'T') mode = filename.substr(1, 3); else mode = filename.substr(0, 3); for (i = 0; i<mode.size(); i++) mode[i] = toupper(mode[i]); unsigned int feedbackSize = mode == "CFB" ? atoi(filename.substr(filename.find_first_of("0123456789")).c_str()) : 0; std::string test; if (algorithm == "DSA" || algorithm == "ECDSA") test = filename.substr(0, filename.size() - 4); else if (algorithm == "RSA") test = filename.substr(3, 3); else if (filename.find("Monte") != std::string::npos) test = "MONTE"; else if (filename.find("MCT") != std::string::npos) test = "MCT"; else test = "KAT"; bool encrypt = (filename.find("vrct") == std::string::npos);
BufferedTransformation *pSink = NULL;
if (argc > 3) { std::string outDir = argv[3];
if (outDir == "auto") { if (dirname.substr(dirname.size()-3) == "req") outDir = dirname.substr(0, dirname.size()-3) + "resp"; }
if (*outDir.rbegin() != '\\' && *outDir.rbegin() != '/') outDir += '/'; std::string outPathname = outDir + filename.substr(0, filename.size() - 3) + "rsp"; pSink = new FileSink(outPathname.c_str(), false); } else pSink = new FileSink(cout);
FileSource(pathname.c_str(), true, new LineBreakParser(new TestDataParser(algorithm, test, mode, feedbackSize, encrypt, pSink)), false); } catch (...) { cout << "file: " << filename << endl; throw; } return 0; }
extern int (*AdhocTest)(int argc, char *argv[]); static int s_i = (AdhocTest = &FIPS_140_AlgorithmTest, 0); #endif
|