int PWSfileV1V2::CheckPasskey(const StringX &filename, const StringX &passkey, FILE *a_fd) { FILE *fd = a_fd; if (fd == NULL) { fd = pws_os::FOpen(filename.c_str(), _T("rb")); } if (fd == NULL) return CANT_OPEN_FILE; unsigned char randstuff[StuffSize]; unsigned char randhash[20]; // HashSize fread(randstuff, 1, 8, fd); randstuff[8] = randstuff[9] = '\0'; // Gross fugbix fread(randhash, 1, 20, fd); if (a_fd == NULL) // if we opened the file, we close it... fclose(fd); unsigned char temphash[20]; // HashSize GenRandhash(passkey, randstuff, temphash); if (0 != memcmp(reinterpret_cast<char *>(randhash), reinterpret_cast<char *>(temphash), MIN(sizeof(randhash), sizeof(temphash)))) { // HashSize return WRONG_PASSWORD; } else { return SUCCESS; } }
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::Encrypt(const stringT &fn, const StringX &passwd, stringT &errmess) { unsigned int len = 0; unsigned char* buf = NULL; Fish *fish = NULL; bool status = true; stringT out_fn; unsigned char *pwd = NULL; size_t passlen = 0; FILE *out = NULL; FILE *in = pws_os::FOpen(fn, _T("rb"));; if (in != NULL) { len = pws_os::fileLength(in); buf = new unsigned char[len]; fread(buf, 1, len, in); if (ferror(in)) { // this is how to detect fread errors status = false; int save_error = errno; fclose(in); errno = save_error; goto exit; } if (fclose(in) != 0) { status = false; goto exit; } } else { status = false; goto exit; } out_fn = fn; out_fn += CIPHERTEXT_SUFFIX; out = pws_os::FOpen(out_fn, _T("wb")); if (out == NULL) { status = false; goto exit; } #ifdef KEEP_FILE_MODE_BWD_COMPAT uint32 i32 = len; SAFE_FWRITE(&i32, 1, sizeof(uint32), out); #else unsigned char randstuff[StuffSize]; unsigned char randhash[SHA1::HASHLEN]; // HashSize PWSrand::GetInstance()->GetRandomData( randstuff, 8 ); // miserable bug - have to fix this way to avoid breaking existing files randstuff[8] = randstuff[9] = TCHAR('\0'); GenRandhash(passwd, randstuff, randhash); SAFE_FWRITE(randstuff, 1, 8, out); SAFE_FWRITE(randhash, 1, sizeof(randhash), out); #endif // KEEP_FILE_MODE_BWD_COMPAT unsigned char thesalt[SaltLength]; PWSrand::GetInstance()->GetRandomData( thesalt, SaltLength ); SAFE_FWRITE(thesalt, 1, SaltLength, out); unsigned char ipthing[8]; PWSrand::GetInstance()->GetRandomData( ipthing, 8 ); SAFE_FWRITE(ipthing, 1, 8, out); ConvertString(passwd, pwd, passlen); fish = BlowFish::MakeBlowFish(pwd, reinterpret_cast<int &>(passlen), thesalt, SaltLength); trashMemory(pwd, passlen); #ifdef UNICODE delete[] pwd; // gross - ConvertString allocates only if UNICODE. #endif try { _writecbc(out, buf, len, 0, fish, ipthing); } catch (...) { // _writecbc throws an exception if it fails to write fclose(out); errno = EIO; status = false; goto exit; } status = (fclose(out) == 0); exit: if (!status) errmess = ErrorMessages(); delete fish; delete[] buf; 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; }
bool PWSfile::Encrypt(const stringT &fn, const StringX &passwd, stringT &errmess) { ulong64 len = 0; size_t slen = 0; unsigned char* buf = nullptr; Fish *fish = nullptr; bool status = true; const stringT out_fn = fn + CIPHERTEXT_SUFFIX; unsigned char *pwd = nullptr; size_t passlen = 0; FILE *out = nullptr; FILE *in = pws_os::FOpen(fn, _T("rb")); if (in == nullptr) { status = false; goto exit; } len = pws_os::fileLength(in); if (len > std::numeric_limits<uint32>::max()) { fclose(in); errno = EFBIG; status = false; goto exit; } slen = static_cast<size_t>(len); buf = new unsigned char[slen]; fread(buf, 1, slen, in); if (ferror(in)) { // this is how to detect fread errors status = false; int save_error = errno; fclose(in); errno = save_error; goto exit; } if (fclose(in) != 0) { status = false; goto exit; } out = pws_os::FOpen(out_fn, _T("wb")); if (out == nullptr) { status = false; goto exit; } unsigned char randstuff[StuffSize]; unsigned char randhash[SHA1::HASHLEN]; // HashSize PWSrand::GetInstance()->GetRandomData( randstuff, 8 ); // miserable bug - have to fix this way to avoid breaking existing files randstuff[8] = randstuff[9] = TCHAR('\0'); GenRandhash(passwd, randstuff, randhash); SAFE_FWRITE(randstuff, 1, 8, out); SAFE_FWRITE(randhash, 1, sizeof(randhash), out); unsigned char thesalt[SaltLength]; PWSrand::GetInstance()->GetRandomData( thesalt, SaltLength ); SAFE_FWRITE(thesalt, 1, SaltLength, out); unsigned char ipthing[8]; PWSrand::GetInstance()->GetRandomData( ipthing, 8 ); SAFE_FWRITE(ipthing, 1, 8, out); ConvertPasskey(passwd, pwd, passlen); fish = BlowFish::MakeBlowFish(pwd, reinterpret_cast<unsigned int &>(passlen), thesalt, SaltLength); trashMemory(pwd, passlen); delete[] pwd; // gross - ConvertPasskey allocates. try { _writecbc(out, buf, slen, 0, fish, ipthing); } catch (...) { // _writecbc throws an exception if it fails to write fclose(out); errno = EIO; status = false; goto exit; } status = (fclose(out) == 0); exit: if (!status) errmess = ErrorMessages(); delete fish; delete[] buf; return status; }
int PWSfileV1V2::Open(const StringX &passkey) { int status = SUCCESS; ASSERT(m_curversion == V17 || m_curversion == V20); m_passkey = passkey; FOpen(); if (m_fd == NULL) return CANT_OPEN_FILE; LPCTSTR passstr = m_passkey.c_str(); size_t passLen = passkey.length(); unsigned char *pstr; #ifdef UNICODE size_t pstr_len = 3 * passLen; pstr = new unsigned char[pstr_len]; size_t len = pws_os::wcstombs(reinterpret_cast<char *>(pstr), 3 * passLen, passstr, passLen, false); ASSERT(len != 0); // hack around OS-dependent semantics - too widespread to fix systematically :-( pstr[len < pstr_len ? len : pstr_len - 1] = '\0'; passLen = strlen(reinterpret_cast<const char *>(pstr)); #else pstr = reinterpret_cast<unsigned char *>(passstr); #endif if (m_rw == Write) { // Following used to verify passkey against file's passkey unsigned char randstuff[StuffSize]; unsigned char randhash[20]; // HashSize PWSrand::GetInstance()->GetRandomData( randstuff, 8 ); randstuff[8] = randstuff[9] = TCHAR('\0'); GenRandhash(m_passkey, randstuff, randhash); SAFE_FWRITE(randstuff, 1, 8, m_fd); SAFE_FWRITE(randhash, 1, 20, m_fd); PWSrand::GetInstance()->GetRandomData(m_salt, SaltLength); SAFE_FWRITE(m_salt, 1, SaltLength, m_fd); PWSrand::GetInstance()->GetRandomData( m_ipthing, 8); SAFE_FWRITE(m_ipthing, 1, 8, m_fd); m_fish = BlowFish::MakeBlowFish(pstr, reinterpret_cast<int &>(passLen), m_salt, SaltLength); if (m_curversion == V20) { status = WriteV2Header(); } } else { // open for read status = CheckPasskey(m_filename, m_passkey, m_fd); if (status != SUCCESS) { #ifdef UNICODE trashMemory(pstr, pstr_len); delete[] pstr; #endif Close(); return status; } fread(m_salt, 1, SaltLength, m_fd); fread(m_ipthing, 1, 8, m_fd); m_fish = BlowFish::MakeBlowFish(pstr, reinterpret_cast<int &>(passLen), m_salt, SaltLength); if (m_curversion == V20) status = ReadV2Header(); } // read mode exit: if (status != SUCCESS) Close(); #ifdef UNICODE trashMemory(pstr, pstr_len); delete[] pstr; #endif return status; }