IBM Skip to main content
Search for:   within 
      Search help  
     IBM home  |  Products & services  |  Support & downloads   |  My account

developerWorks > Java technology | Wireless | Security
developerWorks
Securing your J2ME/MIDP apps
code101KBe-mail it!
Contents:
Java technology in wireless Web services
Security in wireless Web services
Guarantee data integrity using digital signatures
XML digital signatures
Handling the XML digital signature in MIDP applications
Bouncy Castle Crypto APIs
Putting it all together
Handling the digest
DSA signature example
An elliptical curve DSA signature example
An RSA signature example
Performance concerns
Wrapup
Resources
About the author
Rate this article
Related content:
J2ME grows up
alphaWorks XML Security Suite
More dW Web services resources
More dW XML resources
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
How to digitally sign and verify XML documents on wireless devices using the Bouncy Castle Crypto APIs

Level: Intermediate

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.

  1. 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.

  2. When a JSP page is accessed, the server calculates a digest for the response message.

  3. The JSP page then invokes the signer in the "sign" mode and generates a digital signature for the digest using the private key.

  4. The server embeds the signature information including the digest, digital signature itself, and public key parameters in the XML response message.

  5. The client receives the XML document and parses the digest, digital signature, and public key parameters into Java application data.

  6. 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.

  7. The client reconstructs the public key using the embedded key parameters.

  8. 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

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.


code101KBe-mail it!

What do you think of this document?
Killer! (5) Good stuff (4) So-so; not bad (3) Needs work (2) Lame! (1)

Comments?



developerWorks > Java technology | Wireless | Security
developerWorks
  About IBM  |  Privacy  |  Terms of use  |  Contact