General Instructions. Students are required to work together in groups of size 3 or 4. An assignment submitted on behalf of a "group" having fewer than 3 students will receive a grade of F. All members of the group are responsible for understanding the entire assignment and will receive the same grade.
No late assignments will be accepted.
Academic Integrity. Collaboration between groups is prohibited and will be treated as a violation of the University's academic integrity code.
You will be adding security functionality to an electronic voting system this semester. We provide a base system, which is not secure; you design and deploy defenses. The project is partitioned into phases. Each phase addresses certain vulnerabilities and will allow you to put into practice material we discuss in lecture.
The insecure voting system we provide is written in C#. Your job is to augment this program---not to rewrite it completely. Most of us would prefer to design and write a system from scratch, but one rarely has that option in the "real world". So, this project will give you a taste of what it is like to retrofit security functionality into a legacy application.
This first phase involves protecting against bogus servers and passive wiretappers. Implementing defenses will enable you to gain familiarity with the .Net cryptographic library. You will also learn about padding for encryption and decryption.
Document Overview. This specification is divided into two parts.
The electronic voting system we provide is split into four parts:
In an actual deployment, the server would execute on a physically secured computer that has a well-known network address. And the client would run on a computer owned by a voter (e.g., a laptop of cellphone). For ease of testing, you will run the client and server programs on the same computer. Because .Net programs running on the same computer can communicate using TCP as though these programs were located on different machines, the system you develop would then be easy to redeploy in the more realistic setting where clients and server are located on separate computers.
Server. When the server is started, it reads file config.xml containing
The election file is in XML format. A <config> tag contains 2 elements: <port>, which contains the port, and <elections>, which contains information about possible elections. Each election has a name and contains the names of the candidates:
Composer of the year, Stephen Sondheim, Andrew Lloyd Weber, Leonard Bernstein Best name for CU faculty-owned sailboat, Circe, Prof@Large, Wave Train, Sea Fever
The server has a GUI that allows an election official to declare an election as being open or closed. An open election contains * before the name. A vote in some election is counted only if it is received by the server while that election is open.
When an election is declared closed, the server's GUI displays the vote counts for each candidate in the named election; when an election is declared open, the vote count for every candidate in the named election is reset to 0. At any given time, every election is either open or closed; initially, all elections are closed.
Client / Server Interaction. When the client is started, it displays a GUI that allows a voter to specify the name of an election. (The voter must specify this name; no communication with the server occurs until this name has been provided.) The client program then makes a TCP connection to the server, and it sends the election name over that connection to the server. The server replies with the list of candidates for that election. The voter selects exactly one from among those candidates, signifies that a vote be cast for this candidate, and thereby causes the client to send this vote to the server. Upon receipt, the server verifies that that the named election exists, is open, and that the named candidate is part of that election; if these checks are satisfied then the server increments the vote count for the appropriate candidate by one. The following diagram depicts this client-server interaction:
A server implemented by only a single thread is particularly vulnerable to client delays---a client taking a long time to vote will cause the server to block, thereby preventing other clients from being served. Therefore, to insulate server performance from slow clients, our server forks a worker thread for each client request (corresponding to each new TCP connection accepted). The worker thread handles the processing of that request; the original thread resumes waiting for a new request.
The server management interface also has its own thread. This thread is associated with a GUI that allows election officials to interact with the server; this thread does the work associated with declaring an election open or closed.
Since the server is multithreaded, access to shared data must be controlled.
Election objects are read and
modified by more than one thread: two worker threads might tally votes for
elections at the same time, or a worker thread might try to tally a vote at the
same time as the server management thread opens or closes an election.
Election objects can be found as part of the
is thus necessary. Our server never allows their execution to be interleaved.
The documentation files for all the classes in our election system are
available to view:
documentation, and shared
classes (which implement client-server communication).
Note the interaction between the
GUI classes (
with the main logic of the client and server. Using the client as an example,
for the GUI and a
client communication with server, and hooks them together. The GUI handles
interaction with the server and calls the Client object to do the real work,
passing itself as an argument. When the Client needs to display results to the
voter, it calls ClientDisplay methods to add them to the GUI.
Download the code. Unzip it, and open server and client in separate Visual Studio .Net environments. Make sure the config.xml files are in <Server/Client>/Bin/Debug. You can configure the IP address of the server and the port on which it is listening through config.xml files for both client and the server: By default, the server is listening on port 8000 and the client is looking for the localhost server on port 8000. Change the files accordingly if you're running client and server on different machines.
To simplify message serialization, we've created a Shared assembly that must be added as a reference to both Client and Server. You do this by right clicking on the project name (Client, Server) in Solution Explorer in VS environment, selecting "Add Reference", selecting the "Projects" tab, clicking on Browse button, and pointing it to Shared\bin\Debug\shared.dll.
There are many problems with this system, if it is to be used to determine the outcome of an election. Here are just a few:
For Phase I, we tackle (only) the first three vulnerabilities in the above list. Specifically, your task is to augment our electronic voting system so that these three vulnerabilities have been eliminated. Be reluctant about making changes to the existing system---for example, don't add additional messages or message exchanges unless it is necessary.
Here are some detailed suggestions for completing this phase. Ignore these at your peril, because subsequent phases might become unnecessarily difficult if you depart radically from what is outlined here.
Hybrid Encryption. Any client software might ultimately fall into an attacker's hands, so including secrets (keys, etc.) in the client software distribution is a bad idea. Thus, while the significantly lower cost of secret key cryptography makes this mode the clear choice for encrypting during each session between a client and server, it is unreasonable to assume that each client has been initialized with a secret key. It would be reasonable to assume that client software has initially been configured with some public key---store this public key in a file rather than in the program text, for flexibility.
Encryption Operations. Documentation for the cryptographic services provided by .NET can be found on MSDN (developer's guide, class library). The .NET platform comes with ready to use implementations of AES (Rijndael) and RSA.
For secret key cryptography, use the System.Security.Cryptography.Rijndael and System.Security.Cryptography.CryptoStream classes. The CryptoStream class simplifies secret key encryption and decryption by accepting cryptographic transformers produced by the Rijndael class. You may use the default padding mode. Note that the Rijndael implementation makes use of both a key and an initialization vector (IV).
For an RSA implementation, including key pair generation, use the System.Security.Cryptography.RSACryptoServiceProvider class. Key pair generation is rather slow, so you are encouraged to write a separate program to generate a pair of keys once and write this pair to files that can be reread each time the client and server are executed. To implement hybrid encryption, use the System.Security.Cryptography.RSAPKCS1KeyExchangeFormatter class (and the corresponding Deformatter class) to encrypt secret keys. Transmission of IVs is discussed in Schneier, chapter 9, section 3.
The use of other, cryptographically-sound, schemes will not cause points to be deducted. But subsequent phases of the project might be difficult to implement in the presence of other cryptographic or padding schemes. So, think twice if the first message sent to the server does not contain an RSA-encrypted secret key.
Generating Random Numbers. It is surprisingly difficult to find random bits in a computer system. Although many values that might be read from the hardware or lower-levels of the software might look random, too often they can be predicted given information about the exact system configuration. An attacker might know all about the exact system configuration, so an attacker would then be able to anticipate future such "random" values (thereby enabling all sorts of attacks). A famous example is described in this article from the New York Times.
In C#, you can use class System.Security.Cryptography.RandomNumberGenerator to obtain random bytes which can be transformed into integers. The System.Random class does not generate a unique sequence.
Routing Vulnerabilities. Little can be done in the client or server software to defend against an attacker who corrupts the Internet's routing structure. Such corruption could prevent messages between clients and servers from reaching their intended destinations. Either a message gets delivered to a requested IP address or it does not, and that is out of the client's and the server's control. What can be done in client and server software is to ensure that a client knows whether or not a vote it cast actually reached a bona fide server, even in the presence of possible message replays by attackers. Presumably, you can take it from there.
Disposing of sensitive data. The .NET platform does a good job on garbage collection, but cryptographic keys and other sensitive information should not be left to a garbage collector because it does not guarantee when those objects will be replaced in the memory. Please use appropriate methods to destroy sensitive data in memory.
Submission Procedure. Create a .zip file containing the files you wish us to grade. Then submit this .zip file using CMS Your .zip should contain the following files (at least):
Grading. Your grade will be based on the following elements: