Page 3 of 7 FirstFirst 12345 ... LastLast
Results 21 to 30 of 68

Thread: Programming Challenge 9: Vigenère cipher

  1. #21
    Join Date
    Apr 2008
    Beans
    1

    Re: Programming Challenge 9: Vigenère cipher

    Here is a Java implementation of the cipher.

    This implementation will:
    • allow you to encode/decode a string or any input stream (but the included test program will only work with strings from the command line)
    • generate a pseudo-random key based on a seed provided by the user
    • optionally group the output


    Code:
    package challenge;
    
    import java.io.IOException;
    import java.io.Reader;
    import java.io.StringReader;
    import java.util.Random;
    
    public class VigenereCipher
    {
    	private String key;
    
    	/**
    	 * Constructs a new encoder/decoder using the Vigenere Cipher.
    	 *
    	 * @param key the value to use for the key
    	 * @author StevesVR4
    	 */
    	public VigenereCipher(CharSequence key)
    	{
    		this.key = sanitizeValue(key);
    	}
    
    	/**
    	 * Constructs a new encoder/decoder using the Vigenere Cipher with a pseudo-random key.
    	 * The generated key will be the same for all instances which use the same seed and length.
    	 *
    	 * @param seed starting value for the random character generation
    	 * @param length the length of key to generate
    	 * @author StevesVR4
    	 */
    	public VigenereCipher(long seed, int length)
    	{
    		StringBuilder key = new StringBuilder();
    		Random rand = new Random(seed);
    
    		for (int i = 0; i < length; i++)
    		{
    			int nextValue = rand.nextInt(26);
    			key.append((char)(nextValue + 'A'));
    		}
    
    		this.key = key.toString();
    	}
    
    	private int sanitizeCharacter(char value)
    	{
    		// a negative one signifies an invalid character that should not be used
    		int returnValue = -1;
    
    		// make sure only 'A' through 'Z' are acceptable.
    		if (((value >= 'A') && (value <= 'Z')) || ((value >= 'a') && (value <= 'z')))
    		{
    			returnValue = Character.toUpperCase(value);
    		}
    
    		return returnValue;
    	}
    
    	private String sanitizeValue(CharSequence value)
    	{
    		StringBuilder newValue = new StringBuilder();
    
    		// go through and "sanitize" the string.
    		// make sure only 'A' through 'Z' are in the string.  strip out any invalid characters.
    		for (int i = 0; i < value.length(); i++)
    		{
    			int newChar = sanitizeCharacter(value.charAt(i));
    			if (newChar != -1)
    			{
    				newValue.append((char)newChar);
    			}
    		}
    
    		return newValue.toString();
    	}
    
    	/**
    	 * Returns the key used to encode/decode the text.
    	 *
    	 * @return the key
    	 * @author StevesVR4
    	 */
    	public String getKey()
    	{
    		return key;
    	}
    
    	private char getKeyIndex(int index)
    	{
    		int keyLength = key.length();
    		int keyOffset = index % keyLength;
    		return key.charAt(keyOffset);
    	}
    
    	/**
    	 * Encodes the string using the Vigenere Cipher.
    	 *
    	 * @param message the value to encode
    	 * @param the encrypted message
    	 * @author StevesVR4
    	 */
    	public String encode(String message)
    	{
    		return encode(message, 0);
    	}
    
    	/**
    	 * Encodes the string using the Vigenere Cipher.
    	 *
    	 * @param message the value to encode
    	 * @param groupLength the number of characters to group in the output
    	 * @return the encrypted message
    	 * @author StevesVR4
    	 */
    	public String encode(String message, int groupLength)
    	{
    		String value = null;
    
    		try
    		{
    			value = encode(new StringReader(message), groupLength);
    		}
    		catch (IOException ioe)
    		{
    			// this should NEVER happen with a StringReader
    			assert(false);
    			ioe.printStackTrace();
    		}
    
    		return value;
    	}
    
    	/**
    	 * Encodes the contents of the input stream using the Vigenere Cipher.
    	 *
    	 * @param input the stream to encode
    	 * @return the encrypted message
    	 * @author StevesVR4
    	 */
    	public String encode(Reader input) throws IOException
    	{
    		return encode(input, 0);
    	}
    
    	/**
    	 * Encodes the contents of the input stream using the Vigenere Cipher.
    	 *
    	 * @param input the stream to encode
    	 * @param groupLength the number of characters to group in the output
    	 * @return the encrypted message
    	 * @author StevesVR4
    	 */
    	public String encode(Reader input, int groupLength) throws IOException
    	{
    		return transform(input, groupLength, true);
    	}
    
    	/**
    	 * Decodes the contents of the input stream using the Vigenere Cipher.
    	 *
    	 * @param message the string to decode
    	 * @return the decrypted message
    	 * @author StevesVR4
    	 */
    	public String decode(String message)
    	{
    		return decode(message, 0);
    	}
    
    	/**
    	 * Decodes the contents of the input stream using the Vigenere Cipher.
    	 *
    	 * @param message the string to decode
    	 * @param groupLength the number of characters to group in the output
    	 * @return the decrypted message
    	 * @author StevesVR4
    	 */
    	public String decode(String message, int groupLength)
    	{
    		String value = null;
    
    		try
    		{
    			value = decode(new StringReader(message), groupLength);
    		}
    		catch (IOException ioe)
    		{
    			// this should NEVER happen with a StringReader
    			assert(false);
    			ioe.printStackTrace();
    		}
    
    		return value;
    	}
    
    	/**
    	 * Decodes the contents of the input stream using the Vigenere Cipher.
    	 *
    	 * @param input the stream to decode
    	 * @return the decrypted message
    	 * @author StevesVR4
    	 */
    	public String decode(Reader input) throws IOException
    	{
    		return decode(input, 0);
    	}
    
    	/**
    	 * Decodes the contents of the input stream using the Vigenere Cipher.
    	 *
    	 * @param input the stream to decode
    	 * @param groupLength the number of characters to group in the output
    	 * @return the decrypted message
    	 * @author StevesVR4
    	 */
    	public String decode(Reader input, int groupLength) throws IOException
    	{
    		return transform(input, groupLength, false);
    	}
    
    	private String transform(Reader input, int groupLength, boolean encode) throws IOException
    	{
    		StringBuilder output = new StringBuilder();
    		int counter = 0;
    		int curChar;
    
    		while ((curChar = input.read()) != -1)
    		{
    			int newValue = sanitizeCharacter((char)curChar);
    			if (newValue != -1)
    			{
    				int keyChar = getKeyIndex(counter) - 'A';
    				int prevChar = newValue - 'A';
    				int newChar;
    				if (encode)
    				{
    					newChar = (keyChar + prevChar) % 26;
    				}
    				else
    				{
    					newChar = (prevChar - keyChar + 26) % 26;
    				}
    				output.append((char)(newChar + 'A'));
    
    				counter++;
    
    				// now check to see if a blank space should be added to the string
    				// (by waiting until after the counter has been incremented, there is no need
    				// for a special check to prevent padding after the first character)
    				if ((groupLength > 0) && (counter % groupLength == 0))
    				{
    					output.append(' ');
    				}
    			}
    		}
    
    		return output.toString();
    	}
    
    	public static void main(String[] args)
    	{
    		if ((args.length == 3) || (args.length == 4))
    		{
    			boolean encode;
    			boolean randomKey;
    			if (args[0].equals("E"))
    			{
    				encode = true;
    				randomKey = false;
    			}
    			else if (args[0].equals("ER"))
    			{
    				encode = true;
    				randomKey = true;
    			}
    			else if (args[0].equals("D"))
    			{
    				encode = false;
    				randomKey = false;
    			}
    			else if (args[0].equals("DR"))
    			{
    				encode = false;
    				randomKey = true;
    			}
    			else
    			{
    				throw new IllegalArgumentException("The first parameter must be either 'E' or 'ER' to encode a string or 'D' or 'DR' to decode a string.");
    			}
    
    			System.out.println("Operation: " + (encode ? "Encode string" : "Decode string"));
    			VigenereCipher c;
    			if (randomKey == false)
    			{
    				c = new VigenereCipher(args[1]);
    			}
    			else
    			{
    				long seed = Long.parseLong(args[1]);
    				c = new VigenereCipher(seed, args[2].length());
    			}
    			System.out.println("Key: " + c.getKey());
    			System.out.println();
    
    			int group = 0;
    			if (args.length == 4)
    			{
    				group = Integer.parseInt(args[3]);
    			}
    
    			if (encode)
    			{
    				System.out.println("Text to encode: " + args[2]);
    				System.out.println("Encoded text  : " + c.encode(args[2], group));
    			}
    			else
    			{
    				System.out.println("Text to decode: " + args[2]);
    				System.out.println("Decoded text  : " + c.decode(args[2], group));
    			}
    		}
    		else
    		{
    			System.out.println("Three parameters are required: operation, key/seed, text to encode/decode, and (optionally) an output group length.");
    		}
    	}
    }
    To run the test program:
    Code:
    java challenge.VigenereCipher <option> <key | seed> <text> [ <group length> ]
    Available options are:
    • E - encode string
    • ER - encode string with pseudo-random key
    • D - decode string
    • DR - decode string with pseudo-random key


    Examples:
    Code:
    java challenge.VigenereCipher E LEMON ATTACKATDAWN
    Operation: Encode string
    Key: LEMON
    
    Text to encode: ATTACKATDAWN
    Encoded text  : LXFOPVEFRNHR
    
    java challenge.VigenereCipher ER 467782435 ATTACKATDAWN
    Operation: Encode string
    Key: MDBOKOUJVIEJ
    
    Text to encode: ATTACKATDAWN
    Encoded text  : MWUOMYUCYIAW
    
    java challenge.VigenereCipher DR 467782435 MWUOMYUCYIAW
    Operation: Decode string
    Key: MDBOKOUJVIEJ
    
    Text to decode: MWUOMYUCYIAW
    Decoded text  : ATTACKATDAWN
    
    java challenge.VigenereCipher E LEMON ATTACKATDAWN 5
    Operation: Encode string
    Key: LEMON
    
    Text to encode: ATTACKATDAWN
    Encoded text  : LXFOP VEFRN HR

  2. #22
    Join Date
    Apr 2006
    Location
    Edinburgh, Scotland
    Beans
    47
    Distro
    Kubuntu 9.04 Jaunty Jackalope

    Re: Programming Challenge 9: Vigenère cipher

    I enjoyed this one (and lost another few hours of revision)

    my python version takes an input file (ie in.txt) and either prints result to the screen or to an output file if specified

    The key will be converted to uppercase but the input text will be converted regardless of case. Punctuation and odd characters (ie è) will remain unchanged

    Code:
    #! /usr/bin/python
    # vigenere.py by Amar (2008)
    import getopt, sys
    
    def usage():
        print ' vigenere.py -k key -i file.in [-o file.out, -v,-d] '
        print
        print ' -i, --input ',
        print '    input file (Required)'
        print ' -o, --output',
        print '    output file'
        print ' -k, --key   ',
        print '    key (Required)'
        print ' -d          ',
        print '    decript'
        print ' -v          ',
        print '    verbose'
    
    def enc(lin,k):    
        out = ord(lin) + ord(k)-ord('A')
        if (ord(lin)<=ord('Z') and out > ord('Z')) or (out > ord('z')):
            out = out - 26
        return chr(out)
    
    def dec(lin,k):
        out = ord(lin) - ord(k)+ord('A')
        if (out < ord('A')) or (out < ord('a') and ord('a')<=ord(lin)):
            out = out + 26
        return chr(out)
    
    def main():
        try:
            opts, args = getopt.getopt(sys.argv[1:], "dhi:k:o:v",
                                        ["help","key=","input=","output="])
        except getopt.GetoptError, err:
            # print help information and exit:
            print str(err) # will print something like "option -a not recognized"
            usage()
            sys.exit(2)
        output = feed = key = None
        verbose = decode= False
        for o, a in opts:
            if o == "-v":
                verbose = True
            elif o in ("-h", "--help"):
                usage()
                sys.exit()
            elif o == '-d':
                decode= True
            elif o in ("-k", "--key"):
                key = a
            elif o in ("-i", "--input"):
                feed = a
            elif o in ("-o", "--output"):
                output = a
            else:
                assert False, "unhandled option"
        if feed:
            filein = open(feed,'r')
            data = filein.readlines()
        else:
            print 'No input file'
            usage()
            sys.exit()
        if key:
            key = key.upper()
        else:
            print 'No key'
            usage()
            sys.exit()
        if verbose:
            print 'encoding with key-',key
    
        if output:
            fileout = open(output,'w')
    
        i=0
        for ln in data:
            line = ''
            for x in range(len(ln)):
                if (ord('a')<=ord(ln[x])<=ord('z')) or (ord('A')<=ord(ln[x])<=ord('Z')):
                    if decode:
                        line += dec(ln[x],key[(i+x)%len(key)])
                    else:
                        line += enc(ln[x],key[(i+x)%len(key)])
                else:
                    line += ln[x]
            i=(i+len(ln))%len(key)
            if output:
                fileout.write(line)
            elif not verbose:
                print line,
            if verbose:
                print 'in >',ln,'out>',line
    
    if __name__ == "__main__":
        main()
    to encrypt filein.txt using key 'woot' and output to screen:
    Code:
    ./vigenere.py -i filein.txt -k woot

    to encrypt filein.txt using key 'woot' and output to file fileout.txt:
    Code:
    ./vigenere.py -i filein.txt -k woot -o fileout.txt
    to decrypt filein.txt using key 'woot' and output to screen:
    Code:
    ./vigenere.py -i filein.txt -k woot -d
    I haven't fully tested this thing for robustness - I hear my fluid dynamics notes calling me

    /me mutters something unpleasant about exams
    Last edited by amar; April 29th, 2008 at 09:01 PM. Reason: typos!

  3. #23
    Join Date
    Mar 2005
    Location
    Haarlem, The Netherlands
    Beans
    363

    Re: Programming Challenge 9: Vigenère cipher

    Just made one in ksh - as I have to use this in my job it was a nice exercise. It is very basic, e.g. all inputs are hardcoded
    Code:
    #!/bin/ksh
    
    function chr
    {
    	# converts decimal value to its ASCII character representation
    	printf \\$(printf '%03o' $1)
    }
    
    function ord
    {
    	# converts ASCII character to its decimal value
    	printf '%d' "'$1"
    }
    
    function string_to_array
    {
    	typeset -i length=$(echo $1|wc -c)
    	typeset -i i=1
    	typeset ret
    	while [[ $i -lt $length ]]; do
    		ret[$i]=$(echo $1|cut -c$i)
    		i=$(($i+1))
    	done
    	echo ${ret[*]}
    }
    
    
    K=LEMONLEMONLE
    set -A K $(string_to_array $K)
    
    function encrypt
    {
    	typeset C ret i
    	typeset -i j=0
    	for i in $1; do
    		C=$(($(($(ord $i)+$(ord ${K[$j]})-2*$(ord A)))%26))
    		ret[$j]=$(chr $(($C+$(ord A))))
    		j=$(($j+1))
    	done
    
    	echo ${ret[*]}
    }
    
    function decrypt
    {
    	typeset P ret i
    	typeset -i j=0
    	for i in $1; do
    		P=$(($(ord $i)-$(ord ${K[$j]})))
    		if [[ $P -lt 0 ]]; then
    			P=$(($P+26))
    		fi
    		P=$(($P%26))
    		ret[$j]=$(chr $(($P+$(ord A))))
    		j=$(($j+1))
    	done
    
    	echo ${ret[*]}
    }
    
    p=ATTACKATDAWN
    set -A P $(string_to_array $p)
    encrypt "${P[*]}"
    
    c=LXFOPVEFRNHR
    set -A C $(string_to_array $c)
    decrypt "${C[*]}"
    Last edited by Martin Witte; April 29th, 2008 at 09:46 PM. Reason: you have to install package ksh, it is not in the default ubuntu distribution

  4. #24
    Join Date
    Jan 2008
    Beans
    4,757

    Re: Programming Challenge 9: Vigenère cipher

    BASH Cures Cancer

    Code:
    #!/bin/bash
    
    sanity()
    {
        usage()
        {
            echo "Usage: $strzero -c|-d WORD KEY"
            echo "Other Options: --viewsrc"
            exit 1
        }
        case $method in
            -c) export cipher="0";;
            -d) export cipher="1";;
             *) usage;; esac
        if   [ "$word" == "" ]
        then usage
        elif [ "$key" == "" ]
        then usage; fi
    }
    
    vigen()
    {
        encrypt()
        {
            let crypt=$numword+$numkey-$A
        }
        adjust()
        {
            if   [ $crypt -gt 90 ]
            then let crypt=$crypt-26
            elif [ $crypt -lt 65 ]
            then let crypt=$crypt+26; fi
        }
        len=${#word}
        klen=$((${#key} - 1))
        i="0"
        k="0"
    
        while [ $i -lt $len ]
        do
            export A="65"
            export ch=${word:$i:1}
            export kch=${key:$k:1}
            export numword=`printf '%d' "'$ch"`
            export numkey=`printf '%d' "'$kch"`
            if   [ $numkey -gt "96" ]
            then let numkey=$numkey-32; fi
            if   [ $cipher = "1" ]
            then let numkey=-$numkey
                 let A=-$A; fi
            case $numword in
                 48|49|50|51|52|53|54|55|56|57)
                    let numword=$numword+17
                    encrypt
                    let crypt=$crypt-17
                    while [ $crypt -gt "57" ]
                    do    let crypt=$crypt-10; done
                    while [ $crypt -lt "48" ]
                    do    let crypt=$crypt+10; done
                    printf \\$(printf '%03o' $crypt)
                    ;;
    10|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|58|59|60|61|62|63|64|91|92|93|94|95|96|123|124|125|126)
                    printf \\$(printf '%03o' $numword)
                    let 'k--'
                    ;;
                  9)
                    echo -ne "\t"
                    let 'k--'
                    ;;
                -62)
                    echo -n "$"
                    let 'k--'
                    ;;
                *)
                    if   [ $numword -gt "96" ]
                    then let numword=$numword-32
                         encrypt
                         adjust
                         let crypt=$crypt+32
                    else encrypt
                         adjust; fi
                    printf \\$(printf '%03o' $crypt)
                    ;;
            esac
            let 'i++'
            if   [ $k -lt $klen ]
            then let 'k++'
            else export k="0"; fi
        done
        echo
    }
    
    if   [ "$1" = "--viewsrc" ]
    then cat $0 | less
    else export strzero="$0"
         export method="$1"
         if [ -f "$2" ]
         then export word=`cat $2`
         else export word="$2"; fi
         export key="$3"
         sanity
         vigen
    fi
    exit 0
    It's written so it ignores differences in cases, but prints the case of the word you give it anyway!

    Save the source in a file called vigen. And mark it executable (chmod +x vigen).

    And showing it in action:
    PHP Code:
    $ ./vigen -c ATTACKATDAWN LEMON
    LXFOPVEFRNHR
    $ ./vigen -d LXFOPVEFRNHR lemon
    ATTACKATDAWN 
    Generally speaking.
    "vigen -c" Ciphers the text.
    "vigen -d" Deciphers the text.
    Though this is not strictly true, as the algorithm could go either way.

    Features added since its original erection:
    • "Phrases".
    • All Non-Alphabet standard keys (on a generic 105-PC Keyboard) are ported.
    • The symbols: $, !, \ and ` can be put into the input arguments.
      Although, the backslash symbol is required before them. ie: ./vigen -c \$\!\\\` LEMON
    • Numbers are encrypted along with the text.
    • The £ symbol is ported. (With the use of the £ sign, or the ¬ sign).
    • Symbols and Numbers can be included in the key to increase security of encryption.
    • Files are supported now too. All output is printed at the screen unless you tell the command prompt to redirect it using the ">" or ">>" symbols.
      ie: ./vigen -c foo.txt LEMON > encrypt-foo.txt will save the encrypted (or decrypted) text to a file.

    PHP Code:
    $ ./vigen -"ATTACK AT DAWN" LEMON
    LXFOPV EF RNHR
    $ ./vigen -"LXFOPV EF RNHR" LEMON
    ATTACK AT DAWN

    $ ./vigen -"Lxfopv ef Rnhr, 22:31ey" LEMON
    Attack at Dawn
    08:00am

    $ ./vigen -"EWZCGO EW JCAR" +*-C++
    ATTACK AT DAWN 
    Also, don't forget to view the source!
    PHP Code:
    $ ./vigen --viewsrc 
    Enjoy!

    Regards
    Iain
    Last edited by ibuclaw; May 2nd, 2008 at 07:39 PM. Reason: Feature Additions

  5. #25
    Join Date
    Jun 2006
    Location
    Gwangju, Korea
    Beans
    3,479

    Re: Programming Challenge 9: Vigenère cipher

    Quote Originally Posted by Npl View Post
    The problem is that the recipient needs to know the key, else you just did a random-number-generator
    Since you`d either need to agree on a key before or transmit the random key to the recipient alongside the encrypted message this aint a viable approach (instead of securely transmitting a message you now need to securely transmitt a key of the same length). You need a deterministic pseudo-random-number generator, like a Linear Feedback Shift Register, then you can generate long keys from seed-values
    Thanks for the feedback. Secure key exchange is a problem. If I implement a seeded pseudorandom key, then the seed simply becomes the key. Nevertheless, I'll add that feature when I get a chance.

  6. #26
    Join Date
    Oct 2007
    Location
    UK
    Beans
    484
    Distro
    Ubuntu 9.10 Karmic Koala

    Re: Programming Challenge 9: Vigenère cipher

    This is a really short Vigenere cipher written in Perl. I was going for size not functionality, so it doesn't decrypt, or work on files yet.

    Code:
    #!/usr/bin/perl
    # Really short Vigenere cipher
    
    $input  = "ATTACKATDAWN";
    $cipher = "LEMONLEMONLE";
    
    $buffer = ""; while($i  < 
    length($input)){  $buffer 
    .=      chr(((ord(substr(
    $input, $i)) + ord(substr
    ($cipher, $i)))   % 26) + 
    ord('A')); $i++;  } print 
    $buffer . "\n";
    Lucid Beta 2 powered Studio 15 (Core 2 Duo 2.0GHz, 3 GB RAM, HD 3450) & Windows XP powered Scaleo E (Celeron D 3.06GHz, 1.5GB RAM, Intel GMA 915G). Please see Ubuntu Tutorials (my YouTube channel).

  7. #27
    Join Date
    Dec 2007
    Location
    ~
    Beans
    314
    Distro
    Ubuntu 10.04 Lucid Lynx

    Wink Re: Programming Challenge 9: Vigenère cipher

    I am really new with python..... so there may be scope to reduce no of lines of the program using the same algorithm..... if i find something.... ill post it here....

    Code:
    #!/usr/bin/env python
    
    """Encode and decode data using the Vigenere Cipher"""
    
    
    #Make key of correct length
    def makekey(key_input,no_char):
        key = []
        i = 0
        x = 0
        while i < no_char:
            key.append(key_input[x])
            i = i + 1
            x = x + 1
            if x == (key_input.__len__()):
                x = 0
        return key
    
    #Find code for alphabets(0-25)
    def giveNO(char):
        no = ord(char)
        return (no-ord('A'))
    
    #Find alphabets for code
    def giveCHAR(no):
        if no>=0 and no<=25:
            return chr(no+ord('A'))
        elif no>25:
            return chr(no+ord('A')-26)
        elif no<0:
            return chr(no+ord('A')+26)
    
    #Encode data
    def encode(key_input,data):
        key = makekey(key_input,data.__len__())
        i = 0
        enSTR = ""
        while i < data.__len__():
            if data[i] == " ":
                enSTR = enSTR + " "
            else:
                no = giveNO(data[i]) + giveNO(key[i])
                enSTR = enSTR + giveCHAR(no)
            i = i + 1
        print "\n\nEncrypted data: %s"%enSTR
    
    #Decode data
    def decode(key_input,data):
        key = makekey(key_input,data.__len__())
        i = 0
        deSTR = ""
        while i< data.__len__():
            if data[i] == " ":
                deSTR = deSTR + " "
            else:
                no = giveNO(data[i]) - giveNO(key[i])
                deSTR = deSTR + giveCHAR(no)
            i = i + 1
        print "\n\nDecrypted data: %s"%deSTR
    
    
    
    
    
    #Run program
    if __name__ == "__main__":
        ch = 1
        while ch:
             #import os
            #os.system("clear")
            print "\n\n1. Encode"
            print "2. Decode"
            print "0. Exit"
            choice = raw_input("Options? ")
            if choice == "1":
                key = raw_input("\nKey? ")
                data = raw_input("Data? ")
                encode(key,data)
            elif choice == "2":
                key = raw_input("\nKey? ")
                data = raw_input("Data? ")
                decode(key,data)
            elif choice == "0":
                ch = 0
            else:
                print "\n\nIncorrect Input"

  8. #28
    Join Date
    Feb 2007
    Location
    Edinburgh, Scotland
    Beans
    391

    Re: Programming Challenge 9: Vigenère cipher

    Here is my version, written in sloppy Python. Took forever to get encryption working last night (tbh i was doing it at some stupid time in the morning).

    python vigenere.py -e -i ATTACKATDAWN -k LEMONLEMONLE

    Also works with files:

    python vigenere.py -e -f input -k LEMONLEMONLE

    It can also generate a key for a piece of text (useful for thing anything > than 1 line as creating your own key for a 150 line message would take forever):

    python vigenere.py -g -i ATTACKATDAWN


    Code:
    #Vigenere Cipher in Python
    #David Futcher ('bobbo') <bobbocanfly@gmail.com>
    
    import sys, random
    from optparse import OptionParser
    
    #Actual Vigenere Cipher implementation
    class Vigenere:
    
        #Encrypt the string using Vigenere
        def encrypt(self, string, key):
            dec = ""
    
            for i in range(len(string)):
                pbyte = ord(string[i]) - 65
                kbyte = ord(key[i]) - 65
                index = pbyte + kbyte
                byte = 65
    
                for k in range(0, index):
                    byte += 1
                    if byte <65:
                        byte = 90
                    if byte >90:
                        byte = 65
    
                dec += chr(byte)
    
            return dec 
    
        #Decrypt the string using Vigenere
        def decrypt(self, string, key):
            dec = ""
    
            for i in range(len(string)):
                pbyte = ord(string[i]) - 65
                kbyte = ord(key[i]) - 65
                index = pbyte - kbyte
                if index < 0:
                    new = int(str(index).lstrip('-'))
                    index = 26 - new
                byte = 65
    
                for k in range(0, index):
                    byte += 1
                    if byte <65:
                        byte = 90
                    if byte >90:
                        byte = 65
    
                dec += chr(byte)
    
            return dec
    
        #Generates a key based on the length of the input string
        def gen_key(self, string):
            key = ""
            chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    
            for i in range(len(string)):
                key += random.choice(chars)
    
            return key
    
    if __name__ == "__main__":
        
        #Parse the command line options
        parser = OptionParser()
        parser.add_option("-f", "--file", dest="filename",
                          help="write report to FILE", metavar="FILE")
        parser.add_option("-i", "--input", dest="string",
                          help="input to be encrypted/decrypted")
        parser.add_option("-k", "--key", dest="key",
                          help="key to be used in encryption/decryption")
        parser.add_option("-g", "--gen", dest="gen", action="store_true", 
                          default=False, help="option to generate a key (Useful for enciphering more than a line of text")
        parser.add_option("-e", "--encrypt", action="store_true",
                          help="encrypt input", dest="encrypt")
        parser.add_option("-d", "--decrypt", action="store_true",
                          help="decrypt input", dest="decrypt")
    
    
        (options, args) = parser.parse_args()
            
        if options.filename and options.string:
            print "Cannot use -f and -i (--file, --input) switches at the same time"
            sys.exit(1)
    
        if not options.key and not options.gen:
            print "No key given"
            sys.exit(1)
    
        if not options.string and not options.filename:
            print "No input string or filename given"
            sys.exit(1)
    
        if not options.encrypt and not options.decrypt and not options.gen:
            print "encryption, decryption or key generation not selected (-e/-d/-g)"
    
        #user is sane, get on with enciphering/deciphering
        if options.filename:
            file = open(options.filename)
            string = file.read()
            string = string.rstrip()
        else:
            string = options.string
    
        if not options.gen:
            key = options.key
    
        #Check key/string is right length, this can only handle keys the exact length of the string
        if not options.gen and len(key) != len(string):
            print "Invalid input or key length. The key must be the exact length of the input data"
            sys.exit(1)
    
        vig = Vigenere()
        if options.encrypt:
            print vig.encrypt(string, key)
        elif options.decrypt:
            print vig.decrypt(string, key)
        elif options.gen:
            print vig.gen_key(string)
        else:
            print "Unspecified error. Please check your command line input"
    Today we have 15 minutes of fame, tomorrow 15 minutes of anonymity.
    My Blog | Veza - Opensource TinyURL clone with sensible URLs

  9. #29
    Join Date
    Dec 2006
    Location
    Australia
    Beans
    1,097
    Distro
    Ubuntu 12.04 Precise Pangolin

    Re: Programming Challenge 9: Vigenère cipher

    In an example of using the WRONG tool for the job, here's an attempt using Ada. [UPDATE] Now includes fairly robust error checking.[/UPDATE]

    There is some duplication of code, but I think it's OK for the sake of clarity. The greatest obstacle was Ada's greatest strength: extremely strong type-checking. String-handling was the most difficult, as Ada is very rigid in that area. I used fixed-length strings (a string can't be larger or smaller than the predefined length), because of it can be manipulated like arrays which helps when ciphering/deciphering text. Unbounded-length strings (length can vary to whatever size necessary) are easier for general text, but can't be modified as arrays, lacked functionality for this particular application, and is much slower than fixed-length strings.


    Compile by installing gnat:
    Code:
    sudo apt-get install gnat
    Invoke this command to compile:
    Code:
    gnat make vigenere.adb
    (Take note that gnat will complain if the source file is not vigenere.adb.)

    Code:
    with Ada.Text_IO;
    with Ada.Characters.Handling;
    with Ada.Exceptions;
    
    use Ada.Text_IO;
    use Ada.Characters.Handling;
    use Ada.Exceptions;
    
    procedure Vigenere is
    	In_Text, Out_Text, Key : String(1..51);
    	Opt_Text : String(1..7);
    	Menu : Character;
    	Quit : Boolean;
    	L_In, L_Key : Integer;
    	
    	procedure Get_Text is
    		Valid_Input : Boolean;
    	begin
    		Put_Line("Beware: All text is limited to 50 characters.");
    		loop
    			Valid_Input := True;
    			Put("Type the text to " & Opt_Text & ": ");
    			Get_Line(In_Text, L_In);
    			Put("Type the key: ");
    			Get_Line(Key, L_Key);
    			if L_In > 50 or L_Key > 50 then
    				Put_Line("Input is limited to 50 characters. Your input was longer.");
    				Put_Line("Please try again");
    				Valid_Input := False;
    			end if;
    			exit when Valid_Input = True;
    		end loop;
    		Put_Line("Starting " & Opt_Text & "ion...");
    	end;
    	
    	function Code (Ch_In, Key_Ch : Character; Opt : Integer) return Character is
    		type Char_Index is mod 26;
    		Val_Plain, Val_Crypt, Offset : Char_Index;
    		Ch_Out : Character;
    	begin
    		if Opt = 1 then
    			Val_Plain := Char_Index(Character'Pos(Ch_In) - 65);
    			Offset := Char_Index(Character'Pos(Key_Ch) - 65);
    			Val_Crypt := Val_Plain + Offset;
    			Ch_Out := Character'Val(Integer(Val_Crypt) + 65);
    		elsif Opt = 0 then
    			Val_Crypt := Char_Index(Character'Pos(Ch_In) - 65);
    			Offset := Char_Index(Character'Pos(Key_Ch) - 65);
    			Val_Plain := Val_Crypt - Offset;
    			Ch_Out := Character'Val(Integer(Val_Plain) + 65);
    		end if;
    		return Ch_Out;
    	end Code;
    	
    	procedure Process_Text is
    		Count_Key, LU_End : Integer;
    		Temp : Character;
    	begin
    		LU_End := L_In;
    		Count_Key := 1;
    		for I in Integer range 1..L_Key loop
    			Temp := Key(I);
    			Key(I) := To_Upper(Temp);
    		end loop;
    		for I in Integer range 1..L_In loop
    			Temp := In_Text(I);
    			In_Text(I) := To_Upper(Temp);
    			if Menu = 'E' then
    				Out_Text(I) := Code(In_Text(I), Key(Count_Key), 1);
    			elsif Menu = 'D' then
    				Out_Text(I) := Code(In_Text(I), Key(Count_Key), 0);
    			end if;
    			Count_Key := Count_Key + 1;
    			if Count_Key = 0 or Count_Key > L_Key then
    				Count_Key := 1;
    			end if;
    		end loop;
    	end Process_Text;
    	
    begin
    	Quit := False;
    	loop
    		Put("[E]ncrypt, [D]ecrypt, or [Q]uit? ");
    		Get(Menu);
    		Menu := To_Upper(Menu);
    		Skip_Line(1);
    		if Menu = 'E' then
    			Opt_Text := "encrypt";
    			Get_Text;
    			Process_Text;
    			Put_Line("Encrypted text: " & Out_Text(1..L_In));
    		elsif Menu = 'D' then
    			Opt_Text := "decrypt";
    			Get_Text;
    			Process_Text;
    			Put_Line("Decrypted text: " & Out_Text(1..L_In));
    		elsif Menu = 'Q' then
    			Quit := True;
    		else
    			Put_Line("Invalid choice!");
    			Quit := True;
    		end if;
    		exit when Quit = True;
    	end loop;
    exception
    	when Constraint_Error =>
    		Put_Line("A number or other non-alphabet character has been detected.");
    		Put_Line("I can only cipher and decipher alphabet characters. Sorry.");
    		Vigenere;
    end Vigenere;
    Last edited by samjh; May 3rd, 2008 at 09:37 AM.

  10. #30
    Join Date
    Jun 2006
    Location
    Gwangju, Korea
    Beans
    3,479

    Re: Programming Challenge 9: Vigenère cipher

    Quote Originally Posted by mssever View Post
    Thanks for the feedback. Secure key exchange is a problem. If I implement a seeded pseudorandom key, then the seed simply becomes the key. Nevertheless, I'll add that feature when I get a chance.
    Done. I've updated my entry accordingly. I also discovered a bug in Ruby 1.8's String class. "A".length returns 1 as expected. However, "Ä".length returns 2. I've worked around this bug by splitting the text and key strings into arrays anytime the length is important.

Page 3 of 7 FirstFirst 12345 ... LastLast

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •