Programming Challenge 9: Vigenère cipher
Task
Implementing the
Vigenère cipher.
Example:
Code:
Plaintext: ATTACKATDAWN
Key: LEMONLEMONLE
Cipertext: LXFOPVEFRNHR
Possible Ideas
Cipher/Decipher a file.
Generation of a key.
Rules
No use of libraries which implement this cipher.
Due Date
Winner will be decided next monday.
Final Notes
By creative and have fun.
Re: Programming Challenge 9: Vigenère cipher
Hi mate.
Seems that you switched plain text and key around.
ATTACKATDAWN is the plain text, while LEMON is the key used to encrypt the plain text.
Nice challenge, I may have a look at that. Is there any restriction to programming language?
Re: Programming Challenge 9: Vigenère cipher
Quote:
Originally Posted by
achelis
Hi mate.
Seems that you switched plain text and key around.
ATTACKATDAWN is the plain text, while LEMON is the key used to encrypt the plain text.
Nice challenge, I may have a look at that. Is there any restriction to programming language?
Nope, you can write it in whatever you want.
See the sticky regarding the rules of the Programming challenges.
Good luck!
Re: Programming Challenge 9: Vigenère cipher
Quote:
Originally Posted by
achelis
Nice challenge, I may have a look at that. Is there any restriction to programming language?
Not really, but since the person who started the challenge has to run it to see it work it is best to use non proprietary languages.
Re: Programming Challenge 9: Vigenère cipher
Let me see if I got this right from Wiki :
Only capital letters, no spaces, or anything?
Re: Programming Challenge 9: Vigenère cipher
Here's a solution in Java featuring a SWING gui:
PHP Code:
/*
* GUI.java
*
* Created on 28. April 2008, 13:18
*/
package challenge;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
/**
* GUI for the Vinegere cipher class & the class (as private class)
*
* @author Zugzwang
*/
public class GUI extends javax.swing.JFrame {
public static final String messageTitle = "Vinagère cipher";
/**
* Class for performing the Vigenere cipher
*
* @author "Zugzwang"
*/
public class Vigenere {
public class IllegalCodeException extends Exception {};
public char[] code;
public Vigenere(char[] givenCode) throws IllegalCodeException {
code = new char[givenCode.length];
for (int i=0;i<givenCode.length;i++) {
char c = givenCode[i];
if (isSpecialChar(c)) throw new IllegalCodeException();
if ((c>='A') && (c<='Z'))
code[i] = (char)(c-'A');
else
code[i] = (char)(c-'a');
}
}
/**
* Encodes a string
*/
public String code(boolean encode, String input) {
StringBuffer result = new StringBuffer();
int pos = 0;
for (int i=0;i<input.length();i++) {
char in = input.charAt(i);
if (isSpecialChar(in)) {
result.append(in);
} else {
result.append(code(encode,in,code[pos]));
pos = (pos + 1) % code.length;
}
}
return result.toString();
}
/**
* This procedure performs the encoding and decoding of a single character using the Vigenère cipher.
* @param encode If this boolean value is set to true, encoding will be performed, decoding otherwise
* @param input The input character
* @param code The code character to be used
* @return The coded character
*/
private char code(boolean encode, char input, char code) {
int usage = (encode)?code:26-code;
if ((input>='A') && (input<='Z'))
return (char)(((input-'A'+usage) % 26)+'A');
else
return (char)(((input-'a'+usage) % 26)+'a');
}
private boolean isSpecialChar(char c) {
return ((c<'A') || (c>'Z')) && ((c<'a') || (c>'z'));
}
}
/** Creates new form GUI */
public GUI() {
initComponents();
jPanelResult.setVisible(false);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
jPanelSettings = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
jPasswordFieldCode = new javax.swing.JPasswordField();
jTextFieldInputFile = new javax.swing.JTextField();
jComboBoxMode = new javax.swing.JComboBox();
jPanel1 = new javax.swing.JPanel();
jButtonLoad = new javax.swing.JButton();
jButtonAction = new javax.swing.JButton();
jPanelResult = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
jTextPaneResult = new javax.swing.JTextPane();
jButtonSave = new javax.swing.JButton();
getContentPane().setLayout(new java.awt.GridBagLayout());
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Vinag\u00e8re cipher - by Zugzwang");
jPanelSettings.setLayout(new java.awt.GridBagLayout());
jPanelSettings.setBorder(javax.swing.BorderFactory.createTitledBorder("Input and Output"));
jLabel1.setText("Input file:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
jPanelSettings.add(jLabel1, gridBagConstraints);
jLabel2.setText("Password:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
jPanelSettings.add(jLabel2, gridBagConstraints);
jLabel3.setText("Mode:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0);
jPanelSettings.add(jLabel3, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(2, 3, 2, 0);
jPanelSettings.add(jPasswordFieldCode, gridBagConstraints);
jTextFieldInputFile.setEditable(false);
jTextFieldInputFile.setText("- none loaded -");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(2, 3, 2, 0);
jPanelSettings.add(jTextFieldInputFile, gridBagConstraints);
jComboBoxMode.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Encoding", "Decoding" }));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(2, 3, 2, 0);
jPanelSettings.add(jComboBoxMode, gridBagConstraints);
jPanel1.setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanelSettings.add(jPanel1, gridBagConstraints);
jButtonLoad.setText("Load...");
jButtonLoad.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButtonLoadActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
jPanelSettings.add(jButtonLoad, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
getContentPane().add(jPanelSettings, gridBagConstraints);
jButtonAction.setText("OK");
jButtonAction.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButtonActionActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
getContentPane().add(jButtonAction, gridBagConstraints);
jPanelResult.setLayout(new java.awt.GridBagLayout());
jPanelResult.setBorder(javax.swing.BorderFactory.createTitledBorder("Result"));
jScrollPane1.setViewportView(jTextPaneResult);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
jPanelResult.add(jScrollPane1, gridBagConstraints);
jButtonSave.setText("Save results....");
jButtonSave.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButtonSaveActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
jPanelResult.add(jButtonSave, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
getContentPane().add(jPanelResult, gridBagConstraints);
java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
setBounds((screenSize.width-448)/2, (screenSize.height-260)/2, 448, 260);
}// </editor-fold>
/**
* Save functions
*/
private void jButtonSaveActionPerformed(java.awt.event.ActionEvent evt) {
final JFileChooser fc = new JFileChooser();
//In response to a button click:
int returnVal = fc.showSaveDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
if (file.exists()) {
int answer = JOptionPane.showConfirmDialog(null,
"There is already a file with this name. Do you want to overwrite it?",messageTitle,
JOptionPane.OK_CANCEL_OPTION,JOptionPane.QUESTION_MESSAGE);
if (answer==JOptionPane.CANCEL_OPTION) return;
}
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
try {
writer.write(jTextPaneResult.getText());
JOptionPane.showMessageDialog(this,"File successfully written: "+file.getAbsolutePath(),messageTitle,JOptionPane.INFORMATION_MESSAGE);
} finally {
writer.close();
}
} catch (IOException e) {
JOptionPane.showMessageDialog(this,"Couldn't write to output file: "+file.getAbsolutePath()+"\n\n Maybe you do not have the rights to read it?",messageTitle,JOptionPane.ERROR_MESSAGE);
}
}
}
/***
* User has pressed the "load button"
*/
private void jButtonLoadActionPerformed(java.awt.event.ActionEvent evt) {
//Create a file chooser
final JFileChooser fc = new JFileChooser();
//In response to a button click:
int returnVal = fc.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
jTextFieldInputFile.setText(fc.getSelectedFile().getAbsolutePath());
}
}
private void jButtonActionActionPerformed(java.awt.event.ActionEvent evt) {
// Get the encoding
char[] code = jPasswordFieldCode.getPassword();
if ((code==null) || (code.length==0)) {
JOptionPane.showMessageDialog(this,"You need to specify a password.",messageTitle,JOptionPane.ERROR_MESSAGE);
return;
}
// Get the file
String filename = jTextFieldInputFile.getText();
if ((filename==null) || (filename.length()==0)) {
JOptionPane.showMessageDialog(this,"You need to specify an input file.",messageTitle,JOptionPane.ERROR_MESSAGE);
return;
}
try {
// Try to read.
BufferedReader reader = new BufferedReader(new FileReader(filename));
try {
StringBuffer message = new StringBuffer();
String nextline = reader.readLine();
while (nextline!=null) {
if (message.length()!=0) message.append('\n');
message.append(nextline);
nextline = reader.readLine();
}
// OK? Then decode....
Vigenere coder = new Vigenere(code);
String result = coder.code(jComboBoxMode.getSelectedIndex()==0,message.toString());
jTextPaneResult.setText(result);
jPanelResult.setVisible(true);
jPanelSettings.setVisible(false);
jButtonAction.setVisible(false);
} finally {
reader.close();
}
} catch (IOException e) {
JOptionPane.showMessageDialog(this,"Couldn't read input file: "+filename+"\n\n Maybe you do not have the rights to read it?",messageTitle,JOptionPane.ERROR_MESSAGE);
} catch (Vigenere.IllegalCodeException e) {
JOptionPane.showMessageDialog(this,"The password used may only contain of letters between A and Z.",messageTitle,JOptionPane.ERROR_MESSAGE);
}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GUI().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButtonAction;
private javax.swing.JButton jButtonLoad;
private javax.swing.JButton jButtonSave;
private javax.swing.JComboBox jComboBoxMode;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanelResult;
private javax.swing.JPanel jPanelSettings;
private javax.swing.JPasswordField jPasswordFieldCode;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextField jTextFieldInputFile;
private javax.swing.JTextPane jTextPaneResult;
// End of variables declaration
}
Instrunctions for getting it running:
- Install the Sun JDK 5.0 or above. Lower versions might work.
- Create a new directory called "challenge"
- Copy the given source into "GUI.java" in that directory.
- run "javac challenge/GUI.java"
- run "java challenge/gui"
The interpretation wrt. capital letters here is: Capitalize the password/key and keep the capitalization of the text to encode/decode.
Have fun!
Re: Programming Challenge 9: Vigenère cipher
Quote:
Originally Posted by
achelis
Hi mate.
Seems that you switched plain text and key around.
ATTACKATDAWN is the plain text, while LEMON is the key used to encrypt the plain text.
Nice challenge, I may have a look at that. Is there any restriction to programming language?
Your right, I will change it now. I was in a bit of a rush this morning. Thanks for spotting it.
Re: Programming Challenge 9: Vigenère cipher
Here's a really simple lisp implementation.
Code:
(defun vigenere (plain-text key-text &key decrypt)
"encrypt or decrypt plain-text string using key-text"
(let ((key-cycle (make-cycler key-text)))
(map 'string
(lambda (c)
(if decrypt
(decrypt-char c (funcall key-cycle))
(encrypt-char c (funcall key-cycle))))
plain-text)))
(defun make-cycler (seq)
"returns a function that cycles through a sequence"
(let ((len (length seq))
(i -1))
(lambda ()
(incf i)
(elt seq (mod i len)))))
(defun encrypt-char (plain-char key-char)
"return an encrypted char"
(num-letter (mod (+ (letter-num plain-char)
(letter-num key-char))
26)))
(defun decrypt-char (cipher-char key-char)
"return an decrypted char"
(num-letter (mod (- (letter-num cipher-char)
(letter-num key-char))
26)))
(defun num-letter (n)
"returns the char that corresponds to a number"
(code-char (+ n (char-code #\A))))
(defun letter-num (char)
"returns the number that corresponds to a char"
(- (char-code char) (char-code #\A)))
Examples:
Code:
CL-USER> (vigenere "ATTACKATDAWN" "LEMON")
"LXFOPVEFRNHR"
CL-USER> (vigenere "LXFOPVEFRNHR" "LEMON" :decrypt t)
"ATTACKATDAWN"
Just save it as a file and load it into your favorite common lisp implementation.
Re: Programming Challenge 9: Vigenère cipher
Code:
from itertools import cycle
from operator import add, sub
from optparse import OptionParser
class Cypher:
def __init__(self):
toi = lambda x: ord(x) - ord('A')
toc = lambda x: chr(x + ord('A'))
self.apply = lambda f, p, k: toc(f(toi(p), toi(k)) % 26)
def encrypt(self, data, key):
zipped = zip(data, cycle(key))
return "".join(self.apply(add, p, k) for p, k in zipped)
def decrypt(self, data, key):
zipped = zip(data, cycle(key))
return "".join(self.apply(sub, p, k) for p, k in zipped)
if __name__ == "__main__":
parser = OptionParser()
parser.add_option("-i", "--input", dest="data",
help="Data to be encrypted/decrypted", type="string")
parser.add_option("-k", "--key", dest="key",
help="Key for encrypting/decrypting", type="string")
parser.add_option("-e", "--encrypt", action="store_true",
help="Encrypt data [default]", dest="encrypt",
default=True)
parser.add_option("-d", "--decrypt", action="store_false",
help="Decrypt data", dest="encrypt")
(options, args) = parser.parse_args()
errors = []
if not options.key:
errors.append("No key provided!")
if not options.data:
errors.append("No input provided!")
if errors:
print "The following error(s) occured:"
for error in errors:
print ">>> %s" % error
print "Use --help flag for instructions!"
else:
cypher = Cypher()
key = options.key.replace(' ', '').upper()
data = options.data.replace(' ', '').upper()
if options.encrypt:
print cypher.encrypt(data, key)
else:
print cypher.decrypt(data, key)
Most of this is for the command line options, the "Cipher" class is the actual implementation.
Code:
python cipher.py -i ATTACKATDAWN -k LEMON
>>> LXFOPVEFRNHR
python cipher.py -i LXFOPVEFRNHR -k LEMON --d
>>> ATTACKATDAWN
Use "python cipher.py --help" for help.
Re: Programming Challenge 9: Vigenère cipher
I see my little personal project has become a programing challenge.
I've managed to create a simpler version of my actual C code which doesn't read from a file. From the other thread, you know I'm corrupting files with my original code while trying it, so it may even be dangerous to publish it.
PHP Code:
/*Vigenère Simple Version by me in C*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void CallArgError(char *appname)
{
printf("Usage: %s MODE\n\n", appname);
puts("MODE: e = encrypt/d = decrypt");
exit(1);
}
int ReadVar(char *Var)
{
fgets(Var, 258, stdin);
fflush(stdin);
int length = strlen(Var);
int i;
for(i = 0; i < length; i++)
Var[i] = tolower(Var[i]);
return length - 1;
}
void EnDecrypt(char *PlainText, int PlainTextLength, char *Key, int KeyLength, char option)
{
int i, a = 0;
char buf = 0;
for(i = 0; i < PlainTextLength; i++)
{
if(option == 'e')
buf = ((PlainText[i] - 97) + (Key[a] - 97)) % 26;
else if(option == 'd')
buf = ((PlainText[i] - 97) - (Key[a] - 97)) % 26;
buf += 97;
if(isalpha(buf))
printf("%c", tolower(buf));
a++;
if(a > KeyLength)
a = 0;
}
}
int main(int argc, char **argv)
{
char PlainText[258];
printf("Enter a 256-length Plaintext:");
int PlainTextLength = ReadVar(PlainText);
puts("");
char Key[258];
printf("Enter a 256-length key:");
int KeyLength = ReadVar(Key);
puts("");
if((strcmp("e", argv[1]) == 0) || (strcmp("d", argv[1]) == 0))
EnDecrypt(PlainText, PlainTextLength, Key, KeyLength, argv[1][0]);
else
CallArgError(argv[0]);
puts("");
return 0;
}