An overview of the JDK 1.1 JavaSecurity features appears below. First, here are some quick links to relevant pages in this and other related documents:
The JavaSecurity API is a new Java Core API, built around the
java.security package. JavaSecurity is designed to let developers
incorporate both low-level and high-level security functionality into
their Java applications. This includes digital signatures, data
encryption, key management and access control.
The first release of JavaSecurity, available in JDK 1.1, contains a subset of this functionality, including APIs for
JDK 1.1 also has facilities to sign and verify Java
ARchives (JAR), which contain arbitrary
data, including class files, images, sounds, etc. The JDK 1.1 Security
Manager used, for example, by appletviewer and by the
HotJava browser) is aware of these
signatures, and, working in conjunction with the javakey tool,
will grant special privileges to signed and trusted code.
Subsequent releases of JavaSecurity will include APIs for data encryption and key exchange as well as more sophisticated security policies. The encryption API will be an API for block, stream, symmetric and asymmetric encryption, with support for multiple modes of operation and multiple encryption.
JavaSecurity is essentially an abstract layer, and introduces the notion of a Security Package Provider (SPP). An SPP is a package (or set of packages) providing a concrete implementation of a subset of JavaSecurity. JDK 1.1 comes standard with a default provider, the Sun Security Provider.
SPPs are explicitly installed in a Java environment, and configured according to the user's preferences. This is to allow end users of Java runtimes to be able to select the implementations of their choice for critical algorithms, if they so desire.
In JDK 1.1, high-level provider configuration
information appears in the java.security file. Registration
of an SPP can be done by specifying (in java.security) the Provider
subclass whose constructor sets the values of various properties that are
required for the JavaSecurity API to look up the algorithms or other
facilities implemented by the SPP. An SPP can also be registered
dynamically, via a call to the Security addProvider or
insertProviderAt method.
The Sun Security Provider
In JDK 1.1, there is one default provider, called Sun Security.
The sun.security.provider package includes:
Note: the sun.security.provider classes should
never be
accessed directly. They will be instantiated and used by the JavaSecurity
API if "SUN" is the requested service provider, or if no other service
provider is specified, since they provide the default implementation.
Applications should always call the JavaSecurity API
(java.security) interfaces.
Implementations of various classes that are useful when using
java.security are available in other sun.security
subpackages. This includes
Unlike the JavaSecurity is built around several important
design principles:sun.security.provider package, the classes in the
other sun.security subpackages can be accessed directly.
Architecture and Design
Certain types of data relevant to JavaSecurity, such as
certificates, are often encoded in a variety of formats. In the case
of certificates, JavaSecurity defines a certificate interface, and a
mechanism to dynamically specify which classes to use to parse
certificates. In sun.security we include an X.509
certificate. Another provider may add a PGP or SDSI certificate parser.
The same mechanism is true of keys and of algorithms. That is, JavaSecurity defines an interface for each of these, and a mechanism to dynamically specify which classes to actually use for them.
X.509 and
PKCS#8.
If you develop Java applications and Java applets, you may want to use the Java code signing features. Two sample reasons for using code signing features are the following:
appletviewer
and by the HotJava browser) is aware of
signatures, and, working in conjunction with the javakey tool
(which is used to sign code and specify who is trusted),
will grant special privileges to signed and trusted applet code.
In order to be able to sign code, a developer must first take two basic steps:
After obtaining a private key and a certificate, an application may sign code using them.
One new feature of JDK1.1 is the introduction of Java ARchives (or JAR files), which enable the packaging of class files, images, sounds and other digital data in a single file for faster and easier distribution. A tool included with JDK1.1 allows developers to generate JAR files. This tool is called jar. (See Windows for the Windows version.)
Another addition to JDK1.1 is a tool to manage identities, to generate and manage keys and certificates, and to sign and verify JAR files. The tool, javakey is a simple command-line driven utility which uses a persistent database. (See Windows for the Windows version.)
Signers are real-world entities which can both be authenticated and can produce signatures, i.e., they have both a public key and a private key (for signing) associated with them. To create a signer involves generating (or otherwise associating) a public/private key pair with a name, and possibly associating a set of certificates with the public key.
We expect Java licensees to honor signatures generated using javakey.
The Sun Security Provider for JavaSecurity is the default provider included in JDK 1.1. It implements the following classes:
javakey utility to sign and verify files, and to
manage trust.
The basic mechanism for obtaining an appropriate Signature object
is as follows: A user requests a Signature object by calling the
getSignature method in the Signature class, specifying a
signature algorithm (such as "DSA"), and, optionally, a provider. The
getSignature method finds a Signature subclass
that fits the algorithm and provider parameters supplied. If no
provider is specified, getSignature searches the
registered providers, in preference order, for one with a Signature
subclass implementing the specified algorithm. The provider preference
order is set in the java.security file (and possibly
modified when new providers are added dynamically). See configuration information.
The Key, Identity and IdentityScope classes are used for key, certificate and trust management. Identities are reflections of real-world entities, such as persons, companies and organizations. They have keys, certificates and trust levels (permissions) associated with them. There is a system IdentityDatabase, which holds system identities.
import java.security.Signature;
import java.security.NoSuchAlgorithmException;
public class SignFile {
Signature signature;
private void init(String algorithm)
throws NoSuchAlgorithmException{
signature = Signature.getSignature(algorithm);
}
}
generateKeyPair method on Signature. Let
us assume that we just obtained a DSA (Digital Signature Algorithm)
signature object, and that we would like to generate 1024-bit keys.
First, we must initialize the signature object for generation
of keys of 1024 bits:
signature.initGenerateKeyPair(1024);
Then we can generate the keys:
// seed is a byte array with some random bits from, say, the user.
// we use the random seed to generate the keys.
KeyPair kp = signature.generateKeyPair(seed);
The kp object now contains two keys: a public key and
the associated private key.
java.security classes can. As with key generation,
the Signature object must be initialized for signing before the
signing is actually done:
// initializing the signature object for signing signature.initSign(kp.getPrivate());This will initialize the signature with the private key. Signing is done on a set of bytes. The signing interface is stream-oriented, letting you specify what bytes are to be signed through the update method. There are two types of
update methods, one which works on byte arrays and one which
works on a single byte at a time. Here is an example of the use
of the latter, followed by a call to sign to
calculate and return the signature of all the data:
// signature is an initialized signature object
// fileToSign has the name of the file containing the data bytes
File file = new File(fileToSign);
FileInputStream fis = new FileInputStream(file);
while (fis.available() != 0) {
signature.update(fis.read());
}
byte[] realSignature = signature.sign();
Now suppose that we want to verify whether or not an
alleged signature is in fact the authentic signature of the data
associated with it.
In order to verify the signature, we must first initialize a
signature object for verification. To do so, we call
initVerify with the public key for the
identity whose signature is going to be verified. Assuming that
kp is the key pair for the identity,
kp.getPublicKey() is the public key:
// initialize the signature with the public key for verification
signature.initVerify(kp.getPublicKey());
Then we must read in the bytes of data associated with the alleged signature:
// fileToVerify has the name of the file containing the data bytes
File file = new File(fileToVerify);
FileInputStream fis = new FileInputStream(file);
while (fis.available() != 0) {
signature.update(fis.read());
}
Finally, we verify the authenticity of the alleged signature:
if (signature.verify(allegedSignature)) {
System.out.println("Signature checks out");
} else {
System.out.println("Signature does not check out.");
}