Javas Role in Authentication

The secret key approach suffers from two problems. First, it requires a separate key for every pair of parties that need to send encrypted data. If you want to send your encrypted credit card data to ten different Internet stores, you would need ten different keys. Worse yet, if you operated an Internet store and had millions of customers, you would need literally millions of keys −− one per customer. Management of such keys is a very difficult problem. The other problem with this approach is coming up with a method for sharing the keys. Its crucial that the key be kept secret, since anyone with the key can decrypt the data to be shared. Hence, you cant simply send the key over the network without somehow encrypting the key itself; doing so would be tantamount to sending the data itself unencrypted. There are engines that perform secure secret key exchange, however; these key exchanges are the basis of many operations, including SSL. Public and private keys can provide asymmetric operation to cryptographic engines. The public key can be used by one party participating in the algorithm, and the private key can be used by the other party. The usefulness of this type of key pair is that one key can be published to the world. You can email your public key to your friends and your enemies, you can put it on a global key server somewhere, you can broadcast it on the Internet −− as long as you dont lose your private key, you can do anything you like with your public key. Then, when someone wants to send you some sensitive information, they can use your public key to encrypt the data −− and, as long as you have kept your private key private, youll be the only one who is actually able to decrypt the data. Similarly, when you want to send sensitive data to someone, all you need is their public key; when the data has been encrypted with the public key, you know that only the holder of the private key will be able to read what youve sent her. In the area of digital signatures, this key ordering is reversed: you sign a document with your private key, and the recipient of the document needs your public key in order to verify the digital signature. Public key encryption is not without its key management problems as well, however. When you receive a digitally signed document, you need the public key of the signer of the document. The mechanism to obtain that key is very fluid; there are a number of proposals for centralized key warehouses that would hold public keys and for methods to access those keys, but the infrastructure to make this all a reality is not really in place. Hence, users of public keys have adopted a variety of techniques for obtaining the public keys.

7.3.2 Message Digests

The second engines that well examine deal with message digests. A message digest is the digital fingerprint we alluded to earlier. Conceptually, a message digest is a small sequence of bytes that is produced when a given set of data is passed through the message digest engine. Unlike other cryptographic engines, a message digest engine does not always require a key to operate; some do, and some do not. A message digest engine takes a single stream of data as its input and produces a single output. We call the output a message digest or simply a digest, or a hash, and we say that the digest represents the input data. The digest that corresponds to a particular set of data does not reflect any information about that data −− in particular, there is no way to tell from a digest how much data it represents or what the data actually was. A message digest is useful only when the data it represents is also available. If you want to determine whether a particular digest represents a particular set of data, you must recalculate the digest and compare the newly calculated digest with the original digest. If the two are equal, youve verified that the original digest does indeed represent the given set of data. Data that is fed into a message digest engine is always treated as an ordered set of bytes. If even one byte of the data is altered or absent or presented out of order, the digest will be different. Hence, a typical message digest algorithm has an internal accumulator that operates on all data fed into the engine. As each byte of data is fed into the engine, it is combined with the data in the accumulator to produce a new value, which is stored in the accumulator to provide input see Figure 7−3. Figure 7−3. The message digest accumulator As a simple example, consider a message digest algorithm based on the exclusive−or of all the input bytes. The accumulator starts with a value of 0. If the string O Time, thou must untangle this is passed to the engine, the engine considers the bytes one at a time. [1] The first byte, O, has a value of 0x4f, which will xor with the accumulator to provide a value of 0x4f. The next byte, a space 0x20, will xor with the accumulator to produce a value of 0x6f. And so on, such that the final result of the accumulator is 0x67. [1] Dont be confused by the fact that were dealing in bytes here when the characters in a Java string are two bytes long. The data passed to the message digest engine is treated as arbitrary binary data −− it doesnt matter if the data was originally ASCII that is, byte−oriented data, a Java character string, or a binary class file. There are a few differences between this example and a real message digest algorithm. First, standard algorithms typically operate on 4− or 8−byte quantities, so the bytes that are fed into the engine are first grouped into int s or long s, with padding added if the input data is not a multiple of the desired quantity. Second, they produce a digest that is usually 64 or 128 bits long rather than a single byte; this final digest may be the value left in the accumulator or it may be the value left in the accumulator subjected to additional operations. The difference in the output size is one of the crucial differences. At best, the example we just walked through could produce 256 different digests. Any two given inputs have a 1 in 256 chance of producing the same digest, which is clearly not a sufficient guarantee that a digest represents a given set of data. In the example above, the string O Time, thou must untangle this produced a digest of 0x67 −− but so does the string g. An algorithm that produces a 64−bit digest, on the other hand, produces over 18 quintillion unique digests, so the odds that two data sequences will produce the same digest are very remote indeed. This brings us to another of the crucial differences −− a successful message digest algorithm must provide an assurance that it is computationally infeasible to find two messages that produce the same digest. This ensures that a new set of data cannot be substituted for the original data so that each produces the same digest. Note also that a message digest in itself is not a secure entity. A digest is often provided with the data it represents; the recipient of the data then recalculates the digest to make sure that the data was not originally tampered with. But nothing in this scenario prevents someone from modifying both the original data and the digest since both are transmitted and since the calculation of the digest is a well−known operation requiring no key. However, secure message digests can be produced when you introduce a key into the mix; these types of digests are called message authentication codes.