1 //********************************************************************************** 2 //EncryptPad Copyright 2016 Evgeny Pokhilko 3 //<http://www.evpo.net/encryptpad> 4 // 5 //This file is part of EncryptPad 6 // 7 //EncryptPad is free software: you can redistribute it and/or modify 8 //it under the terms of the GNU General Public License as published by 9 //the Free Software Foundation, either version 2 of the License, or 10 //(at your option) any later version. 11 // 12 //EncryptPad is distributed in the hope that it will be useful, 13 //but WITHOUT ANY WARRANTY; without even the implied warranty of 14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 //GNU General Public License for more details. 16 // 17 //You should have received a copy of the GNU General Public License 18 //along with EncryptPad. If not, see <http://www.gnu.org/licenses/>. 19 //********************************************************************************** 20 #include "get_passphrase.h" 21 #include <string> 22 #include <iostream> 23 #include "assert.h" 24 #include "epad_utilities.h" 25 26 #if defined(__MINGW32__) || defined(_MSC_VER) 27 28 #include <windows.h> 29 30 namespace 31 { 32 class HandleTraits 33 { 34 public: InvalidHandle()35 static HANDLE InvalidHandle() 36 { 37 return INVALID_HANDLE_VALUE; 38 } 39 Close(HANDLE h)40 static void Close(HANDLE h) 41 { 42 CloseHandle(h); 43 } 44 }; 45 46 typedef EncryptPad::UniqueHandler<HANDLE, HandleTraits> Hndl; 47 WriteToConsole(const std::string & prompt)48 void WriteToConsole(const std::string &prompt) 49 { 50 using namespace EncryptPad; 51 52 FileHndl file = fopen("CONOUT$", "wt"); 53 if(!file.Valid()) 54 { 55 std::cerr << "Cannot open the terminal descriptor for output" << std::endl; 56 return; 57 } 58 59 fputs(prompt.data(), file.get()); 60 } 61 } 62 63 namespace EncryptPad 64 { GetPassphrase(const std::string & prompt,std::string & passphrase)65 void GetPassphrase(const std::string &prompt, std::string &passphrase) 66 { 67 const char kBackSpace=8; 68 const int kReturn='\n'; 69 70 passphrase.clear(); 71 72 unsigned char ch=0; 73 74 WriteToConsole(prompt); 75 76 DWORD con_mode; 77 Hndl h = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); 78 if(!h.Valid()) 79 { 80 std::cerr << "Cannot open the terminal for input" << std::endl; 81 return; 82 } 83 84 GetConsoleMode(h.get(), &con_mode); 85 SetConsoleMode(h.get(), con_mode & (~ENABLE_ECHO_INPUT)); 86 87 FileHndl file=fopen("CONIN$", "rt"); 88 if(!file.Valid()) 89 { 90 std::cerr << "Cannot open the terminal descriptor for input" << std::endl; 91 return; 92 } 93 94 int result = -1; 95 while((result=getc(file.get()))!=EOF && result != kReturn) 96 { 97 ch = static_cast<unsigned char>(result); 98 if(ch == kBackSpace) 99 { 100 if(passphrase.length() != 0) 101 { 102 passphrase.resize(passphrase.length() - 1); 103 } 104 } 105 else 106 { 107 passphrase+=ch; 108 } 109 } 110 111 SetConsoleMode(h.get(), con_mode); 112 WriteToConsole("\n"); 113 } 114 115 } 116 117 #elif defined(__APPLE__) || defined(unix) || defined(__unix__) || defined(__unix) 118 119 #include "termios.h" 120 #include "unistd.h" 121 #include <cstdio> 122 123 namespace 124 { 125 const char kBackspace = 127; 126 const char kReturn = 10; 127 const char kInvalid = -1; 128 Getch(FILE * f)129 char Getch(FILE *f) 130 { 131 struct termios t_old, t_new; 132 int file_no = fileno(f); 133 134 tcgetattr(file_no, &t_old); 135 t_new = t_old; 136 t_new.c_lflag &= ~(ICANON | ECHO); 137 tcsetattr(file_no, TCSANOW, &t_new); 138 139 char ch; 140 if(fread(&ch, 1, 1, f) != 1) 141 { 142 ch = kInvalid; 143 } 144 145 tcsetattr(file_no, TCSANOW, &t_old); 146 return ch; 147 } 148 } 149 150 namespace EncryptPad 151 { GetPassphrase(const std::string & prompt,std::string & passphrase)152 void GetPassphrase(const std::string &prompt, std::string &passphrase) 153 { 154 passphrase.clear(); 155 unsigned char ch=0; 156 157 const char *termid = ctermid(nullptr); 158 FileHndl term_file(fopen(termid, "r+")); 159 if(!term_file.Valid()) 160 { 161 std::cerr << "Cannot open the terminal for output" << std::endl; 162 return; 163 } 164 165 size_t res = fwrite(prompt.c_str(), 1, prompt.size(), term_file.get()); 166 assert(res == prompt.size()); 167 (void)res; 168 169 while((ch = Getch(term_file.get())) != kReturn && ch != static_cast<unsigned char>(kInvalid)) 170 { 171 if(ch == kBackspace) 172 { 173 if(passphrase.length() != 0) 174 { 175 passphrase.resize(passphrase.length() - 1); 176 } 177 } 178 else 179 { 180 passphrase += ch; 181 } 182 } 183 184 fputc('\n', term_file.get()); 185 } 186 } 187 #endif 188