blob: 0e76f0b32388f28b74c8f0d38dba5b412cbd115e [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Diffie-Hellman-Merkle key exchange
3 *
Paul Bakker84f12b72010-07-18 10:13:04 +00004 * Copyright (C) 2006-2010, Brainspark B.V.
Paul Bakkerb96f1542010-07-18 20:36:00 +00005 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
Paul Bakker84f12b72010-07-18 10:13:04 +00007 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
Paul Bakkerb96f1542010-07-18 20:36:00 +00008 *
Paul Bakker77b385e2009-07-28 17:23:11 +00009 * All rights reserved.
Paul Bakkere0ccd0a2009-01-04 16:27:10 +000010 *
Paul Bakker5121ce52009-01-03 21:22:43 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25/*
26 * Reference:
27 *
28 * http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12)
29 */
30
Paul Bakker40e46942009-01-03 21:51:57 +000031#include "polarssl/config.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000032
Paul Bakker40e46942009-01-03 21:51:57 +000033#if defined(POLARSSL_DHM_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000034
Paul Bakker40e46942009-01-03 21:51:57 +000035#include "polarssl/dhm.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000036
37#include <string.h>
38
39/*
40 * helper to validate the mpi size and import it
41 */
42static int dhm_read_bignum( mpi *X,
43 unsigned char **p,
Paul Bakkerff60ee62010-03-16 21:09:09 +000044 const unsigned char *end )
Paul Bakker5121ce52009-01-03 21:22:43 +000045{
46 int ret, n;
47
48 if( end - *p < 2 )
Paul Bakker40e46942009-01-03 21:51:57 +000049 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000050
51 n = ( (*p)[0] << 8 ) | (*p)[1];
52 (*p) += 2;
53
54 if( (int)( end - *p ) < n )
Paul Bakker40e46942009-01-03 21:51:57 +000055 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000056
57 if( ( ret = mpi_read_binary( X, *p, n ) ) != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +000058 return( POLARSSL_ERR_DHM_READ_PARAMS_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +000059
60 (*p) += n;
61
62 return( 0 );
63}
64
65/*
66 * Parse the ServerKeyExchange parameters
67 */
68int dhm_read_params( dhm_context *ctx,
69 unsigned char **p,
Paul Bakkerff60ee62010-03-16 21:09:09 +000070 const unsigned char *end )
Paul Bakker5121ce52009-01-03 21:22:43 +000071{
72 int ret, n;
73
74 memset( ctx, 0, sizeof( dhm_context ) );
75
76 if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 ||
77 ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 ||
78 ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
79 return( ret );
80
81 ctx->len = mpi_size( &ctx->P );
82
83 if( end - *p < 2 )
Paul Bakker40e46942009-01-03 21:51:57 +000084 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000085
86 n = ( (*p)[0] << 8 ) | (*p)[1];
87 (*p) += 2;
88
89 if( end != *p + n )
Paul Bakker40e46942009-01-03 21:51:57 +000090 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000091
92 return( 0 );
93}
94
95/*
96 * Setup and write the ServerKeyExchange parameters
97 */
98int dhm_make_params( dhm_context *ctx, int x_size,
99 unsigned char *output, int *olen,
100 int (*f_rng)(void *), void *p_rng )
101{
102 int i, ret, n, n1, n2, n3;
103 unsigned char *p;
104
105 /*
Paul Bakkerff7fe672010-07-18 09:45:05 +0000106 * Generate X as large as possible ( < P )
Paul Bakker5121ce52009-01-03 21:22:43 +0000107 */
108 n = x_size / sizeof( t_int );
109 MPI_CHK( mpi_grow( &ctx->X, n ) );
110 MPI_CHK( mpi_lset( &ctx->X, 0 ) );
111
Paul Bakker5121ce52009-01-03 21:22:43 +0000112 p = (unsigned char *) ctx->X.p;
Paul Bakkerff7fe672010-07-18 09:45:05 +0000113 for( i = 0; i < x_size - 1; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000114 *p++ = (unsigned char) f_rng( p_rng );
115
116 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
117 mpi_shift_r( &ctx->X, 1 );
118
Paul Bakkerff7fe672010-07-18 09:45:05 +0000119 /*
120 * Calculate GX = G^X mod P
121 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000122 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
123 &ctx->P , &ctx->RP ) );
124
125 /*
126 * export P, G, GX
127 */
128#define DHM_MPI_EXPORT(X,n) \
129 MPI_CHK( mpi_write_binary( X, p + 2, n ) ); \
130 *p++ = (unsigned char)( n >> 8 ); \
131 *p++ = (unsigned char)( n ); p += n;
132
133 n1 = mpi_size( &ctx->P );
134 n2 = mpi_size( &ctx->G );
135 n3 = mpi_size( &ctx->GX );
136
137 p = output;
138 DHM_MPI_EXPORT( &ctx->P , n1 );
139 DHM_MPI_EXPORT( &ctx->G , n2 );
140 DHM_MPI_EXPORT( &ctx->GX, n3 );
141
142 *olen = p - output;
143
144 ctx->len = n1;
145
146cleanup:
147
148 if( ret != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000149 return( ret | POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED );
Paul Bakker5121ce52009-01-03 21:22:43 +0000150
151 return( 0 );
152}
153
154/*
155 * Import the peer's public value G^Y
156 */
157int dhm_read_public( dhm_context *ctx,
Paul Bakkerff60ee62010-03-16 21:09:09 +0000158 const unsigned char *input, int ilen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000159{
160 int ret;
161
162 if( ctx == NULL || ilen < 1 || ilen > ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000163 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000164
165 if( ( ret = mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000166 return( POLARSSL_ERR_DHM_READ_PUBLIC_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000167
168 return( 0 );
169}
170
171/*
172 * Create own private value X and export G^X
173 */
174int dhm_make_public( dhm_context *ctx, int x_size,
175 unsigned char *output, int olen,
176 int (*f_rng)(void *), void *p_rng )
177{
178 int ret, i, n;
179 unsigned char *p;
180
181 if( ctx == NULL || olen < 1 || olen > ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000182 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000183
184 /*
185 * generate X and calculate GX = G^X mod P
186 */
187 n = x_size / sizeof( t_int );
188 MPI_CHK( mpi_grow( &ctx->X, n ) );
189 MPI_CHK( mpi_lset( &ctx->X, 0 ) );
190
Paul Bakker2a1fadf2009-07-27 21:05:24 +0000191 n = x_size - 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000192 p = (unsigned char *) ctx->X.p;
193 for( i = 0; i < n; i++ )
194 *p++ = (unsigned char) f_rng( p_rng );
195
196 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
197 mpi_shift_r( &ctx->X, 1 );
198
199 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
200 &ctx->P , &ctx->RP ) );
201
202 MPI_CHK( mpi_write_binary( &ctx->GX, output, olen ) );
203
204cleanup:
205
206 if( ret != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000207 return( POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000208
209 return( 0 );
210}
211
212/*
213 * Derive and export the shared secret (G^Y)^X mod P
214 */
215int dhm_calc_secret( dhm_context *ctx,
216 unsigned char *output, int *olen )
217{
218 int ret;
219
220 if( ctx == NULL || *olen < ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000221 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000222
223 MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X,
224 &ctx->P, &ctx->RP ) );
225
226 *olen = mpi_size( &ctx->K );
227
228 MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) );
229
230cleanup:
231
232 if( ret != 0 )
Paul Bakker40e46942009-01-03 21:51:57 +0000233 return( POLARSSL_ERR_DHM_CALC_SECRET_FAILED | ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000234
235 return( 0 );
236}
237
238/*
239 * Free the components of a DHM key
240 */
241void dhm_free( dhm_context *ctx )
242{
243 mpi_free( &ctx->RP, &ctx->K, &ctx->GY,
244 &ctx->GX, &ctx->X, &ctx->G,
245 &ctx->P, NULL );
246}
247
Paul Bakker40e46942009-01-03 21:51:57 +0000248#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000249
250/*
251 * Checkup routine
252 */
253int dhm_self_test( int verbose )
254{
255 return( verbose++ );
256}
257
258#endif
259
260#endif