To download and install Python on your home machines see this page. Remember that this is only to enable you to play with the assignment at home: The final version turned in must work on the ACS Linux machines. While you can use Windows/Mac etc. to begin working with Python, the code you turn in must be that required for the Linux environment.
Code for all programming assignments should be well documented. Documentation entails providing documentation strings for all methods, classes, packages, etc., and comments throughout the code to explain the program logic. Comments in Python are preceded by # and extend to the end of the line. Documentation strings are strings in the first line of a function, method, etc., and are accessible using help(foo) where foo is the name of the method, class, etc. It is understood that some of the exercises in this programming assignment require extremely little code and will not require extensive comments.
The overall objective of this assignment is to introduce you to Python. Emphasis will be placed on text and string manipulations and should use some of Python’s facilities for iterating over structures.
The assignment is spread over three python files
and three files
that you need to download.
The first three files contain several skeleton Python functions, with missing bodies, i.e. expressions, which currently contain the text raise Failure("to be written").
Your task is to replace the text in those files with the the appropriate Python code for each of those expressions. An emphasis should be placed on writing code that is concise and easy to read.
Your functions/programs must compile and/or run on a ACS Linux machine (e.g. ieng6.ucsd.edu) as this is where your solutions will be checked. While you may develop your code on any system, ensure that your code runs as expected on an ACS machine prior to submission. You should test your code in the directories from which the zip files (see below) will be created, as this will approximate the environment used for grading the assignment.
Most of the points, will be awarded automatically, by evaluating your functions against a given test suite. test.ml contains a very small suite of tests which gives you a flavor of of these tests. At any stage, by typing at the UNIX shell :
> python < test.py | grep "130>>" > log
you will get a report on how your code stacks up against the simple tests.
The last line of the file log must contain the word ``Compiled" otherwise you get a zero for the whole assignment.
If for some problem, you cannot get the code to compile, leave it as is with the raise ... with your partial solution enclosed below as a comment.
The second last line of the log file will contain your overall score, and the other lines will give you a readout for each test. You are encouraged to try to understand the code in test.py, and subsequently devise your own tests and add them to test.py, but you will not be graded on this.
Alternately, inside the Python shell, type:
>>> import test
.
.
.
130>> Results: ...
130>> Compiled
and it should return a pair of integers, reflecting your score and the max possible score on the sample tests. If instead an error message appears, your code will receive a zero.
Your solutions to this assignment will be stored in separate files under a directory called solution/, inside which you will place your modified files: misc.py and crack.py. There should be no other files in the directory
After creating and populating the directory as described above, create a zip file called cse130_pa5.zip by going into the directory solution and executing the UNIX shell command:
> zip cse130_pa5.zip *
Once you have created the zip file with your solutions, you will use the turnin program to submit this file for grading by going into the directory solution/ and executing the UNIX shell command:
> turnin -c cs130f -p pa5 cse130_pa5.zip
turnin will provide you with a confirmation of the submission process; make sure that the size of the file indicated by turnin matches the size of your zip file. See the ACS Web page on turnin for more information on the operation of the program.
To load a file foo.py containing the definition of a function bar(), do the following:
>>> import foo
>>> foo.bar()
Suppose you just modified foo.py. To reload it into the python shell, do:
>>> reload(foo)
>>> foo.bar()
You can directly write bar() by importing all the names inside foo.py at once:
> from foo import *
> bar()
However, if you use the above method, you have to restart Python to reload after modifying foo.py.
None doesn’t print a line when it is the return value of a function.None, 0 and [] are all treated as False when used as a predicate (eg in an if statement.)for-loops.Write a function closest_to(l, v) which returns the element of the list l closest in value to v. In the case of a tie, the first such element should be returned. If l is empty, None should be returned.
Once implemented you should get the following behavior at the Python prompt:
>>> from misc import *
>>> closest_to([2,4,8,9], 7)
8
>>> closest_to([2,4,8,9], 5)
4
Now, write a function make_dict(keys, vals) which takes a list of keys and a list of values and returns a dictionary dict pairing keys to corresponding values.
Once you have implemented the function, you should get the following behavior at the Python prompt:
>>> make_dict(["foo", "bar", "baz"], [1.0, 2.0, 3.0])
{'foo': 1.0, 'bar': 2.0, 'baz': 3.0 }
>>> make_dict([1,2,3],[100,200,300])
{1: 100, 2: 200, 3: 300}
Write a Python function word_count(filename) that takes a string, filename, and returns a dictionary mapping words to the number of times they occur in the file filename. For this function, a word is defined as a sequence of alphanumeric characters and underscore. All other characters should be ignored. Words should be returned in lower case, and case should be ignored when counting occurrences.
Once you have implemented the function, you should get the following behavior at the Python prompt:
>>> word_count("news.txt")
{'all': 2, 'code': 2, 'gupta': 1, 'results': 1, 'four': 1, 'edu': 2, ...}
For this problem, you will write a simple dictionary based password cracker. This should primarily be an exercise in string manipulation and data structures. You will be attempting to crack as many passwords as possible in a UNIX password file. The passwords are encrypted using the UNIX crypt() function. For more information see man passwd man crypt on UNIX or Linux.
Write a Python function load_words(filename,regexp) which loads the words from the file filename which match the regular expression regexp. Recall that we have already seen regular expressions in PA4, see this for information on how to match strings against regular expressions in Python.
The input file (corresponding to filename) will have one word per line. The resulting words should be returned in a list in the same order they occur in the input file.
Once you have implemented the function, you should get the following behavior at the Python prompt:
>>> from crack import *
>>> load_words("words",r"^[A-Z].{2}$")
['A-1', 'AAA', 'AAE', ...]
>>> load_words("words",r"^xYx.*$")
[]
Write three python functions to implement the following string transformations: transform_reverse, transform_capitalize, and transform_digits. Each will take a string as an argument and return a list of strings. The order of returned strings does not matter.
The first function, transform_reverse(str) should return a list with the original string and the reversal of the original string.
The second function, transform_capitalize(str) should return a list of all the possible ways to capitalize the input string.
The third function, transform_digits(str) should return return a list of all possible ways to replace letters with similar looking digits according to the following mappings. This should be done without regard to the capitalization of the input string, however when a character is not replaced with a digit, it’s capitalization should be preserved.
o -> 0 i,l -> 1 z -> 2 e -> 3 a -> 4 s -> 5 b -> 6 t -> 7 b -> 8 g,q -> 9
Once you have implemented the function, you should get the following behavior at the Python prompt (order of list elements is not important):
>>> transform_reverse("Moose")
['Moose','esooM']
>>> transform_capitalize("foo")
['foo', 'Foo', 'fOo', 'FOo', 'foO', 'FoO', 'fOO', 'FOO']
>>> transform_digits("Bow")
['Bow', 'B0w', '6ow', '60w', '8ow', '80w']
Write a function check_pass(plain, enc) which will take a plain-text password, plain, and an encrypted password enc and will return True if plain encrypts to enc using the function crypt.
Crypt is available in Python in the crypt module. You can load this modules with import crypt. Then the crypt function is available as crypt.crypt(). See help(crypt.crypt) in Python.
When crypt is used, a salt must be provided to perturb the algorithm. This salt is a random two character string which is returned in the beginning of the password. Since you are going in the other direction, you should extract the salt from the first two characters of the encrypted password (or see here.) for more information).
Once you have implemented the function, you should get the following behavior at the Python prompt:
>>> check_pass("asarta","IqAFDoIjL2cDs")
True
>>> check_pass("foo","AAbcdbcdzyxzy")
False
Now, write a Python function load_passwd(filename) which takes a string as input and returns a list of dictionaries with fields "account", "password", "UID", "GID", "GECOS", "directory", and "shell", each mapping to the corresponding field of the file. The UID and GID fields should be returned as integers. The password file contains lines of the following format (see this for more
account:password:UID:GID:GECOS:directory:shell
Once you have implemented the function, you should get the following behavior at the Python prompt:
>>> load_passwd("passwd")
[{'account': 'root', 'shell': '/bin/bash', 'UID': 0, 'GID': 0, 'GECOS': 'Corema Latterll', 'directory': '/home/root', 'password': 'VgzdTLne0kfs6'},
... ]
Hint: The function re.split may be of use.
Finally, write a function crack_pass_file(filename,words,out) which takes two strings corresponding to a password file and a file with a list of words and a string corresponding to an output file. Attempt to crack as many of the passwords in the password file as possible. As passwords are discovered, they should be written to the output file in the following format:
username=passfor example,
checani=asarta
After each line is written, the output file should be flushed. Your function will only be allowed to run for a limited amount of time (several minutes). Thus, you should attempt to crack the easiest passwords first. All passwords in the input file are between 6 and 8 characters and can be cracked using words in the provided dictionary along with a combination of the transformations above. The base points will be provided if all the passwords which are untransformed strings can be cracked. Fractional credit will be proportional to the number of additional passwords cracked, with the student cracking the most extra words getting the full 25 points.
Once you have implemented the function, you should get the following behavior at the Python prompt:
>>> crack_pass_file("passwd","words","out")</font><br>
# Several minutes pass...
# Hit Ctrl-C
Traceback (most recent call last):
...
KeyboardInterrupt
The file out should contain something like the following:
checani=asarta
root=…
…=…
…=…