//--------------------------------------------------------------------- bool PeerContactProfile::usesContactProfileSecret(const char *contactProfileSecret) { AutoRecursiveLock lock(mLock); if (NULL == contactProfileSecret) return false; if (!mDocument) return false; try { ElementPtr contactProfileElement = getContactProfileElement(); if (!contactProfileElement) return false; ElementPtr proofElement = contactProfileElement->findFirstChildElementChecked("private")->findFirstChildElementChecked("proof"); String proofAsBase64 = proofElement->getText(true); SecureByteBlock proofHash; convertFromBase64(proofAsBase64, proofHash); SecureByteBlock calculatedProofHash(32); if (calculatedProofHash.size() != proofHash.size()) return false; SHA256 shaProof; shaProof.Update((const BYTE *)"proof:", strlen("proof:")); shaProof.Update((const BYTE *)contactProfileSecret, strlen(contactProfileSecret)); shaProof.Final(calculatedProofHash); if (0 != memcmp(calculatedProofHash, proofHash, proofHash.size())) return false; // this is the secret and it is verified mContactProfileSecret = contactProfileSecret; } catch (zsLib::XML::Exceptions::CheckFailed &) { return false; } return true; }
void RandomPool::IncorporateEntropy(const byte *input, size_t length) { SHA256 hash; hash.Update(m_key, 32); hash.Update(input, length); hash.Final(m_key); m_keySet = false; }
void PWSrand::AddEntropy(unsigned char *bytes, unsigned int numBytes) { ASSERT(bytes != nullptr); SHA256 s; s.Update(K, sizeof(K)); s.Update(bytes, numBytes); s.Final(K); }
int sha256_test() { SHA256 sha; byte hash[SHA256::DIGEST_SIZE]; testVector test_sha[] = { testVector("abc", "\xBA\x78\x16\xBF\x8F\x01\xCF\xEA\x41\x41\x40\xDE\x5D\xAE\x22" "\x23\xB0\x03\x61\xA3\x96\x17\x7A\x9C\xB4\x10\xFF\x61\xF2\x00" "\x15\xAD"), testVector("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "\x24\x8D\x6A\x61\xD2\x06\x38\xB8\xE5\xC0\x26\x93\x0C\x3E\x60" "\x39\xA3\x3C\xE4\x59\x64\xFF\x21\x67\xF6\xEC\xED\xD4\x19\xDB" "\x06\xC1") }; int times( sizeof(test_sha) / sizeof(testVector) ); for (int i = 0; i < times; ++i) { sha.Update(test_sha[i].input_, test_sha[i].inLen_); sha.Final(hash); if (memcmp(hash, test_sha[i].output_, SHA256::DIGEST_SIZE) != 0) return -1 - i; } return 0; }
/** * Clear from clipboard data, that we put there previously * @return \c true, if we cleared our data, or stored data don't belong to us */ bool PWSclipboard::ClearCBData() { wxMutexLocker clip(m_clipboardMutex); if (m_set && wxTheClipboard->Open()) { wxTextDataObject obj; if (wxTheClipboard->IsSupported(wxDF_UNICODETEXT) && wxTheClipboard->GetData(obj)) { StringX buf(obj.GetText().data(), obj.GetText().size()); if (buf.length()) { // check if the data on the clipboard is the same we put there unsigned char digest[SHA256::HASHLEN]; SHA256 ctx; ctx.Update(reinterpret_cast<const unsigned char *>(buf.c_str()), buf.length()*sizeof(wchar_t)); ctx.Final(digest); if (memcmp(digest, m_digest, SHA256::HASHLEN) == 0) { // clear & reset wxTheClipboard->Clear(); memset(m_digest, 0, SHA256::HASHLEN); m_set = false; // Also trash data in buffer and clipboard somehow? pws_os::Trace0(L"Cleared our data from buffer.\n"); } else{ pws_os::Trace0(L"Buffer doesn't contain our data. Nothing to clear.\n"); } } } wxTheClipboard->Close(); } return !m_set; }
PWSFileSig::PWSFileSig(const stringT &fname) { const long THRESHOLD = 2048; // if file's longer than this, hash only head & tail m_length = 0; m_iErrorCode = PWSfile::SUCCESS; memset(m_digest, 0, sizeof(m_digest)); FILE *fp = pws_os::FOpen(fname, _T("rb")); if (fp != NULL) { SHA256 hash; unsigned char buf[THRESHOLD]; m_length = pws_os::fileLength(fp); // Minimum size for an empty V3 DB is 232 bytes - pre + post, no hdr or records! // Probably smaller for V1 & V2 DBs if (m_length > 232) { if (m_length <= THRESHOLD) { if (fread(buf, m_length, 1, fp) == 1) { hash.Update(buf, m_length); hash.Final(m_digest); } } else { // m_length > THRESHOLD if (fread(buf, THRESHOLD / 2, 1, fp) == 1 && fseek(fp, -THRESHOLD / 2, SEEK_END) == 0 && fread(buf + THRESHOLD / 2, THRESHOLD / 2, 1, fp) == 1) { hash.Update(buf, THRESHOLD); hash.Final(m_digest); } } } else { // File too small m_iErrorCode = PWSfile::TRUNCATED_FILE; } fclose(fp); } else { m_iErrorCode = PWSfile::CANT_OPEN_FILE; } }
PWSFileSig::PWSFileSig(const stringT &fname) { const long THRESHOLD = 2048; // if file's longer than this, hash only head & tail m_length = 0; m_iErrorCode = PWSfile::SUCCESS; memset(m_digest, 0, sizeof(m_digest)); FILE *fp = pws_os::FOpen(fname, _T("rb")); if (fp != nullptr) { SHA256 hash; m_length = pws_os::fileLength(fp); // Not the right place to be worried about min size, as this is format // version specific (and we're in PWSFile). // An empty file, though, should be failed. if (m_length > 0) { unsigned char buf[THRESHOLD]; if (m_length <= THRESHOLD) { if (fread(buf, size_t(m_length), 1, fp) == 1) { hash.Update(buf, size_t(m_length)); hash.Final(m_digest); } } else { // m_length > THRESHOLD if (fread(buf, THRESHOLD / 2, 1, fp) == 1 && fseek(fp, -THRESHOLD / 2, SEEK_END) == 0 && fread(buf + THRESHOLD / 2, THRESHOLD / 2, 1, fp) == 1) { hash.Update(buf, THRESHOLD); hash.Final(m_digest); } } } else { // Empty file m_iErrorCode = PWSfile::TRUNCATED_FILE; } fclose(fp); } else { m_iErrorCode = PWSfile::CANT_OPEN_FILE; } }
void PWSrand::NextRandBlock() { SHA256 s; s.Update(K, sizeof(K)); s.Final(R); unsigned int *Kp = reinterpret_cast<unsigned int *>(K); unsigned int *Rp = reinterpret_cast<unsigned int *>(R); const int N = SHA256::HASHLEN / sizeof(uint32); Kp[0]++; for (int32 i = 0; i < N; i++) Kp[i] += Rp[i]; }
void PWSfile::HashRandom256(unsigned char *p256) { /** * This is for random data that will be written to the file directly. * The idea is to avoid directly exposing our generated randomness * to the attacker, since this might expose state of the RNG. * Therefore, we'll hash the randomness. * * As the names imply, this works on 256 bit (32 byte) arrays. */ PWSrand::GetInstance()->GetRandomData(p256, 32); SHA256 salter; salter.Update(p256, 32); salter.Final(p256); }
PWSrand::PWSrand() : ibRandomData(SHA256::HASHLEN) { m_IsInternalPRNG = !pws_os::InitRandomDataFunction(); SHA256 s; unsigned slen = 0; unsigned char *p; pws_os::GetRandomSeed(nullptr, slen); p = new unsigned char[slen]; pws_os::GetRandomSeed(p, slen); s.Update(p, slen); delete[] p; s.Final(K); }
/** * Put text data to clipboard * @param[in] data data to store in clipboard * @param isSensitive if data sensitive, we remember its hash and will clear on ClearCBData() call * @return \c true, if we could open the clipboard and put the data */ bool PWSclipboard::SetData(const StringX &data) { wxMutexLocker clip(m_clipboardMutex); bool res = false; if (wxTheClipboard->Open()) { res = wxTheClipboard->SetData(new wxTextDataObject(data.c_str())); wxTheClipboard->Close(); } m_set = true; if (res) { // identify data in clipboard as ours, so as not to clear the wrong data later // of course, we don't want an extra copy of a password floating around // in memory, so we'll use the hash SHA256 ctx; const wchar_t *str = data.c_str(); ctx.Update(reinterpret_cast<const unsigned char *>(str), data.length()*sizeof(wchar_t)); ctx.Final(m_digest); } return res; }
//--------------------------------------------------------------------- PeerContactProfilePtr PeerContactProfile::createExternalFromPrivateProfile(ElementPtr privateProfileElement) { if (!privateProfileElement) return PeerContactProfilePtr(); privateProfileElement = (privateProfileElement->clone())->toElementChecked(); static const char *contactProfileSkeleton = "<contactProfile version=\"0\">\n" " <private>\n" " <salt />\n" " <proof cipher=\"sha256/aes256\" />\n" " <encryptedProfile cipher=\"sha256/aes256\" />\n" " <contactProfileSecret cipher=\"sha256/aes256\" />\n" " </private>\n" "</contactProfile>"; DocumentPtr contactProfileDoc = Document::create(); contactProfileDoc->parse(contactProfileSkeleton); String contactID = services::IHelper::randomString(32); String contactProfileSecret = services::IHelper::randomString(32); // generate external profile { std::string contactSalt; // generate salt { AutoSeededRandomPool rng; SecureByteBlock contactSaltRaw(32); rng.GenerateBlock(contactSaltRaw, contactSaltRaw.size()); contactSalt = convertToBase64(contactSaltRaw, contactSaltRaw.size()); } ElementPtr contactProfileElement = contactProfileDoc->getFirstChildElementChecked(); contactProfileElement->setAttribute("id", contactID); ElementPtr privateElement = contactProfileElement->getFirstChildElementChecked(); ElementPtr saltElement = privateElement->getFirstChildElementChecked(); TextPtr saltText = Text::create(); saltText->setValue(contactSalt); saltElement->adoptAsLastChild(saltText); SecureByteBlock contactProofHash(32); SHA256 contactProof; contactProof.Update((const BYTE *)"proof:", strlen("proof:")); contactProof.Update((const BYTE *)contactProfileSecret.c_str(), contactProfileSecret.size()); contactProof.Final(contactProofHash); String contactProofInBase64 = convertToBase64(contactProofHash, contactProofHash.size()); ElementPtr proofElement = saltElement->getNextSiblingElementChecked(); TextPtr proofText = Text::create(); proofText->setValue(contactProofInBase64); proofElement->adoptAsLastChild(proofText); DocumentPtr privateProfileDocument = Document::create(); privateProfileDocument->adoptAsLastChild(privateProfileElement); ULONG length = 0; boost::shared_array<char> output; output = privateProfileDocument->write(&length); ElementPtr encryptedProfileElement = proofElement->getNextSiblingElementChecked(); String encryptedProfileString = encryptToBase64("profile", contactProfileSecret, contactSalt, (const BYTE *)(output.get()), length); TextPtr encryptProfileText = Text::create(); encryptProfileText->setValue(encryptedProfileString); encryptedProfileElement->adoptAsLastChild(encryptProfileText); ElementPtr contactProfileSecretElement = encryptedProfileElement->getNextSiblingElementChecked(); TextPtr contactProfileSecretText = Text::create(); contactProfileSecretText->setValue(contactProfileSecret); contactProfileSecretElement->adoptAsLastChild(contactProfileSecretText); } PeerContactProfilePtr pThis(new PeerContactProfile); pThis->mThisWeak = pThis; pThis->mDocument = contactProfileDoc; pThis->mContactProfileSecret = contactProfileSecret; return pThis; }