Beginner's Programming Challenge 18
Hi all, as I am the winner of Beginner's Programming Challenge 17 I have the honour of bringing to you Beginner's Programming Challenge 18.
This time the challenge involves some basic cryptography. You must implement the Vigenère cipher in a programming language of your choice. Your program must prompt the user for a plaintext (the message) and a key (the password) and it should output the corresponding cyphertext (the encrypted message). For the sake of simplicity both the message and the key must contain only uppercase letters of the English alphabet.
For bonus points your program should also be able to decrypt a message given a cyphertext and a key.
This is a beginner's challenge, so the source code shouldn't be hard to read. Also please include plenty of comments.
Some reading:
http://en.wikipedia.org/wiki/Caesar_cipher
http://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher
Best of luck to all.
Rouslan
Re: Beginner's Programming Challenge 18
Haskell:
Code:
import Data.Char
import System(getArgs)
data Crypt = Encrypt | Decrypt deriving (Eq)
-- Takes two characters, one from the original string
-- and one from the corresponding index of the key string.
-- Returns the encrypted (or decrypted) character.
vigenere :: Crypt -> Char -> Char -> Char
vigenere e old key = chr $ 65 + ((p_i `f` k_i) `mod` 26)
where p_i = (ord old) - 65
k_i = (ord key) - 65
f = if e == Encrypt then (+) else (-)
-- Expects 3 command line arguments, the password, the key
-- and an 'e' or 'd' if you want to encrypt or decrypt
-- respectively. The password will be cycled as necessary
-- to be the same length as the source text
main = do
args <- getArgs
let [source, pass, x] = take 3 args
password = take (length source) (cycle pass)
e = case (head x) of
'e' -> Encrypt
'd' -> Decrypt
in putStrLn $ zipWith (vigenere e) source password
Here's a similar approach in Python, whited out for the time being:
Code:
import sys
import operator
from itertools import cycle, islice
def vigenere(f, old, key):
p_i = ord(old) - 65
k_i = ord(key) - 65
return chr(65 + (f(p_i, k_i) % 26))
def main():
[source, passw, x] = sys.argv[1:4]
password = list(islice(cycle(passw), 0, len(source)))
if x == "e":
f = operator.add
elif x == "d":
f = operator.sub
s = ""
for i in xrange(len(source)):
s += vigenere(f, source[i], password[i])
print s
main()
Re: Beginner's Programming Challenge 18
Quote:
Originally Posted by
schauerlich
Code:
import Data.Char
import System(getArgs)
-- Takes two characters, one from the original string
-- and the corresponding character of the key string.
-- To encrypt, f should be (+); to decrypt, (-)
vigenere :: (Int -> Int -> Int) -> Char -> Char -> Char
vigenere f old key = chr $ 65 + ((f p_i k_i) `mod` 26)
where p_i = (ord old) - 65
k_i = (ord key) - 65
-- Expects 3 command line arguments, the password, the key
-- and an 'e' or 'd' if you want to encrypt or decrypt
-- respectively. The password will be cycled as necessary
-- to be the same length as the source text
main = do
args <- getArgs
let [source, pass, x] = take 3 args
password = take (length source) (cycle pass)
f = case (head x) of
'e' -> (+)
'd' -> (-)
in putStrLn $ zipWith (vigenere f) source password
what language is that?
Re: Beginner's Programming Challenge 18
It looks like Haskell to me...
Re: Beginner's Programming Challenge 18
Just wanted to get rid of a bad number of posts, bump!
Re: Beginner's Programming Challenge 18
Python solution.
Code:
import string,sys
letters = string.uppercase
def vigenere(p,k,d):
if d:
i = ( ord(p) - ord(k) - 130) % len(letters)
else:
i = ( ord(p) + ord(k) - 130) % len(letters)
return letters[i]
if len(sys.argv)<4:
print "Usage:",sys.argv[0],"[plaintext|ciphertext] key [encrypt|decrypt]"
print "Example:",sys.argv[0]," attackatdawn lemon encrypt"
sys.exit(1)
text = sys.argv[1].upper()
key = sys.argv[2].upper()
decrypt = False
if sys.argv[3]=='decrypt':
decrypt = True
c=0
result = ''
for t in text:
result = result + vigenere(t,key[c % len(key)],decrypt)
c = c + 1
print result
Re: Beginner's Programming Challenge 18
Here my shot at it in Java, I decided to implement it by actually creating the cypher table and looking up the characters.
Code:
public class Cypher {
private static final int ROWS = 26;
private static final int COLS = 26;
private static final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static char[][] table;
//takes 2 args: text, key and 'e' or 'd'
public static void main(String[] args) {
//init the table
table = new char[ROWS][COLS];
for (int r = 0, offset = 0; r < ROWS; r++, offset++) {
for (int c = 0, pos = offset; c < COLS; c++, pos++) {
if (pos == alphabet.length()) {
pos = 0;
}
table[r][c] = alphabet.charAt(pos);
}
}
//Make string upper case
args[0] = args[0].toUpperCase();
args[1] = args[1].toUpperCase();
//append key if needed
while (args[0].length() > args[1].length()) {
args[1] += args[1];
}
args[1] = args[1].substring(0, args[0].length()+1);
//loop through each character and encrypt/decrypt
int pos = 0;
StringBuilder output = new StringBuilder(args[0].length());
for (int i = 0; i < args[0].length(); i++) {
if (args[2].equalsIgnoreCase("e")) {
output.append(encryptChar(args[0].charAt(i), args[1].charAt(i)));
} else if (args[2].equalsIgnoreCase("d")) {
output.append(decryptChar(args[0].charAt(i), args[1].charAt(i)));
}
}
System.out.println(output.toString()); //print output
}
//Encrypt character by looking up in table
private static char encryptChar(char orig, char key) {
int r = 0;
int c = 0;
for (; c < COLS; c++) {
if (table[c][0] == orig) {break;}
}
for (; r < ROWS; r++) {
if (table[0][r] == key) {break;}
}
return table[r][c];
}
//Decrypt character by looking up in table
private static char decryptChar(char crypted, char key) {
int r = 0;
for (; r < ROWS; r++) {
if (table[0][r] == key) {break;}
}
int c = 0;
for (; c < COLS; c++) {
if (table[c][r] == crypted) {break;}
}
return table[0][c];
}
}
Re: Beginner's Programming Challenge 18
Quote:
Originally Posted by
unknownPoster
what language is that?
Haskell.
Re: Beginner's Programming Challenge 18
Bump, since there are hardly any entries.
Re: Beginner's Programming Challenge 18
Quote:
Originally Posted by
schauerlich
Bump, since there are hardly any entries.
This was posted the same week university started back up for me, maybe others are busy as well?
Here's an encrypter in Go. I'll add the decrypter tomorrow if I have time.
Code:
// UFBPC 18
// @TAGS { UFBPC }
package main
import "fmt"
import "bufio"
import "os"
func main() {
bufin := bufio.NewReader(os.Stdin)
fmt.Printf("Enter Message: ")
mess,_ := bufin.ReadString('\n')
mess = mess[0:len(mess)-1] // trim off newline
fmt.Printf("Enter Key: ")
key,_ := bufin.ReadString('\n')
key = key[0:len(key)-1]
enc := ""
for i:=0; i<len(mess); i++ {
enc += vig(mess[i], key[0])
key = cycle(key)
}
fmt.Printf("Encrypted: %s\n", enc)
}
func cycle(in string) string {
ret := in[1:]
ret += in[0:1];
return ret
}
func vig( m, k uint8 ) string {
p_i := m - 65
k_i := k - 65
u_i := (65 + (p_i + k_i) % 26)
return string(u_i);
}
Instructions for getting a Go compiler going: http://golang.org/doc/install.html
Not as easy as something pre-packaged but it's pretty straight forward none the less.