blob: f48841f31fc40476d1ab0e588e3dbe5de6234aba [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Diffie-Hellman-Merkle key exchange
3 *
Paul Bakker77b385e2009-07-28 17:23:11 +00004 * Copyright (C) 2006-2009, Paul Bakker <polarssl_maintainer at polarssl.org>
5 * All rights reserved.
Paul Bakkere0ccd0a2009-01-04 16:27:10 +00006 *
Paul Bakker5121ce52009-01-03 21:22:43 +00007 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21/*
22 * Reference:
23 *
24 * http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12)
25 */
26
Paul Bakker40e46942009-01-03 21:51:57 +000027#include "polarssl/config.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000028
Paul Bakker40e46942009-01-03 21:51:57 +000029#if defined(POLARSSL_DHM_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000030
Paul Bakker40e46942009-01-03 21:51:57 +000031#include "polarssl/dhm.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000032
33#include <string.h>
34
35/*
36 * helper to validate the mpi size and import it
37 */
38static int dhm_read_bignum( mpi *X,
39 unsigned char **p,
Paul Bakkerff60ee62010-03-16 21:09:09 +000040 const unsigned char *end )
Paul Bakker5121ce52009-01-03 21:22:43 +000041{
42 int ret, n;
43
44 if( end - *p < 2 )
Paul Bakker40e46942009-01-03 21:51:57 +000045 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000046
47 n = ( (*p)[0] << 8 ) | (*p)[1];
48 (*p) += 2;
49
50 if( (int)( end - *p ) < n )
Paul Bakker40e46942009-01-03 21:51:57 +000051 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000052
53 if( ( ret = mpi_read_binary( X, *p, n ) ) != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +000054 return( POLARSSL_ERR_DHM_READ_PARAMS_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +000055
56 (*p) += n;
57
58 return( 0 );
59}
60
61/*
62 * Parse the ServerKeyExchange parameters
63 */
64int dhm_read_params( dhm_context *ctx,
65 unsigned char **p,
Paul Bakkerff60ee62010-03-16 21:09:09 +000066 const unsigned char *end )
Paul Bakker5121ce52009-01-03 21:22:43 +000067{
68 int ret, n;
69
70 memset( ctx, 0, sizeof( dhm_context ) );
71
72 if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 ||
73 ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 ||
74 ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
75 return( ret );
76
77 ctx->len = mpi_size( &ctx->P );
78
79 if( end - *p < 2 )
Paul Bakker40e46942009-01-03 21:51:57 +000080 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000081
82 n = ( (*p)[0] << 8 ) | (*p)[1];
83 (*p) += 2;
84
85 if( end != *p + n )
Paul Bakker40e46942009-01-03 21:51:57 +000086 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000087
88 return( 0 );
89}
90
91/*
92 * Setup and write the ServerKeyExchange parameters
93 */
94int dhm_make_params( dhm_context *ctx, int x_size,
95 unsigned char *output, int *olen,
96 int (*f_rng)(void *), void *p_rng )
97{
98 int i, ret, n, n1, n2, n3;
99 unsigned char *p;
100
101 /*
102 * generate X and calculate GX = G^X mod P
103 */
104 n = x_size / sizeof( t_int );
105 MPI_CHK( mpi_grow( &ctx->X, n ) );
106 MPI_CHK( mpi_lset( &ctx->X, 0 ) );
107
Paul Bakker2a1fadf2009-07-27 21:05:24 +0000108 n = x_size - 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000109 p = (unsigned char *) ctx->X.p;
110 for( i = 0; i < n; i++ )
111 *p++ = (unsigned char) f_rng( p_rng );
112
113 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
114 mpi_shift_r( &ctx->X, 1 );
115
116 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
117 &ctx->P , &ctx->RP ) );
118
119 /*
120 * export P, G, GX
121 */
122#define DHM_MPI_EXPORT(X,n) \
123 MPI_CHK( mpi_write_binary( X, p + 2, n ) ); \
124 *p++ = (unsigned char)( n >> 8 ); \
125 *p++ = (unsigned char)( n ); p += n;
126
127 n1 = mpi_size( &ctx->P );
128 n2 = mpi_size( &ctx->G );
129 n3 = mpi_size( &ctx->GX );
130
131 p = output;
132 DHM_MPI_EXPORT( &ctx->P , n1 );
133 DHM_MPI_EXPORT( &ctx->G , n2 );
134 DHM_MPI_EXPORT( &ctx->GX, n3 );
135
136 *olen = p - output;
137
138 ctx->len = n1;
139
140cleanup:
141
142 if( ret != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000143 return( ret | POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED );
Paul Bakker5121ce52009-01-03 21:22:43 +0000144
145 return( 0 );
146}
147
148/*
149 * Import the peer's public value G^Y
150 */
151int dhm_read_public( dhm_context *ctx,
Paul Bakkerff60ee62010-03-16 21:09:09 +0000152 const unsigned char *input, int ilen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000153{
154 int ret;
155
156 if( ctx == NULL || ilen < 1 || ilen > ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000157 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000158
159 if( ( ret = mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000160 return( POLARSSL_ERR_DHM_READ_PUBLIC_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000161
162 return( 0 );
163}
164
165/*
166 * Create own private value X and export G^X
167 */
168int dhm_make_public( dhm_context *ctx, int x_size,
169 unsigned char *output, int olen,
170 int (*f_rng)(void *), void *p_rng )
171{
172 int ret, i, n;
173 unsigned char *p;
174
175 if( ctx == NULL || olen < 1 || olen > ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000176 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000177
178 /*
179 * generate X and calculate GX = G^X mod P
180 */
181 n = x_size / sizeof( t_int );
182 MPI_CHK( mpi_grow( &ctx->X, n ) );
183 MPI_CHK( mpi_lset( &ctx->X, 0 ) );
184
Paul Bakker2a1fadf2009-07-27 21:05:24 +0000185 n = x_size - 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000186 p = (unsigned char *) ctx->X.p;
187 for( i = 0; i < n; i++ )
188 *p++ = (unsigned char) f_rng( p_rng );
189
190 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
191 mpi_shift_r( &ctx->X, 1 );
192
193 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
194 &ctx->P , &ctx->RP ) );
195
196 MPI_CHK( mpi_write_binary( &ctx->GX, output, olen ) );
197
198cleanup:
199
200 if( ret != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000201 return( POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000202
203 return( 0 );
204}
205
206/*
207 * Derive and export the shared secret (G^Y)^X mod P
208 */
209int dhm_calc_secret( dhm_context *ctx,
210 unsigned char *output, int *olen )
211{
212 int ret;
213
214 if( ctx == NULL || *olen < ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000215 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000216
217 MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X,
218 &ctx->P, &ctx->RP ) );
219
220 *olen = mpi_size( &ctx->K );
221
222 MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) );
223
224cleanup:
225
226 if( ret != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000227 return( POLARSSL_ERR_DHM_CALC_SECRET_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000228
229 return( 0 );
230}
231
232/*
233 * Free the components of a DHM key
234 */
235void dhm_free( dhm_context *ctx )
236{
237 mpi_free( &ctx->RP, &ctx->K, &ctx->GY,
238 &ctx->GX, &ctx->X, &ctx->G,
239 &ctx->P, NULL );
240}
241
Paul Bakker40e46942009-01-03 21:51:57 +0000242#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000243
244/*
245 * Checkup routine
246 */
247int dhm_self_test( int verbose )
248{
249 return( verbose++ );
250}
251
252#endif
253
254#endif