blob: 4fff264881c895cc0d94effb92bb46818f26695b [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Diffie-Hellman-Merkle key exchange
3 *
4 * Copyright (C) 2006-2007 Christophe Devine
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20/*
21 * Reference:
22 *
23 * http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12)
24 */
25
26#include "xyssl/config.h"
27
28#if defined(XYSSL_DHM_C)
29
30#include "xyssl/dhm.h"
31
32#include <string.h>
33
34/*
35 * helper to validate the mpi size and import it
36 */
37static int dhm_read_bignum( mpi *X,
38 unsigned char **p,
39 unsigned char *end )
40{
41 int ret, n;
42
43 if( end - *p < 2 )
44 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
45
46 n = ( (*p)[0] << 8 ) | (*p)[1];
47 (*p) += 2;
48
49 if( (int)( end - *p ) < n )
50 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
51
52 if( ( ret = mpi_read_binary( X, *p, n ) ) != 0 )
53 return( XYSSL_ERR_DHM_READ_PARAMS_FAILED | ret );
54
55 (*p) += n;
56
57 return( 0 );
58}
59
60/*
61 * Parse the ServerKeyExchange parameters
62 */
63int dhm_read_params( dhm_context *ctx,
64 unsigned char **p,
65 unsigned char *end )
66{
67 int ret, n;
68
69 memset( ctx, 0, sizeof( dhm_context ) );
70
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 )
74 return( ret );
75
76 ctx->len = mpi_size( &ctx->P );
77
78 if( end - *p < 2 )
79 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
80
81 n = ( (*p)[0] << 8 ) | (*p)[1];
82 (*p) += 2;
83
84 if( end != *p + n )
85 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
86
87 return( 0 );
88}
89
90/*
91 * Setup and write the ServerKeyExchange parameters
92 */
93int dhm_make_params( dhm_context *ctx, int x_size,
94 unsigned char *output, int *olen,
95 int (*f_rng)(void *), void *p_rng )
96{
97 int i, ret, n, n1, n2, n3;
98 unsigned char *p;
99
100 /*
101 * generate X and calculate GX = G^X mod P
102 */
103 n = x_size / sizeof( t_int );
104 MPI_CHK( mpi_grow( &ctx->X, n ) );
105 MPI_CHK( mpi_lset( &ctx->X, 0 ) );
106
107 n = x_size >> 3;
108 p = (unsigned char *) ctx->X.p;
109 for( i = 0; i < n; i++ )
110 *p++ = (unsigned char) f_rng( p_rng );
111
112 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
113 mpi_shift_r( &ctx->X, 1 );
114
115 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
116 &ctx->P , &ctx->RP ) );
117
118 /*
119 * export P, G, GX
120 */
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;
125
126 n1 = mpi_size( &ctx->P );
127 n2 = mpi_size( &ctx->G );
128 n3 = mpi_size( &ctx->GX );
129
130 p = output;
131 DHM_MPI_EXPORT( &ctx->P , n1 );
132 DHM_MPI_EXPORT( &ctx->G , n2 );
133 DHM_MPI_EXPORT( &ctx->GX, n3 );
134
135 *olen = p - output;
136
137 ctx->len = n1;
138
139cleanup:
140
141 if( ret != 0 )
142 return( ret | XYSSL_ERR_DHM_MAKE_PARAMS_FAILED );
143
144 return( 0 );
145}
146
147/*
148 * Import the peer's public value G^Y
149 */
150int dhm_read_public( dhm_context *ctx,
151 unsigned char *input, int ilen )
152{
153 int ret;
154
155 if( ctx == NULL || ilen < 1 || ilen > ctx->len )
156 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
157
158 if( ( ret = mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
159 return( XYSSL_ERR_DHM_READ_PUBLIC_FAILED | ret );
160
161 return( 0 );
162}
163
164/*
165 * Create own private value X and export G^X
166 */
167int dhm_make_public( dhm_context *ctx, int x_size,
168 unsigned char *output, int olen,
169 int (*f_rng)(void *), void *p_rng )
170{
171 int ret, i, n;
172 unsigned char *p;
173
174 if( ctx == NULL || olen < 1 || olen > ctx->len )
175 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
176
177 /*
178 * generate X and calculate GX = G^X mod P
179 */
180 n = x_size / sizeof( t_int );
181 MPI_CHK( mpi_grow( &ctx->X, n ) );
182 MPI_CHK( mpi_lset( &ctx->X, 0 ) );
183
184 n = x_size >> 3;
185 p = (unsigned char *) ctx->X.p;
186 for( i = 0; i < n; i++ )
187 *p++ = (unsigned char) f_rng( p_rng );
188
189 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
190 mpi_shift_r( &ctx->X, 1 );
191
192 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
193 &ctx->P , &ctx->RP ) );
194
195 MPI_CHK( mpi_write_binary( &ctx->GX, output, olen ) );
196
197cleanup:
198
199 if( ret != 0 )
200 return( XYSSL_ERR_DHM_MAKE_PUBLIC_FAILED | ret );
201
202 return( 0 );
203}
204
205/*
206 * Derive and export the shared secret (G^Y)^X mod P
207 */
208int dhm_calc_secret( dhm_context *ctx,
209 unsigned char *output, int *olen )
210{
211 int ret;
212
213 if( ctx == NULL || *olen < ctx->len )
214 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
215
216 MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X,
217 &ctx->P, &ctx->RP ) );
218
219 *olen = mpi_size( &ctx->K );
220
221 MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) );
222
223cleanup:
224
225 if( ret != 0 )
226 return( XYSSL_ERR_DHM_CALC_SECRET_FAILED | ret );
227
228 return( 0 );
229}
230
231/*
232 * Free the components of a DHM key
233 */
234void dhm_free( dhm_context *ctx )
235{
236 mpi_free( &ctx->RP, &ctx->K, &ctx->GY,
237 &ctx->GX, &ctx->X, &ctx->G,
238 &ctx->P, NULL );
239}
240
241#if defined(XYSSL_SELF_TEST)
242
243/*
244 * Checkup routine
245 */
246int dhm_self_test( int verbose )
247{
248 return( verbose++ );
249}
250
251#endif
252
253#endif