[ home | photos | gallery | scheme | notes | blog | facebook | twitter | youtube | last.fm | myspace | del.icio.us | EverythingHerePlus ]
AsymmetricKeyMaker is an excellent example for several reasons. It is a command line program takes user input and returns a result. It utilizes the Java exception system and gives us an opportunity to deal with both abstract and concrete classes. Briefly, let's look at the Java source. Lines 1-3 import the packages used by the program. Line 5 declares the 'class' or program name. Line 7 processes the command line arguments. Line 8 is an example of archaic variable initialization. Line 9 is a conditional statement that passes the command line arguments to the core functionality. Line 11 begins the beginning of a try, catch construction that throws an error if the parameter passed is incorrect. Line 12 through 14 instantiates the key generator object with the requested key algorithm and then generates the key pair. Lines 16 and 17 print out the portions of the key pair. Lines 19 through 21 handle the exception created if the requested algorithm to
KeyPairGenerator is bad. Here is our version of the program in Scheme.
; -*-scheme-*- Copyright © Robert D. Skeels 02/07/2004 <firstname.lastname@example.org> (module-name <AsymmetricKeyMaker>) (define-namespace key-pair-generator "class:java.security.KeyPairGenerator") (define gen-keys (lambda (algorithm) (let* ((our-kpg (key-pair-generator:getInstance algorithm)) (our-key-pair (invoke our-kpg 'generateKeyPair)) (writeln (lambda (args) (display args) (newline)))) (writeln (invoke our-key-pair 'getPublic)) (writeln (invoke our-key-pair 'getPrivate))))) (define try-gen-keys (lambda (algorithm) (try-catch (gen-keys algorithm) (ex <java.security.NoSuchAlgorithmException> (begin (display "usage: java AsymmetricKeyMaker <RSA | DSA>") (newline)))))) (if (> (vector-length command-line-arguments) 0) (try-gen-keys (vector-ref command-line-arguments 0)))
Recreating this functionality in Kawa Scheme is reasonably simple. Although the
module-name declaration on line 3 is unnecessary here, it make it easier to reuse the code later by adding
module-export to call the routines from other code. The global variable `command-line-arguments' referred to in the Kawa Manual §6.4 is a vector. Rather than comparing its length like the Java code, we will use the first argument if it exists. When I was first evaluating the Java code I really didn't understand why they called
java.security.KeyPairGenerator.getInstance without sanity checking the command line input first. Then I read further and discovered the function is case insensitive and will handle any variation of RSA or DSA. The package allows for others to be added as well. An exception are is thrown if algorithm is unrecognized, so it is fine for us to pass the argument as is.
Lines 15 to 21 define
try-gen-keys, which is a simple function that deals with the exception handling and passes control on. Kawa's statement is a very elegant. We could have included the
gen-keys function in the body of the
try-catch statement, but it is more scheme like to call it separately. Further, we could later use
gen-keys to call it from other code, with a different handler for the exception that would be appropriate in a application that isn't be called from the command line. The exception we catch is
java.security.NoSuchAlgorithmException, which is
NoSuchAlgorithmException in the Java source since it was already imported in their source.
Lines 7 to 13 define
gen-keys. This function relies on the
define-namespace declaration on line 5. It is suggested to read §10 and specifically §10.4 of the Kawa manual to understand this more clearly. Unlike the somewhat clumsy and cryptic
keyPair assignments in the Java source, we handle creating the
KeyPair object instance and the invoking its functionality separately. We use
let* because it is important that the statements are handled sequentially, since we cannot access a
KeyPairGenerator object until we have an actual instance of it. On line 9 we bind
our-kpg to the result of the method call
getInstance for the abstract object
KeyPairGenerator with the arguments we've passed from the command line. Our alias to the call java.security.KeyPairGenerator.getInstance(algorithm) created during
our-kpg is now bound to an instance of a
Now that we have an instance or concrete KeyPairGenerator object we can use it. We bind
our-key-pair to the invocation of the
generateKeyPair method in our newly instantiated KeyPairGenerator object bound to
our-kpg. The resulting object bound to
our-key-pair is a KeyPair object. Since I already have a let binding, a quick definition of
writeln on line 11 saves us from two consecutive display, newline calls. Lines 12 and 13 print the public and private portions of the RSA or DSA key pair.
our-key-pair is bound to the
KeyPair object, the accessor functions (methods) access the actual data contained in the object fields. Lines 10 through 13 could have been written in the
define-namespace style as well, but for clarity and for pedagogical reasons we used both styles.
All that is left to do is compile the code and run the program. Please feel free to copy the above code into a AsymmetricKeyMaker.scm file, it is under an ISC/Berkeley license. Compile into a standalone application as per the Kawa Manual §6.4. Don't forget to include Kawa and the AsymmetricKeyMaker.class in your
CLASSPATH. When in the directory with AsymmetricKeyMaker.class I do
setenv CLASSPATH /Users/Shared/share/java/kawa.jar:`pwd`. Running the program is
java AsymmetricKeyMaker RSA or
java AsymmetricKeyMaker DSA.