00001 /* 00002 * Diffie-Hellman-Merkle key exchange 00003 * 00004 * Copyright (C) 2006-2007 Christophe Devine 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License along 00017 * with this program; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00019 */ 00020 /* 00021 * Reference: 00022 * 00023 * http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12) 00024 */ 00025 00026 #include "xyssl/config.h" 00027 00028 #if defined(XYSSL_DHM_C) 00029 00030 #include "xyssl/dhm.h" 00031 00032 #include <string.h> 00033 00034 /* 00035 * helper to validate the mpi size and import it 00036 */ 00037 static int dhm_read_bignum( mpi *X, 00038 unsigned char **p, 00039 unsigned char *end ) 00040 { 00041 int ret, n; 00042 00043 if( end - *p < 2 ) 00044 return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); 00045 00046 n = ( (*p)[0] << 8 ) | (*p)[1]; 00047 (*p) += 2; 00048 00049 if( (int)( end - *p ) < n ) 00050 return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); 00051 00052 if( ( ret = mpi_read_binary( X, *p, n ) ) != 0 ) 00053 return( XYSSL_ERR_DHM_READ_PARAMS_FAILED | ret ); 00054 00055 (*p) += n; 00056 00057 return( 0 ); 00058 } 00059 00060 /* 00061 * Parse the ServerKeyExchange parameters 00062 */ 00063 int dhm_read_params( dhm_context *ctx, 00064 unsigned char **p, 00065 unsigned char *end ) 00066 { 00067 int ret, n; 00068 00069 memset( ctx, 0, sizeof( dhm_context ) ); 00070 00071 if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || 00072 ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || 00073 ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 ) 00074 return( ret ); 00075 00076 ctx->len = mpi_size( &ctx->P ); 00077 00078 if( end - *p < 2 ) 00079 return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); 00080 00081 n = ( (*p)[0] << 8 ) | (*p)[1]; 00082 (*p) += 2; 00083 00084 if( end != *p + n ) 00085 return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); 00086 00087 return( 0 ); 00088 } 00089 00090 /* 00091 * Setup and write the ServerKeyExchange parameters 00092 */ 00093 int dhm_make_params( dhm_context *ctx, int x_size, 00094 unsigned char *output, int *olen, 00095 int (*f_rng)(void *), void *p_rng ) 00096 { 00097 int i, ret, n, n1, n2, n3; 00098 unsigned char *p; 00099 00100 /* 00101 * generate X and calculate GX = G^X mod P 00102 */ 00103 n = x_size / sizeof( t_int ); 00104 MPI_CHK( mpi_grow( &ctx->X, n ) ); 00105 MPI_CHK( mpi_lset( &ctx->X, 0 ) ); 00106 00107 n = x_size >> 3; 00108 p = (unsigned char *) ctx->X.p; 00109 for( i = 0; i < n; i++ ) 00110 *p++ = (unsigned char) f_rng( p_rng ); 00111 00112 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) 00113 mpi_shift_r( &ctx->X, 1 ); 00114 00115 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, 00116 &ctx->P , &ctx->RP ) ); 00117 00118 /* 00119 * export P, G, GX 00120 */ 00121 #define DHM_MPI_EXPORT(X,n) \ 00122 MPI_CHK( mpi_write_binary( X, p + 2, n ) ); \ 00123 *p++ = (unsigned char)( n >> 8 ); \ 00124 *p++ = (unsigned char)( n ); p += n; 00125 00126 n1 = mpi_size( &ctx->P ); 00127 n2 = mpi_size( &ctx->G ); 00128 n3 = mpi_size( &ctx->GX ); 00129 00130 p = output; 00131 DHM_MPI_EXPORT( &ctx->P , n1 ); 00132 DHM_MPI_EXPORT( &ctx->G , n2 ); 00133 DHM_MPI_EXPORT( &ctx->GX, n3 ); 00134 00135 *olen = p - output; 00136 00137 ctx->len = n1; 00138 00139 cleanup: 00140 00141 if( ret != 0 ) 00142 return( ret | XYSSL_ERR_DHM_MAKE_PARAMS_FAILED ); 00143 00144 return( 0 ); 00145 } 00146 00147 /* 00148 * Import the peer's public value G^Y 00149 */ 00150 int dhm_read_public( dhm_context *ctx, 00151 unsigned char *input, int ilen ) 00152 { 00153 int ret; 00154 00155 if( ctx == NULL || ilen < 1 || ilen > ctx->len ) 00156 return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); 00157 00158 if( ( ret = mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) 00159 return( XYSSL_ERR_DHM_READ_PUBLIC_FAILED | ret ); 00160 00161 return( 0 ); 00162 } 00163 00164 /* 00165 * Create own private value X and export G^X 00166 */ 00167 int dhm_make_public( dhm_context *ctx, int x_size, 00168 unsigned char *output, int olen, 00169 int (*f_rng)(void *), void *p_rng ) 00170 { 00171 int ret, i, n; 00172 unsigned char *p; 00173 00174 if( ctx == NULL || olen < 1 || olen > ctx->len ) 00175 return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); 00176 00177 /* 00178 * generate X and calculate GX = G^X mod P 00179 */ 00180 n = x_size / sizeof( t_int ); 00181 MPI_CHK( mpi_grow( &ctx->X, n ) ); 00182 MPI_CHK( mpi_lset( &ctx->X, 0 ) ); 00183 00184 n = x_size >> 3; 00185 p = (unsigned char *) ctx->X.p; 00186 for( i = 0; i < n; i++ ) 00187 *p++ = (unsigned char) f_rng( p_rng ); 00188 00189 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) 00190 mpi_shift_r( &ctx->X, 1 ); 00191 00192 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, 00193 &ctx->P , &ctx->RP ) ); 00194 00195 MPI_CHK( mpi_write_binary( &ctx->GX, output, olen ) ); 00196 00197 cleanup: 00198 00199 if( ret != 0 ) 00200 return( XYSSL_ERR_DHM_MAKE_PUBLIC_FAILED | ret ); 00201 00202 return( 0 ); 00203 } 00204 00205 /* 00206 * Derive and export the shared secret (G^Y)^X mod P 00207 */ 00208 int dhm_calc_secret( dhm_context *ctx, 00209 unsigned char *output, int *olen ) 00210 { 00211 int ret; 00212 00213 if( ctx == NULL || *olen < ctx->len ) 00214 return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); 00215 00216 MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X, 00217 &ctx->P, &ctx->RP ) ); 00218 00219 *olen = mpi_size( &ctx->K ); 00220 00221 MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) ); 00222 00223 cleanup: 00224 00225 if( ret != 0 ) 00226 return( XYSSL_ERR_DHM_CALC_SECRET_FAILED | ret ); 00227 00228 return( 0 ); 00229 } 00230 00231 /* 00232 * Free the components of a DHM key 00233 */ 00234 void dhm_free( dhm_context *ctx ) 00235 { 00236 mpi_free( &ctx->RP, &ctx->K, &ctx->GY, 00237 &ctx->GX, &ctx->X, &ctx->G, 00238 &ctx->P, NULL ); 00239 } 00240 00241 #if defined(XYSSL_SELF_TEST) 00242 00243 /* 00244 * Checkup routine 00245 */ 00246 int dhm_self_test( int verbose ) 00247 { 00248 return( verbose++ ); 00249 } 00250 00251 #endif 00252 00253 #endif