Today, with the advent of pervasive computing technology, you can deploy many kinds of applications, including multimedia services and online interactive games, into a Java 2 Platform, Micro Edition (J2ME) environment. However, security becomes an important issue in order for applications to perform AAA (Authenticate, Authorize, and Audit) operations. Java Cryptography Extension (JCE) is the widely adopted standard security library used in Java 2 Platform, Standard Edition (J2SE) environments. This article helps you transition JCE to J2ME environments with a platform-independent, troubleshooting approach.
Setbacks for implementing JCE in J2ME
In this article, we analyze the common issues associated with using JCE, the standard security library for J2SE, in a J2ME environment. We illustrate how to solve these problems step by step, including sample code, and show how to implement the AES (Advanced Encryption Standard) algorithm with JCE in a J2ME environment. For our working environment, we will use IBM® WebSphere® Studio Device Developer (Device Developer), Foundation Profile, and IBM JCE. However, because the tools and libraries we use conform to an open standard, you can apply the approach to all other kinds of development environments that adhere to J2ME and JCE standards.
To start, we'll review the two steps required in the standard JCE installation for J2SE. The first step is adding a JCE provider, such as the IBM JCE provider, into the java.security file. Listing 1 shows how.
Listing 1. Registering a JCE provider
security.provider.1=com.sun.crypto.provider.SunJCE security.provider.2=com.ibm.crypto.provider.IBMJCE |
The second step is adding JCE-related library files into the CLASSPATH. In IBM JCE, the library files are:
- ibmjcefw.jar
- ibmjceprovider.jar
- ibmpkcs.jar
- ibmpkcs11.jar
- local_policy.jar
- US_export_policy.jar
If you follow these steps for a J2ME environment, however, two kinds of exceptions will likely be thrown: untrusted CA exception or resource not found exception. Listing 2 shows the first kind of exception.
Listing 2. Untrusted CA exception
java.lang.ExceptionInInitializerError: java.lang.SecurityException: Cannot set up certs for trusted CAs |
Listing 3 shows the second kind of exception.
Listing 3. Resource not found exception
NoClassDefFoundError: javax/crypto/KeyGenerator at ... |
Before we solve the exceptions, let's review some background. First, for different versions and types of development tools (JDK, JCE, and even operating systems) an exception belongs to either one of these types: one that deals with CA certificates, or one that deals with a failure to look for prerequisite classes even if they already exist in the CLASSPATH. Exceptions of the same type are similar in nature but reveal different error messages.
Second, according to our tests on many different platforms, only one kind of exception is likely to occur, and, although rare, on some platforms no exception occurs.
Finally, this article does not target a solution for a specific platform, but shows a general way to solve these kinds of exceptions.
Platform-independent solutions
Now, we'll examine the cause of these exceptions and some platform-independent solutions (IDE, JDK, JCE, and operating systems). During prior tests, we found that the two kinds of exceptions result from one of three causes:
- An environment variable
- The integrated development environment's (IDE) internal file system implementation
- The JCE library's registration mechanism
The first cause deals with the environment variable java.home in the java.policy file. JCE libraries must be authorized to have all permissions in the Java Virtual Machine (JVM), as Listing 4 shows; otherwise, the application cannot work.
Listing 4. A sample of the java.policy file
// by default, all system extensions get AllPermission
grant codeBase "file:${java.home}/lib/ext/*" {
permission java.security.AllPermission;
};
|
Notice that there is a system environment variable called java.home. On different platforms, the value of this variable changes. For example, in our environment the value is C:\WSDD571\wsdd5.0\ive-2.2. On another machine the value might be C:\Program Files\IBM\DeviceDeveloper\wsdd5.0\ive-2.2. To enable JCE libraries to have all permissions, we have to place the libraries into the %java.home%/lib/ext/ directory (we use %java.home% to identify the value of the environment variable java.home), and in our environment the value is C:\WSDD571\wsdd5.0\ive-2.2\lib\ext. However, the default installation of some IDEs, including our working IDE, does not create the ext subdirectory automatically during installation; therefore, we must develop the directory manually and put JCE libraries into it.
The second cause relates to the IDE's internal file system implementation. Some IDEs use URLs similar to the representation for local files, causing the IDE to possibly misinterpret special characters (a common example is the space character). You should exclude characters in the IDE's home directory name that have special meaning in a URL presentation.
The third cause deals with the JCE library's registration mechanism. There are two ways to load JCE libraries: static registration (presented in the first section) and dynamic loading. To load dynamically, a program can call either the addProvider() or insertProviderAt() methods in the Security class. Listing 5 shows the dynamic registration of the IBM JCE provider.
Listing 5. A sample dynamic registration of the JCE provider
Provider IBMJce = new com.ibm.crypto.provider.IBMJCE(); Security.addProvider(IBMJce); |
For some platforms, only one of these loading mechanisms can work. If one registration approach is not working, simply try the other mechanism; their functions are the same. However, we have found that in some versions of Device Developer, only the dynamic approach works.
A detailed configuration process in Device Developer
Now, we'll detail the configuration process for our working environment. While the cause-of-exception analyses are relatively complex and tricky, the configuration process is fairly simple:
- For static registration only, you must first register the IBM JCE provider to the java.security file by appending the following line to the
java.providerentry in this file.
Listing 6. IBM JCE provider entry in the java.security filesecurity.provider.2=com.ibm.crypto.provider.IBMJCE
Listing 7 shows the whole
java.providerentry in the java.security file for our environment.
Listing 7. The whole JCE provider entry in the java.security file# set the provider for security security.provider.1=com.ibm.oti.security.provider.OTI security.provider.2=com.ibm.crypto.provider.IBMJCE
Also note that an IDE might contain many files named java.security. In our Device Developer environment, the proper file is located in the C:\WSDD571\wsdd5.0\ive-2.2\lib\security directory. We have verified that adding provider information to other files with the same name has no effect on applications that use JCE in a J2ME environment.
- In the Java Development Kit (JDK) directory of Device Developer, which for our working environment is C:\WSDD571\wsdd5.0\ive-2.2\lib, we create a directory named ext if it does not
exist. Then we put IBM JCE library files, including ibmjcefw.jar, ibmjceprovider.jar, ibmpkcs.jar, ibmpkcs11.jar, local_policy.jar, and US_export_policy.jar into the JDK library's extension directory. In our working environment, the directory is C:\WSDD571\wsdd5.0\ive-2.2\lib\ext.
- To register the new variable
JCEin Device Developer:- Invoke the project's properties window, as shown in Figure 1.
Figure 1. The project property window
- Select Java Build Path from the left frame, shown in Figure 2.
Figure 2. The Java build path window
- Select Add Variable, as shown in Figure 3.
Figure 3. The project property window
- Select Edit.
Figure 4. The edit window
- Select New and enter the correct values. In our working environment, we use
JCEas the variable name andC:/WSDD571/wsdd5.0/ive-2.2/lib/extas the path value. You can generate the path value automatically through the Folder button.
Figure 5. The new variable entry window
- Select OK twice and the window shown in Figure 6 appears.
Figure 6. The window after clicking OK two times
- Select JCE and click Extend (Figure 7).
Figure 7. Select JCE and extend
- Select all entries.
Figure 8. Select all entries
- Select OK. The IDE should look like Figure 9.
Figure 9. Final IDE
- Finally, select OK.
- Invoke the project's properties window, as shown in Figure 1.
- Follow this process to register the
JCEvariable on all the machines your team uses. Your team will share the same variable name,JCE, but the variable's values for each machine can be different. - Note that the Device Developer installation home directory should not contain special characters such as the space character. In our working environment, the Device Developer installation home directory is C:\WSDD571. This step is not required because some platform IDEs work with directory names containing special characters. But we do recommend taking precautions by following this step.
This section provides two sample programs. The first one, shown in Listing 8, deals with the dynamic registration approach; the second, in Listing 9, deals with the static registration approach. If JCE is configured correctly, both programs can run in J2ME and J2SE environments without any modification, proving that this solution supports developers creating real "write once, run everywhere" Java programs.
Listing 8. Dynamic registration approach sample source code
package com.ibm.osg.sample.simple;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import com.ibm.crypto.provider.IBMJCE;
/**
* This program generates an AES key, retrieves its raw bytes, and
* then reinstantiates an AES key from the key bytes.
* The reinstantiated key is used to initialize an AES cipher for
* encryption and decryption.
*/
public class AES {
/**
* Turns array of bytes into string
*
* @param buf Array of bytes to convert to hex string
* @return Generated hex string
*/
public static String asHex (byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10)
strbuf.append("0");
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
public static void main(String[] args) throws Exception {
System.out.println ("Zzz: " +
System.getProperty("java.home"));
// Instantiate the cipher
IBMJCE jce = new IBMJCE();
Security.addProvider(jce);
String message="This is just an example";
// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES", "IBMJCE");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES", "IBMJCE");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted =
cipher.doFinal ("This is just an example".getBytes());
System.out.println("encrypted string: " + asHex(encrypted));
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original =
cipher.doFinal(encrypted);
String originalString = new String(original);
System.out.println("Original string: " +
originalString + " " + asHex(original));
}
}
|
Listing 9. Static registration approach sample
package com.ibm.osg.sample.simple;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import com.ibm.crypto.provider.IBMJCE;
/**
* This program generates an AES key, retrieves its raw bytes, and
* then reinstantiates an AES key from the key bytes.
* The reinstantiated key is used to initialize an AES cipher for
* encryption and decryption.
*/
public class AES {
/**
* Turns array of bytes into string
*
* @param buf Array of bytes to convert to hex string
* @return Generated hex string
*/
public static String asHex (byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10)
strbuf.append("0");
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
public static void main(String[] args) throws Exception {
System.out.println ("Zzz: " +
System.getProperty("java.home"));
String message="This is just an example";
// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES", "IBMJCE");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES", "IBMJCE");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted =
cipher.doFinal ("This is just an example".getBytes());
System.out.println("encrypted string: " + asHex(encrypted));
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original =
cipher.doFinal(encrypted);
String originalString = new String(original);
System.out.println("Original string: " +
originalString + " " + asHex(original));
}
}
|
Though this solution for using JCE in J2ME development works in the sample environment, you should consider it carefully before using it. First, using JCE to provide cipher functions is one way to offer security solutions, which can save you time writing customized cipher libraries. But note that JCE is a relatively large library and has a big footprint relative to the J2ME environment. For mission-critical applications, light-weight customized cipher libraries are more suitable. Additionally, JCE is not currently part of the J2ME specification. Therefore, you must consider compatibility and legal issues if you are targeting a commercial product. Thorough testing is the only way to verify compatibility.
- Learn about and even download Cloudscape, a small-footprint database for embedding Java applications (it's user-friendly and requires no administration for end users).
- Read Java Security, Second Edition, (Scott Oaks, 2001, O'Reilly) to learn about the Java features that provide security.
- Also read Cryptography and Network Security Principles and Practices, Third Edition, (William Stallings, 2003, Prentice Hall) for comprehensive information on computer organization.
- For more about JCE, review the Java Cryptography Extension (JCE) Documents.
- Visit the IBM WebSphere Device Developer Web site and learn how Device Developer can help you.
- Review the specifications at J2ME technology resources to learn more about J2ME.
- Review the specifications at J2ME Foundation Profile Specification for information on supporting resource-constrained devices without a standards-based GUI system.
- Browse for books on these and other technical topics.
Lin Ma is a Software Engineer at the IBM China Software Development Lab. His work focuses on pervasive computing technologies and services. He can be reached at mallin@cn.ibm.com.
Yu Chen Zhou is a Staff Software Engineer at the IBM China Software Development Lab. His work focuses on pervasive and portal solutions. He can be reached at zhouyuc@cn.ibm.com.
Lei Ma is a Software Engineer at the IBM China Software Development Lab focusing on pervasive computing technologies. He can be reached at malei@cn.ibm.com.
Jian Lin is the Manager of Pervasive Computing Device Software Development and Services, IBM China Software Development Lab. He can be reached at jianlin@cn.ibm.com.




