Generating and Exchanging Parameters

186 Diffie-Hellman guarantees a shared secret will be created that is suitable to use as the key to a symmetric algorithm. Failing to provide authentication through some other means, either with authenticated extensions to the implementation or through use of another algorithm such as DSA, leaves the protocol susceptible to man-in-the-middle attacks. Well discuss the details of this type of attack with regard to Diffie-Hellman toward the end of this section.

8.2.1 The Basics

The low-level interface to Diffie-Hellman provided by OpenSSL consists of a structure of the type DH and a set of functions that operate on that structure. The DH structure and functions are made accessible by including the openssldh.h header file. The DH structure itself contains many data members that are of little or no interest to us, but four members are important, as shown in the following abbreviated DH structure definition: typedef struct dh_st { BIGNUM p; BIGNUM g; BIGNUM pub_key; BIGNUM priv_key; } DH; The p and g members, known as Diffie-Hellman parameters, are public values that must be shared between the two parties using the algorithm to create a shared secret. Because theyre public values, no harm will come from a potential attacker discovering them, which means that they can be agreed upon beforehand or exchanged over an insecure medium. Typically, one side of the conversation generates the parameters and shares them with the peer. The p member is a prime number that is randomly generated. For temporary keys, it is typically at least 512 bits in length, whereas persistent keys should more appropriately be at least 1,024 bits. These sizes correspond to the notion of ephemeral and static keys presented in Chapter 5 . The prime that will be used for p is generated such that p-12 is also prime. Such a prime is known as a safe or strong prime . The g member, also known as the generator, is usually a small number greater than one. OpenSSL functions best when this number is either two or five. A value of two is sometimes used for performance reasons, but keep in mind that faster key generation also means that an attacker can break the algorithm faster. In general, we recommend that a value of five be used. Using the two public parameters, p and g , each pair chooses a random large integer for the priv_key member. A value for the pub_key member is computed from the priv_key member and shared with the peer. It is important that only the value of the pub_key member be shared. The value of the priv_key member should never be shared. Using the values of priv_key and the peers pub_key , each peer can independently compute the shared secret. The shared secret is suitable for use as the key for a symmetric cipher. The entire exchange between the peers can be done over an insecure medium. Even if someone captures the parameter and key exchange, the attacker will not be able to determine the shared secret.

8.2.2 Generating and Exchanging Parameters

Diffie-Hellman requires that both parties involved in the key exchange use the same parameters to generate public keys. This means the parameters either need to be agreed upon and exchanged before the conversation begins, or the parameters must be generated and exchanged as part of the key exchange. Either way, the parameters must first be generated by one party and given to the other, or perhaps generated by a third party and given to both. For the purposes of this discussion, 187 we will assume that the generation of the parameters will be done as part of the key exchange process, although this is often not desirable because it can take a significant amount of time to generate the parameters. The participants in the key agreement must first agree which party will be responsible for generating the parameters that theyll both use. In a clientserver scenario, the parameters are usually generated by the server. Often, the server will generate the parameters when it starts up or retrieve them from a file that contains already generated parameters, and use the same parameters for each client that connects. It is also common for both the client and server to have a copy of the parameters built into the respective applications. OpenSSL provides the function DH_generate_parameters , which will create a new DH object that is initialized with fresh values for p and g . The generation of the parameters generates a value only for p . The value of g is specified by the caller and is not chosen randomly by OpenSSL. The value of g should be a small number greater than one, usually either two or five. DH DH_generate_parametersint prime_len, int generator, void callbackint, int, void , void cb_arg; prime_len The size of the prime to be generated, specified in terms of bits. generator The value to be used for g . In general, either DH_GENERATOR_2 or DH_GENERATOR_5 should be used for this argument. callback A pointer to a function that will be called during the prime generation process to report the status of the prime generation. The callback is the same as the callback used by BN_generate_prime , which we discussed in Chapter 4 . In fact, DH_generate_parameters uses BN_generate_prime , and it is BN_generate_prime that actually makes the calls to the callback function. This argument may be specified as NULL if no callbacks are desired. cb_arg A pointer to application-specific data. OpenSSL does not use this value for anything itself. It is used only when passed as an argument to the specified callback function. Using the generation function alone can be dangerous. While the generation function does have validity checks for the prime that it generates, it could generate a prime that is not suitable for use with the algorithm. For this reason, the function DH_check should always be used to ensure that the generated prime is suitable. int DH_checkDH dh, int codes; dh The DH object containing the parameters we wish to check. codes 188 An integer that will be treated as a bit mask by DH_check and will contain the results of the check when the function returns successfully. If the function encounters an error unrelated to the validity of the generated prime, the return will be zero; otherwise, it will be nonzero. When the function returns successfully, the codes argument will contain a bit mask that indicates whether the parameters are suitable for use or not. If none of the bits is set, the parameters should be considered suitable for use. If any of the following bits are set, the parameters may not be suitable for use. In most cases, the parameters should be thrown away, and new ones should be generated. DH_CHECK_P_NOT_PRIME If this bit is set, it indicates that the generated prime is not actually a prime number. Ordinarily, this bit should never be set when the parameters are generated using DH_generate_parameters , but it could very well be set when checking parameters retrieved from disk or from a peer. DH_CHECK_P_NOT_SAFE_PRIME If this bit is set, it indicates that the generated prime is not safe. That is, p-12 is not also a prime number. As with DH_CHECK_P_NOT_PRIME , this bit should never be set when the parameters were generated using DH_generate_parameters , but it could very well be set when checking parameters retrieved from disk or from a peer. DH_NOT_SUITABLE_GENERATOR If this bit is set, it indicates that the generated prime and the generator are not suitable for use together. The parameters dont necessarily need to be thrown away and regenerated if this bit is set. Instead, the generator could be changed and the check retried. DH_UNABLE_TO_CHECK_GENERATOR If this bit is set, a nonstandard generator is being used, so the DH_check function is unable to check to see that the prime and the generator are suitable for use. If you know that youve set a nonstandard generator intentionally, its up to you to decide whether it is safe to ignore this bit being set or not. Once the parameters have been generated, they can be transmitted to the peer. The details of how the data is sent depend on the medium that is being used for the exchange. To transmit the parameters over a TCP connection, the BIGNUM functions BN_bn2bin and BN_bin2bn are obvious candidates. The party that generates the parameters calls DH_generate_parameters to obtain a DH object. The party that is receiving the parameters must also obtain a DH object. This is easily done by calling the function DH_new , which will allocate and initialize a new DH object. The parameters that are received from the peer can then be directly assigned to the DH objects p and g data members, using the appropriate BIGNUM functions. When were done with a DH object, we must be sure to destroy it by calling the function DH_free , and passing the pointer returned by either DH_generate_parameters or DH_new as the only argument.

8.2.3 Computing Shared Secrets