Articles Index
Cryptography: The Ancient Art of Secret Messages
Monica Pawlan
The word cryptography comes from the Greek words kryptos
meaning hidden and graphein meaning writing. Cryptography is the
study of hidden writing, or the science of encrypting and decrypting text.
Nineteenth century scholars decrypted
ancient Egyptian hieroglyphics when Napoleon's soldiers
found the Rosetta Stone in 1799 near Rosetta, Egypt. Its inscription
praising King Ptolemy V was in three ancient languages: Demotic,
hieroglyphics, and Greek. The scholars who could read ancient Greek,
decrypted the other languages by translating the Greek and comparing
the three inscriptions.
In the twentieth century world of computer networks, messages are digitally
encrypted on the sending side and decrypted on the receiving side using
cryptographic services and algorithms. Algorithms are mathematical techniques
or rules that apply a cryptographic service to a message. Cryptographic services
include hashing a message, encrypting and decrypting a message, and signing or verifying
the signature on a message.
A message digest object uses a hashing algorithm
to make a hash digest of the original message, key pairs use a key
algorithm compatible with the hashing algorithm to encrypt and decrypt the message,
and a signature object uses the key pairs to sign and verify the signature on a
message.
The JavaTM Cryptography Architecture (JCA) framework
in the Java Development Kit (JDKTM) 1.2 provides a
full range of cryptographic services and algorithms to keep messages sent over the
network secure. The framework is extensible and interoperable. Not only can you add
cryptographic service implementations by different vendors to the framework, but, for
example, the signature service implementation by one vendor will work seamlessly with
the signature service implementation by another vendor as long as both vendors'
implementations use the same signature algorithm. Given how implementations can vary
from vendor to vendor, the flexibility built into the JCA framework lets you choose
an implementation that best meets your application requirements.
You will find additional JCA features in Java Cryptography Extension (JCE) 1.2
in a separate download (JDK 1.2 is required). JCE 1.2 provides ciphers (symmetric,
asymmetric, block, and stream), secure Java streams, and key generation.
JCE 1.2 features are not covered in this article.
JCA Cryptographic Services
Cryptographic services include message digests, encryption keys,
digital signatures, and algorithm parameters.
Message Digests:
A message digest is a unique and reliable hash of the message
that lets the receiver know that the message received is the exact
same message that was sent. Every message digest is unique and in no way
reveals anything about the message contents. On the sending side, the
digest is calculated and sent with the message. On the receiving
side, the message hash is calculated again and compared with the hash
received with the message. If the two hashes are the same, it is very unlikely
the message was altered on its way to its destination.
In JDK 1.2 the MessageDigest
class subclasses from the MessageDigestSpi class for backwards
compatibility with JDK 1.1.
Encryption Keys:
An encryption key is a secret value used to encrypt and decrypt
messages or hashes. The key value is known only to the sender and receiver
of the data. When data is encrypted, the key algorithm transforms the
original data to cipher text, and when the data is decrypted, the key
algorithm transforms the cipher text to original text. In the diagram,
the message is hashed and the hash encrypted. The message could be
encrypted too, but is not in this case because the contents of
the message are not private. The hash is encrypted so the receiving side
can verify the message arrived without being altered on its way.
Data is encrypted an decrypted with public and private key
pairs. The private key is kept secret and public key is generally
available. The keys in the pair have a mathematical relationship,
so if you encrypt data with your own private key, the recipient of
the data can decrypt it with your public key. Likewise, anyone can
send another person data encrypted with the recipient's public key,
which the recipient decrypts with the private key. On the sending side,
the data is encrypted with a key and remains inaccessible to anyone
on the receiving side who does not have the other key in the pair to
decrypt the data.
Sometimes certificates are used with keys. A certificate is a digitally
signed statement from a third-party saying the public key of another
party has a particular value. A certificate guards against the possibility
that the encryption key value has been illicitly changed. JDK 1.2. adds the
java.security.cert package so you can create different types of
certificates and manage lists of revoked certificates.
The algorithm in use and secrecy of the private key determine the
effectiveness of the key encryption, or how hard it is to break the
encrypted message. The JCA framework provides classes that let you
obtain keys in the following ways:
- Extract a public key from the
X509Certificate class.
-
Generate public and private key pairs with the
KeyGenerator class.
-
Obtain public and private keys with the
keyFactory class.
Keys are stored in the keystore database, which is a file-based repository
for keys and certificates. JDK 1.2 provides Key Tool to manage the key pairs and
certificates in the keystore database, and the KeyStore class for
developers who want to create a custom keystore database.
Digital Signatures:
A digital signature is added to the encrypted data
after the data is key encrypted to indicate exactly who sent the data and
who is to receive it. On the sending side, the
data is signed, and on the receiving side, the signature on
the data is verified. If the verification succeeds, it is
very likely the sender and receiver are who they are supposed to be.
In the diagram, the hash is key encrypted and signed so the
the receiving side can verify the signature on the hash. The
message could also be signed if needed or desired.
In JDK 1.2 the Signature
class subclasses from the SignatureSpi class for backwards
compatibility.
Algorithm Parameters:
Algorithms are created from values or algorithm parameters.
For example, the Digital Signal Algorithm (DSA) consists of the
parameters P, Q, and G. The DSA specification for a private key consists
of key X and parameters P, Q, and G, and the DSA specification for a
public key consists of key Y and parameters P, Q, and G. In JDK 1.2, you can
access algorithm parameters, get the algorithm name and encoding
format associated with a parameter set, and generate the parameters for a
specified algorithm.
Providers use algorithm parameters to implement
an algorithm-independent key initialization for a key service.
Programmers can use algorithm parameters with the Keyfactory
class to generate a public or private key.
Providers
A provider is a package or set of packages by some vendor that implement cryptographic
services. When you request a cryptographic service in your code, you have two options:
Specify the desired algorithm and let the framework search the available providers
according to a preset preference order, or specify the algorithm and provider.
The JCA framework application programming interfaces (APIs) let you
query the installed providers and algorithms.
Default Provider Package:
The JCA framework has one default provider package, SUN. This package contains
the following:
-
Signature class with the Digital Signal Algorithm (DSA) NIST FIPS 186.
-
MessageDigest class with the Message Digest (MD5) RFC 1321 and Secure Hash Algorithm (SHA-1) NIST FIPS 180-1 message digest algorithms.
-
KeyFactory class with DSA and bidirectional conversions between
a key representation that provides direct access to algorithm parameters (transparent representation).
-
A key representation that provides no direct access (opaque
representation).
Adding New Provider Packages:
You can use the default provider package, install and use provider packages by
other vendors, or create and use your own provider package. Implementations
by different providers can exchange keys and verify each other's signatures
as long as all provider-package implementations keep to the general design
pattern inherent in the JCA interfaces and classes.
All you do is subclass the java.security.Provider class and implement the
cryptographic services you want with the algorithms you need.
A new provider must be installed and configured before it can be used in code.
Here is a list of JCE 1.2 Cryptographic
Service Providers.
Calculating a Message Digest Object
The following code creates a message digest object, supplies the message
data in three arbitrarily sized byte arrays, and calculates the digest,
which has a fixed size. The MessageDigest.getInstance string input
specifies the Secure Hash Algorithm (SHA-1) as defined in Secure Hash
Standard, NIST FIPS 180-1. This is a message digest algorithm that
outputs a 160 bit hash. The provider is not specified.
MessageDigest sha = MessageDigest.getInstance("SHA-1")
sha.update(inputOne);
sha.update(inputTwo);
byte[] hash = sha.digest(inputThree);
Generating Key Pairs
This code creates, initializes, and generates an algorithm-independent
public and private key pair using the DSA algorithm as defined in Digital
Signal Standard, NIST FIPS 186. This algorithm defines a digital signature
algorithm that uses the RawDSA asymmetric transformation with the SHA-1 message
digest algorithm.
The key has a 1024-bit modulus length and a user-derived random
seed. The provider is not specified. A long modulus length with a
random number makes the encryption stronger and the cipher text harder
to break.
Algorithm-dependent key pair generation is possible by passing
algorithm parameters to the KeyGen.initialize method in place
of the modulus length. The modulus length is one of the
algorithm parameters passed.
KeyPairGenerator keyGen =
KeyPairGenerator.getInstance("DSA");
KeyGen.initialize(1024, new SecureRandom(userSeed));
KeyPair pair = KeyGen.generateKeyPair();
Signing Messages and Verifying Signatures
This code creates a Signature object, initializes it with
the private key generated above, and signs the message.
Signature dsa = Signature.getInstance("DSA");
PrivateKey priv = pair.getPrivate();
dsa.initSign(priv);
dsa.update(data);
byte[] sig = dsa.sign();
This code verifies the signature on the data that was signed using the public
key generated in the key pair generation example above.
air.getPublic();
dsa.initVerify(pub);
dsa.update(data);
boolean verifies = dsa.verify(sig);
System.out.println("signature verfies: " + verifies);
Conclusion
The JCA framework gives you a full range of cryptographic services that are flexible
and easy to use. Each service can be used alone or in combination with one or
more other services to create the level of cryptographic security you need.
You can request a cryptographic service by specifying the algorithm
you want and let the framework find the provider, or specify the algorithm and provider
you want. It is easy to add new provider packages so you readily have the service and
algorithm implementations that work best for your application requirements.
Related Links
The JCA API Specification and Reference
covers the information in this article in more detail.
Visit the frequently asked questions (FAQ) on cryptography for more information on cryptography and its uses.
The Security Tools documents provide more information on the keystore database, certificates,
key tool, and writing your own keystore database.
See the JDK 1.2 security features article
for information on the new JDK 1.2 security features and tools as they apply to
end users and system administrators.
Monica Pawlan
is a staff writer on the JDC team.
She has a background in 2D and 3D graphics, security, database
products, and loves to explore emerging technologies.
monica.pawlan@eng.sun.com
Reader Feedback
Tell us what you think of this article.