00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "filename.h"
00016 #include "encrypt_string.h"
00017 #include "pnotify.h"
00018 #include "panda_getopt.h"
00019 #include "preprocess_argv.h"
00020
00021 string password;
00022 bool got_password = false;
00023 string algorithm;
00024 bool got_algorithm = false;
00025 int key_length = -1;
00026 bool got_key_length = false;
00027 int iteration_count = -1;
00028 bool got_iteration_count = false;
00029
00030 void
00031 usage() {
00032 cerr
00033 << "\nUsage:\n"
00034 << " pencrypt [opts] file [file2 file3 ...]\n"
00035 << " pencrypt -o dest_file file\n\n"
00036
00037 << "This program will apply an encryption algorithm to a file (or multiple files),\n"
00038 << "creating an encrypted version of each file which can only be recovered using\n"
00039 << "pdecrypt and the same password that was supplied to pencrypt. The compressed\n"
00040 << "versions are written to a file with the same name as the original, but the\n"
00041 << "extension .pe added to the filename, and the original file is removed\n"
00042 << "(unless the version with -o is used, in which case you can encrypt only one\n"
00043 << "file, you specify the destination file name, and the original file is not\n"
00044 << "removed).\n\n"
00045
00046
00047 << "Note that if you are adding files to a Panda multifile (.mf file) with\n"
00048 << "the multify command, it is not necessary to encrypt them separately;\n"
00049 << "multify has an inline encryption option.\n\n"
00050
00051 << "Options:\n\n"
00052
00053 << " -p \"password\"\n"
00054 << " Specifies the password to use for encryption. There are no\n"
00055 << " restrictions on the password length or contents, but longer passwords\n"
00056 << " are more secure. If this is not specified, the user is prompted from\n"
00057 << " standard input.\n\n"
00058
00059 << " -t Read the file as a text file. This will automatically convert\n"
00060 << " universal end-of-line characters into a newline character, ascii\n"
00061 << " 10.\n\n"
00062
00063 << " -a \"algorithm\"\n"
00064 << " Specifies the particular encryption algorithm to use. The complete\n"
00065 << " set of available algorithms is defined by the current version of\n"
00066 << " OpenSSL. The default algorithm is taken from the encryption-\n"
00067 << " algorithm config variable.\n\n"
00068
00069 << " -k key_length\n"
00070 << " Specifies the key length, in bits, for the selected encryption\n"
00071 << " algorithm. This only makes sense for those algorithms that support\n"
00072 << " a variable key length. The default value is taken from the\n"
00073 << " encryption-key-length config variable.\n\n"
00074
00075 << " -i iteration_count\n"
00076 << " Specifies the number of times the password is hashed to generate\n"
00077 << " a key. The only purpose of this is to make it computationally\n"
00078 << " more expensive for an attacker to search the key space exhaustively.\n"
00079 << " This should be a multiple of 1,000 and should not exceed about 65\n"
00080 << " million; the value 0 indicates just one application of the hashing\n"
00081 << " algorithm. The default value is taken from the encryption-iteration-\n"
00082 << " count config variable.\n\n";
00083 }
00084
00085 int
00086 main(int argc, char **argv) {
00087 extern char *optarg;
00088 extern int optind;
00089 const char *optstr = "o:p:ta:k:i:h";
00090
00091 Filename dest_filename;
00092 bool got_dest_filename = false;
00093 bool text_file = false;
00094
00095 preprocess_argv(argc, argv);
00096 int flag = getopt(argc, argv, optstr);
00097
00098 while (flag != EOF) {
00099 switch (flag) {
00100 case 'o':
00101 dest_filename = Filename::from_os_specific(optarg);
00102 got_dest_filename = true;
00103 break;
00104
00105 case 't':
00106 text_file = true;
00107 break;
00108
00109 case 'p':
00110 password = optarg;
00111 got_password = true;
00112 break;
00113
00114 case 'a':
00115 algorithm = optarg;
00116 got_algorithm = true;
00117 break;
00118
00119 case 'k':
00120 key_length = atoi(optarg);
00121 got_key_length = true;
00122 break;
00123
00124 case 'i':
00125 iteration_count = atoi(optarg);
00126 got_iteration_count = true;
00127 break;
00128
00129 case 'h':
00130 case '?':
00131 default:
00132 usage();
00133 return 1;
00134 }
00135 flag = getopt(argc, argv, optstr);
00136 }
00137
00138 argc -= (optind-1);
00139 argv += (optind-1);
00140
00141 if (argc < 2) {
00142 usage();
00143 return 1;
00144 }
00145
00146 if (got_dest_filename && argc > 2) {
00147 cerr << "Only one input file allowed in conjunction with -o.\n";
00148 return 1;
00149 }
00150
00151 bool all_ok = true;
00152 for (int i = 1; i < argc; i++) {
00153 Filename source_file = Filename::from_os_specific(argv[i]);
00154 if (source_file.get_extension() == "pe") {
00155 cerr << source_file << " already ends .pe; skipping.\n";
00156 } else {
00157 Filename dest_file = dest_filename;
00158 if (!got_dest_filename) {
00159 dest_file = source_file.get_fullpath() + ".pe";
00160 }
00161
00162
00163 pifstream read_stream;
00164 if (text_file) {
00165 source_file.set_text();
00166 } else {
00167 source_file.set_binary();
00168 }
00169 if (!source_file.open_read(read_stream)) {
00170 cerr << "Couldn't read: " << source_file << endl;
00171 all_ok = false;
00172
00173 } else {
00174
00175 pofstream write_stream;
00176 dest_file.set_binary();
00177 if (!dest_file.open_write(write_stream, true)) {
00178 cerr << "Failed to open: " << dest_file << endl;
00179 all_ok = false;
00180
00181 } else {
00182
00183 if (!got_password) {
00184 cerr << "Enter password: ";
00185 getline(cin, password);
00186 got_password = true;
00187 }
00188
00189 cerr << dest_file << "\n";
00190 bool success = encrypt_stream(read_stream, write_stream, password,
00191 algorithm, key_length, iteration_count);
00192
00193 read_stream.close();
00194 write_stream.close();
00195
00196 if (!success) {
00197 cerr << "Failure writing " << dest_file << "\n";
00198 all_ok = false;
00199 dest_file.unlink();
00200
00201 } else {
00202 if (!got_dest_filename) {
00203 source_file.unlink();
00204 }
00205 }
00206 }
00207 }
00208 }
00209 }
00210
00211 if (all_ok) {
00212 return 0;
00213 } else {
00214 return 1;
00215 }
00216 }