#!/bin/sh # the next line restarts using wish \ exec wish "$0" "$@" # TkCryptDir - encrypt/decrypt files in specified directories # Version 0.2, 2001-05-13 # # Copyright (C) 2001 by Tom Sato # # http://member.nifty.ne.jp/tsato/tkdeskset/ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU General Public License for more details. # Usage: # tkcryptdir [ directory... ] set program_name "TkCryptDir" set title "$program_name (Version 0.2)" set crypt_command "crypt" if { [ catch { set cmd [ exec which $crypt_command ] } ] \ || ! [ file executable $cmd ] } { set crypt_command "enigma" } set decrypt_command $crypt_command set md5sum_command "md5sum" set mode "Encrypt" set use_md5 1 set verbose 0 set org_dir [ pwd ] set lang "C" if { ! [ catch { kanji code "abc" } ] } { catch { set lang $env(LANG) } catch { set lang $env(LC_ALL) } catch { set lang $env(LC_MESSAGES) } } set env(LC_MESSAGES) "C" proc gettext msg { global lang if [ regexp {^ja_|^japanese|^ja$} $lang junk ] { switch -glob $msg { "Encrypt" { return "暗号化" } "Decrypt" { return "復号化" } "Set" { return "設定" } "Cancel" { return "取消" } "Abort" { return "中止" } "Quit" { return "終了" } "Current Directory:" { return "現在のディレクトリ:" } "Operation:" { return "操作:" } "Directory:" { return "ディレクトリ:" } "Encryption Key:" { return "暗号鍵:" } "Re-type the Encryption Key:" { return "暗号鍵を再入力:" } "Use MD5 Fingerprint?" { return "MD5 指紋を使用する?" } "No such directory: %s" { return "ディレクトリがありません: %s" } "Processed Files: %-5d" { return "処理されたファイル: %-5d" } "Failed Files: %-5d" { return "失敗したファイル: %-5d" } "Encryption key not specified" { return "暗号鍵が指定されていません" } "Encryption key mismatch" { return "暗号鍵が一致していません" } "%d files encrypted" { return "%d 個のファイルを暗号化しました" } "%d files decrypted\n%d files failed" \ { return "%d 個のファイルを復号化しました\n\ %d 個のファイルの復号に失敗しました" } "%d files decrypted successfully" \ { return "%d 個のファイルを復号化しました" } "Encrypted file not found in the directory" \ { return "ディレクトリ内に暗号化されたファイルが見付かりません" } "Directory \"%s\" is not writable.*" \ { return "ディレクトリ \"%s\" は書き込み可能ではありません。\n\ 本当にこのディレクトリのファイルの暗号化/復号化を行ないますか?" } default \ { return $msg } } } return $msg } proc update_progress_panel {} { global processed_files failed_files if { ! [ winfo exists .progress_panel ] } { toplevel .progress_panel -border 1m wm title .progress_panel "TkCryptDir - Progress" wm transient .progress_panel . frame .progress_panel.frame -border 2 -relief groove pack .progress_panel.frame -pady 1m label .progress_panel.frame.processed label .progress_panel.frame.failed pack .progress_panel.frame.processed .progress_panel.frame.failed \ -side top -anchor w button .progress_panel.abort -text [ gettext "Abort" ] \ -command { abort_processing } pack .progress_panel.abort -side top -anchor w } .progress_panel.frame.processed configure \ -text [ format [ gettext "Processed Files: %-5d" ] $processed_files ] .progress_panel.frame.failed configure \ -text [ format [ gettext "Failed Files: %-5d" ] $failed_files ] update } proc abort_processing {} { global aborted set aborted 1 } proc crypt {} { global top_dir crypt_command decrypt_command md5sum_command verbose global mode password password2 use_md5 global processed_files failed_files aborted if { $top_dir == "" } { set top_dir "/" } if { ! [ file isdirectory $top_dir ] } { tk_messageBox -title "TkCryptDir - Error" \ -type ok -icon warning \ -message [ format [ gettext "No such directory: %s" ] $top_dir ] return } if { ! [ file writable $top_dir ] } { if { [ tk_messageBox -title "TkCryptDir - Confirm" \ -type yesno -icon question \ -message [ format [ gettext "Directory \"%s\" is not writable.\n\n\ Do you realy want to encrypt/decrypt files\ in this directory?" ] $top_dir ] ] != "yes" } { return } } set cur_password $password if { $cur_password == "" } { tk_messageBox -title "TkCryptDir - Error" -type ok -icon warning \ -message [ gettext "Encryption key not specified" ] return } set aborted 0 set processed_files 0 set failed_files 0 .crypt configure -state disabled update if { $mode == "Encrypt" } { if { $cur_password != $password2 } { tk_messageBox -title "TkCryptDir - Error" -type ok -icon warning \ -message [ gettext "Encryption key mismatch" ] } else { set f [ open "| find $top_dir -type f -print" r ] while { 0 <= [ gets $f filename ] } { if { ! [ regexp {\.crypt(-md5)?$} $filename ] } { if { $use_md5 } { eval exec "$md5sum_command < $filename > $filename.crypt-md5" } catch { eval exec "$crypt_command $cur_password < $filename > $filename.crypt" } if { [ file size $filename ] == [ file size $filename.crypt ] } { if { $verbose } { puts "$filename - crypted" } catch { file delete $filename } incr processed_files } else { if { $verbose } { puts "$filename - failed" } catch { file delete $filename.crypt $filename.crypt-md5 } incr failed_files } update_progress_panel if { $aborted } { break } } } catch { close $f } if [ winfo exists .progress_panel ] { destroy .progress_panel } tk_messageBox -title "TkCryptDir - Summary" -type ok -icon info \ -message [ format [ gettext "%d files encrypted" ] \ $processed_files ] } } else { set dir [ open "| find $top_dir -type f -print" r ] while { 0 <= [ gets $dir filename ] } { set ok 0 if [ regexp {\.crypt$} $filename ] { regsub {\.crypt$} $filename "" basename if [ file exists $basename ] { if { $verbose } { puts "$filename - skipped (\"$basename\" exists)" } } else { set tmpfile "$basename.decrypted" if { $use_md5 } { if [ file exists $filename-md5 ] { catch { eval exec "$decrypt_command $cur_password < $filename > $tmpfile" } set f [ open "| $md5sum_command < $tmpfile" r ]; gets $f s1; close $f set f [ open $filename-md5 r ]; gets $f s2; close $f if { $s1 == $s2 } { set ok 1 } else { if { $verbose } { puts "$filename - failed (MD5 fingerprint)" } } } } else { catch { eval exec "$decrypt_command $cur_password < $filename > $tmpfile" } if { [ file size $filename ] == [ file size $tmpfile ] } { set ok 1 } else { if { $verbose } { puts "$filename - failed (file size mismatch)" } } } } if { $ok } { if { $verbose } { puts "$filename - decrypted" } file rename $tmpfile $basename catch { file delete $filename $filename-md5 } incr processed_files } else { incr failed_files } catch { file delete $tmpfile } update_progress_panel if { $aborted } { break } } } catch { close $dir } if [ winfo exists .progress_panel ] { destroy .progress_panel } if { $failed_files != 0 } { tk_messageBox -title "TkCryptDir - Summary" -type ok -icon info \ -message [ format [ gettext "%d files decrypted\n%d files failed" ] \ $processed_files $failed_files ] } elseif { $processed_files != 0 } { tk_messageBox -title "TkCryptDir - Summary" -type ok -icon info \ -message [ format [ gettext "%d files decrypted successfully" ] \ $processed_files ] } else { tk_messageBox -title "TkCryptDir - Summary" -type ok -icon info \ -message [ gettext "Encrypted file not found in the directory" ] } } catch { file delete $tmpfile } .crypt configure -state normal } proc mode_changed { { name 1 } { op 2 } { var 3 } } { global mode password2 if { $mode == "Encrypt" } { .form.password2.label configure -fg black .form.password2.entry configure -state normal -border 2 .crypt configure -text [ gettext "Encrypt" ] } else { set password2 "" .form.password2.label configure -fg gray50 .form.password2.entry configure -state disabled -border 1 .crypt configure -text [ gettext "Decrypt" ] } } ################################################################ # File browser proc browse_directory { mode dir } { global program_name browse_mode cur_folder set browse_mode $mode set cur_folder $dir if [ winfo exists .dir ] { destroy .dir } toplevel .dir wm title .dir "$program_name - Browse" wm transient .dir . frame .dir.bottom_frame label .dir.folder_label -text [ gettext "Current Directory:" ] entry .dir.cur_folder -textvariable cur_folder -width 50 bind .dir.cur_folder { refresh_directroy } listbox .dir.list -width 30 -height 10 \ -selectmode single -exportselection false \ -yscrollcommand ".dir.scroll set" scrollbar .dir.scroll -orient vertical -command ".dir.list yview" button .dir.done -text [ gettext "Set" ] -command { browse_done } button .dir.cancel -text [ gettext "Cancel" ] -command { destroy .dir } pack .dir.folder_label -side top -anchor w pack .dir.cur_folder -side top -anchor w -padx 6m -fill x pack .dir.bottom_frame -side bottom pack .dir.list -side left -pady 3m -fill both -expand true pack .dir.scroll -side right -pady 3m -fill y pack .dir.done .dir.cancel -in .dir.bottom_frame -side left -padx 1m # set_geometry .dir bind .dir.list { refresh_directroy } refresh_directroy } proc refresh_directroy {} { global browse_mode cur_folder org_dir if { $cur_folder == "" } { set cur_folder "/" } set n [ .dir.list curselection ] set s "/" if { 0 <= $n } { set s [ .dir.list get $n ] if { ! [ string match "*/" $cur_folder ] } { append cur_folder "/" } if [ string match "..*" $s ] { regexp {^(.*/)[^/]+/?$} $cur_folder junk cur_folder } else { set s "$cur_folder$s" if [ file isdirectory $s ] { set cur_folder $s } } } if [ file isdirectory $s ] { .dir.list delete 0 end if { ! [ change_dir $cur_folder ] } { set cur_folder $org_dir change_dir $cur_folder } if { $cur_folder != "/" } { .dir.list insert end ".." } catch { foreach f [ lsort [ glob * ] ] { if [ file isdirectory $f ] { .dir.list insert end "$f/" } } if { $browse_mode != "basedir" } { foreach f [ lsort [ glob * ] ] { if { ! [ file isdirectory $f ] } { .dir.list insert end $f } } } } } } proc browse_done {} { global cur_folder top_dir set top_dir $cur_folder destroy .dir } # Change directory to $base_dir # proc change_dir dir { global org_dir base_dir debug if { $dir == "" } { set dir "/" } # if { $debug } { puts "change_dir($dir)" } cd $org_dir if { ! [ file isdirectory $dir ] } { tk_messageBox -title "TkCryptDir - Error" -type ok -icon warning \ -message [ format [ gettext "No such directory: %s" ] $dir ] return 0; } cd $dir return 1 } ################################################################ # The main routine. # set top_dir $argv wm title . $title wm iconname . $program_name option add *Dialog.msg.wrapLength 6i frame .mode label .mode.label -text [ gettext "Operation:" ] radiobutton .mode.encrypt -variable mode -value "Encrypt" -text [ gettext "Encrypt" ] radiobutton .mode.decrypt -variable mode -value "decrypt" -text [ gettext "Decrypt" ] pack .mode.label .mode.encrypt .mode.decrypt -side left pack .mode -fill x -expand false -padx 1m -pady 1m trace variable mode w { mode_changed } frame .form -borderwidth 2 -relief groove pack .form -fill x -expand true -padx 1m if { $top_dir == "" } { set top_dir $org_dir set folder_image [image create bitmap -data { #define folder_width 32 #define folder_height 16 static unsigned char folder_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x18, 0xf8, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x33, 0x33, 0xfc, 0xff, 0x33, 0x33, 0xf0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, }; } ] frame .form.directory label .form.directory.label -text [ gettext "Directory:" ] entry .form.directory.entry -width 40 -textvariable top_dir -font { fixed } button .form.directory.button -image $folder_image -pady 1 \ -command { browse_directory basedir $top_dir } pack .form.directory.label .form.directory.entry .form.directory.button -side left -padx 1m pack .form.directory -side top -padx 2m -pady 3m } frame .form.password label .form.password.label -text [ gettext "Encryption Key:" ] entry .form.password.entry -textvariable password -show "*" -width 10 -font { fixed } pack .form.password.label .form.password.entry -side left -padx 1m -pady 1m frame .form.password2 label .form.password2.label -text [ gettext "Re-type the Encryption Key:" ] entry .form.password2.entry -textvariable password2 -show "*" -width 10 -font { fixed } pack .form.password2.label .form.password2.entry -side left -padx 1m -pady 0m frame .form.md5 checkbutton .form.md5.toggle -variable use_md5 \ -text [ gettext "Use MD5 Fingerprint?" ] pack .form.md5.toggle -side left -padx 1m -pady 3m pack .form.password .form.password2 .form.md5 -side top -fill x -padx 2m frame .buttons pack .buttons -side top -fill x -padx 1m -pady 1m button .crypt -text [ gettext "Encrypt" ] -command { crypt } pack .crypt -in .buttons -side left button .quit -text [ gettext "Quit" ] -command { exit } pack .quit -in .buttons -side right