Panda3D
pencrypt.cxx
1 // Filename: pencrypt.cxx
2 // Created by: drose (01Sep04)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pystub.h"
16 #include "filename.h"
17 #include "encrypt_string.h"
18 #include "pnotify.h"
19 #include "panda_getopt.h"
20 #include "preprocess_argv.h"
21 
22 string password;
23 bool got_password = false;
24 string algorithm;
25 bool got_algorithm = false;
26 int key_length = -1;
27 bool got_key_length = false;
28 int iteration_count = -1;
29 bool got_iteration_count = false;
30 
31 void
32 usage() {
33  cerr
34  << "\nUsage:\n"
35  << " pencrypt [opts] file [file2 file3 ...]\n"
36  << " pencrypt -o dest_file file\n\n"
37 
38  << "This program will apply an encryption algorithm to a file (or multiple files),\n"
39  << "creating an encrypted version of each file which can only be recovered using\n"
40  << "pdecrypt and the same password that was supplied to pencrypt. The compressed\n"
41  << "versions are written to a file with the same name as the original, but the\n"
42  << "extension .pe added to the filename, and the original file is removed\n"
43  << "(unless the version with -o is used, in which case you can encrypt only one\n"
44  << "file, you specify the destination file name, and the original file is not\n"
45  << "removed).\n\n"
46 
47 
48  << "Note that if you are adding files to a Panda multifile (.mf file) with\n"
49  << "the multify command, it is not necessary to encrypt them separately;\n"
50  << "multify has an inline encryption option.\n\n"
51 
52  << "Options:\n\n"
53 
54  << " -p \"password\"\n"
55  << " Specifies the password to use for encryption. There are no\n"
56  << " restrictions on the password length or contents, but longer passwords\n"
57  << " are more secure. If this is not specified, the user is prompted from\n"
58  << " standard input.\n\n"
59 
60  << " -t Read the file as a text file. This will automatically convert\n"
61  << " universal end-of-line characters into a newline character, ascii\n"
62  << " 10.\n\n"
63 
64  << " -a \"algorithm\"\n"
65  << " Specifies the particular encryption algorithm to use. The complete\n"
66  << " set of available algorithms is defined by the current version of\n"
67  << " OpenSSL. The default algorithm is taken from the encryption-\n"
68  << " algorithm config variable.\n\n"
69 
70  << " -k key_length\n"
71  << " Specifies the key length, in bits, for the selected encryption\n"
72  << " algorithm. This only makes sense for those algorithms that support\n"
73  << " a variable key length. The default value is taken from the\n"
74  << " encryption-key-length config variable.\n\n"
75 
76  << " -i iteration_count\n"
77  << " Specifies the number of times the password is hashed to generate\n"
78  << " a key. The only purpose of this is to make it computationally\n"
79  << " more expensive for an attacker to search the key space exhaustively.\n"
80  << " This should be a multiple of 1,000 and should not exceed about 65\n"
81  << " million; the value 0 indicates just one application of the hashing\n"
82  << " algorithm. The default value is taken from the encryption-iteration-\n"
83  << " count config variable.\n\n";
84 }
85 
86 int
87 main(int argc, char **argv) {
88  extern char *optarg;
89  extern int optind;
90  const char *optstr = "o:p:ta:k:i:h";
91 
92  Filename dest_filename;
93  bool got_dest_filename = false;
94  bool text_file = false;
95 
96  preprocess_argv(argc, argv);
97  int flag = getopt(argc, argv, optstr);
98 
99  while (flag != EOF) {
100  switch (flag) {
101  case 'o':
102  dest_filename = Filename::from_os_specific(optarg);
103  got_dest_filename = true;
104  break;
105 
106  case 't':
107  text_file = true;
108  break;
109 
110  case 'p':
111  password = optarg;
112  got_password = true;
113  break;
114 
115  case 'a':
116  algorithm = optarg;
117  got_algorithm = true;
118  break;
119 
120  case 'k':
121  key_length = atoi(optarg);
122  got_key_length = true;
123  break;
124 
125  case 'i':
126  iteration_count = atoi(optarg);
127  got_iteration_count = true;
128  break;
129 
130  case 'h':
131  case '?':
132  default:
133  usage();
134  return 1;
135  }
136  flag = getopt(argc, argv, optstr);
137  }
138 
139  argc -= (optind-1);
140  argv += (optind-1);
141 
142  if (argc < 2) {
143  usage();
144  return 1;
145  }
146 
147  if (got_dest_filename && argc > 2) {
148  cerr << "Only one input file allowed in conjunction with -o.\n";
149  return 1;
150  }
151 
152  bool all_ok = true;
153  for (int i = 1; i < argc; i++) {
154  Filename source_file = Filename::from_os_specific(argv[i]);
155  if (source_file.get_extension() == "pe") {
156  cerr << source_file << " already ends .pe; skipping.\n";
157  } else {
158  Filename dest_file = dest_filename;
159  if (!got_dest_filename) {
160  dest_file = source_file.get_fullpath() + ".pe";
161  }
162 
163  // Open source file
164  pifstream read_stream;
165  if (text_file) {
166  source_file.set_text();
167  } else {
168  source_file.set_binary();
169  }
170  if (!source_file.open_read(read_stream)) {
171  cerr << "Couldn't read: " << source_file << endl;
172  all_ok = false;
173 
174  } else {
175  // Open destination file
176  pofstream write_stream;
177  dest_file.set_binary();
178  if (!dest_file.open_write(write_stream, true)) {
179  cerr << "Failed to open: " << dest_file << endl;
180  all_ok = false;
181 
182  } else {
183  // Prompt for password.
184  if (!got_password) {
185  cerr << "Enter password: ";
186  getline(cin, password);
187  got_password = true;
188  }
189 
190  cerr << dest_file << "\n";
191  bool success = encrypt_stream(read_stream, write_stream, password,
192  algorithm, key_length, iteration_count);
193 
194  read_stream.close();
195  write_stream.close();
196 
197  if (!success) {
198  cerr << "Failure writing " << dest_file << "\n";
199  all_ok = false;
200  dest_file.unlink();
201 
202  } else {
203  if (!got_dest_filename) {
204  source_file.unlink();
205  }
206  }
207  }
208  }
209  }
210  }
211 
212  if (all_ok) {
213  return 0;
214  } else {
215  return 1;
216  }
217 }
bool open_write(ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
Definition: filename.cxx:2045
string get_fullpath() const
Returns the entire filename: directory, basename, extension.
Definition: filename.I:398
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:494
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:507
string get_extension() const
Returns the file extension.
Definition: filename.I:477
bool open_read(ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:2003
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
bool unlink() const
Permanently deletes the file associated with the filename, if possible.
Definition: filename.cxx:2554
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).
Definition: filename.cxx:332