Keys are a necessary component of many cryptographic algorithms −− in particular, keys are required to create and verify digital signatures or to perform encryption. Different algorithms require different keys.
There are two general types of keys:
Asymmetric
Symmetric.
Asymmetric keys come in two types as well, public and private. A public key and a private key are related and are referred to as a key pair.
Symmetric keys are also called secret keys.
when public keys are transmitted electronically, they are often embedded within certificates
Keys and certificates are normally associated with some person or organization, and the way in which keys are stored, transmitted, and shared is an important topic in the security package.
The security providers that come with Sun's implementation of Java provide two types of asymmetric keys:DSA and RSA.
JCE provides an additional type of asymmetric key: Diffie−Hellman. Each of these have their own interface that allows you to determine fundamental information about the key. For most programmers,
however, keys are opaque objects, and the algorithm−specific features of keys are not needed (except in certain cases when you need to transfer keys).
Certificates
When you are given a public and private key, you often need to provide other people with your public key. If you sign a digital document (using your private key), the recipient of that document will need your public key in order to verify your digital signature.
The inherent problem with a key is that it does not provide any information about the identity to which it belongs; a key is really just a sequence of seemingly arbitrary numbers. If I want you to accept a document
that I digitally signed, I could mail you my public key, but you normally have no assurance that the key (and the original email) came from me at all. I could, of course, digitally sign the email so that you knew that it
came from me, but there's a circular chain here −− without my public key, you cannot verify the digital signature. You would need my public key in order to authenticate the public key I've just sent you.
Certificates solve this problem by having a well−known entity (called a certificate authority, or CA) verify the public key that is being sent to you. A certificate can give you the assurance that the public key in the
certificate does indeed belong to the entity that the certificate authority says it does. However, the certificate only validates the public key it contains: just because Fred sends you his public key in a valid certificate does not mean that Fred is to be trusted; it only means that the public key in question does in fact belong to Fred.
In practice, the key may not belong to Fred at all; certificate authorities have different levels at which they assess the identity of the entity named in the certificate. Some of these levels are very stringent and require the CA to do an extensive verification that Fred is who he says he is. Other levels are not stringent at all, and if Fred can produce a few dollars and a credit card, he is assumed to be Fred. Hence, one of the steps in the process of deciding whether or not to trust the entity named in the certificate includes the level at which the certificate authority generated the certificate. Each certificate authority varies in its approach to validating identities, and each publishes its approach to help you understand the potential risks involved in accepting such a certificate.
A certificate contains three pieces of information :
· The name of the entity for whom the certificate has been issued. This entity is referred to as the subject of the certificate.
· The public key associated with the subject.
. A digital signature that verifies the information in the certificate. The certificate is signed by the issuer of the certificate.
Consider the security necessary to support XYZ Corporation's payroll application. When an employee wants to view her payroll statements, she must submit a digitally signed request to do so. Hence, XYZ should
distribute to each employee a private key to be used to create the digital signature. XYZ can also store the employee's public keys in a database; when a request comes that claims to be from a particular employee, the payroll server can simply examine the database to obtain that employee's public key and verify the signature. No certificate is required in this case −− and in general, no certificate is required when the recipient of the digital signature is already known to have the public key of the entity that signed the data. For applications within a corporation, this is almost always the case.
Key Management Terms
There are a number of terms that are important in our discussion of Java's key management facilities:
keystore
The keystore is the file that actually holds the set of keys and certificates. By convention, this file is called .keystore and is held in the user's home directory ($HOME on Unix systems, C:\WINDOWS on
Microsoft Windows systems, and so on). However, there is great flexibility about where this file is located: the key management tools allow you to specify the location of the file, and the key management API allows you to use any arbitrary input stream. In fact, at the end of this chapter we'll discuss how the set of keys may be held in a persistent store like a centralized database.
alias
Every key in the keystore belongs to an entity. An alias is a shortened, keystore−specific name for an entity that has a key or certificate in the keystore. I choose to store my public and private key in my
local keystore under the alias "sdo"; if you have a copy of my public key certificate, you may use that alias, or you may use another alias (like "ScottOaks"). The alias used for a particular entity is
completely up to the discretion of the individual who first enters that entity into the keystore.
DN (distinguished name)
The distinguished name for an entity in the keystore is a subset of its full X.500 name. This is a long string; for example,
my DN is: CN=Scott Oaks, OU=JSD, O=Sun Microsystems, L=New York, S=NY, C=US
DNs are used by certificate authorities to refer to the entities to whom they supply a certificate. Hence, unlike an alias, the DN for a particular key is the same no matter what keystore it is located in: if I send you my public key, it will have the DN encoded in the public key's certificate.
However, nothing prevents me from having two public keys with different DNs (I might have one for personal use that omits references to my place of employment). And there is no guarantee that two unrelated individuals will not share the same DN (in fact, you can count on this type of namespace collision to occur).
The common name (CN) within a DN is usually the domain name of the organization to which the certificate belongs. In fact, SSL uses this convention to verify the identity of the server to which it connects.
X509 certificates (and many other ANSI standards) make use of the idea of a distinguished name (usually referred to as a DN). The distinguished name of an individual includes these fields:
Common name (CN)
The (full) common name of the individual.
Organizational unit (OU)
The unit the individual is associated with.
Organization (O)
The organization the individual is associated with.
Location (L)
The city where the individual is located.
State (S)
The state/province where the individual is located.
Country (C)
The country where the individual is located.
The DN specification allows other fields as well, although these are the only fields used internally in Java. The organization that is associated with an individual is typically the company the individual works for, but it can be any other organization (and of course, you may not be associated with an organization under a variety of circumstances).
The idea behind a DN is that it limits name duplication to some extent. There are other people named Scott Oaks in the world, but only one who has a
DN of: CN=Scott Oaks, OU=JSD, O=Sun Microsystems, L=NY, S=NY, C=US
key entries
A keystore may hold two types of entries. The first type of entry is called a key entry. A key entry may hold either an asymmetric key pair (private key and public key certificate) or a single secret key.
If the entry holds a key pair, it may store a chain of certificates: the first certificate always contains the public key of the entity. Other certificates may be present that establish a chain to the root
certificate of the CA that issued the entity's certificate.
certificate entries
A certificate entry contains only a public key certificate; there is no private key associated with this entry. Certificate entries hold a single certificate rather than a chain, and the certificate is self−signed.
These certificates are generally the root certificates of certificate authorities that you trust to issue certificates.
JKS, JCEKS, and PKCS12
The keystore is an engine within the Java API, and Sun's various security providers supply three different algorithms of the keystore. The default algorithm is JKS and is supplied by the security
manager within the core API. It is capable of reading and storing key entries and certificate entries; however, the key entries can store only private keys. If you want to use the keystore for secret keys,
you must use the JCEKS implementation, which is supplied by the security provider that comes with JCE. The JCEKS keystore can hold either private or secret keys for each key entry.
The private keys held by JKS or JCEKS are encrypted. The encryption used by JKS is weaker than that used by JCEKS; it was designed to pass the old export restrictions of the U.S. The JCEKS
keystore provides a much stronger encryption.
For these two reasons, JCEKS is a preferable keystore; for compatibility reasons the default keystore remains JKS. Both the Java key management API and keytool allow you to specify the algorithm
name when operating on a keystore, so you can use either algorithm at any time. However, if you want to change the default algorithm, you can edit the $JREHOME/lib/security/java.security file, find
the entry for keystore.type, and change it to read:
keystore.type=JCEKS
The PKCS12 algorithm does not supply a fully−functional keystore. You can read a keystore in this format and export information (such as the encoded certificate) from that keystore, but you cannot
write or modify a keystore in that format. This format is used to import certificates from your Netscape browser into your Java keystore, as we'll show a little later.
Trusted certificate authorities
Sun's implementation of Java comes with a set of trusted certificates from known certificate authorities. These certificates are held in $JREHOME/lib/security/cacerts, which is itself a keystore.
That keystore holds ten certificate entries, each of which is the root certificate of a CA. This keystore should usually be considered read−only: you'll use it when you want to verify a certificate that was
issued by one of these CAs, but you should not add your own key entries to this keystore.
The SunJCE security provider implements one key agreement algorithm: Diffie−Hellman key agreement. This key agreement is based on the following protocol:
1. Alice (the first party in the exchange) generates a Diffie−Hellman public key/private key pair.Alice transmits the public key and the algorithm specification of the key pair to Bob (the second party
in the exchange).
2.Bob uses the algorithm specification to generate his own public and private keys; he sends the public key to Alice.
3.Alice uses her private key and Bob's public key to create a secret key. In the KeyAgreement class, this requires two phases: one that uses her private key and one that uses her public key.
4. Bob performs the same operations with his private key and Alice's public key. Due to the properties of a Diffie−Hellman key pair, this generates the same secret key Alice generated.
5. This secret key can then be used for a variety of operations: it can be used directly for creating MACs, or it
can be converted into a DES key for use in a cipher
Nothing in this key agreement protocol prevents someone from impersonating Bob −− Alice could exchange keys with me, I could say that I am Bob, and then Alice and I could exchange encrypted data. So even though the transmissions of the public keys do not need to be encrypted, they should be signed for maximum safety
This algorithm works because of the properties of the Diffie−Hellman public key/private key pair. These keys are not suitable for use in an encryption algorithm; they are used only in a key agreement such as this.
Secure Message Digests
The message digest by itself does not give us a very high level of security. We can tell whether somehow the output file in this example has been corrupted because the text that we read in won't produce the same message digest that was saved with the file. But there's nothing to prevent someone from changing both the text and the digest stored in the file in such a way that the new digest reflects the altered text.
A secure message digest is called a Message Authentication Code (MAC). A MAC has the property that it cannot be created solely from the input data; it requires a secret key that is shared by the sender and receiver. Hence, an intermediate party cannot change both the data and the MAC without the receiver detecting that the data has been corrupted
The Mac Class
The Mac class (javax.crypto.Mac) is part of the Java Cryptography Extension because it involves a cryptographic operation: a secret key is used to calculate the message digest. This mean that in order to use
the Mac class, both sender and receiver must agree upon which secret key to use. that means the sender and receiver must have previously exchanged and stored secret keys, either using a Diffie−Hellman key exchange or another means.
Sun's implementation of JCE provides two algorithms for calculating a MAC: HmacSHA1 and HmacMD5, each of which is based on its respective message digest.
Calculating Your Own MAC
A second way to create a MAC is to calculate one directly. This requires that both the sender and receiver of the data have a shared passphrase that they have kept secret, though that's often easier than sharing a secret key.
Using this passphrase, calculating a MAC requires that we:
1.Calculate the message digest of the secret passphrase concatenated with the data:
MessageDigest md = MessageDigest.getInstance("SHA");
String data = "This have I thought good to deliver thee, that thou mightst not lose the dues of rejoicing by being ignorant of what greatness is promised thee.";
String passphrase = "Sleep no more";
byte dataBytes[] = data.getBytes( );
byte passBytes[] = passphrase.getBytes( );
md.update(passBytes);
md.update(dataBytes);
byte digest1[] = md.digest( );
2. Calculate the message digest of the secret passphrase concatenated with the just−calculated digest:
md.update(passBytes);
md.update(digest1);
byte mac[] = md.digest( );
As long as we use exactly the same data for the passphrase in both the transmitting and receiving class, the message digests (that is, the MACs) still compare as equal. That gives a certain level of security to the
message digest, but it requires that the sender and the receiver agree on what data to use for the passphrase; the passphrase cannot be transmitted along with the text. In this case, the security of the message digest depends upon the security of the passphrase. Normally, of course, you would prompt for that passphrase rather than hardcoding into the source as we've done above. In addition, a good passphrase would not be a well−known string such as we've selected; it would be random bytes (and hence indistinguishable from a secret key).
The Signature Class
When you handle digital signatures programatically, you perform two operations on them. You create them by taking a piece of data, creating a message digest of the data, and signing the message digest with a private key. The digitally signed data is then transmitted to someone else, who must verify the digital signature by creating a message digest of the data and verifying the signed digest using a public key. All of these
operations are embodied within the Signature class (java.security.Signature):
In order to create the digital signature we must accomplish the following:
Obtain the private key that is used to sign the data. Here we're using the keystore handler we wrote previously and the command−line arguments to obtain the alias and password of the private key we
want to use.
1. Obtain a signing object via the getInstance( ) method and initialize it. Since we're creating a signature in this example, we use the initSign( ) method for initialization.
2. Pass the data to be signed as a series of bytes to the update( ) method of the signing object.Multiple calls could be made to the update( ) method even though in this example we only need one.
3. Obtain the signature by calling the sign( ) method. We save the signature bytes and write them to a file with the data so that the data and the signature can be retrieved at a later date.
The process of verifying the signature still requires four steps. The major differences are that in step two, we initialize the signing object for verification by using the initVerify( ) method, and in step four, we
verify (rather than create) the existing signature by using the verify( ) method. Note that we still have to know who signed the message in order to look up the correct key