by Michael Juntao Yuan

Data security in mobile Java applications

how-to
Dec 20, 200228 mins

Learn how to select and use third-party security toolkits

The recent release of MIDP (Mobile Information Device Profile) features a major improvement over version 1.0. Version 2.0 includes enhanced mobile code and application security through a well-defined security manager and provisioning process. On the data and communication security front, MIDP 2.0 makes HTTPS support mandatory. HTTPS is currently the most widely used data security protocol in PersonalJava and J2ME/CDC (Java 2 Platform, Micro Edition/Connected Device Configuration) applications.

Although HTTPS proves sufficient for most of today’s Internet commerce applications, future mobile applications demand more flexible, customizable, and better-optimized security schemes. In this article, I discuss the security requirements of future mobile commerce and how third-party J2ME tools can help developers meet those requirements.

I begin by discussing advanced mobile commerce security requirements and why HTTPS alone is not sufficient.

Content-based security

HTTPS, SSL, (Secure Socket Layer), and TLS (Transaction Layer Security) are connection-based security protocols. The basic idea is to secure communication channels and hence, secure everything that passes through those channels. This approach has several problems:

  • Direct connection between client and server must be established: If our application has multiple intermediaries to provide value-added services, multiple HTTPS connections must be piped together. That not only opens potential security holes at connecting nodes, but also creates a public key certificate management nightmare. Figure 1 illustrates an example mobile transaction involving multiple intermediaries.
  • All content is encrypted: In some application scenarios, such as broadcasting stock quotes or getting multilevel approval of a transaction, parts of the communication should be open. Yet we still want to verify the authenticity of those quotes and approval signatures. Connection-based security is no use here. Unnecessarily encrypting all content also introduces more processing overhead.
  • HTTPS is inflexible for applications that have special security and performance requirements: It lacks support for custom handshake or key exchange mechanisms. For example, HTTPS does not require clients to authenticate themselves. Another example is that any minor digital certificate-formatting problem causes the entire HTTPS handshake to fail. The developer has no way to specify what errors can be tolerated.

Other connection channel-based security technologies, such as Virtual Private Network (VPN), have similar problems. For future mobile commerce applications, we must secure content rather than channels.

Distributed access control

Mobile applications often interact with multiple backend servers, pull information from them as needed, and assemble personalized displays for users. Each information service provider might have its own user authentication and authorization protocols. It is a major inconvenience for mobile users to sign on to each backend server manually.

One way to combat this problem is through the use of single sign-on services. Single sign-on servers manage user profiles and provide time-stamped access tokens, such as Kerberos tickets, to authenticated users. Service providers interact with single sign-on servers to validate tokens. Figure 2 illustrates that process. Being a one-to-one protocol, HTTPS is unfit in single sign-on schemes.

Single sign-on domains can form alliances and federations. Allied domains recognize tokens from each other. Important single sign-on alliances include Microsoft .Net Passport and Sun Microsystems’ Liberty Alliance Project. Figure 3 illustrates the structure of federated single sign-on domains. To integrate into single sign-on service domains, smart mobile clients must be able to handle security tokens. Those tokens are often cryptographic hashes with attached digital signatures.

Device security

Mobile devices are easy to steal or lose. We must prevent nonauthorized personnel from accessing a device’s sensitive data. For example, your company’s financial data or private keys should not be recovered from a stolen mobile device. On-device information security is one of the most important challenges we face today.

HTTPS does not support on-device information security. Mobile clients are responsible for protecting their own data. Strong passwords usually protect on-device information.

Lightweight mobile cryptography toolkits

To take advantage of advanced security technologies, mobile developers must have programmatic access to cryptographic algorithms. So, throughout the rest of this article, I discuss third-party J2ME cryptography toolkits. Those toolkits let us implement flexible solutions meeting the above requirements.

Those toolkits prove crucial to the CLDC (Connected Limited Device Configuration)/MIDP platform since standard CLDC/MIDP does not provide any cryptography APIs. Higher end J2ME platforms such as profiles based on CDC (or PersonalJava) can optionally support the java.security package in JCA (Java Cryptography Architecture) but not the javax.crypto package. As a result, crucial security APIs such as encryption/decryption ciphers are missing from all these standard profiles. Even for APIs in the java.security package, the bundled JCA provider might not implement the proprietary algorithm we need or have an inefficient implementation. So for high-end J2ME devices, lightweight toolkits also prove essential.

General requirements

A toolkit suitable for mobile commerce must meet some general requirements:

  • Fast: Mobile devices are personal devices that must be responsive. On the other hand, they have slow CPUs, and Java is not known for its raw performance. Handling CPU-intensive cryptography tasks, especially public key algorithms, at an acceptable speed on J2ME devices is a big challenge.
  • Small footprint: Most modern comprehensive cryptography packages consume several MBs of storage space. However, a MIDP phone device might have only 100 KBs of storage space. We must balance features with footprint.
  • Comprehensive algorithm support: A cryptography package’s goal is to support flexible security schemes. Such flexibility comes from the ability to choose from a range of algorithms. Important cryptographic algorithms include the following:

    • Symmetric key encryption
    • Public key encryption
    • Digital signatures
    • Password-based encryption
  • Sensible APIs: To support a wide range of algorithms through a consistent interface, cryptography package APIs often have multiple layers of abstractions and complex inheritance structures. However, a complex API will hinder its adoption.
  • Easy key identification and serialization: In a general-purpose cryptography package, keys for different algorithms must be identified and matched properly on both communication ends. The public key pair generation process is often too slow on devices. So, we must pregenerate keys on the server side and then transport keys to devices. The API should provide the means to ease and secure this process.
  • Good reputation: A security solution provider must be trustworthy and have a good track record. Also, no algorithm is secure if the implementation is poorly conceived.
  • Timely bug fixes: Security holes and algorithm weaknesses are discovered frequently around the world. The security solution provider must track this information and provide fixes or patches promptly.
Note: Secure random numbers
Cryptographic algorithms rely on truly random numbers to function securely. Most implementations provide quasi-random number generators based on the current time. To leverage truly random events, such as user typing pattern and battery voltage, secure random number generators should come from the device vendor.

Bouncy Castle lightweight API

Bouncy Castle (BC) started out as a community effort to implement a free, clean-room, open source JCE provider. BC developers developed their own lightweight API (BC lightweight crypto API) to be wrapped in BC JCE provider classes. The BC lightweight API can also be used standalone, with minimum dependence on other J2SE classes.

The Bouncy Castle J2ME download package contains the implementation of the BC lightweight API as well as two core Java classes not supported in J2ME/CLDC: java.math.BigInteger and java.security.SercureRandom.

BC’s strength comes from its open source development model:

  • When security holes or bugs are found, they are fixed quickly.
  • BC’s flexible API design and community development model allow anyone to contribute new algorithm implementations. BC supports a range of well-known cryptographic algorithms.
  • The BC community is constantly optimizing existing implementations. For example, BC 1.16 has three AES (Advanced Encryption Standard) implementations that provide a range of compromises between speed and memory usage. From BC 1.11 to 1.16, the BigInteger implementation has improved so much that the time needed for RSA (Rivest-Shamir-Adleman) encryption is only one-fortieth of what it used to be.
  • Since BC implements an open source JCE provider, you can look at the BC JCE source code to figure out how to use the lightweight API for various tasks. This provides a powerful learning tool for advanced developers.
  • It is free.

However, the ad hoc development model also brings some problems:

  • Many BC algorithm implementations come straight from textbooks. There are simply too many algorithms and too few volunteer developers to optimize everything. The lack of optimization results in relatively poor performance, especially for some public key algorithms. As of version 1.16, BC public key performance proves sufficient for only high-end phones or PDAs.
  • The BC API design is flexible but quite complex, and beginners find it hard to learn. Some developer-friendly API features are missing. For example, although BC provides full support for ASN.1 (Abstract Syntax Notation.1), it lacks a set of ready-to-use general-key serialization APIs.
  • The community support via mailing list often works well. But there is no guarantee that someone will answer your question, much less in your specified time frame.

To support so many algorithms, BC has a large footprint. The lightweight API jar file itself is nearly 1 MB. However, most mobile applications use only a small subset of BC algorithms. BC’s free license terms allow you to pack and redistribute only the classes required in your application. Some J2ME post-processing tools and IDEs (for example, IBM WebSphere Device Developer) can automatically find class dependence and delete unused files from your jar file. Those tools prove handy when you develop with BC.

Note: Obfuscation for BC classes
BC provides clean-room implementations of two Java core language classes not supported in J2ME/CLDC. However, the J2ME code security model dictates that an application should not overload classes in Java core language namespaces. So, if you deploy a BC application directly to a device, it might result in a security exception. A workaround is to obfuscate your byte code. The obfuscation process replaces package, class, variable, and method names to make them shorter and less human-readable. The obfuscated package names will not collide with Java core package names.

Phaos Technology Micro Foundation toolkit

Phaos Technology is a Java and XML security solution provider. It offers toolkits for secure XML Java APIs, J2ME lightweight crypto APIs, and one of the first implementations of the SSL protocol on J2ME/CLDC. In this article, I focus on the Phaos Micro Foundation (MF) lightweight crypto API.

Phaos XML security packages do not currently work with J2ME. However, they are at a leading position to provide future secure Web services tools for mobile applications. Phaos toolkits are available for free evaluation. You must email the company to get a 30-day license key, which comes with tech support.

Phaos is a reputable security company with a good track record. The technical support staff is also very knowledgeable and responsive. All my support questions were answered via email within 24 hours.

The Phaos MF runs on both CLDC and CDC. The CDC version also runs under J2SE. The toolkit footprint is 187 KB for the CLDC version and 169 KB for the CDC version. The Phaos API is intuitive and comes with excellent documentation and code examples.

Phaos MF supports a set of frequently used cryptographic algorithms to strike a balance between performance and features. Those algorithms include symmetric ciphers, such as AES, DES (Data Encryption Standard), RC2, and RC4; PKI (Public Key Infrastructure) ciphers and signature schemes, such as DSA (Digital Signature Algorithm) and RSA; password-based encryption schemes (PBES), such as PKCS (Public Key Cryptography Standard) #5 and PKCS #12. Phaos MF also supports X.509 certificate parsing, ASN.1 encoding, and efficient memory pooling.

Phaos PBES implementations used in my examples perform worse than their Bouncy Castle counterparts. For RSA and DSA algorithms, Phaos implementations are better optimized than Bouncy Castle 1.16. But public key tasks still take seconds on even high-end mobile phones. In fact, no matter how much optimization you do, those classic PKI algorithms might just prove too heavy for the smallest devices. Novel algorithms and approaches are needed. NTRU and a start-up company called B3 Security provide such solutions.

NTRU Neo for Java toolkit

NTRU PKI algorithms include an encryption algorithm NTRUEncrypt and a signature algorithm NTRUSign, invented and developed by four math professors at Brown University. In my sample programs, NTRU algorithms perform 5 to 30 times faster compared with other public key algorithms with similar cryptographic strength. NTRU algorithms are published and on their way to becoming IEEE (Institute of Electrical and Electronics Engineers) and IETF (Internet Engineering Task Force) standards. NTRU patented the algorithms to protect their business interests. NTRU algorithm patents have been licensed by a variety of mobile software, smart card, and DSP (Digital Signal Processor) chip vendors, including Sony and Texas Instruments.

Cryptographic algorithms are scrutinized and improved repeatedly before considered mature and ready for general public adoption. Although NTRU algorithms have been inspected many times by both academic and business worlds, they are still relatively new. Security weaknesses were identified in NTRUEncrypt as late as May 2001. Those weaknesses do not undermine NTRU algorithm fundamentals and have since been fixed. As you should with any critical project, research NTRU security before licensing it.

NTRU provides an implementation of its algorithms in a Java package called NTRU Neo for Java. You must work out an agreement with NTRU before you can evaluate the package. In addition to NTRU public key algorithms, Neo for Java also includes an implementation of the AES Rijndael symmetric key algorithm. The Neo for Java package runs on CLDC, CDC, and J2SE platforms. It has a memory footprint of 37 KB without signature key generation classes, which have a footprint of 35 KB.

The Neo for Java API is simple and easy to use. In fact, it might be too simplistic. For example, the block encryption method requires users to divide plaintext data into blocks.

Using Neo for Java, NTRUEncrypt key pairs can be generated quickly from pass phrases. The same pass phrase always produces the same key pair. For that reason, Neo for Java does not provide a password-based key store facility. NTRUSign keys, however, are slow to generate and require floating-point support. The Neo for Java package provides a floating-point emulation class, which can support NTRUSign key generation on a CLDC device. But on-device NTRUSign key pair generation takes a long time to complete. Generating and distributing NTRUSign keys from a server computer is a better approach. Fortunately, a signature key can sign thousands of messages before it needs replacement.

B3 Security

B3 Security is a San Jose, Calif. startup that specializes in developing new lightweight security infrastructures that minimize the current overhead associated with PKI. Its flagship products are B3 Tamper Detection and Digital Signature (B3Sig) SDK and B3 End-to-End (B3E2E) Security SDK. Both are available for J2ME. The B3E2E SDK (still in beta) provides features equivalent to SSL in the PKI world, but with a shorter handshake, faster session key establishment, and less management overhead, especially for pushed messages.

I tested the B3Sig SDK, which runs on the J2ME/CLDC platform. The B3 digital signature scheme is based on keyed hash (HMAC, or Keyed-Hashing for Message Authentication) technology, which has been around for many years and has proven security. B3 uniquely uses HMAC properties instead of more computationally intensive public key algorithms, such as large integer factoring, to form a B3 tamper-proof block of bytes and digital signature. In a mobile enterprise application setting, it works like so:

  • In its preferred operation mode, the B3Sig SDK uses two pairs of shared and nonshared secrets. Analogous to the PKI world, a shared secret acts like a public key with targeted distribution scope, and a nonshared secret acts like a private key.

    Each user knows her own password in an existing enterprise identity management system. The system only stores a hash (for example, MD5, or Message Digest 5) of the password. No clear text password is stored anywhere. The B3 SDK uses that hash as the first shared secret. The first nonshared secret comes from a different hash (for example, SHA-1, or Secure Hash Algorithm-1) of the same password.

    B3 software on a device generates a private root key and the corresponding shared secret. They form the second pair of secrets, which ensures stronger authentication. The second shared secret can be used for third-party verification. A B3 protocol can also use the second pair to efficiently reset a forgotten password.

  • Nonshared secrets are used together with the message (or transaction) itself and user ID to generate a unique signing key for every message.
  • A B3 algorithm then generates a digital signature containing three interrelated parts.
  • A B3 algorithm can verify message and user ID integrity with shared secrets. The receiving party can query the password system to verify the sender’s authenticity.

B3 scheme has the following advantages:

  • Speed: Cryptographic hash and HMAC algorithms can run 1,000 times faster than public key algorithms.
  • Seamless integration with existing enterprise authentication infrastructure: Various password-based identity management systems are already widely deployed in enterprises (the simplest example is a password file). Utilizing existing password-based identity management systems avoids the expensive overhead of digital certificate management associated with PKI digital signature.
  • Strong two-factor authentication: Only the person who has access to the specific device and knows her application password can generate the correct shared and nonshared secrets to sign messages. That also helps to prevent password guessing and dictionary attacks.
  • Tamper detection: B3Sig SDK has a conservative design: It assumes that no algorithm is permanently secure, including its own. In case of a successful crypto attack on B3 signature and verification algorithms, the sender can still prove that he did not send the forged message. Part of the B3 signature is linked to the nonshared secrets through well-established non-B3 one-way algorithms (HMACs).

B3 solutions do not dictate complete replacement of the current PKI infrastructure. Rather, B3 solutions can coexist and interoperate with the current system. For example, we can use HTTPS as well as B3E2E SDK to pass shared secrets during setup. The application can add delegated PKI signatures on top of the B3 signatures if desired. To use B3 signatures without an existing identity/password management system, we also need to set up a B3 shared secrets store. To learn more technical details about B3 solutions, please contact B3 directly for whitepapers and evaluation SDKs.

Leading security experts in the financial services industry, such as Larry Suto, FTCS cochair at Wells Fargo Bank, and Jim Anderson, a VP of information security at Visa, have agreed to be references for the B3 solutions. If B3 does deliver on its promises, it could become one of the most important security solutions for mobile enterprise applications. However, B3 is still a young company, and its approach has not been tested in large-scale real-world environments. I recommend you investigate the feasibility of B3 solutions yourself.

Device-specific APIs

MIDP device vendors (for example, Motorola iDEN phones) also provide device-specific cryptography API extensions. Those packages utilize device native cryptography libraries and special hardware features. Thus, they likely have good on-device performance.

But applications using vendor-specific APIs are no longer portable to other devices. That causes J2ME platform fragmentation and defeats one of Java’s greatest advantages. I do not discuss those APIs in detail here. Interested readers can refer to their device manufacturers’ developer manuals.

One way to avoid such fragmentation yet still take advantage of native performance is to develop standard J2ME cryptography API specifications and allow device vendors to plug in their own implementations. The CDC/FP/PP device vendors can implement native JCE providers. However, at the time of this writing, no MIDP compatible lightweight crypto API JSR (Java Specification Request) is being developed in the Java Community Process.

Overview of examples

The sample applications accompanying this article illustrate how to incorporate cryptographic functionalities into your application. They demonstrate how to use symmetric key encryption, public key encryption, digital signature, and password-based encryption. However, due to space limitations, I only discuss the source code for digital signature.

The zip archive, which you can download from Resources, contains three sample applications—each demonstrates API usage of a crypto package (Bouncy Castle, Phaos, and Neo for Java). Inside each sample application, the most important class is CryptoEngine, which stores keys and provides thin wrappers over API methods. CryptoEngine sports a monolithic single class design not optimized for code reuse. Do not consider it a best-practice example. Instead, the examples are designed to get you started with working code quickly. Each CryptoEngine method demonstrates a complete application task (for example, to encrypt a message using RSA).

The CryptoEngine‘s constructor constructs pregenerated keys from files in the JAR’s keys/ directory (work/res/keys directory in the build system). CryptoEngine also has methods to support key generation on mobile devices.

All the toolkits used in the sample applications run on both CLDC and CDC platforms. But to evaluate their performance in the most restricted environment, I provided user interface (UI) drivers for MIDP. Those MIDlets are in the MIDlets package. They measure time spent on each task. Classes in directory work/keygensrc pregenerate keys and serialize them to files in directory work/res/keys before MIDP suite packaging.

Building and running the sample applications is easy. You simply change the parameters in the build.xml file to reflect your system settings and run Ant tasks package and run. I bundled Bouncy Castle 1.16 in the BC sample. For other toolkit samples, you must contact vendors to obtain their software and evaluation licenses. You need to un-JAR the toolkit files into the work/classes directory.

Note: Phaos secure number generator
The Phaos MF for CLDC package is not shipped with random generator classes. You must supply your own generator, which implements the com.phaos.micro.crypto.RandomBitsSource interface using secure random facilities provided by the device vendor. For testing purposes, I supplied SecureRandom and SecureRBS classes in my example package com.enterprisej2me.PhaosMobile.security. Class SecureRandom is based on the Bouncy Castle implementation of java.security.SecureRandom, and SecureRBS implements the com.phaos.micro.crypto.RandomBitsSource interface.

Digital signature examples

Digital signature can guarantee message integrity and authenticity in an open network. To generate a signature, you first calculate a hash (also called digest) of your message. Then you encrypt that hash with your private key to generate a signature. The party at the receiving end first decrypts your signature into a hash using your public key. Then she calculates the hash from your message. If the two hashes match, the message is indeed from you and unaltered.

If someone altered the message during its transmission and generated a new hash based on the modified message, public key algorithms guarantee that he cannot produce a matching signature without knowing your private key. The two parties must share four pieces of information: the message itself, its digital signature, hash and signing algorithms, and the public key.

Figure 4 shows the example application’s digital signature MIDlet user interface.

Bouncy Castle

Bouncy Castle supports DSA, RSA, and ECC (Elliptic Curve Cryptography) digital signature algorithms. My code example only shows how to use the RSA signature.

To generate an RSA key pair, BC requires the developer to pick a public exponent. A common pick is 65537 (Hex 10001) for strong security and fast performance:

Listing 1. Bouncy Castle RSA key generation in CryptoEngine

public void generateRSAKeyPair () throws Exception {
  SecureRandom sr = new SecureRandom();
  BigInteger pubExp = new BigInteger("10001", 16);
  RSAKeyGenerationParameters RSAKeyGenPara =
       new RSAKeyGenerationParameters(pubExp, sr, 1024, 80);
  RSAKeyPairGenerator RSAKeyPairGen = new RSAKeyPairGenerator();
  RSAKeyPairGen.init(RSAKeyGenPara);
  AsymmetricCipherKeyPair keyPair = RSAKeyPairGen.generateKeyPair();
  RSAprivKey = (RSAPrivateCrtKeyParameters) keyPair.getPrivate();
  RSApubKey = (RSAKeyParameters) keyPair.getPublic();
}

Bouncy Castle’s lightweight package lacks a good key serialization API. To serialize keys for transportation or future use, we must export key parameters one by one:

Listing 2. Bouncy Castle RSA key serialization in keygensrc/GenerateAllKeys.java

BigInteger mod = RSAprivKey.getModulus();
out = new FileOutputStream(outdir + "RSAmod.dat");
out.write(mod.toByteArray());
out.flush();
out.close();
BigInteger privExp = RSAprivKey.getExponent();
out = new FileOutputStream(outdir + "RSAprivExp.dat");
out.write(privExp.toByteArray());
out.flush();
out.close();
pubExp = RSAprivKey.getPublicExponent();
if ( !pubExp.equals(new BigInteger("10001", 16)) )
  throw new Exception("public exponent does not match");
out = new FileOutputStream(outdir + "RSApubExp.dat");
out.write(pubExp.toByteArray());
out.flush();
out.close();
BigInteger dp = RSAprivKey.getDP();
out = new FileOutputStream(outdir + "RSAdp.dat");
out.write(dp.toByteArray());
out.flush();
out.close();
BigInteger dq = RSAprivKey.getDQ();
out = new FileOutputStream(outdir + "RSAdq.dat");
out.write(dq.toByteArray());
out.flush();
out.close();
BigInteger p = RSAprivKey.getP();
out = new FileOutputStream(outdir + "RSAp.dat");
out.write(p.toByteArray());
out.flush();
out.close();
BigInteger q = RSAprivKey.getQ();
out = new FileOutputStream(outdir + "RSAq.dat");
out.write(q.toByteArray());
out.flush();
out.close();
BigInteger qInv = RSAprivKey.getQInv();
out = new FileOutputStream(outdir + "RSAqInv.dat");
out.write(qInv.toByteArray());
out.flush();
out.close();

Among those parameters, mod and pubExp are needed for reconstructing the public key. To reconstruct public and private keys from serialized parameters, we use the following code in CryptoEngine‘s constructor:

Listing 3. Reconstruct key pair in CryptoEngine’s constructor

is = c.getResourceAsStream("/keys/RSAmod.dat");
BigInteger RSAmod = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAprivExp.dat");
BigInteger RSAprivExp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSApubExp.dat");
BigInteger RSApubExp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAdp.dat");
BigInteger RSAdp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAdq.dat");
BigInteger RSAdq = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAp.dat");
BigInteger RSAp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAq.dat");
BigInteger RSAq = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAqInv.dat");
BigInteger RSAqInv = new BigInteger(readFromStream(is));
is.close();
RSAprivKey = new RSAPrivateCrtKeyParameters(RSAmod, RSApubExp,
                  RSAprivExp, RSAp, RSAq, RSAdp, RSAdq, RSAqInv);
RSApubKey = new RSAKeyParameters(false, RSAmod, RSApubExp);

Once you have keys, signing the digest is simple. Here we use SHA-1 digest:

Listing 4. Bouncy Castle RSA signature generation in CryptoEngine

public byte [] RSASign (byte [] toSign) throws Exception {
  if (RSAprivKey == null)
    throw new Exception("Generate RSA keys first!");
  SHA1Digest dig = new SHA1Digest();
  RSAEngine eng = new RSAEngine();
  PSSSigner signer = new PSSSigner(eng, dig, 64);
  signer.init(true, RSAprivKey);
  signer.update(toSign, 0, toSign.length);
  return signer.generateSignature();
}

The receiving party must have prior knowledge of the public key and digest/signature algorithms to verify the signature:

Listing 5. Bouncy Castle RSA signature verification in CryptoEngine

public boolean RSAVerify (byte [] mesg, byte [] sig)
                                        throws Exception {
  if (RSApubKey == null)
    throw new Exception("Generate RSA keys first!");
  SHA1Digest dig = new SHA1Digest();
  RSAEngine eng = new RSAEngine();
  PSSSigner signer = new PSSSigner(eng, dig, 64);
  signer.init(false, RSApubKey);
  signer.update(mesg, 0, mesg.length);
  return signer.verifySignature(sig);
}

Phaos Micro Foundation

Phaos MF supports DSA and RSA digital signatures. Generating DSA key pairs using the Phaos API is simple. Please note that variable DSApubKeyDer is not the public key itself. Rather, it is a byte array representation of the public key in DER (Distinguished Encoding Rules) format. The public key can be reconstructed from this array using an appropriate algorithm identifier. See more below:

Listing 6. Phaos DSA key pair generation in CryptoEngine

// 1024-bit DSA key
private DSAPrivateKey DSAprivKey;
// This is the DSA public key data you can serialize
private byte [] DSApubKeyDer;
public void generateDSAKeyPair () throws Exception {
  DSAKeyGenParams params =
     new DSAKeyGenParams(1024, RandomBitsSource.getDefault());
  KeyPairGenerator kpg = 
            KeyPairGenerator.getInstance(OIDList.DSA, params);
  KeyPair kp = kpg.generateKeyPair();
  DSAprivKey = (DSAPrivateKey)kp.privateKey;
  ByteArrayOutputStream baos = new ByteArrayOutputStream ();
  ((DSAPublicKey)kp.publicKey).output(baos);
  DSApubKeyDer = baos.toByteArray();
  return;
}

The Phaos API provides convenient ways for serializing keys. Note that in addition to keys themselves, you must serialize DSA key generation parameters for algorithm identification purposes:

Listing 7. Phaos DSA key pair serialization in keygensrc/GenerateAllKeys.java

DSAPublicKey pubKey = (DSAPublicKey)kp.publicKey;
DSAPrivateKey privKey = (DSAPrivateKey)kp.privateKey;
pubKey.output(new FileOutputStream(outdir + "DSApubKey.der"));
privKey.output(new FileOutputStream(outdir + "DSAprivKey.der"));
DSAParams dsaParams =
   new DSAParams(
     new ByteArrayInputStream(
       privKey.createAlgID(true).encodeParameters()));
dsaParams.output(new FileOutputStream(outdir + "DSAparams.der"));

In CryptoEngine‘s constructor, we reconstruct the private key using private key DER data and the algorithm identifier. The public key DER data is also read in, but the public key itself is not reconstructed until the verification process starts:

Listing 8. Reconstruct Phaos DSA private key and read in public key data in CryptoEngine constructor

// The DSA private key
is = c.getResourceAsStream("/keys/DSAparams.der");
DSAParams params = new DSAParams(is);
AlgorithmIdentifier algID = getDSAalgID(params);
is.close();
is = c.getResourceAsStream("/keys/DSAprivKey.der");
DSAprivKey = new DSAPrivateKey(algID, is);
is.close();
// The DSA public key byte array
is = c.getResourceAsStream("/keys/DSApubKey.der");
baos = new ByteArrayOutputStream();
b = new byte[1];
while ( is.read(b) != -1 ) {
   baos.write(b);
}
is.close();
DSApubKeyDer = baos.toByteArray();
baos.close();

The getDSAalgID() method used in the above listing also retrieves the algorithm identifier from DSA parameters:

Listing 9. Retrieve the algorithm identifier in CryptoEngine

private AlgorithmIdentifier getDSAalgID (DSAParams params) 
                                              throws Exception {
  ByteArrayOutputStream paramsOut = new ByteArrayOutputStream();
  params.output(paramsOut);
  paramsOut.close();
  return new AlgorithmIdentifier(OIDList.DSA, 
                                 paramsOut.toByteArray());
}

Now, we can sign a DSA signature using the private key. Note that both the Phaos algorithm identifier and the signature data itself are written into the output array:

Listing 10. Generate a Phaos DSA signature in CryptoEngine

public byte [] DSASign (byte [] toSign) throws Exception {
  if (DSAprivKey == null)
    throw new Exception("Generate DSA keys first!");
  Signature signature = 
              Signature.getInstance(AlgIDList.SHA1_WITH_DSA,
                                    DSAprivKey);
  byte [] result = 
     signature.sign(toSign, 0, toSign.length).toByteArray(true); 
  DSAParams params = new DSAParams(
      new ByteArrayInputStream(
        DSAprivKey.createAlgID(true).encodeParameters()));
  AlgorithmIdentifier algID = getDSAalgID (params);
  ByteArrayOutputStream baos = new ByteArrayOutputStream ();
  algID.output(baos);
  baos.write(result, 0, result.length);
  baos.flush();
  baos.close();
  return baos.toByteArray();
}

To verify the signature, you must first extract the algorithm identifier from the signature and then construct the public key. Due to the proprietary algorithm identifier format, Phaos signatures are best verified by the Phaos API at the receiving end:

Listing 11. Phaos DSA signature verification in CryptoEngine

public boolean DSAVerify (byte [] mesg, byte [] sig)
                                         throws Exception {
  InputStream is = new ByteArrayInputStream(sig);
  AlgorithmIdentifier algID = new AlgorithmIdentifier(is);
  PooledArray sigBytes = ByteArrayPool.getArray(is.available());
  is.read(sigBytes.buffer, 0, sigBytes.length);
  is.close();
  DSAPublicKey DSApubKey = new DSAPublicKey(algID,
                      new ByteArrayInputStream(DSApubKeyDer));
  Signature signature = 
       Signature.getInstance(AlgIDList.SHA1_WITH_DSA,
                             DSApubKey);
  return signature.verify(mesg, 0, mesg.length,
                        sigBytes.buffer, 0, sigBytes.length);
}

NTRU Neo for Java

As I have mentioned, NTRU Neo for Java probably has the simplest API due to its single algorithm nature. To use any methods in the Neo for Java package, you must first generate a secure random context:

Listing 12. Neo for Java secure context

private RandomNumber rn;
private Context ctx;
public CryptoEngine () {
  try {
    rn = new RandomNumber(NTRUConst.NTRU_SHA1_HASH);
    ctx = new Context(rn);
    ... ...
}

Generating an NTRU key pair for digital signature takes only one line of code. The following code generates an NTRU 251-bit signing key, which has cryptographic strength equivalent to a 1,024-bit RSA key:

Listing 13. NTRU signature key generation in CryptoEngine

public void generateNTRUsgnKeys () throws Exception {
  NTRUsgnKeys = new SgnKeys(ctx, NTRUConst.NTRU_KEYSTRENGTH_251,
                            NTRUConst.NTRU_SHA1_HASH);
  return;
}

Complete key serialization by calling the appropriate export methods:

Listing 14. NTRU signature key serialization in keygensrc/GenerateAllKeys.java

byte [] pubKey = NTRUsgnKeys.exportPubKey(null, 0);
out = new FileOutputStream(outdir + "SgnPubKey.dat");
out.write(pubKey);
out.flush();
out.close();
byte [] privKey = NTRUsgnKeys.exportPrivKey(null, 0);
out = new FileOutputStream(outdir + "SgnPrivKey.dat");
out.write(privKey);
out.flush();
out.close();

Reconstructing serialized keys is also simple:

Listing 15. Reconstruct NTRU signature key pair in CryptoEngine constructor

is = c.getResourceAsStream("/keys/SgnPubKey.dat");
byte [] sgnPubKeyData = readFromStream(is);
is.close();
is = c.getResourceAsStream("/keys/SgnPrivKey.dat");
byte [] sgnPrivKeyData = readFromStream(is);
is.close();
NTRUsgnKeys = new SgnKeys (sgnPubKeyData, 0, sgnPubKeyData.length,
                           sgnPrivKeyData, 0, sgnPrivKeyData.length);

Now, we generate the signature:

Listing 16. Generate NTRU signature in CryptoEngine

public byte [] NTRUSign (byte [] message) throws Exception {
  if ( NTRUsgnKeys == null )
    throw new Exception("Generate NTRU encryption keys first!");
  MessageDigest dig = new MessageDigest(NTRUConst.NTRU_SHA160_HASH);
  Signature sig = new Signature(NTRUConst.NTRU_KEYSTRENGTH_251,
                                NTRUConst.NTRU_SHA160_HASH);
  dig.updateMessageDigest(message, 0, message.length);
  dig.completeMessageDigest();
  sig.sign(ctx, NTRUsgnKeys, dig);
  return sig.export();
}

The receiving party must verify the signature using the NTRU algorithm:

Listing 17. Verify NTRU signature in CryptoEngine

public boolean NTRUVerify (byte [] message, byte [] sigData)
                            throws Exception {
  Signature sig = new Signature(sigData, 0, sigData.length);
  MessageDigest dig = new MessageDigest(sig.getHashAlg());
  dig.updateMessageDigest(message, 0, message.length);
  dig.completeMessageDigest();
  try {
    sig.verify(ctx, NTRUsgnKeys, dig);
    return true;
  } catch (NTRUException e) {
    return false;
  }
}

Secure your mobile data

Advanced mobile commerce applications require content-based and single sign-on security solutions that protect both communication and on-device data. Today’s popular HTTPS solution does not meet those requirements due to its point-to-point nature, inflexible protocol design, and slow algorithms.

Third-party vendors have come up with excellent security tools that will meet those future mobile commerce requirements. Those toolkits give developers programmatic access to cryptographic algorithms, especially algorithms specially designed for mobile applications. I encourage you to try those tools and better safeguard your crucial mobile data!

I would like to thank Bouncy Castle lead developer David Hook for help with this article, and Phaos Technology Corporation, NTRU Cryptosystems, and B3 Security for providing evaluation software and technical support.

Michael Yuan is a PhD candidate at the University of Texas, where he is a research associate at the Center for Research in Electronic Commerce and an open source Java developer.