size_t PWSfile::ReadCBC(unsigned char &type, unsigned char* &data, size_t &length) { unsigned char *buffer = NULL; size_t buffer_len = 0; size_t retval; ASSERT(m_fish != NULL && m_IV != NULL); retval = _readcbc(m_fd, buffer, buffer_len, type, m_fish, m_IV, m_terminal, m_fileLength); if (buffer_len > 0) { if (buffer_len < length || data == NULL) length = buffer_len; // set to length read // if buffer_len > length, data is truncated to length // probably an error. if (data != NULL) { memcpy(data, buffer, length); trashMemory(buffer, buffer_len); delete[] buffer; } else { // NULL data means pass buffer directly to caller data = buffer; // caller must trash & delete[]! } } else { // no need to delete[] buffer, since _readcbc will not allocate if // buffer_len is zero } return retval; }
size_t PWSfileV1V2::ReadCBC(unsigned char &type, StringX &data) { unsigned char *buffer = NULL; size_t buffer_len = 0; size_t retval; ASSERT(m_fish != NULL && m_IV != NULL); retval = _readcbc(m_fd, buffer, buffer_len, type, m_fish, m_IV, m_terminal); if (buffer_len > 0) { wchar_t *wc = new wchar_t[buffer_len+1]; size_t wcLen = pws_os::mbstowcs(wc, buffer_len + 1, reinterpret_cast<const char *>(buffer), buffer_len, false); ASSERT(wcLen != 0); if (wcLen < buffer_len + 1) wc[wcLen] = TCHAR('\0'); else wc[buffer_len] = TCHAR('\0'); data = wc; trashMemory(wc, wcLen); delete[] wc; trashMemory(buffer, buffer_len); delete[] buffer; } else { data = _T(""); // no need to delete[] buffer, since _readcbc will not allocate if // buffer_len is zero } return retval; }
bool PWSfile::Decrypt(const stringT &fn, const StringX &passwd, stringT &errmess) { size_t len; unsigned char* buf = NULL; bool status = true; unsigned char salt[SaltLength]; unsigned char ipthing[8]; unsigned char randstuff[StuffSize]; unsigned char randhash[SHA1::HASHLEN]; unsigned char temphash[SHA1::HASHLEN]; FILE *in = pws_os::FOpen(fn, _T("rb")); if (in == NULL) { status = false; goto exit; } #ifdef KEEP_FILE_MODE_BWD_COMPAT uint32 i32; fread(&i32, 1, sizeof(uint32), in); // XXX portability issue len = i32; #else fread(randstuff, 1, 8, in); randstuff[8] = randstuff[9] = TCHAR('\0'); // ugly bug workaround fread(randhash, 1, sizeof(randhash), in); GenRandhash(passwd, randstuff, temphash); if (memcmp(reinterpret_cast<char *>(randhash), reinterpret_cast<char *>(temphash), SHA1::HASHLEN) != 0) { fclose(in); LoadAString(errmess, IDSC_BADPASSWORD); return false; } #endif // KEEP_FILE_MODE_BWD_COMPAT { // decryption in a block, since we use goto fread(salt, 1, SaltLength, in); fread(ipthing, 1, 8, in); unsigned char dummyType; unsigned char *pwd = NULL; size_t passlen = 0; long file_len = pws_os::fileLength(in); ConvertString(passwd, pwd, passlen); Fish *fish = BlowFish::MakeBlowFish(pwd, reinterpret_cast<int &>(passlen), salt, SaltLength); trashMemory(pwd, passlen); #ifdef UNICODE delete[] pwd; // gross - ConvertString allocates only if UNICODE. #endif if (_readcbc(in, buf, len,dummyType, fish, ipthing, 0, file_len) == 0) { delete fish; delete[] buf; // if not yet allocated, delete[] NULL, which is OK return false; } delete fish; fclose(in); } // decrypt { // write decrypted data size_t suffix_len = CIPHERTEXT_SUFFIX.length(); size_t filepath_len = fn.length(); stringT out_fn = fn; out_fn = out_fn.substr(0,filepath_len - suffix_len); FILE *out = pws_os::FOpen(out_fn, _T("wb")); if (out != NULL) { size_t fret = fwrite(buf, 1, len, out); if (fret != len) { int save_errno = errno; fclose(out); errno = save_errno; goto exit; } if (fclose(out) != 0) { status = false; goto exit; } } else { // open failed status = false; goto exit; } } // write decrypted exit: if (!status) errmess = ErrorMessages(); delete[] buf; // allocated by _readcbc return status; }
bool PWSfile::Decrypt(const stringT &fn, const StringX &passwd, stringT &errmess) { ulong64 file_len; size_t len; unsigned char* buf = nullptr; bool status = true; unsigned char salt[SaltLength]; unsigned char ipthing[8]; unsigned char randstuff[StuffSize]; unsigned char randhash[SHA1::HASHLEN]; unsigned char temphash[SHA1::HASHLEN]; FILE *in = pws_os::FOpen(fn, _T("rb")); if (in == nullptr) { status = false; goto exit; } file_len = pws_os::fileLength(in); if (file_len < (8 + sizeof(randhash) + 8 + SaltLength)) { fclose(in); LoadAString(errmess, IDSC_FILE_TOO_SHORT); return false; } fread(randstuff, 1, 8, in); randstuff[8] = randstuff[9] = TCHAR('\0'); // ugly bug workaround fread(randhash, 1, sizeof(randhash), in); GenRandhash(passwd, randstuff, temphash); if (memcmp(reinterpret_cast<char *>(randhash), reinterpret_cast<char *>(temphash), SHA1::HASHLEN) != 0) { fclose(in); LoadAString(errmess, IDSC_BADPASSWORD); return false; } { // decryption in a block, since we use goto fread(salt, 1, SaltLength, in); fread(ipthing, 1, 8, in); unsigned char dummyType; unsigned char *pwd = nullptr; size_t passlen = 0; ConvertPasskey(passwd, pwd, passlen); Fish *fish = BlowFish::MakeBlowFish(pwd, reinterpret_cast<unsigned int &>(passlen), salt, SaltLength); trashMemory(pwd, passlen); delete[] pwd; // gross - ConvertPasskey allocates. if (_readcbc(in, buf, len,dummyType, fish, ipthing, 0, file_len) == 0) { delete fish; delete[] buf; // if not yet allocated, delete[] nullptr, which is OK return false; } delete fish; fclose(in); } // decrypt { // write decrypted data size_t suffix_len = CIPHERTEXT_SUFFIX.length(); size_t filepath_len = fn.length(); stringT out_fn = fn; out_fn = out_fn.substr(0,filepath_len - suffix_len); FILE *out = pws_os::FOpen(out_fn, _T("wb")); if (out != nullptr) { size_t fret = fwrite(buf, 1, len, out); if (fret != len) { int save_errno = errno; fclose(out); errno = save_errno; goto exit; } if (fclose(out) != 0) { status = false; goto exit; } } else { // open failed status = false; goto exit; } } // write decrypted exit: if (!status) errmess = ErrorMessages(); delete[] buf; // allocated by _readcbc return status; }