📄 sdsa.cpp
字号:
if (!ok) { // used to say: "Invalid DSA signature" (I keep this for grepping value) xsecurity("The DSA signature does not match"); }}void DSAVerifier::trans(DataBlock &data){ verify(data, data);}// ---------------- DSABrandedPublicKey --------------------DSABrandedPublicKey::DSABrandedPublicKey(DSABrandedPublicKey const &obj) : DSAPublicKey(obj), name(obj.name), brandedKey(obj.brandedKey){} DSABrandedPublicKey::~DSABrandedPublicKey(){}DSABrandedPublicKey::DSABrandedPublicKey( DSASigner &signer, char const *aName, int aVersion) : DSAPublicKey(signer), name(aName), brandedKey(), // start empty version(aVersion){ validateVersion(); // construct a branded key in the 'brandedKey' block if (version == 1) { // format: // [ encoded public key ][ encoded name ][ signature ] signer.DSAPublicKey::encode(brandedKey); appendString(brandedKey, name); signer.trans(brandedKey); } else { xfailure("unknown DSA key version number"); } // append the version number (note that the signature does // *not* include the version number-- this could turn into // a security hole if we are careless with how versions are // defined) appendByte(brandedKey, (byte)version);}// since this is used above, where the version is// supplied by an argument, it's slightly nonideal// to throw xFormat always, but whatevervoid DSABrandedPublicKey::validateVersion(){ checkFormat(1 <= version && version <= MAX_POSSIBLE_VERSION, "DSA public key version is outside legal range."); if (version > CURRENT_KEY_VERSION) { xformat("DSA public key version is unknown"); }}DSABrandedPublicKey::DSABrandedPublicKey(DataBlock const &bkey) : DSAPublicKey(DSAParameters(DSA_512bit_parameters), 1 /*y*/), // dummy public key, at first brandedKey(bkey), version(0){ // we want to map any invalid formatting to an xSecurity since // it is a reasonable conclusion that bad formatting is a // consequence of tampering try { // get version DataBlock stream(bkey); version = removeByte(stream); validateVersion(); if (version == 1) { // extract name and public key checkFormat(stream.getDataLen() >= DSA_SIGNATURE_LENGTH, "Key is too small to contain a DSA signature."); stream.growDataLen(-DSA_SIGNATURE_LENGTH); name = removeString(stream); DSAPublicKey pubKey(stream); // verify signature stream = bkey; stream.growDataLen(-1); // since the version byte is not DSA-signed DSAVerifier ver(pubKey); ver.trans(stream); // this throws an exception when the signature is invalid // since signature matches, assign pubKey's members // to this object's public-key values p = pubKey.getP(); q = pubKey.getQ(); g = pubKey.getG(); y = pubKey.getY(); } else { // this would be a bug; validateVersion should have caught it before here xfailure("validateVersion failed to detect an unknown version"); } } catch (xFormat &x) { xsecurity(stringb("Corrupt branded DSA key: " << x.cond())); }}string DSABrandedPublicKey::getShaString() const{ // compute sha of key DataBlock sha = Sha1(brandedKey); // render it as a hex string int datalen = sha.getDataLen(); string ret(datalen * 3 + 1); for (int i=0; i<datalen; i++) { sprintf(ret.pchar() + i*3, "%02X ", sha.getDataC()[i]); } // trim final space ret[datalen*3] = 0; return ret;}// -------------------- test code -------------------------------#ifdef TEST_SDSA#include "rng.h" // LC_RNG//#include "nbtheory.h" // IsPrime#include "test.h" // USUAL_MAINinline bool IsPrime(Integer const &v) { return probablyPrime(v); }// simple random number generatorLC_RNG rng(1);bool testWithParameters(char const * const params[3]){ bool pass = true; Integer const p(params[0], 10); Integer const q(params[1], 10); Integer const g(params[2], 10); // make up a new private key Integer x, y; { TimedSection ts("keygen"); DSA_keygen( x, y, // new key pair p, q, g, // parameters rng); // randomness } // print what we got //PVAL(p); //PVAL(q); //PVAL(g); PVAL(x); PVAL(y); // verify properties { TimedSection ts("parameter verification"); PVAL(IsPrime(p)); PVAL( ((p-1)/q)*q == p-1 ); PVAL(IsPrime(q)); PVAL(g > 1); PVAL( a_exp_b_mod_c(g, x, p) == y ); } { TimedSection ts("find h"); int h; enum { MAX_H = 6 }; for (h=2; h<=MAX_H; h++) { if (a_exp_b_mod_c(h, (p-1)/q, p) == g) { cout << h << "^((p-1)/q) mod p = g (h = " << h << ")\n"; break; } } if (h > MAX_H) { cout << "couldn't find h (tried 2 through " << (int)MAX_H << ")\n"; } } // sign something (use a value that will be treated as a digest, // rather than going through the hassle of using SHA here) byte const message[] = "abcdefghijklmnopqrst"; // 160 bits Integer const digest(dataBlock2Integer(DataBlock(message, 20))); //Integer const digest(message, 20); // this ctor just uses the raw bits Integer r, s; { TimedSection ts("sign"); DSA_sign(r, s, // signature output p, q, g, // parameters x, // private key digest, // message to sign rng); // for computing k } PVAL(r); PVAL(s); // verify the signature bool ok; { TimedSection ts("verify"); ok = DSA_verify(p, q, g, // parameters y, // public key r, s, // signature digest); // message digest pass &= ok; } cout << "verification: " << ok << endl; // try to verify a false signature { TimedSection ts("false verify"); ok = DSA_verify(p, q, g, y, r, s+1 /*wrong*/, digest); pass &= !ok; } cout << "false verification: " << ok << endl; return pass;} // print a diagnostic saying what we are doing and what the key size isvoid sayWhatDoing(char const *funcname, char const * const *params_array){ int bits = 0; if (params_array == DSA_512bit_parameters) { bits = 512; } else if (params_array == DSA_1024bit_parameters) { bits = 1024; } else { xfailure("unknown params array"); } printf("%s: %d bits\n", funcname, bits);} bool testSignerAndVerifier(DSASigner &signer, DSAVerifier &verifier); bool objectTest(char const * const *params_array){ bool ok = true; sayWhatDoing("object test", params_array); // decode array DSAParameters params(params_array); // generate a new private key, and encode the // keys as a pair of DataBlocks DataBlock pubKeyBlock, privKeyBlock; { DSAPrivateKey keys(params, rng); keys.DSAPublicKey::encode(pubKeyBlock); keys.encode(privKeyBlock); } // create encryption objects from DataBlocks DSASigner signer(privKeyBlock, rng); DSAVerifier verifier(pubKeyBlock); return ok & testSignerAndVerifier(signer, verifier);} bool testSignerAndVerifier(DSASigner &signer, DSAVerifier &verifier){ bool ok = true; // some sample messages to sign DataBlock const arr[] = { DataBlock("abcdefghijkl"), DataBlock("a\0b\0c\0d\0", 8), DataBlock("this is a message to sign") }; loopi(TABLESIZE(arr)) { // sign the block DataBlock block(arr[i]); signer.trans(block); // verify the block try { verifier.trans(block); xassert(block == arr[i]); } catch (xSecurity &x) { cout << x << ":" << endl; arr[i].print("failing block"); ok = false; } // sign it again signer.trans(block); // modify the signature by flipping a bit block.getData()[ block.getDataLen() - 1 ] ^= 0x40; // observe failure to verify try { cout << "Expecting an exception: "; verifier.trans(block); cout << "failed to detect false signature:" << endl; arr[i].print("failing block"); ok = false; } catch (xSecurity &) {} } // test as a general trans/inverse pair TransPair pair(signer, verifier); ok &= pair.test(5 /*iters*/, false /*echo*/); return ok;}bool brandingTest(char const * const *params_array){ bool ok = true; sayWhatDoing("branding test", params_array); // decode array DSAParameters params(params_array); // generate a new private key, and encode the // keys as a pair of DataBlocks DataBlock brandedPubKeyBlock, privKeyBlock; { // make private key DSAPrivateKey keys(params, rng); keys.encode(privKeyBlock); // make branded public key DSASigner signer(keys, rng); DSABrandedPublicKey bkey(signer, "ftp.yadda-smacker.com"); brandedPubKeyBlock = bkey.encode(); } // verify that we can read + verify the branded key DSABrandedPublicKey pubKey(brandedPubKeyBlock); cout << "branded name: " << pubKey.getName() << endl; // make a signer and verifier DSASigner signer(privKeyBlock, rng); DSAVerifier verifier(pubKey); // test them together ok &= testSignerAndVerifier(signer, verifier); // confirm that a modified branded key won't verify brandedPubKeyBlock.getData()[5] ^= 0x40; // flip 1 bit cout << "expecting exception: "; try { DSABrandedPublicKey pubKey(brandedPubKeyBlock); cout << "FAILED to detect modified branded key!\n"; ok = false; } catch (...) {} return ok;}// helper for robustnessTestclass RobustTestTrans : public Trans {public: virtual void trans(DataBlock &data); void testblock(DataBlock &data);};void RobustTestTrans::trans(DataBlock &data){ // try block as-is (almost always fails version check) testblock(data); // append a 1, so it will pass version test, then // try it DataBlock temp(data); appendByte(temp, CURRENT_KEY_VERSION); testblock(data);}void RobustTestTrans::testblock(DataBlock &data){ try { DSABrandedPublicKey pubkey(data); xfailure("random data passed test ?!?!"); } catch (xSecurity &x) { // this is what we want, always } // otherwise, the exception escapes}// test DSABrandedPublicKey's ability to not throw anything// except xSecurity when presented with any argumentbool robustnessTest(){ cout << "DSA branding robustness test\n"; // since we're going to be throwing exceptions all // over the place, turn off logging bool prev = xBase::logExceptions; xBase::logExceptions = false; // this sequence is just a convenient way of // presenting RobustTestTrans::trans with lost // of random buffers Trans identity; RobustTestTrans testPubkey; TransPair pair(testPubkey, identity); bool ret = pair.test(100 /*iters*/); // turn exception logging back on (I know, an // exception thrown from here defeats this.. it // doesn't really matter, since we'd just print // it and exit anyway) xBase::logExceptions = prev; return ret;}void entry(){ bool ok = true; ok &= objectTest(DSA_512bit_parameters); //ok &= objectTest(DSA_1024bit_parameters); //ok &= testWithParameters(DSA_512bit_parameters); //ok &= testWithParameters(DSA_1024bit_parameters); //ok &= brandingTest(DSA_512bit_parameters); //ok &= brandingTest(DSA_1024bit_parameters); //ok &= robustnessTest(); if (ok) { cout << "all tests PASSED\n"; } else { cout << "at least one test FAILED\n"; }} USUAL_MAIN#endif // TEST_SDSA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -