hehe %-)
[syren.git] / src / xyssl / library / dhm.c
blob742cbf02b479cf0dd7c851efc01caf03e11d6a0e
1 /*
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,
18 * MA 02110-1301 USA
21 * Reference:
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"
32 #include <string.h>
35 * helper to validate the mpi size and import it
37 static int dhm_read_bignum( mpi *X,
38 unsigned char **p,
39 unsigned char *end )
41 int ret, n;
43 if( end - *p < 2 )
44 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
46 n = ( (*p)[0] << 8 ) | (*p)[1];
47 (*p) += 2;
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 );
55 (*p) += n;
57 return( 0 );
61 * Parse the ServerKeyExchange parameters
63 int dhm_read_params( dhm_context *ctx,
64 unsigned char **p,
65 unsigned char *end )
67 int ret, n;
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 )
74 return( ret );
76 ctx->len = mpi_size( &ctx->P );
78 if( end - *p < 2 )
79 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
81 n = ( (*p)[0] << 8 ) | (*p)[1];
82 (*p) += 2;
84 if( end != *p + n )
85 return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
87 return( 0 );
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;
98 unsigned char *p;
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 ) );
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 );
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 ) );
119 * export P, G, GX
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 );
130 p = output;
131 DHM_MPI_EXPORT( &ctx->P , n1 );
132 DHM_MPI_EXPORT( &ctx->G , n2 );
133 DHM_MPI_EXPORT( &ctx->GX, n3 );
135 *olen = p - output;
137 ctx->len = n1;
139 cleanup:
141 if( ret != 0 )
142 return( ret | XYSSL_ERR_DHM_MAKE_PARAMS_FAILED );
144 return( 0 );
148 * Import the peer's public value G^Y
150 int dhm_read_public( dhm_context *ctx,
151 unsigned char *input, int ilen )
153 int ret;
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 );
161 return( 0 );
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 )
171 int ret, i, n;
172 unsigned char *p;
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 ) );
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 );
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 ) );
197 cleanup:
199 if( ret != 0 )
200 return( XYSSL_ERR_DHM_MAKE_PUBLIC_FAILED | ret );
202 return( 0 );
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 )
211 int ret;
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 ) );
223 cleanup:
225 if( ret != 0 )
226 return( XYSSL_ERR_DHM_CALC_SECRET_FAILED | ret );
228 return( 0 );
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,
238 &ctx->P, NULL );
241 #if defined(XYSSL_SELF_TEST)
244 * Checkup routine
246 int dhm_self_test( int verbose )
248 return( verbose++ );
251 #endif
253 #endif