3 ###########################################################################
7 # URL: http://www.cipherdyne.org/gpgdir/
9 # Purpose: To encrypt/decrypt whole directories
11 # Author: Michael Rash (mbr@cipherdyne.com)
15 # Copyright (C) 2002-2008 Michael Rash (mbr@cipherdyne.org)
17 # License: GNU General Public License version 2 (GPLv2)
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 ###########################################################################
31 # $Id: gpgdir 335 2009-02-13 04:48:54Z mbr $
42 ### set the current gpgdir version and file revision numbers
43 my $version = '1.9.4';
44 my $revision_svn = '$Revision: 335 $';
46 ($rev_num) = $revision_svn =~ m
|\
$Rev.*:\s
+(\S
+)|;
48 ### establish some defaults
49 my $encrypt_user = '';
59 my $exclude_file = '';
61 my $include_file = '';
62 my $lib_dir = '/usr/lib/gpgdir';
64 my $total_encrypted = 0;
65 my $total_decrypted = 0;
70 my $test_and_exit = 0;
72 my $skip_test_mode = 0;
75 my $use_gpg_agent = 0; ### use gpg-agent for passwords
76 my $gpg_agent_info = '';
83 my $use_default_key = 0;
85 my $wipe_cmd = '/usr/bin/wipe';
86 my $wipe_cmdline = '';
87 my $wipe_interactive = 0;
88 my $interactive_mode = 0;
89 my $ascii_armor_mode = 0;
90 my @exclude_patterns = ();
91 my @include_patterns = ();
94 my %obfuscate_ctrs = ();
95 my %obfuscated_dirs = ();
96 my $total_mapped_files = 0;
97 my $have_obfuscated_file = 0;
98 my $cmdline_no_password = 0;
99 my $obfuscate_mode = 0;
100 my $obfuscate_map_filename = '.gpgdir_map_file';
101 my $overwrite_encrypted = 0;
102 my $overwrite_decrypted = 0;
103 my $symmetric_mode = 0;
104 my $DEL_SOURCE_FILE = 1;
105 my $NO_DEL_SOURCE_FILE = 0;
107 my $locale = 'C'; ### default LC_ALL env variable
111 my $ACCEPT_YES_DEFAULT = 1;
112 my $ACCEPT_NO_DEFAULT = 2;
114 ### turn off buffering
118 die "[*] Real and effective uid must be the same. Make sure\n",
119 " gpgdir has not been installed as a SUID binary.\n",
125 ### make Getopts case sensitive
126 Getopt
::Long
::Configure
('no_ignore_case');
128 die "[*] Use --help for usage information.\n" unless(GetOptions
(
129 'encrypt-dir=s' => \
$encrypt_dir, # Encrypt files in this directory.
130 'decrypt-dir=s' => \
$decrypt_dir, # Decrypt files in this directory.
131 'sign-dir=s' => \
$sign_dir, # Sign files in this directory.
132 'verify-dir=s' => \
$verify_dir, # Verify files in this directory.
133 'gnupg-dir=s' => \
$gpg_homedir, # Path to /path/to/.gnupg directory.
134 'pw-file=s' => \
$pw_file, # Read password out of this file.
135 'agent' => \
$use_gpg_agent, # Use gpg-agent for passwords.
136 'Agent-info=s' => \
$gpg_agent_info, # Specify GnuPG agent connection
138 'Wipe' => \
$wipe_mode, # Securely delete unencrypted files.
139 'wipe-path=s' => \
$wipe_cmd, # Path to wipe command.
140 'wipe-interactive' => \
$wipe_interactive, # Disable "wipe -I"
141 'wipe-cmdline=s' => \
$wipe_cmdline, # Specify wipe command line.
142 'Obfuscate-filenames' => \
$obfuscate_mode, # substitute real filenames
143 # with manufactured ones.
144 'obfuscate-map-file=s' => \
$obfuscate_map_filename, # path to mapping file.
145 'Force' => \
$force_mode, # Continue if files can't be deleted.
146 'overwrite-encrypted' => \
$overwrite_encrypted, # Overwrite encrypted files
147 # even if they exist.
148 'overwrite-decrypted' => \
$overwrite_decrypted, # Overwrite decrypted files
149 # even if they exist.
150 'Exclude=s' => \
$exclude_pat, # Exclude a pattern from encrypt/decrypt
152 'Exclude-from=s' => \
$exclude_file, # Exclude patterns in <file> from
153 # encrypt decrypt cycle.
154 'Include=s' => \
$include_pat, # Specify a pattern used to restrict
155 # encrypt/decrypt operation to.
156 'Include-from=s' => \
$include_file, # Specify a file of include patterns to
157 # restrict all encrypt/decrypt
159 'test-mode' => \
$test_and_exit, # Run encrypt -> decrypt test only and
161 'Trial-run' => \
$trial_run, # Don't modify any files; just show what
162 # would have happened.
163 'quiet' => \
$quiet, # Print as little as possible to
165 'Interactive' => \
$interactive_mode, # Query the user before encrypting/
166 # decrypting/deleting any files.
167 'Key-id=s' => \
$encrypt_user, # Specify encrypt/decrypt key
168 'Default-key' => \
$use_default_key, # Assume that default-key is set within
170 'Symmetric' => \
$symmetric_mode, # encrypt using symmetric cipher.
171 # (this option is not required to
172 # also decrypt, GnuPG handles
173 # that automatically).
174 'Plain-ascii' => \
$ascii_armor_mode, # Ascii armor mode (creates non-binary
176 'skip-test' => \
$skip_test_mode, # Skip encrypt -> decrypt test.
177 'no-recurse' => \
$norecurse, # Don't encrypt/decrypt files in
179 'no-delete' => \
$no_delete, # Don't delete files once they have
181 'no-password' => \
$cmdline_no_password, # Do not query for a password (only
182 # useful for when the gpg literally
184 'user-homedir=s' => \
$homedir, # Path to home directory.
185 'no-preserve-times' => \
$no_fs_times, # Don't preserve mtimes or atimes.
186 'LC_ALL=s' => \
$locale,
187 'locale=s' => \
$locale, # synonym
188 'no-LC_ALL' => \
$no_locale,
189 'no-locale' => \
$no_locale, # synonym
190 'Lib-dir=s' => \
$lib_dir, # Path to perl module path
191 'verbose' => \
$verbose, # Verbose mode.
192 'Version' => \
$printver, # Print version
193 'help' => \
$help # Print help
195 &usage_and_exit
() if $help;
197 ### set LC_ALL env variable
198 $ENV{'LC_ALL'} = $locale unless $no_locale;
200 print "[+] gpgdir v$version (file revision: $rev_num)\n",
201 " by Michael Rash <mbr\@cipherdyne.org>\n"
202 and exit 0 if $printver;
204 if ($symmetric_mode and ($use_gpg_agent or $gpg_agent_info)) {
205 die "[*] gpg-agent incompatible with --Symmetric mode";
208 die "[*] Cannot --sign-dir and --verify-dir"
209 if $sign_dir and $verify_dir;
212 $encrypt_dir = $sign_dir;
214 } elsif ($verify_dir) {
215 $decrypt_dir = $verify_dir;
219 if ($encrypt_dir and $overwrite_decrypted) {
220 die "[*] The -e and --overwrite-decrypted options are incompatible.";
222 if ($decrypt_dir and $overwrite_encrypted) {
223 die "[*] The -d and --overwrite-encrypted options are incompatible.";
226 ### import perl modules (GnuPG::Interface, etc.)
227 &import_perl_modules
();
230 unless (-e
$wipe_cmd) {
231 die "[*] Can't find wipe command at: $wipe_cmd,\n",
232 " use --wipe-path to specify path.";
234 unless (-e
$wipe_cmd) {
235 die "[*] Can't execute $wipe_cmd";
239 my $initial_dir = cwd
or die "[*] Could not get CWD: $!";
242 ### it was specified on the comamnd line
243 if ($gpg_homedir !~ m
|^/|) {
244 $gpg_homedir = $initial_dir . '/' . $gpg_homedir;
248 ### build up GnuPG options hash
250 %options = ('homedir' => $gpg_homedir);
254 'homedir' => $gpg_homedir
258 $options{'armor'} = 1 if $ascii_armor_mode or $signing_mode;
260 ### get the path to the user's home directory
261 $homedir = &get_homedir
() unless $homedir;
263 unless ($symmetric_mode) {
264 unless ($gpg_homedir) {
265 $gpg_homedir = "${homedir}/.gnupg"
266 if -d
"${homedir}/.gnupg";
268 unless (-d
$gpg_homedir) {
269 die "[*] GnuPG directory: $gpg_homedir does not exist. Please\n",
270 " create it by executing: \"gpg --gen-key\". Exiting.\n";
273 ### get the key identifier from ~/.gnupg
274 $encrypt_user = &get_key
() unless $encrypt_user or $use_default_key;
277 if ($decrypt_dir and $encrypt_dir) {
278 die "[*] Cannot encrypt and decrypt the same directory, see --help\n";
281 unless ($decrypt_dir or $encrypt_dir or $test_and_exit) {
282 die "[*] Please specify -e <dir>, -d <dir>, or --test-mode, see --help\n";
285 if ($obfuscate_mode) {
287 die "[*] -O mode incompatible with --sign-dir";
288 } elsif ($verify_dir) {
289 die "[*] -O mode incompatible with --verify-dir";
293 ### exclude file pattern
294 push @exclude_patterns, $exclude_pat if $exclude_pat;
297 open P
, "< $exclude_file" or die "[*] Could not open file: $exclude_file";
300 for my $line (@lines) {
301 next unless $line =~ /\S/;
303 push @exclude_patterns, qr{$line};
307 ### include file pattern
308 push @include_patterns, $include_pat if $include_pat;
311 open P
, "< $include_file" or die "[*] Could not open file: $include_file";
314 for my $line (@lines) {
315 next unless $line =~ /\S/;
317 push @include_patterns, qr{$line};
324 } elsif ($decrypt_dir) {
330 die "[*] Directory does not exist: $dir" unless -e
$dir;
331 die "[*] Not a directory: $dir" unless -d
$dir;
334 ### don't need to test encrypt/decrypt ability if we are running
335 ### in --Trial-run mode.
336 $skip_test_mode = 1 if $trial_run or $signing_mode or $verify_mode;
340 } elsif ($dir !~ m
|^/|) {
341 $dir = $initial_dir . '/' . $dir;
343 $dir =~ s
|/$||; ### remove any trailing slash
345 ### make sure another gpgdir process is not trying to operate
346 ### on the same directory
347 $pid_file = "$dir/.gpgdir.pid";
351 if ($symmetric_mode or $signing_mode) {
354 &get_password
() unless (($encrypt_mode and $skip_test_mode)
358 ### run a test to make sure gpgdir and encrypt and decrypt a file
359 unless ($skip_test_mode) {
360 my $rv = &test_mode
();
361 exit $rv if $test_and_exit;
365 print "[+] Signing files in directory: $dir\n" unless $quiet;
366 } elsif ($encrypt_mode) {
367 print "[+] Encrypting files in directory: $dir\n" unless $quiet;
368 } elsif ($verify_mode) {
369 print "[+] Verifying signatures in directory: $dir\n" unless $quiet;
371 print "[+] Decrypting files in directory: $dir\n" unless $quiet;
374 ### build a hash of file paths to work against
377 ### perform the gpg operation (encrypt/decrypt)
380 &obfuscated_mapping_files
() if $obfuscate_mode;
382 unless ($obfuscate_mode) {
383 if ($have_obfuscated_file) {
384 print "[-] Obfuscated filenames detected, try decrypting with -O\n"
390 print "[+] Total number of files signed: " .
391 "$total_encrypted\n" unless $quiet;
392 } elsif ($encrypt_mode) {
393 print "[+] Total number of files encrypted: " .
394 "$total_encrypted\n" unless $quiet;
395 } elsif ($verify_mode) {
396 print "[+] Total number of files verified: " .
397 "$total_decrypted\n" unless $quiet;
399 print "[+] Total number of files decrypted: " .
400 "$total_decrypted\n" unless $quiet;
404 unlink $pid_file or die "[*] Could not remove pid file $pid_file: $!";
408 #==================== end main =====================
410 sub encrypt_or_sign_file
() {
411 my ($in_file, $out_file, $del_flag) = @_;
413 my $gpg = GnuPG
::Interface
->new();
414 $gpg->options->hash_init(%options);
416 die "[*] Could not create new gpg object with ",
417 "homedir: $gpg_homedir" unless $gpg;
419 unless ($symmetric_mode or $use_default_key) {
420 $gpg->options->default_key($encrypt_user);
421 $gpg->options->push_recipients($encrypt_user);
424 my ($input_fh, $output_fh, $error_fh, $pw_fh, $status_fh) =
425 (IO
::File
->new($in_file),
426 IO
::File
->new("> $out_file"),
431 my $handles = GnuPG
::Handles
->new(
433 stdout
=> $output_fh,
435 passphrase
=> $pw_fh,
438 $handles->options('stdin')->{'direct'} = 1;
439 $handles->options('stdout')->{'direct'} = 1;
443 if ($use_gpg_agent or $gpg_agent_info) {
445 ### set environment explicitly if --Agent was specified
446 if ($gpg_agent_info) {
447 $ENV{'GPG_AGENT_INFO'} = $gpg_agent_info;
450 $pid = $gpg->encrypt('handles' => $handles,
451 'command_args' => [ qw( --use-agent ) ]);
454 if ($symmetric_mode) {
455 $pid = $gpg->encrypt_symmetrically('handles' => $handles);
456 } elsif ($signing_mode) {
457 $pid = $gpg->detach_sign('handles' => $handles);
459 $pid = $gpg->encrypt('handles' => $handles);
466 my @errors = <$error_fh>;
469 my @status = <$status_fh>;
481 print if /bad\s+pass/;
485 if (-s
$out_file == 0) {
486 &delete_file
($out_file);
487 &delete_file
($in_file) if $del_flag == $DEL_SOURCE_FILE;
488 if ($use_gpg_agent) {
489 die "[*] Created zero-size file: $out_file\n",
490 " Maybe gpg-agent does not yet have the password for that key?\n",
491 " Try with --verbose";
493 die "[*] Created zero-size file: $out_file\n",
494 " Bad password? Try with --verbose";
501 sub decrypt_or_verify_file
() {
502 my ($in_file, $out_file, $del_flag) = @_;
505 my $bad_passphrase = 0;
506 my $bad_signature = 0;
507 my $file_encrypted_with_expected_key = 0;
515 my $gpg = GnuPG
::Interface
->new();
516 $gpg->options->hash_init(%options);
518 die "[*] Could not create new gpg object with ",
519 "homedir: $gpg_homedir" unless $gpg;
521 unless ($verify_mode or $symmetric_mode or $use_default_key) {
522 $gpg->options->default_key($encrypt_user);
523 $gpg->options->push_recipients($encrypt_user);
527 ($input_fh, $output_fh, $error_fh, $status_fh) =
532 $handles = GnuPG
::Handles
->new(
534 stdout
=> $output_fh,
539 ($input_fh, $output_fh, $error_fh, $pw_fh, $status_fh) =
540 (IO
::File
->new($in_file),
541 IO
::File
->new("> $out_file"),
545 $handles = GnuPG
::Handles
->new(
547 stdout
=> $output_fh,
549 passphrase
=> $pw_fh,
552 $handles->options('stdin')->{'direct'} = 1;
553 $handles->options('stdout')->{'direct'} = 1;
556 if ($use_gpg_agent) {
557 $pid = $gpg->decrypt('handles' => $handles,
558 'command_args' => [ qw( --use-agent ) ]);
561 $pid = $gpg->wrap_call(
562 'commands' => [ qw( --verify ) ],
563 'command_args' => [ ( $in_file ) ],
564 'handles' => $handles
567 $pid = $gpg->decrypt('handles' => $handles);
571 unless ($verify_mode) {
576 my @errors = <$error_fh>;
579 my @status = <$status_fh>;
589 ### [GNUPG:] BADSIG 9EEEEE6BEE428EEE Some User <someone@domain.com>
590 $bad_signature = 1 if /BADSIG/;
592 ### [GNUPG:] BAD_PASSPHRASE C326F95CE133EA4E
593 $bad_passphrase = 1 if /BAD_?PASS/;
594 if (/NEED_PASSPHRASE\s\S+\s+\S+$encrypt_user\s/) {
595 ### [GNUPG:] NEED_PASSPHRASE CDE4D7DDFD66DCB9 95D85DDDDD42D39D 16 0
596 $file_encrypted_with_expected_key = 1;
597 } elsif ((length($encrypt_user) == 8)
598 and /USERID_HINT\s+.*$encrypt_user/) {
599 $file_encrypted_with_expected_key = 1;
605 print " GnuPG errors:\n";
607 print " GnuPG status:\n";
619 if ($bad_passphrase) {
620 if (-s
$out_file == 0) {
621 &delete_file
($out_file);
622 &delete_file
($in_file) if $del_flag == $DEL_SOURCE_FILE;
623 if ($file_encrypted_with_expected_key) {
624 die "[*] Bad passphrase, try gpgdir with -v";
626 print "[-] Skipping file encrypted with different ",
627 "GnuPG key: $in_file\n" unless $quiet;
631 "[*] Bad passphrase, but created non-zero sized output file, should not\n",
632 " happen. Try with --verbose";
634 } elsif (-s
$out_file == 0) {
635 &delete_file
($out_file);
636 &delete_file
($in_file) if $del_flag == $DEL_SOURCE_FILE;
637 if ($use_gpg_agent) {
638 die "[*] Created zero-size file: $out_file\n",
639 " Maybe gpg-agent does not yet have the password for that key?\n",
640 " Try with --verbose";
642 die "[*] Created zero-size file: $out_file\n",
643 " Bad password? Try with --verbose";
646 if ($bad_signature) {
655 return if $no_delete;
656 return unless -e
$file;
661 $cmd .= " $wipe_cmdline ";
663 if ($wipe_interactive) {
671 print " Executing: $cmd\n";
682 my $msg = "[-] Could not delete file: $file\n";
684 print $msg unless $quiet;
686 die $msg unless $quiet;
692 sub gpg_operation
() {
694 ### sort by oldest to youngest mtime
695 FILE
: for my $file (sort
696 {$files{$a}{'mtime'} <=> $files{$b}{'mtime'}} keys %files) {
698 ### see if we have an exclusion pattern that implies
699 ### we should skip this file
700 if (@exclude_patterns and &exclude_file
($file)) {
701 print "[+] Skipping excluded file: $file\n"
702 if $verbose and not $quiet;
706 ### see if we have an inclusion pattern that implies
707 ### we should process this file
708 if (@include_patterns and not &include_file
($file)) {
709 print "[+] Skipping non-included file: $file\n"
710 if $verbose and not $quiet;
714 ### dir is always a full path
715 my ($dir, $filename) = ($file =~ m
|(.*)/(.*)|);
717 unless (chdir($dir)) {
718 print "[-] Could not chdir $dir, skipping.\n" unless $quiet;
722 my $mtime = $files{$file}{'mtime'};
723 my $atime = $files{$file}{'atime'};
727 my $encrypt_filename = "$filename.gpg";
729 if ($obfuscate_mode) {
731 unless (defined $obfuscate_ctrs{$dir}) {
733 ### create a new gpgdir mapping file for obfuscated file
734 ### names, but preserve any previously encrypted file
736 &handle_old_obfuscated_map_file
();
738 ### make obfuscated file names start at 1 for each
740 $obfuscate_ctrs{$dir} = 1;
743 $encrypt_filename = 'gpgdir_' . $obfuscate_ctrs{$dir} . '.gpg';
746 if ($ascii_armor_mode or $signing_mode) {
747 $encrypt_filename = "$filename.asc";
750 if (-e
$encrypt_filename and not $overwrite_encrypted) {
751 my $str = 'Encrypted';
752 $str = 'Signed' if $signing_mode;
753 print "[-] $str file $dir/$encrypt_filename already ",
754 "exists, skipping.\n" unless $quiet;
758 if ($interactive_mode) {
760 $str = 'Sign' if $signing_mode;
761 next FILE
unless (&query_yes_no
(
762 " $str: $file ([y]/n)? ", $ACCEPT_YES_DEFAULT));
765 my $str = 'Encrypting';
766 $str = 'Signing' if $signing_mode;
767 print "[+] $str: $file\n" unless $quiet;
769 unless ($trial_run) {
771 my $rv = &encrypt_or_sign_file
($filename, $encrypt_filename,
772 $NO_DEL_SOURCE_FILE);
774 if (-e
$encrypt_filename and -s
$encrypt_filename != 0) {
775 ### set the atime and mtime to be the same as the
777 unless ($no_fs_times) {
778 if (defined $mtime and $mtime and
779 defined $atime and $atime) {
780 utime $atime, $mtime, $encrypt_filename;
784 unless ($signing_mode) {
785 ### only delete the original file if
786 ### the encrypted one exists
787 if ($wipe_mode and not $quiet) {
788 print " Securely deleting file: $file\n";
790 &delete_file
($filename);
792 if ($obfuscate_mode) {
794 ### record the original file name mapping
795 &append_obfuscated_mapping
($filename,
798 $obfuscate_ctrs{$dir}++;
806 $str = 'sign' if $signing_mode;
807 print "[-] Could not $str file: $file\n" unless $quiet;
814 ### allow filenames with spaces
815 my $decrypt_filename = '';
816 if ($filename =~ /^(.+)\.gpg$/) {
817 $decrypt_filename = $1;
818 } elsif ($filename =~ /^(.+)\.asc$/) {
819 $decrypt_filename = $1;
822 if ($obfuscate_mode) {
824 &import_obfuscated_file_map
($dir)
825 unless defined $obfuscated_dirs{$dir};
827 if (defined $obfuscated_dirs{$dir}{$filename}) {
828 $decrypt_filename = $obfuscated_dirs{$dir}{$filename};
831 print "[-] Obfuscated file map does not exist for ",
832 "$filename in\n $obfuscate_map_filename, ",
833 "skipping.\n" unless $quiet;
838 if (not $force_mode and ($file =~ /gpgdir_\d+_\d+\.gpg/
839 or $file =~ /gpgdir_\d+\.gpg/)) {
840 ### be careful not to decrypt obfuscated file unless we
841 ### are running in -O mode. This ensures that the
842 ### original file names will be acquired from the
843 ### /some/dir/.gpgdir_map_file
844 $have_obfuscated_file = 1;
849 ### length() allows files named "0"
850 next FILE
unless length($decrypt_filename) > 0;
853 unless (-e
$decrypt_filename) {
854 print "[-] Original file $decrypt_filename ",
855 "does not exist, skipping.\n";
859 ### don't decrypt a file on top of a normal file of
861 if (-e
$decrypt_filename and not $overwrite_decrypted) {
862 print "[-] Decrypted file $dir/$decrypt_filename ",
863 "already exists. Skipping.\n" unless $quiet;
868 if ($interactive_mode) {
870 $str = 'Verify' if $verify_mode;
871 next FILE
unless (&query_yes_no
(
872 " $str: $file ([y]/n)? ", $ACCEPT_YES_DEFAULT));
875 unless ($trial_run) {
876 my $str = 'Decrypting';
877 $str = 'Verifying' if $verify_mode;
878 print "[+] $str: $dir/$filename\n" unless $quiet;
879 my $rv = &decrypt_or_verify_file
($filename, $decrypt_filename,
880 $NO_DEL_SOURCE_FILE);
883 $total_decrypted++ if $rv;
885 if (-e
$decrypt_filename and -s
$decrypt_filename != 0) {
886 ### set the atime and mtime to be the same as the
888 unless ($no_fs_times) {
889 if (defined $mtime and $mtime and
890 defined $atime and $atime) {
891 utime $atime, $mtime, $decrypt_filename;
894 if ($wipe_mode and not $quiet) {
895 print " Securely deleting file: $file\n";
897 ### only delete the original encrypted
898 ### file if the decrypted one exists
899 &delete_file
($filename);
904 print "[-] Could not decrypt file: $file\n"
912 print "\n" unless $quiet;
913 chdir $initial_dir or die "[*] Could not chdir: $initial_dir\n";
920 print "[+] Building file list...\n" unless $quiet;
922 opendir D
, $dir or die "[*] Could not open $dir: $!";
923 my @files = readdir D
;
926 for my $file (@files) {
927 next if $file eq '.';
928 next if $file eq '..';
929 &check_file_criteria
("$dir/$file");
932 ### get all files in all subdirectories
933 find
(\
&find_files
, $dir);
940 for my $pat (@exclude_patterns) {
941 if ($file =~ m
|$pat|) {
942 print "[+] Skipping $file (matches exclude pattern: $pat)\n"
943 if $verbose and not $quiet;
952 for my $pat (@include_patterns) {
953 if ($file =~ m
|$pat|) {
954 print "[+] Including $file (matches include pattern: $pat)\n"
955 if $verbose and not $quiet;
962 sub obfuscated_mapping_files
() {
967 $dirs_href = \
%obfuscate_ctrs;
969 $dirs_href = \
%obfuscated_dirs;
972 DIR
: for my $dir (keys %$dirs_href) {
973 unless (chdir($dir)) {
974 print "[-] Could not chdir $dir, skipping.\n" unless $quiet;
979 next DIR
unless -e
$obfuscate_map_filename;
980 ### encrypt the map file now that we have encrypted
982 print "[+] Encrypting mapping file: ",
983 "$dir/$obfuscate_map_filename\n" unless $quiet;
984 unless ($trial_run) {
985 &encrypt_or_sign_file
($obfuscate_map_filename,
986 "$obfuscate_map_filename.gpg", $NO_DEL_SOURCE_FILE);
988 unlink $obfuscate_map_filename;
991 next DIR
unless -e
"$obfuscate_map_filename.gpg";
992 ### delete the map file since we have decrypted
994 print "[+] Decrypting mapping file: ",
995 "$dir/$obfuscate_map_filename.gpg\n" unless $quiet;
996 unless ($trial_run) {
997 &decrypt_or_verify_file
("$obfuscate_map_filename.gpg",
998 $obfuscate_map_filename, $NO_DEL_SOURCE_FILE);
1000 unlink "$obfuscate_map_filename.gpg";
1001 if ($total_mapped_files == $total_decrypted) {
1002 ### we are confident that we decrypted all of them,
1003 ### so delete the mapping file.
1004 unlink $obfuscate_map_filename;
1012 sub handle_old_obfuscated_map_file
() {
1013 return unless -e
"$obfuscate_map_filename.gpg";
1015 &decrypt_or_verify_file
("$obfuscate_map_filename.gpg",
1016 $obfuscate_map_filename, $NO_DEL_SOURCE_FILE);
1018 unlink "$obfuscate_map_filename.gpg";
1020 my @existing_obfuscated_files = ();
1022 open F
, "< $obfuscate_map_filename" or die "[*] Could not open ",
1023 "$obfuscate_map_filename: $!";
1025 if (/^\s*.*\s+(gpgdir_\d+_\d+\.gpg)/) {
1027 push @existing_obfuscated_files, $_;
1029 } elsif (/^\s*.*\s+(gpgdir_\d+\.gpg)/) {
1031 push @existing_obfuscated_files, $_;
1037 if (@existing_obfuscated_files) {
1038 ### there are some obfuscated files from a previous gpgdir
1040 open G
, "> $obfuscate_map_filename" or die "[*] Could not open ",
1041 "$obfuscate_map_filename: $!";
1042 print G
for @existing_obfuscated_files;
1048 sub append_obfuscated_mapping
() {
1049 my ($filename, $encrypt_filename) = @_;
1051 open G
, ">> $obfuscate_map_filename" or die "[*] Could not open ",
1052 "$obfuscate_map_filename: $!";
1053 print G
"$filename $encrypt_filename\n";
1058 sub import_obfuscated_file_map
() {
1061 $obfuscated_dirs{$dir} = {};
1063 return unless -e
"$obfuscate_map_filename.gpg";
1065 &decrypt_or_verify_file
("$obfuscate_map_filename.gpg",
1066 $obfuscate_map_filename, $NO_DEL_SOURCE_FILE);
1068 open G
, "< $obfuscate_map_filename" or die "[*] Could not open ",
1069 "$obfuscate_map_filename: $!";
1071 if (/^\s*(.*)\s+(gpgdir_\d+_\d+\.gpg)/) {
1072 $obfuscated_dirs{$dir}{$2} = $1;
1073 $total_mapped_files++;
1074 } elsif (/^\s*(.*)\s+(gpgdir_\d+\.gpg)/) {
1075 $obfuscated_dirs{$dir}{$2} = $1;
1076 $total_mapped_files++;
1087 if (-e
'/etc/passwd') {
1088 open P
, '< /etc/passwd' or
1089 die "[*] Could not open /etc/passwd. Exiting.\n";
1092 for my $line (@lines) {
1093 ### mbr:x:222:222:Michael Rash:/home/mbr:/bin/bash
1095 if ($line =~ /^(?:.*:){2}$uid:(?:.*:){2}(\S+):/) {
1101 $homedir = $ENV{'HOME'} if defined $ENV{'HOME'};
1103 die "[*] Could not determine home directory. Use the -u <homedir> option."
1109 if (-e
"${homedir}/.gpgdirrc") {
1110 open F
, "< ${homedir}/.gpgdirrc" or die "[*] Could not open ",
1111 "${homedir}/.gpgdirrc. Exiting.\n";
1115 for my $line (@lines) {
1117 if ($line =~ /^\s*default_key/) {
1118 ### prefer to use the default GnuPG key
1119 $use_default_key = 1;
1121 } elsif ($line =~ /^\s*use_key\s+(.*)$/) {
1122 ### GnuPG accepts strings to match the key, so we don't
1123 ### have to strictly require a key ID... just a string
1124 ### that matches the key
1129 "[*] Please edit ${homedir}/.gpgdirrc to include your gpg key identifier\n",
1130 " (e.g. \"D4696445\"; see the output of \"gpg --list-keys\"), or use the\n",
1131 " default GnuPG key defined in ~/.gnupg/options";
1133 print "[+] Creating gpgdir rc file: $homedir/.gpgdirrc\n";
1134 open F
, "> ${homedir}/.gpgdirrc" or die "[*] Could not open " .
1135 "${homedir}/.gpgdirrc. Exiting.\n";
1137 print F
<<_CONFIGRC_
;
1138 # Config file for gpgdir.
1140 # Set the key to use to encrypt files with "use_key <key>", e.g.
1141 # "use_key D4696445". See "gpg --list-keys" for a list of keys on your
1142 # GnuPG key ring. Alternatively, if you want gpgdir to always use the
1143 # default key that is defined by the "default-key" variable in
1144 # ~/.gnupg/options, then uncomment the "default_key" line below.
1146 # Uncomment to use the GnuPG default key defined in ~/.gnupg/options:
1149 # If you want to use a specific GnuPG key, Uncomment the next line and
1150 # replace "KEYID" with your real key id:
1156 "[*] Please edit $homedir/.gpgdirrc to include your gpg key identifier,\n",
1157 " or use the default GnuPG key defined in ~/.gnupg/options. Exiting.\n";
1161 my $file = $File::Find
::name
;
1162 &check_file_criteria
($file);
1166 sub check_file_criteria
() {
1168 ### skip all links, zero size files, all hidden
1169 ### files (includes the .gnupg directory), etc.
1172 unless ($force_mode) {
1173 if ($file =~ m
|/\
.|) {
1174 print "[-] Skipping file: $file\n"
1175 if $verbose and not $quiet;
1180 if (-e
$file and not -l
$file and -s
$file != 0
1181 and $file !~ m
|\
.gpgdir\
.pid
| and $file !~ m
|\
.gnupg
|) {
1182 if ($encrypt_mode or $signing_mode) {
1183 if ($file =~ m
|\
.gpg
| or $file =~ m
|\
.asc
|) {
1184 print "[-] Skipping encrypted/signed file: $file\n" unless $quiet;
1187 } elsif ($verify_mode) {
1188 unless ($file =~ m
|\
.asc
|) {
1189 ### only pick up the signature files
1193 unless ($file =~ m
|\
.gpg
| or $file =~ m
|\
.asc
|) {
1194 print "[-] Skipping unencrypted file: $file\n" unless $quiet;
1198 my ($atime, $mtime) = (stat($file))[8,9];
1199 $files{$file}{'atime'} = $atime;
1200 $files{$file}{'mtime'} = $mtime;
1202 print "[-] Skipping file: $file\n"
1203 if $verbose and not $quiet;
1208 sub get_password
() {
1210 ### this is only useful if the gpg key literally has no password
1211 ### (usually this is not the case, but gpgdir will support it if
1213 return if $cmdline_no_password;
1215 ### if we are using gpg-agent for passwords, then return
1216 return if $use_gpg_agent;
1219 open PW
, "< $pw_file" or die "[*] Could not open $pw_file: $!";
1224 print "[+] Executing: gpgdir @args_cp\n" unless $quiet;
1225 if ($symmetric_mode) {
1226 print " [Symmetric mode]\n" unless $quiet;
1228 if ($use_default_key) {
1229 print " Using default GnuPG key.\n" unless $quiet;
1231 print " Using GnuPG key: $encrypt_user\n" unless $quiet;
1234 if ($test_and_exit) {
1235 print " *** test_mode() ***\n" unless $quiet;
1237 if ($signing_mode) {
1238 print " Enter signing password.\n" unless $quiet;
1239 } elsif ($encrypt_mode) {
1240 print ' Enter password (for initial ' .
1241 "encrypt/decrypt test)\n" unless $quiet;
1243 my $msg = 'Password: ';
1244 ### get the password without echoing the chars back to the screen
1262 chdir $dir or die "[*] Could not chdir($dir): $!";
1264 my $test_file = "gpgdir_test.$$";
1265 print "[+] test_mode(): Encrypt/Decrypt test of $test_file\n"
1266 if (($test_and_exit or $verbose) and not $quiet);
1268 if (-e
$test_file) {
1269 &delete_file
($test_file) or
1270 die "[*] test_mode(): Could not remove $test_file: $!";
1272 if (-e
"$test_file.gpg") {
1273 &delete_file
("$test_file.gpg") or
1274 die "[*] test_mode(): Could not remove $test_file.gpg: $!";
1277 open G
, "> $test_file" or
1278 die "[*] test_mode(): Could not create $test_file: $!";
1279 print G
"gpgdir test\n";
1282 if (-e
$test_file) {
1283 print "[+] test_mode(): Created $test_file\n"
1284 if (($test_and_exit or $verbose) and not $quiet);
1286 die "[*] test_mode(): Could not create $test_file\n";
1289 &encrypt_or_sign_file
($test_file, "${test_file}.gpg", $DEL_SOURCE_FILE);
1291 if (-e
"$test_file.gpg" and (-s
$test_file != 0)) {
1292 print "[+] test_mode(): Successful encrypt of $test_file\n"
1293 if (($test_and_exit or $verbose) and not $quiet);
1294 &delete_file
($test_file) if -e
$test_file;
1296 die "[*] test_mode(): not encrypt $test_file (try adding -v).\n";
1299 &decrypt_or_verify_file
("${test_file}.gpg", $test_file, $DEL_SOURCE_FILE);
1301 if (-e
$test_file and (-s
$test_file != 0)) {
1302 print "[+] test_mode(): Successful decrypt of $test_file\n"
1303 if (($test_and_exit or $verbose) and not $quiet);
1305 die "[*] test_mode(): Could not decrypt $test_file.gpg ",
1306 "(try adding -v).\n";
1308 open F
, "< $test_file" or
1309 die "[*] test_mode(): Could not open $test_file: $!";
1313 if (defined $line and $line =~ /\S/) {
1315 if ($line eq 'gpgdir test') {
1316 print "[+] test_mode(): Decrypted content matches original.\n",
1317 "[+] test_mode(): Success!\n\n"
1318 if (($test_and_exit or $verbose) and not $quiet);
1320 die "[*] test_mode(): Decrypted content does not match ",
1321 "original (try adding -v).";
1324 die "[*] test_mode(): Fail (try adding -v).\n";
1326 &delete_file
($test_file) if -e
$test_file;
1327 &delete_file
("$test_file.gpg") if -e
"$test_file.gpg";
1329 chdir $initial_dir or die "[*] Could not chdir($initial_dir)";
1331 return 0; ### exit status
1334 sub query_yes_no
() {
1335 my ($msg, $style) = @_;
1337 while ($ans ne 'y' and $ans ne 'n') {
1340 if ($style == $ACCEPT_YES_DEFAULT) {
1341 return 1 if $ans eq "\n";
1342 } elsif ($style == $ACCEPT_NO_DEFAULT) {
1343 return 0 if $ans eq "\n";
1347 return 1 if $ans eq 'y';
1352 return unless -e
$pid_file;
1353 open P
, "< $pid_file" or die "[*] Could not open $pid_file: $!";
1358 die "[*] Another gpgdir process (pid: $pid) is already ",
1359 "running against\n $dir";
1365 open P
, "> $pid_file" or die "[*] Could not open $pid_file: $!";
1371 sub import_perl_modules
() {
1373 my $mod_paths_ar = &get_mod_paths
();
1375 if ($#$mod_paths_ar > -1) { ### /usr/lib/gpgdir/ exists
1376 push @
$mod_paths_ar, @INC;
1377 splice @INC, 0, $#$mod_paths_ar+1, @$mod_paths_ar;
1381 print "[+] import_perl_modules(): The \@INC array:\n";
1382 print "$_\n" for @INC;
1385 require GnuPG
::Interface
;
1386 require Term
::ReadKey
;
1388 Term
::ReadKey
->import(qw
/ReadMode ReadLine/);
1393 sub get_mod_paths
() {
1397 unless (-d
$lib_dir) {
1398 my $dir_tmp = $lib_dir;
1399 $dir_tmp =~ s
|lib
/|lib64/|;
1401 $lib_dir = $dir_tmp;
1407 opendir D
, $lib_dir or die "[*] Could not open $lib_dir: $!";
1408 my @dirs = readdir D
;
1411 push @paths, $lib_dir;
1413 for my $dir (@dirs) {
1414 ### get directories like "/usr/lib/gpgdir/x86_64-linux"
1415 next unless -d
"$lib_dir/$dir";
1416 push @paths, "$lib_dir/$dir"
1417 if $dir =~ m
|linux
| or $dir =~ m
|thread
|
1418 or (-d
"$lib_dir/$dir/auto");
1423 sub usage_and_exit
() {
1426 gpgdir
; Recursive direction encryption
and decryption with GnuPG
1428 [+] Version
: $version (file revision
: $rev_num)
1429 By Michael Rash
(mbr\
@cipherdyne.org
)
1430 URL
: http
://www
.cipherdyne
.org
/gpgdir/
1432 Usage
: gpgdir
-e
|-d
<directory
> [options
]
1435 -e
, --encrypt
<directory
> - Recursively encrypt all files
in
1436 <directory
> and all subdirectories
.
1437 -d
, --decrypt
<directory
> - Recursively decrypt all files
in
1438 <directory
> and all subdirectories
.
1439 --sign
<directory
> - Recursively sign all files
in <directory
>
1440 and all subdirectories
.
1441 --verify
<directory
> - Recursively verify all GnuPG signatures
1443 -K
, --Key
-id
<id
> - Specify GnuPG key ID
, or key
-matching
1444 string
. This overrides the use_key value
1446 -D
, --Default
-key
- Use the key that GnuPG defines as the
1447 default (i
.e
. the key that is specified
1448 by the
default-key option
in
1450 -a
, --agent
- Acquire password information from a
1451 running instance of gpg
-agent
.
1452 -A
, --Agent
-info
<info
> - Specify the value
for the GPG_AGENT_INFO
1453 environment variable as returned by
1454 'gpg-agent --daemon'.
1455 -g
, --gnupg
-dir
<dir
> - Specify a path to a
.gnupg directory
for
1456 gpg
keys (the
default is
~/.gnupg
if this
1457 option is
not used
).
1458 -S
, --Symmetric
- Use symmetric encryption instead of the
1459 default asymmetric encryption
.
1460 -p
, --pw
-file
<file
> - Read password
in from
<file
>.
1461 --skip
-test
- Skip encrypt
-> decrypt test
.
1462 -t
, --test
-mode
- Run encrypt
-> decrypt test
and exit.
1463 -T
, --Trial
-run
- Show what filesystem actions would take
1464 place without actually doing them
.
1465 -P
, --Plain
-ascii
- Ascii armor mode
(creates non
-binary
1467 --Interactive
- Query the user before encrypting
,
1468 decrypting
, or deleting any files
.
1469 --Exclude
<pattern
> - Skip all filenames that match
<pattern
>.
1470 --Exclude
-from
<file
> - Skip all filenames that match any pattern
1471 contained within
<file
>.
1472 --Include
<pattern
> - Include only those filenames that match
1474 --Include
-from
<file
> - Include only those filenames that match a
1475 pattern contained within
<file
>.
1476 -O
, --Obfuscate
-filenames
- Substitute all real filenames
in a
1477 directory with manufactured ones
(the
1478 original filenames are preserved
in a
1479 mapping file
and restored
when the
1480 directory is decrypted
).
1481 --obfuscate
-map_file
<file
> - Specify path to obfuscated mapping file
1483 -F
, --Force
- Continue to run even
if files cannot be
1484 deleted
(because of permissions problems
1486 --overwrite
-encrypted
- Overwrite encrypted files even
if a
1487 previous
<file
>.gpg file already
exists.
1488 --overwrite
-decrypted
- Overwrite decrypted files even
if the
1489 previous unencrypted file already
exists.
1490 -q
, --quiet
- Print as little to the screen as possible
1491 -W
, --Wipe
- Use the
'wipe' command to securely
delete
1492 unencrypted copies of files after they
1493 have been encrypted
.
1494 --wipe
-path
<path
> - Specify path to the wipe command
.
1495 --wipe
-interactive
- Force interactive mode with the wipe
1497 --wipe
-cmdline
<args
> - Manually specify command line arguments
1498 to the wipe command
.
1499 --no-recurse
- Don
't recursively encrypt/decrypt
1501 --no-delete - Don't
delete original unencrypted files
.
1502 --no-preserve
-times - Don
't preserve original mtime and atime
1503 values on encrypted/decrypted files.
1504 --no-password - Assume the gpg key has no password at all
1505 (this is not common).
1506 -u, --user-homedir <dir> - Path to home directory.
1507 -l, --locale <locale> - Manually define a locale setting.
1508 --Lib-dir <path> - Path to the perl modules directory (not
1510 --no-locale - Don't set the locale to anything
(the
1511 default is the
"C" locale
).
1512 --verbose
- Run
in verbose mode
.
1513 -V
, --Version
- print version
.
1514 -h
, --help
- print help
.