|
|
|
Contents: |
|
|
|
Related content: |
|
|
|
Subscriptions: |
|
|
| How to digitally sign and verify XML documents on wireless
devices using the Bouncy Castle Crypto APIs
Michael
Juntao Yuan (mailto:juntao@mail.utexas.edu?cc=&subject=Securing
your J2ME/MIDP apps) Research Associate, Center for Research in
Electronic Commerce, University of Texas at Austin 18 June 2002
XML digital signature technology can help you implement
lightweight and flexible security solutions for wireless Web services
applications. In this article, Michael Yuan discusses the importance of
XML digital signatures and their application. He also walks through the
digital signature APIs of the Bouncy Castle cryptography package,
providing examples in the context of secure XML messaging between a
J2ME/MIDP wireless front end and a JSP page back end.
Java technology in wireless Web
services Java-based Web services and wireless Java
development were the two most prominent topics at JavaOne 2002. They
represent the future back- and front-end Java technologies in a world of
pervasive computing.
Web services are loosely coupled, interoperable software components
based on standard XML communication protocols. The use of Web services
enables a vendor to offer services in a specific market where its core
competency lies. Customers can then choose to purchase services from
multiple vendors, according to their various needs. This convenience means
that Web services are perfectly suited to serve wireless front ends. The
convenience and dynamic nature of wireless information devices allow
mobile users to take advantage of modularized and dynamically
re-configurable back-end services.
The Java platform can play several important roles in wireless Web
services application development. On the wireless end, Java 2 Micro
Edition (J2ME) offers cross-device compatibility, advanced language
features, and extensive libraries to all wireless devices from cell phones
to complex home wireless information appliances. A key component of J2ME
is the Mobile Information Device Profile (MIDP), which defines Java APIs
and runtime environments on cell phones and low-end PDAs. Due to the large
number of low-end devices, MIDP is expected to become widely deployed in
the future.
From the Web services end, Java 2 Enterprise Edition (J2EE) already has
all the necessary APIs and libraries to handle Web services XML messages.
Core J2EE functions implemented in EJB technology, the JDBC API, and the
RMI API can easily be made available to the outside world through Web
services interfaces or gateways. To bring these features together and
enable wireless Web services applications, the J2ME Web services
specification has also been proposed and is currently in the Java
Community Process (JSR 172).
Security in wireless Web
services Although Java-based wireless Web services have a
bright future in the world of pervasive mobile commerce, the current
technology is not yet mature. Security is among the remaining issues yet
to be resolved. Wireless communications are easy targets for air wave
interception, and wireless devices rarely have the computing power to
support strong encryption of all communication data. Moreover, on the back
end, Web services run outside corporate firewalls and interact with each
other using open messaging protocols. Wireless Web services are likewise
vulnerable targets for various cracking attacks. Well developed
point-to-point security technologies such as SSL/TLS and HTTPS are not
suitable for the multiple vendor, multiple intermediary Web services
network topography -- the focus needs to be on securing the contents
themselves rather than the connections over which they travel. Despite the
new challenges, Web services themselves, however, can be used to enhance
mobile commerce security. Emerging Web services security specifications
enable you to use Web services as security utilities.
In the paragraphs below, I'll discuss a commonly used security
technique: digital signature. I will show you how digital signatures are
used in XML messages to guarantee end-to-end data integrity. I'll cover
some examples that illustrate how to implement XML digital signatures
using the popular J2ME/MIDP platform on the wireless end and JavaServer
Pages (JSP) technology on the back end. Finally, I will discuss
performance issues and the feasibility of using digital signatures on
current MIDP devices. MIDP programming details are beyond the scope of
this article; if you need a refresher, please see the Resources
section.
The elements of secure
communication
Data integrity is just one aspect of
securing communication. Digital signatures can provide solutions to
other aspects as well. Generally, secure network communications must
meet the following criteria:
- Authentication: Parties have to identify themselves.
The digital signature on a public key certificate can validate the
authenticity of the public key and therefore the party who holds
it.
- Data integrity: The parties must make sure that the
contents are not altered during transmission. Digital signature is
the most commonly used technology to guarantee data integrity.
- Data confidentiality: Sometimes, the communication data
is sensitive and has to be kept secret. Digital signature does not
provide data confidentiality. We have to use data encryption.
- Non-repudiation: After a message is sent, the sender
should not be able deny it later. Digital signature provides a
partial solution. If the message is digitally signed, the sender
cannot deny its responsibility because only he can provide such
signature.
|
Guarantee data integrity using digital
signatures Let's suppose that you are a stock trader and
that you use a cell phone to track stock price changes when you are not on
the trading floor. In the middle of your commute to work, your phone
alerts you that the price of a stock you have been monitoring has dropped
below a threshold. Now, should you buy it based on this tip and take
advantage of the low price? Before you take any action, you want to be
absolutely sure that the tip itself is authentic. If a competitor could
intercept and change the message (for example, change the stock symbol),
he could lure you into buying the wrong stock and dump his high-priced
equity to you. How do you know that your message has not been tampered
with en route from your monitoring service to your phone?
Indeed, data integrity is one of the most important aspects of
communication security. Physically secure networks are very expensive and
do not cover a wide geographic area. If your business has to rely on the
Internet to communicate, you have to face the fact that the Internet
offers little security by itself. Internet data packets have to travel
through multiple routers and hosts that are controlled by neither party in
the conversation before they reach their destinations. Data communications
are especially vulnerable over the wireless Internet.
The tools that come to our rescue are the Public Key Infrastructure
(PKI) and digital signature. (As with MIDP programming, digital signature
is beyond the scope of this article; interested readers can refer to the
Resources
section for more information.) In a nutshell, in a PKI digital signature
scheme, each party has two cryptography keys: the public key is available
to anyone and the private key is kept secret to oneself. A message
encrypted by the private key can only be correctly decrypted by the
corresponding public key. When a sender sends out a message, he can
accompany the message with a private key encrypted version of the same
message, as well as his public key. The recipient decrypts the encrypted
version using the sender's public key. If it matches the clear text
message, the recipient can know for sure that the message is authentic.
The private key encrypted version of the message serves as an integrity
verification token and it is called a "digital signature."
Because the original message might be quite long, and public key
algorithms to generate and verify digital signatures are resource
intensive, the sender normally calculates a short version of the original
message called the "digest" and digitally signs only this version. The
digest is a fixed-length, one-way hash of an any-length input message; its
calculation is very fast. The recipient first verifies that the message
received produces the correct digest. If the digest does not match, the
message is rejected before any public key algorithm is performed. That
could help prevent a clogging attack, in which the attacker overwhelms a
server's computational resources by flooding it with fake public key
requests.
In most practical applications, public keys themselves are digitally
signed by trusted authorities, becoming "digital certificates" to validate
the sender's identification. Digital certificate handling is beyond the
scope of this article, however, so in the following examples, I will
assume that the senders are trusted and use unsigned public keys to
illustrate the approaches.
XML digital signatures
defined As I mentioned earlier, XML is becoming a major data
exchange protocol in the world of Web services. XML messages that drive
Web services often need to go through multiple intermediaries before they
reach destinations. So, it is important that we secure the communication
content from end to end. The best way to do it is to ship an XML document
and its security information (such as signatures, digests, keys, and so
on.) altogether as a single document.
The XML digital signature is a W3C specification to add a digital
signature to an XML document. The sender can choose to digitally sign the
entire document or only part of it. Digital signatures, digests, and
public keys are formatted into XML elements. Those extra elements of
security information can envelop the entire original XML message, or
alternatively they can be embedded into the original message. In this
article, I will use the enveloping format for convenience.
For the sake of clarity, the XML digital signature examples I use in
this article are not completely W3C compliant. For example, I have left
out the canonicalization (standardization of XML tags) part because it
only ensures the conformity of XML documents and has nothing to do with
security itself. Also, instead of using encoded public keys certificates,
I break a key into several parameters and pass those parameters in
separate XML elements under the public key element KeyInfo .
That establishes more obvious connections between keys and the Java code
that handles them.
Handling the XML digital signature in
MIDP applications IBM alphaWorks develops a Java package
called XML Security Suite, which supports the latest XML digital signature
specification. JSR 105 is a community effort to standardize a set of Java
APIs to process XML digital signatures. However, they only work for Java 2
Standard Edition (J2SE), which means that you can use XML Security Suite
or JSR 105 Java XML digital signature APIs on the server side, but not on
the MIDP wireless device side.
To handle XML digital signatures, the wireless devices being used need
to support the following functions:
- Read and write data from/to an XML document. In our example
MIDP applications, XML documents and elements are parsed into Java
objects by the kXML parser (see Resources).
In addition to kXML, there are several other MIDP XML parsers available
under different license terms.
- Sign the message and verify the signature. These functions
require a cryptography API that is not part of the current MIDP 1.0
specification.
In the next section, I will discuss a lightweight Java cryptography
package that you can use on both the server side and wireless MIDP device
side to generate and verify XML digital signatures.
Digital signatures in secure mobile
code
Digital signatures not only help to secure
application data communications, they also help to secure
applications themselves. Wireless devices often need to download
applications over the air to dynamically adjust themselves to new
environments and tasks. It is possible that hostile parties can
intercept the mobile code distribution and insert virus and other
harmful Trojan code segments to the downloaded application. How do
we make sure that the mobile code is authentic? The mobile code
provider can digitally sign the whole JAR archive with his digital
certificate. The wireless user can determine a security domain for
that application based on the trust level of the provider.
|
The Bouncy Castle Crypto
APIs Bouncy Castle is an open source, lightweight
cryptography package for the Java platform. It supports a large number of
cryptography algorithms and provides an implementation for JCE 1.2.1.
Because Bouncy Castle is designed to be lightweight, it can run from J2SE
1.4 to J2ME (including MIDP) platforms. It is the only complete
cryptography package that runs on MIDP.
However powerful, there is one major problem with the Bouncy Castle
package: the lack of documentation. Online documentation is non-existent
and its JavaDoc is not very well written. Similar to many other advanced
cryptography packages, the Bouncy Castle package uses type polymorphism
extensively to separate general concepts from implementing algorithms.
It's hard for beginners to decipher the relationships between classes and
the correct types for methods arguments and return values. Often, the
developer has to peek into the source code and test cases to investigate
correct ways to do things. Clearly, a guide for the Bouncy Castle package
is very much in order.
In the rest of this article, we will walk through the XML digital
signature specification and the usage of several different Bouncy Castle
key generators, encoding engines, digital signature singers, and a digest
engine.
Putting it all
together We've discussed a number of technologies and
concepts so far. Below, I've illustrated the complete process: key
generation, signing documents on the server side, encoding and
transporting documents in secure XML format, and verifying documents on
the client side.
- The server generates a pair consisting of a random public key and a
private key using a set of key model parameters. In real production
system, this step is usually not necessary because the key pairs are
usually pre-generated and stored in server key stores.
- When a JSP page is accessed, the server calculates a digest for the
response message.
- The JSP page then invokes the signer in the "sign" mode and
generates a digital signature for the digest using the private
key.
- The server embeds the signature information including the digest,
digital signature itself, and public key parameters in the XML response
message.
- The client receives the XML document and parses the digest, digital
signature, and public key parameters into Java application data.
- The client calculates a digest from the clear text message and
compares it with the digest from the server. If the two digests do not
match, the document verification fails; if they do match, go to the next
step.
- The client reconstructs the public key using the embedded key
parameters.
- The client invokes the signer in "verify" mode and passes the
digest, the signature, and the public key to verify the signature.
We'll follow these steps to implement several examples in the next
several sections. Because our examples use the same Bouncy Castle Crypto
APIs on both server side and client side, it is very easy to change them
to sign a message on the wireless device and verify it on the server
side.
Handling the digest As I
mentioned earlier, to improve performance and avoid clogging attacks, you
actually sign the message digest rather than the message itself. Listing 1
illustrates how to compute an encoded digest from a piece of text message
using the SHA1Digest digest engine.
static public String getDigest( String mesg ) throws Exception {
SHA1Digest digEng = new SHA1Digest();
byte [] mesgBytes = mesg.getBytes();
digEng.update( mesgBytes, 0, mesgBytes.length );
byte [] digest = new byte[digEng.getDigestSize()];
digEng.doFinal(digest, 0);
// Encode the digest into ASCII format for XML
return (new String(Base64.encode(digest)));
}
|
In the next several sections, we'll see how to sign and verify digital
signatures using Bouncy Castle's DSA, ECC, and RSA signers. Those signers
use different algorithms and different keys, and need different
parameters. We'll also discuss how to embed security information
(signatures, digests, and public keys) in XML documents. At the end, I'll
compare the three signers and suggest future improvements.
DSA signature example The
method DSASigUtil.generateKeys() generates key pairs. As I
have discussed, this step is normally done offline by a central
certificate authority, as shown in Listing 2:
// Get a secure random source.
SecureRandom sr = new SecureRandom();
// Generate DSA parameters.
DSAParametersGenerator DSAParaGen = new DSAParametersGenerator();
DSAParaGen.init(1024, 80, sr);
DSAPara = DSAParaGen.generateParameters();
// Get DSA key generation parameters.
DSAKeyGenerationParameters DSAKeyGenPara =
new DSAKeyGenerationParameters(sr, DSAPara);
// Generate keys.
DSAKeyPairGenerator DSAKeyPairGen = new DSAKeyPairGenerator();
DSAKeyPairGen.init( DSAKeyGenPara );
AsymmetricCipherKeyPair keyPair = DSAKeyPairGen.generateKeyPair();
privKey = (DSAPrivateKeyParameters) keyPair.getPrivate();
pubKey = (DSAPublicKeyParameters) keyPair.getPublic();
|
The generated public key is characterized by a parameter
Y , and it is retrieved by the pubKey.getY()
method. Parameters G , P , and Q
describe the model. The following methods in class DSAUtil
retrieve the model and key parameters, which are necessary to reconstruct
the public key object:
public static String getG() throws Exception {
return (new String(Base64.encode(DSAPara.getG().toByteArray())));
}
public static String getP() throws Exception {
return (new String(Base64.encode(DSAPara.getP().toByteArray())));
}
public static String getQ() throws Exception {
return (new String(Base64.encode(DSAPara.getQ().toByteArray())));
}
public static String getY() throws Exception {
return (new String(Base64.encode(pubKey.getY().toByteArray())));
}
|
Using the generated private key, the utility class
DSASigUtil can get a two-part DSA signature, R
and S , from a digest:
static public String [] getSignature (String digest) throws Exception {
// Sign
DSASigner signer = new DSASigner();
signer.init( true, privKey );
BigInteger [] sigArray = signer.generateSignature( digest.getBytes());
String [] result = new String [2];
// Signature R
result[0] = new String(Base64.encode(sigArray[0].toByteArray()));
// Signature S
result[1] = new String(Base64.encode(sigArray[1].toByteArray()));
return result;
}
|
The server encodes the digest, signature, and key parameters into ASCII
text form and embeds the text in the XML digital signature format, as
shown in Listing 5:
<SignedMesg>
<mesg>Hello World</mesg>
<Signature>
<SignedInfo>
<SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1" />
<DigestValue>Ck1VqNd45QIvq3AZd8XYQLvEhtA=</DigestValue>
</SignedInfo>
<SignatureValue>
<R>AMfVKyIUyPGdeUCtJxU+N9kQJc2x</R>
<S>RwGahqpopPx//bMYXzH8dtY0lhA=</S>
</SignatureValue>
<KeyInfo>
<KeyValue>
<DSAKeyValue>
<G>
FgLTXVdxKAmDQtQHkDdFF5zthKSpQhUCzRgXxz7yzxM
OLYrRoj5D8AXdGLS+5CzT4gu55MbO62dBfyEWKbWTIO
6E+CuOfa53wvqjMl67tGxc8szgWWA6ZvRwVVVmJ6wqB
m5hNLr7q1X2eJKQ+u3XYpFflJktOjV8O3zeEPOtsTQ=
</G>
<P>
AOAu2WqVEKGTF8Zcxgde4vxc8f/Z+hk8A10M0AtY2lU
8CX54dz2MuD6hOmhqGXJxIVlV9085d9D0yHcMv2wl9V
Vt0/ww+aqFukCKZj9fHgZzq26nOBXMqibDo67J2vfQw
EZMvCnyBXdS665whjzl5i7ubXu2Su+AqsodnvG9pyYB
</P>
<Q>AMjJUZy1RnQRqe/22BS83k2Hk8VR</Q>
<Y>
AM/9leouAW7nyON24xeqibMUpVOW8RyzcdNjp9NiPdfm
HT42BvB4JL/cXx0tCbyHtcR5G+vALoOo7Mh3JJ+/gjx7
sS8uHNngqx6O6dADrc9VdPvyllNDR0szLja1RTRCIy9M
8p0dKe/U8iotAj2zctjfbrroMu/fTOBhkvb2gVvR
</Y>
</DSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</SignedMesg>
|
The verification MIDP application parses the digest, key parameters,
and signature out of the XML document, reconstructs the public key, and
uses the following method to validate the signature:
static public boolean verify (String digest,
String sig_r, String sig_s,
String key_g, String key_p,
String key_q, String key_y ) {
BigInteger g = new BigInteger( Base64.decode(key_g) );
BigInteger p = new BigInteger( Base64.decode(key_p) );
BigInteger q = new BigInteger( Base64.decode(key_q) );
BigInteger y = new BigInteger( Base64.decode(key_y) );
BigInteger r = new BigInteger( Base64.decode(sig_r) );
BigInteger s = new BigInteger( Base64.decode(sig_s) );
DSAParameters DSAPara = new DSAParameters(p, q, g);
DSAPublicKeyParameters DSAPubKeyPara = new DSAPublicKeyParameters(y,
DSAPara);
// Verify
DSASigner signer = new DSASigner();
signer.init( false, DSAPubKeyPara );
boolean result = signer.verifySignature( digest.getBytes(), r, s );
return result;
}
|
An elliptical curve DSA signature
example In the ECDSASigUtil class, you first
define the elliptical curve model you plan to use, as shown in Listing 7:
private static BigInteger q = new
BigInteger("6277101735386680763835789423207666416083908700390324961279");
private static BigInteger a = new
BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16);
private static BigInteger b = new
BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16);
private static BigInteger n = new
BigInteger("6277101735386680763835789423176059013767194773182842284081");
private static byte [] G =
Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012");
|
The ECDSASigUtil.generateKeys() method generates random
key pairs using the model in Listing 7. As mentioned earlier, this step is
normally done offline by a central certificate authority.
// Get a secure random source.
SecureRandom sr = new SecureRandom();
ECCurve.Fp curve = new ECCurve.Fp(q, a, b);
ECDomainParameters ECDomPara = new ECDomainParameters(curve,
curve.decodePoint(G),
n );
ECKeyGenerationParameters ECKeyGenPara =
new ECKeyGenerationParameters(ECDomPara, sr);
ECKeyPairGenerator ECKeyPairGen = new ECKeyPairGenerator();
ECKeyPairGen.init( ECKeyGenPara );
AsymmetricCipherKeyPair keyPair = ECKeyPairGen.generateKeyPair();
privKey = (ECPrivateKeyParameters) keyPair.getPrivate();
pubKey = (ECPublicKeyParameters) keyPair.getPublic();
|
The public key is characterized by a parameter Q , and it
is retrieved by the pubKey.getQ() method. To avoid confusion
with the model parameter q , you use QQ in the
method and XML element names for capital Q . Listing 9 show
the methods in the ECDSAUtil class. These methods retrieve
the model and key parameters, which are necessary to reconstruct the
public key object.
// public key specific field
public static String getQQ() throws Exception {
return (new String(Base64.encode(pubKey.getQ().getEncoded())));
}
// Key parameter fields. Could also be retrieved from pubKey.
public static String getQ() throws Exception {
return (new String(Base64.encode(q.toByteArray())));
}
public static String getA() throws Exception {
return (new String(Base64.encode(a.toByteArray())));
}
public static String getB() throws Exception {
return (new String(Base64.encode(b.toByteArray())));
}
public static String getN() throws Exception {
return (new String(Base64.encode(n.toByteArray())));
}
public static String getG() throws Exception {
return (new String(Base64.encode(G)));
}
|
Using the generated private key, the utility class
ECDSASigUtil can get a two-part DSA signature, R
and S , from a digest:
static public String [] getSignature (String digest) throws Exception {
// Sign
ECDSASigner signer = new ECDSASigner();
signer.init( true, privKey );
BigInteger [] sigArray = signer.generateSignature( digest.getBytes());
String [] result = new String [2];
// Signature R
result[0] = new String(Base64.encode(sigArray[0].toByteArray()));
// Signature S
result[1] = new String(Base64.encode(sigArray[1].toByteArray()));
return result;
}
|
The server encodes the digest, signature, and key parameters into ASCII
text form and embeds the text in XML digital signature format. As in the
retrieval method name, the public key parameter Q is noted as
QQ to differentiate it from the key parameter q ,
in the corresponding XML element, as shown in Listing 11:
<SignedMesg>
<mesg>Hello World</mesg>
<Signature>
<SignedInfo>
<SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1" />
<DigestValue>Ck1VqNd45QIvq3AZd8XYQLvEhtA=</DigestValue>
</SignedInfo>
<SignatureValue>
<R>NK/EIL2lrbFFCThnEuYlUWzh6IEfMsts</R>
<S>AMeJDecKWrQO6Eeehl3het+FlDDL4IedCA==</S>
</SignatureValue>
<KeyInfo>
<KeyValue>
<ECKeyValue>
<QQ>AwCiF5uG+DII/x1XTq84fLm4eGN2fED1PYc=</QQ>
<Q>AP////////////////////7//////////w==</Q>
<A>AP////////////////////7//////////A==</A>
<B>ZCEFGeWcgOcPp+mrciQwSf643uzBRrmx</B>
<N>AP///////////////5ne+DYUa8mxtNIoMQ==</N>
<G>AxiNqA6wMJD2fL8g60OhiAD0/wr9gv8QEg==</G>
</ECKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</SignedMesg>
|
The verification MIDP application parses the digest, key parameters,
and signature out of the XML document, reconstructs the public key, and
uses the method shown in Listing 12 to validate the signature:
static public boolean verify (String digest,
String sig_r, String sig_s,
String key_q, String key_a,
String key_b, String key_n,
String key_G, String key_Q ) {
BigInteger q = new BigInteger( Base64.decode(key_q) );
BigInteger a = new BigInteger( Base64.decode(key_a) );
BigInteger b = new BigInteger( Base64.decode(key_b) );
BigInteger n = new BigInteger( Base64.decode(key_n) );
byte [] G = Base64.decode(key_G);
byte [] Q = Base64.decode(key_Q);
BigInteger r = new BigInteger( Base64.decode(sig_r) );
BigInteger s = new BigInteger( Base64.decode(sig_s) );
ECCurve.Fp curve = new ECCurve.Fp(q, a, b);
ECDomainParameters ECDomPara = new ECDomainParameters(
curve, curve.decodePoint(G), n );
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
curve.decodePoint(Q), ECDomPara );
// Verify
ECDSASigner signer = new ECDSASigner();
signer.init( false, pubKey );
boolean result = signer.verifySignature( digest.getBytes(), r, s );
return result;
}
|
An RSA signature
example The RSA algorithm only has one model parameter,
Exponent :
private static BigInteger pubExp = new BigInteger("11", 16);
|
The RSASigUtil.generateKeys() method generates random key
pairs using Exponent . Again, this step is normally done
offline by a central certificate authority.
SecureRandom sr = new SecureRandom();
RSAKeyGenerationParameters RSAKeyGenPara =
new RSAKeyGenerationParameters(pubExp, sr, 1024, 80);
RSAKeyPairGenerator RSAKeyPairGen = new RSAKeyPairGenerator();
RSAKeyPairGen.init(RSAKeyGenPara);
AsymmetricCipherKeyPair keyPair = RSAKeyPairGen.generateKeyPair();
privKey = (RSAPrivateCrtKeyParameters) keyPair.getPrivate();
pubKey = (RSAKeyParameters) keyPair.getPublic();
|
The public key is characterized by a parameter, Modulus ,
and it is retrieved by the pubKey.getModulus() method.
Listing 14 shows the methods in the RSAUtil class. These
methods retrieve Exponent and Modulus , the model
and key parameters, which are necessary to reconstruct the public key
object.
// Public key specific parameter.
public static String getMod() throws Exception {
return (new String(Base64.encode(pubKey.getModulus().toByteArray())));
}
// General key parameter. pubExp is the same as pubKey.getExponent()
public static String getPubExp() throws Exception {
return (new String(Base64.encode(pubExp.toByteArray())));
}
|
Using the generated private key, the utility class
RSASigUtil can get a byte array RSA signature from a digest:
static public String getSignature (String mesg) throws Exception {
SHA1Digest digEng = new SHA1Digest();
RSAEngine rsaEng = new RSAEngine();
PSSSigner signer = new PSSSigner(rsaEng, digEng, 64);
signer.init(true, privKey);
byte [] sig = signer.generateSignature( mesg.getBytes() );
String result = new String( Base64.encode(sig) );
return result;
}
|
The server encodes the digest, signature, and key parameters into ASCII
text form and embeds the text in XML digital signature format:
<SignedMesg>
<mesg>Hello World</mesg>
<Signature>
<SignedInfo>
<SignatureMethod Algorithm="rsa-sha1" />
<DigestValue>Ck1VqNd45QIvq3AZd8XYQLvEhtA=</DigestValue>
</SignedInfo>
<SignatureValue>
IhJ/UMitJX7sWbzhnG8UKIdDYiZ0mfOUoAwemGiG08C
WcQ3cUszgJXoIclHW/LN7w54w2FQyLStB+hPKASEC6r
OjjgTBs6pwhjHCh2XxWx7hS7fdi9/Qk/ybH6xYGaeaZ
3oHDBjFz3hEDtrvBYcHn3keCavncE22idRX7kBl8Do=
</SignatureValue>
<KeyInfo>
<KeyValue>
<RSAKeyValue>
<Modulus>
AKT1SyxSm4uT1zYWEPY9IaFY7vDhpkIM7FZeIQ
OGnKeSEE5d3sPfONkCiHfO2oe4x6jNCXg/ngRi
tmixBkjfKgHzF4trZZtNQZjfzAgcXGljzp9MD2
ZEWQbHKvMZvZyJVrT2SlxLzusxWLwXdacprIDG
bqDAmldBOBpkmrUdPpF9
</Modulus>
<Exponent>EQ==</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</SignedMesg>
|
The verification MIDP application parses the digest, key parameters,
and signature out of the XML document, reconstructs the public key, and
uses the following method to validate the signature:
static public boolean verify (String mesg, String signature,
String mod, String pubExp) {
BigInteger modulus = new BigInteger( Base64.decode(mod) );
BigInteger exponent = new BigInteger( Base64.decode(pubExp) );
SHA1Digest digEng = new SHA1Digest();
RSAEngine rsaEng = new RSAEngine();
RSAKeyParameters pubKey = new RSAKeyParameters(false, modulus, exponent);
PSSSigner signer = new PSSSigner(rsaEng, digEng, 64);
signer.init(false, pubKey);
boolean res = signer.verifySignature( mesg.getBytes(),
Base64.decode(signature) );
return res;
}
|
Performance concerns My
tests show that XML parsing and digest generation on wireless devices are
both very fast. The main performance bottleneck, as expected, is the slow
public key algorithms.
The Bouncy Castle Crypto package provides several signer classes using
DSA, RSA, and ECC algorithms to sign and verify messages. However, not all
of them are practical in real-world devices. Because the Bouncy Castle
Crypto package is based purely on the Java language, it relies on the slow
JVM to perform even the most intensive big integer mathematical operations
without special optimization.
As a result, only the RSA algorithm gives an acceptable performance,
and it is barely acceptable. It can verify a simple digital signature with
a 1024-bit public key in slightly more than a minute on a 16MHz Palm VII
device. The performance can be improved by choosing a weaker key. But even
so, the verification process must run as a background thread in any
real-world application to avoid user interface lockup.
DSA and ECC algorithm performances are completely unacceptable in their
current implementations. A DSA signature with a 1024-bit key and an ECC
signature with a 192-bit key take more than an hour to verify on standard
Palm VII MIDP.
The performance problems strongly suggest that we need JVMs optimized
for big integer mathematical operations and public key algorithms. The JVM
must also take advantage of available special hardware and underlying OS
features to accelerate security-related math operations. Public key
algorithms are used at the handshakes in secure connections such as HTTPS.
Many current MIDP VMs can support the HTTPS protocol with reasonable
performances. The MIDP4Palm VM can make use of Palm OS's underlying
inethttps protocol to establish secure connections. It is
conceivable that future VMs and core language libraries will not only
optimize public key operations associated with secure connections, but
also make the optimization available to general security functions such as
digital signature.
Wrapup In this article,
you learned the importance of security in wireless Web services and
illustrated techniques to process XML digital signatures on both the
wireless and the Web services sides. I used the pure Java implementation
of Bouncy Castle Java cryptography package to handle digital signatures.
Of all the algorithms Bouncy Castle offers, only the RSA algorithm offers
marginally acceptable performance on wireless devices. However, future
advancement in MIDP runtime environment could make digital signatures more
readily available to mobile users.
Resources
- Download the sample
code of the examples in this article.
- Michael Yuan and his co-author Ju Long focus on general
security issues of the J2ME/MIDP platform (developerWorks,
June 2002) in this article from the developerWorks Wireless zone.
- For a refresher on J2ME/MIDP application programming, check out the
tutorial "The
MIDlets advantage" (developerWorks, March 2002).
- In "J2ME
grows up" (developerWorks, May 2001), Todd Sundsted shows how
J2ME provides developers with a way to leverage their skills across a
wide range of devices.
- In "Make
your software behave: Cryptography essentials "
(developerWorks, July 2000), security expert Gary McGraw explains
basics of secure hashing and digital signatures.
- IBM alphaWorks XML
Security Suite supports the latest XML digital signature and other
secure XML protocols.
- Find out more about XML
digital signatures in this comprehensive article by Larry Loeb
(developerWorks, December 2001).
- Read the W3C XML
digital signature standard.
- To process XML digital signatures on server side Java platforms,
check out this proposed Java
XML digital signature APIs.
- The J2ME Web services
specification proposes APIs to handle XML messages and Web services
XML-RPC on J2ME platforms.
- The JavaOne 2002 conference focused on Web services and wireless
applications. In "JavaOne
2002: Top innovations" (developerWorks, March 2002), Govind
Seshadri summarizes the innovations making headlines.
- In "Security
in a Web Services World: A Proposed Architecture and Roadmap"
(developerWorks, April 2002), IBM and Microsoft have proposed
strategies and models to address security in a Web services environment.
- This article uses the kXML
parser to parse XML documents in the examples.
- The Bouncy Castle Crypto
lightweight cryptography package runs on both J2SE and J2ME/MIDP
platforms.
- Most Bouncy Castle algorithm implementations are directly from the
Handbook
of Applied Cryptography by Alfred J. Menezes, Paul C. Van
Oorschot, Scott A. Vanstone, 1996, CRC Press.
- This comparison
table highlights the cryptography strengths and performances of DSA,
RSA, and ECC algorithms.
- Find other Java programming resources on the developerWorks
Java technology zone.
About the
author Michael J. Yuan is a Ph.D. candidate at the
University of Texas at Austin. He is interested in using Java
technology to facilitate science education and research. You can
contact him at juntao@mail.utexas.edu.
|
|
|