2 * Diffie-Hellman-Merkle key exchange
4 * Copyright (C) 2006-2007 Christophe Devine
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License, version 2.1 as published by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 * http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12)
26 #include "xyssl/config.h"
28 #if defined(XYSSL_DHM_C)
30 #include "xyssl/dhm.h"
35 * helper to validate the mpi size and import it
37 static int dhm_read_bignum( mpi
*X
,
44 return( XYSSL_ERR_DHM_BAD_INPUT_DATA
);
46 n
= ( (*p
)[0] << 8 ) | (*p
)[1];
49 if( (int)( end
- *p
) < n
)
50 return( XYSSL_ERR_DHM_BAD_INPUT_DATA
);
52 if( ( ret
= mpi_read_binary( X
, *p
, n
) ) != 0 )
53 return( XYSSL_ERR_DHM_READ_PARAMS_FAILED
| ret
);
61 * Parse the ServerKeyExchange parameters
63 int dhm_read_params( dhm_context
*ctx
,
69 memset( ctx
, 0, sizeof( dhm_context
) );
71 if( ( ret
= dhm_read_bignum( &ctx
->P
, p
, end
) ) != 0 ||
72 ( ret
= dhm_read_bignum( &ctx
->G
, p
, end
) ) != 0 ||
73 ( ret
= dhm_read_bignum( &ctx
->GY
, p
, end
) ) != 0 )
76 ctx
->len
= mpi_size( &ctx
->P
);
79 return( XYSSL_ERR_DHM_BAD_INPUT_DATA
);
81 n
= ( (*p
)[0] << 8 ) | (*p
)[1];
85 return( XYSSL_ERR_DHM_BAD_INPUT_DATA
);
91 * Setup and write the ServerKeyExchange parameters
93 int dhm_make_params( dhm_context
*ctx
, int x_size
,
94 unsigned char *output
, int *olen
,
95 int (*f_rng
)(void *), void *p_rng
)
97 int i
, ret
, n
, n1
, n2
, n3
;
101 * generate X and calculate GX = G^X mod P
103 n
= x_size
/ sizeof( t_int
);
104 MPI_CHK( mpi_grow( &ctx
->X
, n
) );
105 MPI_CHK( mpi_lset( &ctx
->X
, 0 ) );
108 p
= (unsigned char *) ctx
->X
.p
;
109 for( i
= 0; i
< n
; i
++ )
110 *p
++ = (unsigned char) f_rng( p_rng
);
112 while( mpi_cmp_mpi( &ctx
->X
, &ctx
->P
) >= 0 )
113 mpi_shift_r( &ctx
->X
, 1 );
115 MPI_CHK( mpi_exp_mod( &ctx
->GX
, &ctx
->G
, &ctx
->X
,
116 &ctx
->P
, &ctx
->RP
) );
121 #define DHM_MPI_EXPORT(X,n) \
122 MPI_CHK( mpi_write_binary( X, p + 2, n ) ); \
123 *p++ = (unsigned char)( n >> 8 ); \
124 *p++ = (unsigned char)( n ); p += n;
126 n1
= mpi_size( &ctx
->P
);
127 n2
= mpi_size( &ctx
->G
);
128 n3
= mpi_size( &ctx
->GX
);
131 DHM_MPI_EXPORT( &ctx
->P
, n1
);
132 DHM_MPI_EXPORT( &ctx
->G
, n2
);
133 DHM_MPI_EXPORT( &ctx
->GX
, n3
);
142 return( ret
| XYSSL_ERR_DHM_MAKE_PARAMS_FAILED
);
148 * Import the peer's public value G^Y
150 int dhm_read_public( dhm_context
*ctx
,
151 unsigned char *input
, int ilen
)
155 if( ctx
== NULL
|| ilen
< 1 || ilen
> ctx
->len
)
156 return( XYSSL_ERR_DHM_BAD_INPUT_DATA
);
158 if( ( ret
= mpi_read_binary( &ctx
->GY
, input
, ilen
) ) != 0 )
159 return( XYSSL_ERR_DHM_READ_PUBLIC_FAILED
| ret
);
165 * Create own private value X and export G^X
167 int dhm_make_public( dhm_context
*ctx
, int x_size
,
168 unsigned char *output
, int olen
,
169 int (*f_rng
)(void *), void *p_rng
)
174 if( ctx
== NULL
|| olen
< 1 || olen
> ctx
->len
)
175 return( XYSSL_ERR_DHM_BAD_INPUT_DATA
);
178 * generate X and calculate GX = G^X mod P
180 n
= x_size
/ sizeof( t_int
);
181 MPI_CHK( mpi_grow( &ctx
->X
, n
) );
182 MPI_CHK( mpi_lset( &ctx
->X
, 0 ) );
185 p
= (unsigned char *) ctx
->X
.p
;
186 for( i
= 0; i
< n
; i
++ )
187 *p
++ = (unsigned char) f_rng( p_rng
);
189 while( mpi_cmp_mpi( &ctx
->X
, &ctx
->P
) >= 0 )
190 mpi_shift_r( &ctx
->X
, 1 );
192 MPI_CHK( mpi_exp_mod( &ctx
->GX
, &ctx
->G
, &ctx
->X
,
193 &ctx
->P
, &ctx
->RP
) );
195 MPI_CHK( mpi_write_binary( &ctx
->GX
, output
, olen
) );
200 return( XYSSL_ERR_DHM_MAKE_PUBLIC_FAILED
| ret
);
206 * Derive and export the shared secret (G^Y)^X mod P
208 int dhm_calc_secret( dhm_context
*ctx
,
209 unsigned char *output
, int *olen
)
213 if( ctx
== NULL
|| *olen
< ctx
->len
)
214 return( XYSSL_ERR_DHM_BAD_INPUT_DATA
);
216 MPI_CHK( mpi_exp_mod( &ctx
->K
, &ctx
->GY
, &ctx
->X
,
217 &ctx
->P
, &ctx
->RP
) );
219 *olen
= mpi_size( &ctx
->K
);
221 MPI_CHK( mpi_write_binary( &ctx
->K
, output
, *olen
) );
226 return( XYSSL_ERR_DHM_CALC_SECRET_FAILED
| ret
);
232 * Free the components of a DHM key
234 void dhm_free( dhm_context
*ctx
)
236 mpi_free( &ctx
->RP
, &ctx
->K
, &ctx
->GY
,
237 &ctx
->GX
, &ctx
->X
, &ctx
->G
,
241 #if defined(XYSSL_SELF_TEST)
246 int dhm_self_test( int verbose
)