Ever wonder what all the fighting is about?
On the one hand, we have Java, with its basis in object-oriented theory, automatic memory management, dependency on a runtime, and a robust library. And on the other, we have Microsoft.NET, with its basis in object-oriented theory, automatic memory management, dependency on a runtime, and a robust library.
You'd think with all these two kids have in common, they would get along better. No such luck.
Up until now, getting Java to talk to Microsoft.NET has been only slightly more fun than being on the receiving end of a root canal. One book I picked up recently was all about interoperability using Web Services. Web Services! Not that there is anything wrong with Web Services in general, but I why do I need a web server, WSDL, and the overhead of two-way XML serialization if I just want a list of the processes on my local system (something Java cannot do)?
Maybe you've tried something like passing data to a spawned process using standard-input and standard-output. It's limited, but it works. You still need something like SOAP or XStream if you want to work with objects, and at least you don't have the overhead of a full blown web server. But it's still not simple. Or maybe you've tried using sockets. Same thing, but without incurring the overhead of starting and stopping a process every time you need to do something that is windows-ey. Still, that's not simple.
You are probably thinking, "There must be a better way." And that would make sense, because you took the time to read the title of this article, correct? I am here to tell you - there is a better way. In fact, I am here to tell you, it's easy.
Microsoft's Component Object Model (COM)
Microsoft spent decades developing this technology called COM. It stands for Component Object Model. "Wait a second," you say. "I think I remember reading about that somewhere. Isn't COM dead? Doesn't .NET make it obsolete?" You might think so, but look how long .NET has been around, and Microsoft Office is still compiled from plain old ANSI C++. Consider also that the .NET libraries for Microsoft Office are thin wrappers around the COM libraries that Office exposes. COM is embedded deeply in Windows, it is mature, stable, and it's not going anywhere.
Microsoft.NET has excellent support for COM interoperability. You can create and consume managed COM libraries using VB.NET, C#, or C++/CLI. It's almost trivial to do so in VB.NET, for example. You just set a few properties, build the project, and you've got a COM-callable DLL.
So if COM is there, it's mature, it's stable over decades, and it works for what you are doing, why not just use it?
Groovy and Scriptom
Groovy, for those who aren't already familiar with it, is a very cool dynamic language that is designed specifically to run on the Java JVM. The syntax is based on Java, and everything gets compiled to Java bytecode. Java programmers have an easy learning curve, and Groovy can be integrated seamlessly (and quickly) into existing Java projects. Groovy is a lot more expressive than Java, so you can typically get things done in about half the lines of code. And once you get used to it, Groovy is easier to read than Java.
Scriptom is an optional module for Groovy that lets you use COM objects without having to know anything (or at least very little) about the inner workings of COM. Scriptom takes advantage of Groovy's dynamic (late-bound) nature to map COM objects into Groovy objects at run-time. There are no type-libraries to deal with and no wrappers to maintain. Just code it and run it. It really is a lot like writing code using VBScript (except that Groovy is far more advanced as a language). It is almost eerie at times to see Java comingled with what appears to be something straight out of WSH (Windows Script Host). Thus, the name - "Script-om." It's very script-like.
Let's Do Something! FIPS 140-1 on Java
It's high time for an example. It is said that the best way to learn is by doing, so let's put together a small application. And what's more, let's make it practical.
I was working on a project recently that needed a FIPS 140-1 compliant cryptographic hash/digest algorithm. I needed to protect user passwords, and my client has some pretty strict rules about which cryptographic algorithms may and may not be used. Java implements several hash/digest algorithms, but none of them are compliant with FIPS 140-1. What this means is that I had to look outside of Java for a solution.
After Googling for several hours, I realized that it is pretty hard to find anything that is certified as FIPS 140-1 compliant. There are some big libraries, mostly written in C++ with Java JNI wrappers. One or two are open source, but most cost money (and they don't list a price - you know what that means). All of them were far to complex for my needs. I don't want to have to maintain yet-another-set-of-libraries for just one measley function point.
So, cutting to the chase, it turns out that a number of the algorithms available in the MS-CAPI (Microsoft Crypto API) are certified FIPS 140-1 compliant! That's right, what I needed was built right in to the base installation of Windows. All I needed to do was figure out how to get from the Windows SDK API level into Java. After a little more research, I discovered that Microsoft has wrapped parts of the MS-CAPI into the .NET Framework. One of these wraps the FIPS 140-1 compliant implementation of SHA-1. Perfect!
So all I had to do was:
- create a .NET DLL with COM-accessible objects, and
- access it using Groovy and Scriptom.
Piece of cake!
What I am showing you here isn't sufficient for securely hashing a password. You'd need to add a unique seed value, such as the user's name or ID number, to prevent simple birthday attacks. There are some other things you would need to do to strengthen the password to prevent easy brute-force attacks. Consult your local security guru before using any cryptography. If you don't understand what you are doing, you are probably doing it wrong (and fooling yourself about how secure you are in the process). Poorly implemented cryptography is often as bad, or worse, than none at all.
Create a COM-Accessible VB.NET Library
First things first. Let's create the DLL. We'll be wrapping Microsoft's SHA1CryptoServiceProvider (pretty trivial to code), and we'll also be walking through all the steps to make the DLL COM-accessible. I'm using Visual Basic in this example, but with a little translation this should work with any of the mainstream .NET languages.
Step 1. Create a New Project
Open Visual Studio and create a new VB class library project called MyFips140Crypto.
Step 2. Add the Code
Rename Class1 to SHA and add the following code:
Step 3. Enable COM
To enable COM support, open the project properties and click the Assembly Info button. Fill in the dialog any way you want, but make sure that Make assembly COM-Visible is checked.
Step 4. Give It a Strong Name
What is a "strong name," you ask? Well, it is some sort of Microsoft security cryptographic digital signature thingy. Why do you care? In most cases, you won't. The important thing to remember is that you won't be able to successfully register the library later without this.
Lucky for us, Microsoft has made this step relatively easy. From the project properties page, you can have Visual Studio create a new strong name key file for you. You can optionally protect the key file with a password.
Once the strong name key file is associated with your project, you generally don't have to worry about it again.
Step 5. Build It
Build the project.
Step 6. Register It
Open Visual Studio 2005 Command Prompt. It is one of the tools that comes standard with Visual Studio. Navigate to the folder where your compiled DLL is going to reside, and type in the following command:
The /codebase parameter must be specified. If you forget, the assembly will appear to be registered correctly, but you will get a "Could not co-create object" exception when you try to run this from Groovy.
If you have been lucky enough to get everything right so far, you'll get a confirmation message telling you that the assembly was registered successfully. Congratulations!
If you are using Visual Studio Express, you may not have a Visual Studio 2005 Command Prompt. The regasm.exe utility is available on your machine, and you can access it by searching for the file and adjusting your path environment variable, or by installing the full Microsoft.NET SDK.
If you add new COM-visible classes to your library, you will have to re-register the DLL in order for Groovy to be able to see them.
The regasm.exe utility requires Administrator privileges to execute. This can affect installations, and is particularly relevant on Windows Vista, since the command prompt must be started with the correct privileges.
Okay, that was tough (not really). There are a couple of not-so-obvious steps involved in creating even a simple COM-enabled .NET library. Fortunately, once you know all the steps, you just follow the same recipe. Once you have set up a .NET project this way, it is easy to add additional methods and classes.
You might expect that for the Groovy portion of this project, there is a similar type of overhead incurred. You'd be wrong though. With Groovy, it is more like scripting. I wasn't lying earlier when I said this was easy. Here is all the code you need to compute a FIPS 140-1 compliant SHA-1 hash of an arbitrary string:
There you have it. A FIPS 140-1 approved SHA-1 implementation in about 20 lines of code. That was easy.
COM objects always run in an "apartment." Different "apartments" correspond to different threading models, and the COM threading models don't quite correspond to Java's threading model. To help you with initialization and teardown of COM apartments within Java, Scriptom provides the .inApartment method. It is considered best practice to wrap any COM objects in an .inApartment closure. Threading in Scriptom can also be managed by calling the methods on the com.jacob.com.ComThread object.
Integrating with Java
This part is for you if you are new to Groovy. If you have been using Groovy for a while, you're done. Go forth and codify already.
At first glance, it might not be obvious how easy it is to integrate this into your existing Java project. It's easy. It's really, really easy. Groovy objects are compiled to Java byte-code. In other words, Groovy objects are Java objects. So for the most part, Java can call methods on Groovy objects just like calling methods on another Java object. That's what they mean when they say: "Groovy is Java!"
So let's wrap our script into a Groovy object so that it can be easily called from Java. Create a file called Fips140Sha1.groovy in /org/yourcompany/yourproject:
Look familiar? It's kind of hard to tell the difference between Groovy syntax and Java syntax sometimes, isn't it? Compile your project with Groovyc (either the command-line executable or the ANT task) and you are done.
We've only just scratched the surface of what it is possible to do with Scriptom and .NET, not to mention all the things you can do with the hundreds of existing COM libraries that are available in Windows. No one is suggesting that you give up WORA, but for those MeSsy jobs that Java just can't do, this is one approach that is quick, painless, and pretty easy to maintain over time. If you like what you see, or if you want to provide some constructive criticism, drop by the Groovy users mailing list and let us know what you think.
Jason Smith is currently a member of the Scriptom development team.