Vigenere

Here is a program that applies Vigenère's encryption method [L1 ] to files.

At first It transposes input to base 64 encoding [L2 ], then it applies Vigenere's algorithm.

The file .vgnr in home directory contains the key or secret used to encrypt, decrypt.

Usage is, to encrypt :

        tclsh vigenere.tcl filename
        => this will create a directory vgnr and create a file with the same filename but with encrypted content 

to decrypt :

        tclsh vigenere.tcl vgnr/filename
        => this will create a directory clear and create filename but with decrypted content 

Here is a transcript of a linux session:

        [lg@bjorn example]$ ll
        total 576
        -rwxrwx---. 1 lg lg 579556 28 oct.  11:15 image.jpg
        -rw-rw-r--. 1 lg lg   6435 28 oct.  11:15 vigenere.tcl
        [lg@bjorn example]$ tclsh vigenere.tcl image.jpg 
        [lg@bjorn example]$ ls -la vgnr/image.jpg 
        -rw-rw-r--. 1 lg lg 782910 28 oct.  11:15 vgnr/image.jpg
        [lg@bjorn example]$ tclsh vigenere.tcl vgnr/image.jpg 
        [lg@bjorn example]$ ls -la clear/image.jpg 
        -rw-rw-r--. 1 lg lg 579556 28 oct.  11:16 clear/image.jpg
        [lg@bjorn example]$ md5sum image.jpg 
        532c492532e8c441cab0ed6f9de01962  image.jpg
        [lg@bjorn example]$ md5sum clear/image.jpg 
        532c492532e8c441cab0ed6f9de01962  clear/image.jpg

md5sum filename and md5sum clear/filename give the same md5sum.

The source code is also stored at [L3 ] and at [L4 ]

Here is the source code :

#! /usr/local/bin/tclsh8.6
# vigenere.tcl --
#
#       encrypt, decrypt a file following vigenere algorithm.
#
#       a secret or key must be present as a file named .vgnr in home directory
#
#       example:
#
#         tclsh vigenere.tcl notes.txt
#         => will produce the file vgnr/notes.txt (encryption)
#         tclsh vigenere.tcl vgnr/notes.txt
#         => will produce the file clear/notes.txt (decryption)
#
# Copyright (c) 2009-2022 Laurent Gateau.
#
# version 1.3
#
package require Tcl 8.6

namespace eval vigenere {
        namespace export encode decode encrypt decrypt        
        variable alphabet64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
        variable bufferlen 57 
        variable version "1.3"
}

# vigenere::engine --
#
# Arguments: 
#    key and data variables must be part of alphabet64 
#    key and data variables might result from binary encode base64 call
#    encode must be either 1 (encode) or 0 (decode)
#
# Results:
#    result is a cyphered string containing symbols from alphabet64
#
proc vigenere::engine { key data {encode -encode}} {
                variable alphabet64
                set result ""
                set ii 0
                set keylen [string length $key]
                while {$ii < [string length $data]} {
                        set car [string index $data $ii]                        
                        if {$encode && ($car == "=")} {
                                incr ii
                                continue
                        }
                        set keyii [expr $ii % $keylen]
                        set keycar [string index $key $keyii]
                        set index1 [string first $car $alphabet64]
                        set index2 [string first $keycar $alphabet64]                        
                        if {$encode} {
                                set jj [expr ($index1 + $index2) % 64]
                        } else {
                                set jj [expr ($index1 - $index2) % 64]                
                        }
                        append result "[string index $alphabet64 $jj]"
                        incr ii
                }
                return $result
}

# vigenere::encode --        
#
# Arguments: 
#    key and data variables must be part of alphabet64
#    key and data variables might result from binary encode base64 call
#
# Results:
#    result is a cyphered string containing symbols from alphabet64
#
proc vigenere::encode { key data } {
        return [vigenere::engine "$key" "$data" 1]
}

# vigenere::decode --
#
# Arguments: 
#    key and data variables must contains only symbol from alphabet64
#    key variable might result from a call of binary decode base64
#
# Results:
#    result is a clear string containing symbols from alphabet64
#    result might be a parameter given to a call of binary decode base64
#
proc vigenere::decode { key data } {
        return [vigenere::engine "$key" "$data" 0]
}

# vigenere::encrypt --
#
# Arguments:
#    key is a pass phrase ; the longer the better secrets are kept.
#    fin is the input stream
#    fout is the output stream 
# Results:
#    fin has reached its end
#    fout has been written with encrypted data
#
proc vigenere::encrypt { key fin fout } {
        variable bufferlen
        while { ! [eof $fin] } {
                set input [read $fin $bufferlen]
                set data [binary encode base64 -maxlen [expr $bufferlen * 4 / 3] $input]
                puts $fout [::vigenere::encode [binary encode base64 "$key"] "$data"]
        }
}

# vigenere::decrypt --
#
# Arguments: 
#   key is a pass phrase ; the longer the better secrets are kept.
#   fin is the input stream
#   fout is the output stream
# 
# Results:
#   fin has reached its end
#   fout has been written with decrypted (clear) data.
#
proc vigenere::decrypt { key fin fout } {
        while { ! [eof $fin] } {
                set input [gets $fin]
                set data [::vigenere::decode [binary encode base64 "$key"] "$input"]
                puts -nonewline $fout [binary decode base64 "$data"]
        }
}        

# vigenere::command --
#
# Arguments:
#    command line arguments : arc and argv
#    mode is either -encrypt or -decrypt
#    key is the cypher key
#    input file name
#    output file name
#
# Results:
#    write output file or display usage.
#
proc vigenere::command {} {
        global argc argv
        if { $argc == 1 } {
        set keyfile [open "~/.vgnr" "r"]
        fconfigure $keyfile -translation binary
        set key [read $keyfile]
        close $keyfile

        set filename [lindex $argv 0]
        set outFilename ${filename}.out
        if [string match "vgnr/*" $filename] {
            set mode "-decrypt"
            set outFilename "clear/[string range $filename 5 end]"
            if {![file exists "clear"]} {
                    file mkdir "clear"
            }
        } else {
            set mode "-encrypt"
            set outFilename "vgnr/${filename}"
            if {![file exists "vgnr"]} {
                    file mkdir "vgnr"
            }
        }

        switch -exact -- $mode {
               -encrypt {
                                set fin [open $filename "r"]
                                fconfigure $fin -translation binary
                                set fout [open $outFilename "w"]
                                fconfigure $fout -translation binary
                                encrypt "$key" $fin $fout        
                exit 0
                        }
                        -decrypt {
                                set fin [open $filename  "r"]
                                fconfigure $fin -translation binary
                                set fout [open $outFilename "w"]
                                fconfigure $fout -translation binary
                                decrypt "$key" $fin $fout                                
                exit 0
                        }
                }
        }
    ::vigenere::usage 
     
}

proc vigenere::usage {} {
    puts "usage: vigenere [vgnr/]<file>"
    puts "  file ~/.vgnr must exists and will be the secret key"
    puts "  example: vigenere input_file"
    puts "    encrypt input_file as vgnr/input_file"
    puts "  example: vigenere vgnr/input_file"
    puts "    decrypt vgnr/input_file as clear/input_file"
    exit 1
}

package provide vigenere $::vigenere::version

vigenere::command

See also Base 64 encode/decode [L5 ]