blob: 904b5922fe019b8db55f64d0613e15db0d43b50e [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Diffie-Hellman-Merkle key exchange
3 *
Paul Bakkerfc8c4362010-03-21 17:37:16 +00004 * Copyright (C) 2006-2010, Paul Bakker <polarssl_maintainer at polarssl.org>
Paul Bakker77b385e2009-07-28 17:23:11 +00005 * 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 /*
Paul Bakkerff7fe672010-07-18 09:45:05 +0000102 * Generate X as large as possible ( < P )
Paul Bakker5121ce52009-01-03 21:22:43 +0000103 */
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 Bakker5121ce52009-01-03 21:22:43 +0000108 p = (unsigned char *) ctx->X.p;
Paul Bakkerff7fe672010-07-18 09:45:05 +0000109 for( i = 0; i < x_size - 1; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000110 *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
Paul Bakkerff7fe672010-07-18 09:45:05 +0000115 /*
116 * Calculate GX = G^X mod P
117 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000118 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
119 &ctx->P , &ctx->RP ) );
120
121 /*
122 * export P, G, GX
123 */
124#define DHM_MPI_EXPORT(X,n) \
125 MPI_CHK( mpi_write_binary( X, p + 2, n ) ); \
126 *p++ = (unsigned char)( n >> 8 ); \
127 *p++ = (unsigned char)( n ); p += n;
128
129 n1 = mpi_size( &ctx->P );
130 n2 = mpi_size( &ctx->G );
131 n3 = mpi_size( &ctx->GX );
132
133 p = output;
134 DHM_MPI_EXPORT( &ctx->P , n1 );
135 DHM_MPI_EXPORT( &ctx->G , n2 );
136 DHM_MPI_EXPORT( &ctx->GX, n3 );
137
138 *olen = p - output;
139
140 ctx->len = n1;
141
142cleanup:
143
144 if( ret != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000145 return( ret | POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED );
Paul Bakker5121ce52009-01-03 21:22:43 +0000146
147 return( 0 );
148}
149
150/*
151 * Import the peer's public value G^Y
152 */
153int dhm_read_public( dhm_context *ctx,
Paul Bakkerff60ee62010-03-16 21:09:09 +0000154 const unsigned char *input, int ilen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000155{
156 int ret;
157
158 if( ctx == NULL || ilen < 1 || ilen > ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000159 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000160
161 if( ( ret = mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000162 return( POLARSSL_ERR_DHM_READ_PUBLIC_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000163
164 return( 0 );
165}
166
167/*
168 * Create own private value X and export G^X
169 */
170int dhm_make_public( dhm_context *ctx, int x_size,
171 unsigned char *output, int olen,
172 int (*f_rng)(void *), void *p_rng )
173{
174 int ret, i, n;
175 unsigned char *p;
176
177 if( ctx == NULL || olen < 1 || olen > ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000178 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000179
180 /*
181 * generate X and calculate GX = G^X mod P
182 */
183 n = x_size / sizeof( t_int );
184 MPI_CHK( mpi_grow( &ctx->X, n ) );
185 MPI_CHK( mpi_lset( &ctx->X, 0 ) );
186
Paul Bakker2a1fadf2009-07-27 21:05:24 +0000187 n = x_size - 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000188 p = (unsigned char *) ctx->X.p;
189 for( i = 0; i < n; i++ )
190 *p++ = (unsigned char) f_rng( p_rng );
191
192 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
193 mpi_shift_r( &ctx->X, 1 );
194
195 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
196 &ctx->P , &ctx->RP ) );
197
198 MPI_CHK( mpi_write_binary( &ctx->GX, output, olen ) );
199
200cleanup:
201
202 if( ret != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000203 return( POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000204
205 return( 0 );
206}
207
208/*
209 * Derive and export the shared secret (G^Y)^X mod P
210 */
211int dhm_calc_secret( dhm_context *ctx,
212 unsigned char *output, int *olen )
213{
214 int ret;
215
216 if( ctx == NULL || *olen < ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000217 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000218
219 MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X,
220 &ctx->P, &ctx->RP ) );
221
222 *olen = mpi_size( &ctx->K );
223
224 MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) );
225
226cleanup:
227
228 if( ret != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000229 return( POLARSSL_ERR_DHM_CALC_SECRET_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000230
231 return( 0 );
232}
233
234/*
235 * Free the components of a DHM key
236 */
237void dhm_free( dhm_context *ctx )
238{
239 mpi_free( &ctx->RP, &ctx->K, &ctx->GY,
240 &ctx->GX, &ctx->X, &ctx->G,
241 &ctx->P, NULL );
242}
243
Paul Bakker40e46942009-01-03 21:51:57 +0000244#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000245
246/*
247 * Checkup routine
248 */
249int dhm_self_test( int verbose )
250{
251 return( verbose++ );
252}
253
254#endif
255
256#endif