📄 sec_de3s.cpp
字号:
}int DE3S_Control::maximumEncodedSize(int decodedLen) const{ int len = decodedLen; //tdiagnostic("%d: len = %d\n", __LINE__, len); len += 8; // flag, sequence # //tdiagnostic("%d: len = %d\n", __LINE__, len); len += sha1HMacSigner->DigestSize(); //tdiagnostic("%d: len = %d\n", __LINE__, len); len = controlTripleDesEnc->maxOutputSize(len); //tdiagnostic("%d: len = %d\n", __LINE__, len); return len;}void DE3S_Control::decode(DataBlock &data){ int srclen = data.getDataLen(); xassert(state == S_AUTHENTICATED); tdiagDataBlock(data, "ciphertext"); // triple-des decode controlTripleDesDec->trans(data); tdiagDataBlock(data, "un-3des'd"); // check SHA1HMac code checkDigest(data, *sha1HMacVerifier, "SHA1HMac does not match."); tdiagDataBlock(data, "removed sig"); // check sequence number checkNBO32(data, receiveSequenceNumber++, "Sequence number does not match."); tdiagDataBlock(data, "removed seqnum"); // check flags checkNBO32(data, FLAG_CONTROL | (amClient()? FLAG_SERVER : FLAG_CLIENT), "Flags word does not match."); tdiagDataBlock(data, "plaintext"); xassert(data.getDataLen() <= maximumDecodedSize(srclen));}int DE3S_Control::maximumDecodedSize(int encodedLen) const{ int len = encodedLen; //tdiagnostic("%d: len = %d\n", __LINE__, len); len = controlTripleDesDec->maxOutputSize(len); //tdiagnostic("%d: len = %d\n", __LINE__, len); len -= sha1HMacVerifier->DigestSize(); //tdiagnostic("%d: len = %d\n", __LINE__, len); len -= 8; // flags, sequence # //tdiagnostic("%d: len = %d\n", __LINE__, len); return len;}// ---------------------- DES3_Data -------------------------DE3S_Data::DE3S_Data(DE3S_Shared &sh) : shared(sh), dataTripleDesEnc(NULL), dataTripleDesDec(NULL), sequenceNumber(INITIAL_SEQUENCE_NUMBER), fileNumber(INITIAL_FILE_NUMBER), fileDSL(DSL_NONE) // to detect failure to call newFile{}DE3S_Data::~DE3S_Data(){ deleteCryptoObjs();}void DE3S_Data::deleteCryptoObjs(){ delete dataTripleDesEnc; dataTripleDesEnc = NULL; delete dataTripleDesDec; dataTripleDesDec = NULL;}void DE3S_Data::buildCryptoObjs(){ // construct the initialization vector: // 64-bit big-endian representation of file # DataBlock IV; appendNBO32(IV, 0); // high 32 bits are 0 appendNBO32(IV, fileNumber); // low 32 bits are file # // Some rationale on initialization vectors: The basic idea is that we // only need, for each encrypted message (with a particular key), to use // a *different* IV. We don't need secret IVs, nor random IVs. The reason // secrecy is not necessary is, because of the construction, all IVs after // the first are transmitted in the clear anyway, as the ciphertext blocks // themselves. The reason randomness isn't necessary is because we XOR the // IV with the first plaintext block, and *then* encrypt-- the encryption // effectively jumbles things up. Even the first IV, which is 0, isn't a // problem because it will still be unique. // // Most of this reasoning is based on Schneier, pp. 193-194. // The CRC Handbook of Cryptography seems to confirm this. // Note that using the file # as the initialization vector means if the // client and server get out of sync, decryption becomes impossible and // the HMAC will not match. // construct crypto objects dataTripleDesEnc = new CBC3DESEncTrans( shared.amClient? shared.clientData3DesKey : shared.serverData3DesKey, IV); dataTripleDesDec = new CBC3DESDecTrans( shared.amClient? shared.serverData3DesKey : shared.clientData3DesKey, IV);}// I'm letting part of the object's initialization take place after// the ctor because it's convenient to construct it early, but the// data we need (the 3des keys) isn't available thenvoid DE3S_Data::ensureCryptoObjs() const{ // verify they're either both null, or both non-null xassert((dataTripleDesEnc == NULL) == (dataTripleDesDec == NULL)); // build them if necessary if (dataTripleDesEnc == NULL) { // this call is a violation of this fn being 'const'; however, // since 'ensureCryptoObjs' is called before any use of them, // the state change that occurs here is not visible from the // outside const_cast<DE3S_Data*>(this)-> buildCryptoObjs(); }}void DE3S_Data::encode(DataBlock &data){ if (fileDSL == DSL_NONE) { xfailure("you have to call newFile before encode"); } ensureCryptoObjs(); int srclen = data.getDataLen(); tdiagDataBlock(data, "plaintext"); // flags appendNBO32(data, FLAG_DATA | (shared.amClient? FLAG_CLIENT : FLAG_SERVER)); tdiagDataBlock(data, "with flags block"); // sequencing appendNBO32(data, fileNumber); appendNBO32(data, sequenceNumber++); tdiagDataBlock(data, "with sequencing info"); // attach the message authentication code appendDigest(data, *shared.sha1HMacSigner); tdiagDataBlock(data, "signed"); if (fileDSL == DSL_PRIVATE) { // encrypt it dataTripleDesEnc->trans(data); tdiagDataBlock(data, "cihpertext"); } xassert(data.getDataLen() <= maximumEncodedSize(srclen, fileDSL));}int DE3S_Data::maximumEncodedSize(int decodedSize, DataSecurityLevel level) const{ ensureCryptoObjs(); int len = decodedSize; len += 12; // flags, sequencing len += shared.sha1HMacSigner->DigestSize(); if (level == DSL_PRIVATE) { len = dataTripleDesEnc->maxOutputSize(len); } return len;}int DE3S_Data::maximumEncodedSize(int decodedSize) const{ // largest encoding is with privacy on return maximumEncodedSize(decodedSize, DSL_PRIVATE);}void DE3S_Data::decode(DataBlock &data){ if (fileDSL == DSL_NONE) { xfailure("you have to call newFile before decode"); } ensureCryptoObjs(); int srclen = data.getDataLen(); tdiagDataBlock(data, "ciphertext"); if (fileDSL == DSL_PRIVATE) { // decrypt dataTripleDesDec->trans(data); tdiagDataBlock(data, "decrypted"); } // verify message authentication code checkDigest(data, *shared.sha1HMacVerifier, "SHA1HMac does not match."); tdiagDataBlock(data, "removed sig"); // check sequence number checkNBO32(data, sequenceNumber++, "Sequence number does not match."); tdiagDataBlock(data, "removed seqnum"); // check file # checkNBO32(data, fileNumber, "File number does not match."); tdiagDataBlock(data, "removed file #"); // check flags checkNBO32(data, FLAG_DATA | (shared.amClient? FLAG_SERVER : FLAG_CLIENT), "Flags word does not match."); tdiagDataBlock(data, "removed flags"); if (!( data.getDataLen() <= maximumDecodedSize(srclen, fileDSL) )) { breaker(); } xassert(data.getDataLen() <= maximumDecodedSize(srclen, fileDSL));}int DE3S_Data::maximumDecodedSize(int encodedSize, DataSecurityLevel level) const{ ensureCryptoObjs(); int len = encodedSize; if (level == DSL_PRIVATE) { len = dataTripleDesDec->maxOutputSize(len); } len -= shared.sha1HMacVerifier->DigestSize(); len -= 12; // flags, sequencing return len;}int DE3S_Data::maximumDecodedSize(int encodedSize) const{ // max decoded happens when the data was *not* encrypted return maximumDecodedSize(encodedSize, DSL_INTEGRITY);}DataSecurityLevel DE3S_Data::getSupportedProtLevels() const{ // this object does *not* support cleartext -- that is handled // by having the data simply never pass through the DE3S_Data // object return (DataSecurityLevel)(DSL_INTEGRITY | DSL_PRIVATE); // I continue to be annoyed by the erratic treatment enums gets // w/respect to bitwise or..}// called between data channel filesvoid DE3S_Data::newFile(DataSecurityLevel level){ // check that level is among named levels DataSecurity::newFile(level); sequenceNumber = INITIAL_SEQUENCE_NUMBER; fileNumber++; fileDSL = level; // this will force them to be created anew deleteCryptoObjs();}char DE3S_Data::getCodeForLevel(DataSecurityLevel level) const{ switch (level) { case DSL_INTEGRITY: return 'T'; case DSL_PRIVATE: return 'P'; default: xfailure("invalid security level"); return '!'; // silence warning }}DataSecurityLevel DE3S_Data::getLevelForCode(char code) const{ // Note: I am assuming the argument to PROT case-sensitive // see which level it is switch (code) { case 'S': // 2228: "safe" case 'E': // 2228: "confidential" case 'P': // 2228: "private" (integrity + confidentiality) // unfortunately, my original implementation mapped S, E, and P // all to P, effectively. so, rather than change the meaning of // existing letters, we continue to support the original meaning.. return DSL_PRIVATE; case 'T': // means (roughly) what 2228 means by "safe" // ..and instead *extend*, by using what was before an illegal code return DSL_INTEGRITY; default: // unknown code return DSL_NONE; }}// ---------------- DE3S_Provider -------------------------DE3S_Provider::DE3S_Provider(KeyEnvironment *env, IPAddress myAddr, IPAddress peerAddr){ // I was forced to make these objects separate from the // provider by one of two things: // 1. g++ sucks // 2. I forgot to recompile after a certain change // since I already know that (1) is true I'm not going to // waste time finding out if it was responsible for this // particular issue _control = new DE3S_Control(env, myAddr, peerAddr); _data = new DE3S_Data(*_control);}DE3S_Provider::~DE3S_Provider(){ delete _control; delete _data;}// -------------- test code -----------------// at this point, this just tests CBC3DES{Enc,Dec}Trans and SHA1HMAC// (provider.cc gives everything a good workout)#ifdef TEST_SEC_DE3S#include "test.h" // USUAL_MAINvoid entry(){ bool ok = true; DataBlock key("abcdefghijklmnopqrstuvwx", 24), IV("12345678", 8); CBC3DESEncTrans enc(key, IV); CBC3DESDecTrans dec(key, IV); TransPair desPair(enc, dec); ok &= desPair.test(100 /*iters*/); // the following lines don't compile, I don't // care why #if 0 SHA1HMAC sign(key); SHA1HMAC verify(key); TransPair hmacPair(sign, verify); ok &= hmacPair.test(100 /*iters*/); #endif // 0 PVAL(ok);}USUAL_MAIN#endif // TEST_SEC_DE3S
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -