Introduction
This article, above all else, demonstrates how you can piece together a useful application from the amazing amount of code that is available at The Code Project and on the Internet in general. Using completely public domain code, I put together a little XML Control Panel. The control panel manages XML file sets, allowing you to perform digital signing, compression, and encryption on the file set.
The project consists of two significant components--the UI front end (implemented in MyXaml
) and the API that you can include separately in your application for digital signing/verification, compression/decompression, and encryption/decryption services.
Note that you may also use this application for encryption and compression of non-XML files. Only the digital signing is XML specific.
Features
This control panel is a GUI wrapper around the following functionality:
- digital signing
- encryption
- compression
allowing you to selectively choose one or more of these options for your XML files. Non-XML files may take advantage of the encryption and compression functions.
- The control panel has command line capability so it can be used as part of a post-build process.
- A separate API is used for the encoding and decoding algorithms, allowing you to include the API in your own application separate from the UI.
Digital Signing
The digital signing and signature verification code is built entirely on the work presented by Heath Stewart. The application will sign each XML file with a randomly generated key. The key is written out to "keyfile.snk". This key is registered into a key container on your machine. The public key is extracted and placed in the file "publicKey.xml". Please read Heath's article regarding options on how to embed the public key into your application.
If all you're doing is signing the XML files, each of the input files will be written out with the extension changed to ".sgn", indicating that it has been signed.
This signing portion utilizes the "sn.exe" utility and uses the ShellAPI code from "arikp
".
Encryption
Encryption/Decryption is accomplished using the .NET cryptography providers as described in the MSDN Library article. Please note that the TripleDES algorithm accepts 16 or 24 byte keys only but requires an 8 byte initial vector (IV), while the Rijndael algorithm accepts a 16 or 24 byte key but requires a 16 byte IV.
If compression isn't used, each encrypted XML file (whether signed or not) is written out with the same base filename, having the extension changed to ".enc".
Encrypted files are always written out as binary rather than using base64
encoding, since this would defeat (or at least reduce) the advantage of compression.
Compression
Compression/decompression is provided by the SharpZipLib library. Only ZIP and TAR compression is supported, as these are the only two that allow multiple files to be combined into a single file.
If encryption is not used, the signed files are all placed into a single compressed file having the base filename of the configuration name and with the extension ".zip" or ".tar", depending on the selected compression.
If encryption is used, then the extension is ".enc". Compression is always done before encryption because it is assumed that the compression algorithm will be much more efficient working with the original XML files. This seems reasonable, given how tokenized an XML file is.
The User Interface
The user interface is implemented with MyXaml and is a good illustration of using styles, flow panels, runtime property containers and data binding. The original article on flow panels was written by Matt Dockins and I've made some significant changes to it (see my comments in his article), including implementing a grid panel.
Usage
To create a new configuration that will manage your XML files:
- load XML files into the configuration tree view
- select the desired operations to perform on the collection of XML files
- save this configuration
- encode it!
To use an existing configuration, simply open the configuration.
Internally, the application preserves the original path of the XML files in the configuration, however, the encoded file(s) are written out to the current working directory.
Command Line Mode
You can pass the configuration file (for example, "test.xmlcp") to the application, and it generates the encoded file(s) in the working directory. If "Always Create A New Key" is unchecked, make sure that the public key file is also in the working directory.
Key Sizes
(I think I have this right):
Algorithm | Key Size | IV Size |
DES | 8 | 8 |
RC2 | >4 | 8 |
Rijndael | 16 or 24 | 16 |
TripleDES | 16 or 24 | 8 |
The Test Application
A simple test application is provided that verifies the basic functionality of the application and illustrates using the XCPAPI
for extracting two XML files from an encrypted and ZIP compressed file, then verifying its signature. Extracting the same files from a non-encrypted TAR compressed file is also demonstrated.
using System;
using System.IO;
using System.Text;
using XCPAPI;
namespace Test
{
class TestApp
{
[STAThread]
static void Main(string[] args)
{
FileStream fs=new FileStream("test.enc", FileMode.Open, FileAccess.Read);
BinaryReader r=new BinaryReader(fs);
byte[] data=r.ReadBytes((int)fs.Length);
r.Close();
fs.Close();
Decryptor dec=new Decryptor(EncryptionAlgorithm.Des);
dec.IV=Encoding.ASCII.GetBytes("init vec");
data=dec.Decrypt(data, Encoding.ASCII.GetBytes("password"));
Decompression decomp=new Decompression(CompressionAlgorithm.Zip, data);
string fn1;
byte[] data1=decomp.GetFile(out fn1, data);
string text1=Encoding.ASCII.GetString(data1);
string fn2;
byte[] data2=decomp.GetFile(out fn2, data);
string text2=Encoding.ASCII.GetString(data2);
string xmlKey="[...omitted...]";
Signer signer=new Signer();
signer.XmlKey=xmlKey;
bool ret=signer.VerifySignature(text1);
Console.WriteLine("Signature verification for "+fn1+": "+ret.ToString());
ret=signer.VerifySignature(text2);
Console.WriteLine("Signature verification for "+fn2+": "+ret.ToString());
StreamWriter sw=new StreamWriter(fn1);
sw.Write(text1);
sw.Flush();
sw.Close();
sw=new StreamWriter(fn2);
sw.Write(text2);
sw.Flush();
sw.Close();
fs=new FileStream("test.tar", FileMode.Open, FileAccess.Read);
r=new BinaryReader(fs);
data=r.ReadBytes((int)fs.Length);
r.Close();
fs.Close();
decomp=new Decompression(CompressionAlgorithm.TAR, data);
data1=decomp.GetFile(out fn1, data);
text1=Encoding.ASCII.GetString(data1);
data2=decomp.GetFile(out fn2, data);
text2=Encoding.ASCII.GetString(data2);
ret=signer.VerifySignature(text1);
Console.WriteLine("Signature verification for "+fn1+": "+ret.ToString());
ret=signer.VerifySignature(text2);
Console.WriteLine("Signature verification for "+fn2+": "+ret.ToString());
}
}
}
Things Of Note
The user interface is implemented with MyXaml
as well as a runtime container that manages the property settings. If you inspect the xcp.myxaml file, you'll see some interesting things:
DockPadding
defined for the application form - A simple style applied to buttons, groupboxes, radiobuttons, and checkboxes
- A declarative approach to initializing
OpenFileDialog
and SaveFileDialog
- Resource binding of icons to menu item bitmaps
- Flow panels used in various configurations which avoids specifying absolute coordinates for controls
- Data binding--note how databinding is used not just for the container properties but also the
Enabled
property of some controls are bound to the CheckBox
Checked
property. This mechanism provides a code free way of manipulating the visual state of the controls that correspond to the check state.
Limits
- The compression algorithm expects that filenames will be unique and does not preserve any directory hierarchy.
- Only alphanumeric keys are supported and must be specified in the edit box.
- Both key and initial vector (IV) must be provided. Random generation is not supported.
Licensing
This UI application and the XCPAPI
are licensed under the BSD License. MyXaml
is licensed under the GNU GPL.
References