Skip to content

added submission for sandips #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 222 additions & 0 deletions sandips-assign1/SandipAssignment1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
"""
Assignment 1: Cryptography
Course: CS 92SI
Name: SANDIP SRINIVAS
Date: 7 OCTOBER 2015

This program implements multiple cryptography types: caesar, vigniere, and Railfence.
The program gives the user the option of encrypting/decrypting into a file or string,
and gives output accordingly.
"""

def encrypt_caesar(plaintext):
mapping = {}
for number in range(97, 122):
if (number < 120):
mapping[chr(number)] = chr(number + 3)
else:
mapping[chr(number)] = chr(97 + (number - 120))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've got a fair bit of magic constants here.

ciphertext = ""
for letter in plaintext:
ciphertext += mapping[letter]
return ciphertext

def decrypt_caesar(ciphertext):
mapping = {}
for number in range(97, 122):
if (number > 100):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100 seems a little arbitrary - would like see use of isUpper since its a little more semantically appropriate

mapping[chr(number)] = chr(number - 3)
else:
mapping[chr(number)] = chr(122 - (99 - number))
plaintext = ""
for letter in ciphertext:
plaintext += mapping[letter]
return plaintext


def encrypt_vigenere(plaintext, keyword):
mapping = {}
for number in range(1, 26):
mapping[chr(number + 96)] = number
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be really cool to build this map with the builtin lowercase letters provided by Python's ascii module and the zip utility:

import string
letters = string.ascii_lowercase
mapping = zip(letters,range(len(letters))

ciphertext = ""
for index in range(0, len(plaintext)):
ciphertext += chr(((mapping[plaintext[index]] + mapping[keyword[index]]) % 26) + 95)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah so this line is causing you issues when len(keyword) > len(plaintext) We actually want to perform the modular division operator on len(keyword) itself (not 26)

return ciphertext


def decrypt_vigenere(ciphertext, keyword):
print(ciphertext)
print(keyword)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove debug prints

mapping = {}
for number in range(1, 26):
mapping[chr(number + 96)] = number
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a more pythonic way of building this map would be:

import string
letters = string.ascii_lowercase
mapping = dict(zip(letters, range(1,len(letters)+1))

plaintext = ""
for index in range(0, len(ciphertext)):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 is actually implied here

if (mapping[ciphertext[index]] >= mapping[keyword[index]]):
plaintext += chr(mapping[ciphertext[index]] - mapping[keyword[index]] + 97)
else:
plaintext += chr(27 - abs(mapping[ciphertext[index]] - mapping[keyword[index]]) + 96)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not super clear where the 27 came from?

return plaintext


def encrypt_railfence(plaintext, num_rails):
ciphertext = ""
indexAdjust = 2
for rail in range(1, num_rails + 1):
index = rail - 1
if (rail == 1 or rail == num_rails):
ciphertext += plaintext[rail-1:len(plaintext):2*(num_rails -1)]
else:
ciphertext += plaintext[rail - 1]
while (index < len(plaintext) - 1):
index += ((2*(num_rails -1)))
if (num_rails != 3): index -= indexAdjust
if ( index < len(plaintext) - 1):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some weird spacing here

ciphertext += plaintext[index]
index += ((2*(num_rails -1)) - indexAdjust + 2)
if (index < len(plaintext) - 1):
ciphertext += plaintext[index]
indexAdjust += 2
return ciphertext

def decrypt_railfence(ciphertext, num_rails):
plaintext = ciphertext[0]
index = 0
adjust1 = 0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a more descriptive variable name here?

while (len(plaintext) < len(ciphertext)):
index += (int)(len(ciphertext) / num_rails) - 1 + adjust1
if (index < len(ciphertext)):
plaintext += ciphertext[index]
index += (int)(len(ciphertext) / (num_rails - 1)) - adjust1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all a fair bit repeated - would appreciate factoring this logic out

if (index < len(ciphertext)):
plaintext += ciphertext[index]
index -= (int)(len(ciphertext) / (num_rails - 1)) - adjust1 - 1
if (index < len(ciphertext)):
plaintext += ciphertext[index]
index -= (int)(len(ciphertext) / num_rails) - 1 + adjust1
if (index < len(ciphertext)):
plaintext += ciphertext[index]
++adjust1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, this segment of code is a little hard to understand - we'd appreciate some comments in the future to explain some of the more complicated code segments


print(plaintext)


def read_from_file(filename):
with open(filename, 'r') as f:
content = f.read()
return str(content)


def write_to_file(filename, content):
with open(filename, 'w') as f:
f.write(content)

def run_suite():
"""
Runs a single iteration of the cryptography suite.

Asks the user for input text from a string or file, whether to encrypt
or decrypt, what tool to use, and where to show the output.
"""
print("*Input*")
fileOrString = input("(F)ile or (S)tring? ")
fileOrString = fileOrString.lower()
while (not fileOrString.isalpha() or len(fileOrString) != 1 or
fileOrString not in ['f', 's']):
fileOrString = input("Please enter either an F for File or an S for String: ")
fileOrString = fileOrString.lower()
if (fileOrString == 'f'):
filename = input("Filename? ")
name = read_from_file(filename)
else:
name = input("Enter the string to encrypt: ")

print("*Transform*")
encryptOrDecrypt = input("(E)ncrypt or (D)ecrypt? ")
encryptOrDecrypt = encryptOrDecrypt.lower()
while (not encryptOrDecrypt.isalpha() or len(encryptOrDecrypt) != 1 or
encryptOrDecrypt not in ['e', 'd']):
encryptOrDecrypt = input("Please enter either an E for Encrypt or an D for Decrypt: ")
encryptOrDecrypt = encryptOrDecrypt.lower()

cipherType = input("(C)aesar, (V)igenere, or (R)ailfence? ")
cipherType = cipherType.lower()
while (not cipherType.isalpha() or len(cipherType) != 1 or
cipherType not in ['c', 'v', 'r']):
cipherType = input("Please enter either a C for Caesar, V for Vigniere, or R for Railfence: ")
cipherType = cipherType.lower()

if (cipherType == 'c'):
if (encryptOrDecrypt == 'e'):
print("Encrypting", name, "using Caesar cipher")
output = encrypt_caesar(name.lower())
if (encryptOrDecrypt == 'd'):
print("Decrypting", name, "using Caesar cipher")
output = decrypt_caesar(name.lower())

if (cipherType == 'v'):
passkey = input("Passkey? ")
while (not passkey.isalpha()):
passkey = input("Please enter a passkey of only English letters: ")
if len(passkey) < len(name):
difference = len(name) - len(passkey)
for index in range(0, difference):
passkey += passkey[index%len(name)]
if len(passkey) > len(name):
passkey = passkey[:len(name)-1]
if (encryptOrDecrypt == 'e'):
print("Encrypting", name, "using Vigniere cypher with key", passkey)
output = encrypt_vigenere(name.lower(), passkey.lower())
if (encryptOrDecrypt == 'd'):
print("Decrypting", name, "using Vigniere cypher with key", passkey)
output = decrypt_vigenere(name.lower(), passkey.lower())

if (cipherType == 'r'):
rails = input("Enter number of rails: ")
while (not rails.isnumeric):
rails = input("Please enter a positive integer number of rails: ")
if (encryptOrDecrypt == 'e'):
print("Encrypting", name, "using Railfence cipher with", rails, "rails")
output = encrypt_railfence(name, int(rails))
if (encryptOrDecrypt == 'd'):
print("Decrypting", name, "using Railfence cipher with", rails, "rails")
output = decrypt_railfence(name, int(rails))

print("*Output*")
fileOrString = input("(F)ile or (S)tring? ")
fileOrString = fileOrString.lower()
while (not fileOrString.isalpha() or len(fileOrString) != 1 or
fileOrString not in ['f', 's']):
fileOrString = input("Please enter either an F for File or an S for String: ")
fileOrString = fileOrString.lower()
if (fileOrString == 'f'): name = input("Filename? ")
else: print(output) # Print or write the transformed output


# Do not modify code beneath this point.
def should_continue():
"""
Asks the user whether they would like to continue.
Responses that begin with a `Y` return True. (case-insensitively)
Responses that begin with a `N` return False. (case-insensitively)
All other responses (including '') cause a reprompt.
"""
choice = input("Again (Y/N)? ").upper()
while not choice or choice[0] not in ['Y', 'N']:
choice = input("Please enter either 'Y' or 'N'. Again (Y/N)? ").upper()
return choice[0] == 'Y'


def main():
"""Harness for the Cryptography Suite"""
print("Welcome to the Cryptography Suite!")
run_suite()
while should_continue():
run_suite()
print("Goodbye!")


if __name__ == '__main__':
"""This block is run if and only if the Python script is invoked from the
command line."""
main()
23 changes: 23 additions & 0 deletions sandips-assign1/feedback.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Name: Sandip Srinivas
1) How long did this assignment take you to complete?
Roughly 5 hours


2) What has been the best part of the class so far?
Doing practice problems in class (anagrams, cyclone phrases, etc)




3) What can we do to make this class more enjoyable for you?
Teach more cool python specific things




4) What types of assignments would excite you in this class?
Games (i.e. brick breaker, boggle, but not as time consuming as boggle)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it - thanks for the suggestions