A Java API for Historical Ciphers : An Object-Oriented Design Project Ralph Morelli, Ralph Walde, Gregg Marcuccio Computer Science Department T rinit y College Hartford, CT 06106
[email protected]
Abstract
As a means of testing their design, students implemented a CryptoTool prototype which provided several dierent cipher algorithms, including Caesar, Simple Substitution, and AÆne. The user could select a cipher object from a menu and use it to encrypt and decrypt text that was input into a Java TextArea.
This paper describes a project suitable for a software engineering or object-oriented design course. The project consists of asking students to design an applic ation programming interface (API) for a particular range of applications. An API-design project has sev eral features not always found in application-design projects: It forces students to focus carefully on the distinction betw een the programming and the user interfaces; it provides a good justi cation for studying existing APIs as model code; it provides a natural way to divide tasks betw een dierent groups of designers/programmers; and, the nal product can be used as the basis for programming projects in other courses. In this case the particular project we describe is the design of an API for implementing Historical Cipher algorithms. 1 Introduction
Soft w are engineeringcourses and courses that emphasize object-oriented design often involve projects whose focus is to design an application of some sort. ([5]) Indeed the idea for this API-design project grew out of an application project that w eha ve used in our Soft w are Engineering course. In that course students were asked to design a GUI application program which could be used to encrypt and decrypt text using a menu of cipher algorithms. The goals of the project were to make use of appropriate object-oriented design (OOD) principles such as inheritance and polymorphism and to base the application's design on some of the reusable patterns that were being studied in the course. One of the texts used in the course was Patterns in Java [4].
(Paste cop yrigh t notice here.)
Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. SIGCSE 2001 2/01 Charlotte, NC USA Copyright 2000 ACM 1-58113-329-4/01/0002 ... $5.00
In assessing the project at the end of the course, one of the shortcomings identi ed w as thatthe design did not make a clear enough distinction between the Cipher classes, those parts of the application that were used for encryption/decryption, and the GUI classes, those parts of the program used to implement the user in terface. Developers of the dierent cipher algorithms noticed that a portion of their code had nothing to do really with the encryption task. Even tually the design teams came to see the importance of maintaining a sharp distinction betw een theprogramming interface and the user interfac e. This insight led to a redesign of the project into two parts: One team is responsible for designing an API for implementing the cipher algorithms. Other teams are responsible for designing and implementing speci c encryption systems and other teams are responsible for designing applications that make use the encryption systems. In the remainder of this paper we describe the main features of the project in terms of its design goals and other features. We conclude with some observations about the main strengths of an API-design project, including w ays that the API itself can be useful as a programming platform in other courses (CS1 and CS2). 1.1
Cryptography Basics
Before describing the project, we give some background on cipher algorithms. There are a number of good references available on historical cryptography, including Kahn [2] and Beker and Piper [1]. Cryptography is the art and science of designing systems for transmitting secret messages. The message to be kept secret is called the plaintext and the process of hiding its meaning is called encryption (or enciphering).
307
In addition to these constraints, we identi ed a number of other design goals that focused on how the API would be used:
The secret message is called the ciphertext and the process of translating the ciphertext to plaintext is called decryption (or deciphering). A cipher is an algorithm for translating plaintext to ciphertext and vice versa. Normally the translation will depend on some kind of cryptographic key, which is used by the algorithm to encrypt or decrypt the message. There are a wide range of historical ciphers, but generally speaking they fall into two distinct groups: substitution ciphers and transposition ciphers. For example, a very simple substitution cipher is the Caesar cipher, in which each of the letters a through z is represented by the letter which occurs three places after it in the alphabet, with the last three letters, x through z, wrapping around to the beginning of the alphabet. So for the standard plaintext alphabet, we get the following ciphertext alphabet:
The API should minimize the amount of program-
ming eort needed to implement an historical cipher system.
The API should not constrain the potential user in-
terfaces that it may be used with.
The API's design should be based on basic OOD prin-
ciples and widely used design patterns.
2.1
Project Teams
The project involves three types of design/programming teams, two of which may have several instances. There is virtually no limit to the number of teams that could be involved in this type of project.
Plaintext: a b c d e f g h i j k l m n o p q r s t u v w x y z Ciphertext: D E F G H I J K L M N O P Q R S T U V W X Y Z A B C
The API Team should perhaps be made up of the strongest students in the course. It is responsible for designing and implementing the API itself. Their product, the classes contained in the API, will be used by all the other teams.
To encrypt the message \caesar was a roman" we simply replace each plaintext character with the corresponding ciphertext character: FDHVDU ZDV D URPDQ. Decryption would perform the substitution in the opposite direction.
The Service Provider Teams, of which there may be several instances depending on the class size, are responsible for using the API to develop speci c cipher systems. For example, one service provider might develop a cipher system for Caesar cipher, another for a particular kind of transposition cipher, another for a simple substitution cipher, and so on. Because these teams must use the API in their programs, they can give important feedback to the API-design team. Do the API's classes pose any undesirable contraints on the type types of ciphers that can be implemented? Do the API's methods contain the right parameters? In giving these teams their charge, it's important to stick to fairly simple cipher algorithms in order to keep the focus on design of the API rather than on design of cipher algorithms.
A transposition cipher rearranges the letters in the original message. For example, in one type of transposition cipher, the transposition key 43210 describes how to rearrange the letters in a 5-character block in which the character positions are numbered 0 through 4. Using this key a transposition cipher would encrypt \caesa rwasa roman" into ASEAC ASAWR NAMOR. 2 Project Description
The overall goal of the project is to design an application programming interface (API) to support the creation of historical cipher algorithms. The resulting API should provide a means of implementing the full range of historical ciphers, including those that perform substitutions on a single character (Caesar) and those that rearrange the letters in an entire block of characters (transposition). Therefore the nal product, the API, should meet the following speci c design constraints:
The Application Teams, of which there may be several instances depending on class size, focuses on design of cryptography applications. For example, one team might develop a program that encrypts and decrypts les using a command-line interface. Another might develop a GUI application that encrypts and decrypts text that's entered interactively. These teams can help insure that the design of the API does depend on or constrain the design of the applications that use it. For example, one of the design goals given these teams should be that their program need not know the names of the cipher algorithms it uses.
The API should provide a general way for any cipher
system to describe how it translates plaintext into ciphertext and vice versa.
The API should provide a means to construct an ap-
propriate cryptographic key for any particular cipher algorithm.
Although the three types of teams have dierent tasks in the project the main goal is to design the API. So everyone participates in the design discussions, with members
The API should enable the algorithms to work on var-
ious character sets { i.e., uppercase and lowercase letters, digits, printable ASCII characters, and so forth.
308
The cipher algorithm itself is implemented in the CaesarCipherSpi class.
of the dierent types of teams having dierent perspectives on the problem.
The following example shows how an application would make use of the Caesar cipher provided by MyProvider. In this case the application speci es both the name of the algorithm (Caesar) and the name of the provider (Myname):
3 Design Issues
In this section we look at the API classes that the students need to design and implement and point out some of the standard design patterns that these classes exemplify.
import historicalcrypto.cipher.*; import historicalcrypto.provider.*;
Students at this stage need to start with a well-thoughtout design to which they can make modi cations. Therefore, rather than attempt to design the API from scratch, students are required to base their design on an existing API. Studying an existing API, designed by professional programmers, is one of the advantages of a API-design project over a simple application project.
public class TestCipher { public static void main(String args[]) { Provider.addProvider(new MyProvider("Myname")); Cipher cipher = Cipher.getInstance("Caesar", "Myname"); CaesarKey key = new CaesarKey("3/AZ"); cipher.init(key); System.out.println(cipher.encrypt("THIS IS A TEST"); } }
In keeping with this goal, we begin this project by studying the Java Cryptography Extension (JCE), an API that provides a programming framework for encryption algorithms. Rather than provide a library of encryption algorithms, the JCE enables its users to create their own cryptography libraries. So the JCE is a perfect model for our goal of designing a framework for implementing a potentially limitless number of historical ciphers. On the other hand, the JCE is far more complex and comprehensive than what we needed for our project. So one of the challenges is to decide how to simplify the JCE, both in terms of the number of classes and the complexity of the classes.
This example assumes that the programmer has implemented a proprietary version of the Caesar cipher in the provider named "Myname". The algorithm is being used with a shift of 3 to encrypt strings of uppercase characters. 3.2
Cipher -spi:CipherSpi -provider : String -algorithm : String
The Historical Cipher API is organized into three Java packages. The cipher package provides classes and methods for implementing cipher algorithms, keys and alphabets. The provider package de nes the service provider interface for the API. The demo package, provides a small collection of built-in cipher implementations that illustrate how to use the API. 3.1
Factory Method Pattern: The Cipher Class
+Cipher() +init() +encrypt() : String +decrypt() : String
CipherSpi -uses >
1
1
#engineInit() #engineEncrypt() : String #engineDecrypt() : String
BlockCipher
CaesarCipher -shift : int
Searchable Container Pattern: The Provider Class
#engineInit() #engineEncode() : String #engineDecode() : String
Like the JCE, the Historical Cipher API supports dynamic loading of cipher systems, and like the JCE it uses a provider interface for this purpose. The top-level Provider class serves as a searchable container. Service provider teams can add one or more cipher algorithms into a Provider object, and application programs can retrieve ciphers by name. In this example a service provider MyProvider is providing an implementation of a Caesar cipher:
#blocksize : int #alphabet : String #engineEncrypt() : String #engineDecrypt() : String #engineEncode() : String #engineDecode() : String
TranspositionCipher -transposition : String #engineInit() #engineEncode() : String #engineDecode() : String
Figure 1: A UML representation of the Cipher class hierarchy.
public class MyProvider extends Provider { public MyProvider(String name) { this.name = name; put("Caesar", "CaesarCipherSpi"); } }
Figure 1 provides an overview of the cipher package. The Cipher class provides the main functionality for
309
the responsibility of algorithm-speci c key classes, e.g., CaesarKey, to de ne the instance variables and methods that are needed by its particular cipher algorithm.
creating and initializing cipher objects and then encrypting and decrypting data. The design of this class is based on the factory method pattern. A factory method is a creation pattern that allows an application to create objects according to certain speci cations. [4] The getInstance(String) is the factory method. As shown in the TestCipher example (above), the getInstance() method takes a string giving the name of a cipher algorithm { \Caesar" { and returns an object that implements that algorithm. In this way an application program can create instances of ciphers dynamically. 3.3
The Alphabet class de nes the character set for the key and the cipher engine. This too is an area where students can exert considerable design innovation, since there is no real analog for it in the JCE. The design adopted for this project allows the following character ranges: az, AZ, azAZ, azAZ09, printable ASCII, and ASCII. It provides methods that assist a cipher engine in implementing an algorithm that is de ned for these particular character sets, but the details are, of course, algorithm speci c.
Delegation Pattern: The CipherSpi Classes
In order to extend its functionality to an unlimited range of cipher algorithms, the Cipher class delegates the encryption and decryption tasks to speci c CipherSpi objects { i.e., to instances of subclasses of CipherSpi.
3.5
The Service Provider Teams use the API to create new cipher algorithms by implementing Spi subclasses. All Spi subclasses must implement three abstract methods: engineInit(HistoricalSecretKey), engineEncode(String), and engineDecode(String). Here's an implementation for the NullCipherSpi, a cipher that does not transform the plaintext.
The Spi suÆx in CipherSpi stands for Service Provider Interface. Spi classes serve as the cipher engines. Classes so named are implemented by service providers. They can be added to the cryptography libraries at run time using the provider interface described above.
public class NullCipherSpi extends BlockCipher public NullCipherSpi() {} public void engineInit(HistoricalKey hKey) throws Exception if (! (hKey instanceof NullKey)) throw new Exception("Invalid Key"); } public String engineEncode(String s) throws Exception return s; } public String engineDecode(String s) throws Exception return s; } }
For example if you asked for an instance of Caesar cipher, then the Cipher.getInstance() method would nd a CaesarSpi object that implements that algorithm and would delegate the actual encrypting and decrypting tasks to that object. This delegation model follows the design of the Java Cryptography Extension (JCE). 3.4
Using the API
Keys and Alphabets
An important part of implementing a cipher algorithm is de ning an appropriate key for the algorithm. As you would expect, keys are algorithm speci c. For example, the key for a Caesar cipher requires an integer value that represents the shift by which the alphabet is rotated. A transposition cipher requires a string of digits that represent how a block should be transposed.
{ {
{
{
Of course, for a real cipher algorithm, the programmer would have to provide nontrivial implementations of these three methods. However, in keeping with the project's goal of focusing on the design of the API, it is very straightforward to implement some of the simple historical ciphers. In fact, once the API is implemented, it can be used as a framework or substratum for interesting and easy-to-implement programming exercises in the CS1 and CS2 courses.
This is the area in which the students can exert the most in uence over the nal design of the API. The main class, HistoricalSecretKey, represents a substantial simpli cation of the main key classes found in the JCE. To provide the most exibility in the API's design, all keys are constructed by passing them a key speci cation string, which takes the form keyword/alphabet. The keyword portion of the speci cation provides the keyspeci c data. For the Caesar cipher this would be the shift, \3". For the transposition cipher this would be the transpose pattern \10432". The alphabet portion of the speci cation de nes the character set that will be used by the key (and the cipher algorithm). It is
4 Concluding Observations
We conclude with a number of observations about the Historical Cipher API and its use or the use of similar APIs in a number of undergraduate computer science courses.
310
4.1
4.3
Design Patterns
The API used the following major design patterns, all of which are appropriate objects of study for a software engineering or object-oriented design course:
Another plus for this type of project is that once the API is designed and implemented it can be used as the basis for programming projects in other courses. For example historical ciphers provide a good basis for studying string processing algorithms of the sort that might be covered in CS1, and certain historical ciphers pose interesting design issues for the CS2 course. For example, what data structures should be used to implement a simulation of the Enigma machine? The API could also be used as a basis for studying algorithm eÆciency and complexity.
Interface Pattern: A cryptographic key is imple-
mented as an interface.
Factory Method Pattern: Cipher objects are created
by a factory method
Delegation Pattern: Encryption and decryption tasks
are delegated to speci c implementations of the ciphering engines.
Although our API focuses on historical ciphers, similar points could be made about APIs that address other application areas. Here are some possibilities:
Searchable Container Pattern: Implementations of
speci c algorithms are stored in a searchable container.
4.2
Using the API in Other Courses
Design an API for testing algorithms. Design an API for doing mathematic computations on
The API Model of Software Development
arbitrary precision integers and oating point numbers.
For the software engineering course, designing and implementing an API is a good model for learning how to develop software. For one thing, studying a related API, such as the JCE, is an excellent way to learn about Object Oriented Design. Indeed one of the strengths of the Patterns in Java text is that each of the design patterns discussed is illustrated by a reference to the Java API. [4] Not only does this give students the sense that they are dealing with real-world software, but it forces them to study software that truly is well-designed.
Design an API for supporting multi-user network
communication.
4.4
Plans for the Future
Our plan is to use the API approach, either with the Historical Cipher API or with another one, the next time we teach the software engineering course. The API, which is freely available on the Web at http:starbase.trincoll.edu/ ram, is now being used to implement a wide collection of historical ciphers.
Second, as we have tried to indicate, developing an API forces students to address a number of important design issues, not all of which arise in developing an application program. For example, in designing an application it is sometimes tempting to rely on programming and design hacks because the software itself is not going to be examined by the user. The program just needs to work. But in designing an API, since other programmers are going to depend on the quality of your design, it's easier to instill good programming and design practices. During the project itself, students on the API Team have ample opportunity to receive feedback on their design from the Service Provider Teams and the Application Teams.
5 References
1. Henry Beker & Fred Piper. Cipher Systems. New York: John Wiley & Sons, 1967. 2. David Kahn. The Codebreakers. New York: Macmillan, 1967. 3. Jonathan Knudsen. Java Cryptography. Cambridge: O'Reilly & Associates, Inc., 1998. 4. Mark Grand. Patterns in Java, Volume 1. New York: Wiley Computer Publishing, 1998.
Designing software that will be used primarily by other programmers places a number of important constraints on the project:
5. Viera K. Proulx. \Hospital Emergency Room Simluation: Object Oriented Design Issues for CS2," SIGCSE Bulletin, 31,1, March 1999.
The API's objects and methods must be well designed
for use by a wide range of other applications.
6. Java Cryptography Extension. http://java.sun.com/products/jce/.
The API's design must incorporate appropriate levels
of information hiding.
The API has to be well documented.
311
URL: