source: trunk/programs/pkey/dh_client.c @ 1254

Revision 1254, 7.6 KB checked in by paul, 3 weeks ago (diff)
  • Fixed for new DHM handling (TLS 1.2)
Line 
1/*
2 *  Diffie-Hellman-Merkle key exchange (client side)
3 *
4 *  Copyright (C) 2006-2011, Brainspark B.V.
5 *
6 *  This file is part of PolarSSL (http://www.polarssl.org)
7 *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 *  All rights reserved.
10 *
11 *  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#ifndef _CRT_SECURE_NO_DEPRECATE
27#define _CRT_SECURE_NO_DEPRECATE 1
28#endif
29
30#include <string.h>
31#include <stdio.h>
32
33#include "polarssl/config.h"
34
35#include "polarssl/net.h"
36#include "polarssl/aes.h"
37#include "polarssl/dhm.h"
38#include "polarssl/rsa.h"
39#include "polarssl/sha1.h"
40#include "polarssl/entropy.h"
41#include "polarssl/ctr_drbg.h"
42
43#define SERVER_NAME "localhost"
44#define SERVER_PORT 11999
45
46#if !defined(POLARSSL_AES_C) || !defined(POLARSSL_DHM_C) ||     \
47    !defined(POLARSSL_ENTROPY_C) || !defined(POLARSSL_NET_C) ||  \
48    !defined(POLARSSL_RSA_C) || !defined(POLARSSL_SHA1_C) ||    \
49    !defined(POLARSSL_FS_IO) || !defined(POLARSSL_CTR_DRBG_C)
50int main( int argc, char *argv[] )
51{
52    ((void) argc);
53    ((void) argv);
54
55    printf("POLARSSL_AES_C and/or POLARSSL_DHM_C and/or POLARSSL_ENTROPY_C "
56           "and/or POLARSSL_NET_C and/or POLARSSL_RSA_C and/or "
57           "POLARSSL_SHA1_C and/or POLARSSL_FS_IO and/or "
58           "POLARSSL_CTR_DRBG_C not defined.\n");
59    return( 0 );
60}
61#else
62int main( int argc, char *argv[] )
63{
64    FILE *f;
65
66    int ret;
67    size_t n, buflen;
68    int server_fd = -1;
69
70    unsigned char *p, *end;
71    unsigned char buf[1024];
72    unsigned char hash[20];
73    char *pers = "dh_client";
74
75    entropy_context entropy;
76    ctr_drbg_context ctr_drbg;
77    rsa_context rsa;
78    dhm_context dhm;
79    aes_context aes;
80
81    ((void) argc);
82    ((void) argv);
83
84    memset( &rsa, 0, sizeof( rsa ) );
85    memset( &dhm, 0, sizeof( dhm ) );
86
87    /*
88     * 1. Setup the RNG
89     */
90    printf( "\n  . Seeding the random number generator" );
91    fflush( stdout );
92
93    entropy_init( &entropy );
94    if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
95                               (unsigned char *) pers, strlen( pers ) ) ) != 0 )
96    {
97        printf( " failed\n  ! ctr_drbg_init returned %d\n", ret );
98        goto exit;
99    }
100
101    /*
102     * 2. Read the server's public RSA key
103     */
104    printf( "\n  . Reading public key from rsa_pub.txt" );
105    fflush( stdout );
106
107    if( ( f = fopen( "rsa_pub.txt", "rb" ) ) == NULL )
108    {
109        ret = 1;
110        printf( " failed\n  ! Could not open rsa_pub.txt\n" \
111                "  ! Please run rsa_genkey first\n\n" );
112        goto exit;
113    }
114
115    rsa_init( &rsa, RSA_PKCS_V15, 0 );
116
117    if( ( ret = mpi_read_file( &rsa.N, 16, f ) ) != 0 ||
118        ( ret = mpi_read_file( &rsa.E, 16, f ) ) != 0 )
119    {
120        printf( " failed\n  ! mpi_read_file returned %d\n\n", ret );
121        goto exit;
122    }
123
124    rsa.len = ( mpi_msb( &rsa.N ) + 7 ) >> 3;
125
126    fclose( f );
127
128    /*
129     * 3. Initiate the connection
130     */
131    printf( "\n  . Connecting to tcp/%s/%d", SERVER_NAME,
132                                             SERVER_PORT );
133    fflush( stdout );
134
135    if( ( ret = net_connect( &server_fd, SERVER_NAME,
136                                         SERVER_PORT ) ) != 0 )
137    {
138        printf( " failed\n  ! net_connect returned %d\n\n", ret );
139        goto exit;
140    }
141
142    /*
143     * 4a. First get the buffer length
144     */
145    printf( "\n  . Receiving the server's DH parameters" );
146    fflush( stdout );
147
148    memset( buf, 0, sizeof( buf ) );
149
150    if( ( ret = net_recv( &server_fd, buf, 2 ) ) != 2 )
151    {
152        printf( " failed\n  ! net_recv returned %d\n\n", ret );
153        goto exit;
154    }
155
156    n = buflen = ( buf[0] << 8 ) | buf[1];
157    if( buflen < 1 || buflen > sizeof( buf ) )
158    {
159        printf( " failed\n  ! Got an invalid buffer length\n\n" );
160        goto exit;
161    }
162
163    /*
164     * 4b. Get the DHM parameters: P, G and Ys = G^Xs mod P
165     */
166    memset( buf, 0, sizeof( buf ) );
167
168    if( ( ret = net_recv( &server_fd, buf, n ) ) != (int) n )
169    {
170        printf( " failed\n  ! net_recv returned %d\n\n", ret );
171        goto exit;
172    }
173
174    p = buf, end = buf + buflen;
175
176    if( ( ret = dhm_read_params( &dhm, &p, end ) ) != 0 )
177    {
178        printf( " failed\n  ! dhm_read_params returned %d\n\n", ret );
179        goto exit;
180    }
181
182    if( dhm.len < 64 || dhm.len > 256 )
183    {
184        ret = 1;
185        printf( " failed\n  ! Invalid DHM modulus size\n\n" );
186        goto exit;
187    }
188
189    /*
190     * 5. Check that the server's RSA signature matches
191     *    the SHA-1 hash of (P,G,Ys)
192     */
193    printf( "\n  . Verifying the server's RSA signature" );
194    fflush( stdout );
195
196    p += 2;
197
198    if( ( n = (size_t) ( end - p ) ) != rsa.len )
199    {
200        ret = 1;
201        printf( " failed\n  ! Invalid RSA signature size\n\n" );
202        goto exit;
203    }
204
205    sha1( buf, (int)( p - 2 - buf ), hash );
206
207    if( ( ret = rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1,
208                                  0, hash, p ) ) != 0 )
209    {
210        printf( " failed\n  ! rsa_pkcs1_verify returned %d\n\n", ret );
211        goto exit;
212    }
213
214    /*
215     * 6. Send our public value: Yc = G ^ Xc mod P
216     */
217    printf( "\n  . Sending own public value to server" );
218    fflush( stdout );
219
220    n = dhm.len;
221    if( ( ret = dhm_make_public( &dhm, 256, buf, n,
222                                 ctr_drbg_random, &ctr_drbg ) ) != 0 )
223    {
224        printf( " failed\n  ! dhm_make_public returned %d\n\n", ret );
225        goto exit;
226    }
227
228    if( ( ret = net_send( &server_fd, buf, n ) ) != (int) n )
229    {
230        printf( " failed\n  ! net_send returned %d\n\n", ret );
231        goto exit;
232    }
233
234    /*
235     * 7. Derive the shared secret: K = Ys ^ Xc mod P
236     */
237    printf( "\n  . Shared secret: " );
238    fflush( stdout );
239
240    n = dhm.len;
241    if( ( ret = dhm_calc_secret( &dhm, buf, &n ) ) != 0 )
242    {
243        printf( " failed\n  ! dhm_calc_secret returned %d\n\n", ret );
244        goto exit;
245    }
246
247    for( n = 0; n < 16; n++ )
248        printf( "%02x", buf[n] );
249
250    /*
251     * 8. Setup the AES-256 decryption key
252     *
253     * This is an overly simplified example; best practice is
254     * to hash the shared secret with a random value to derive
255     * the keying material for the encryption/decryption keys,
256     * IVs and MACs.
257     */
258    printf( "...\n  . Receiving and decrypting the ciphertext" );
259    fflush( stdout );
260
261    aes_setkey_dec( &aes, buf, 256 );
262
263    memset( buf, 0, sizeof( buf ) );
264
265    if( ( ret = net_recv( &server_fd, buf, 16 ) ) != 16 )
266    {
267        printf( " failed\n  ! net_recv returned %d\n\n", ret );
268        goto exit;
269    }
270
271    aes_crypt_ecb( &aes, AES_DECRYPT, buf, buf );
272    buf[16] = '\0';
273    printf( "\n  . Plaintext is \"%s\"\n\n", (char *) buf );
274
275exit:
276
277    net_close( server_fd );
278    rsa_free( &rsa );
279    dhm_free( &dhm );
280
281#if defined(_WIN32)
282    printf( "  + Press Enter to exit this program.\n" );
283    fflush( stdout ); getchar();
284#endif
285
286    return( ret );
287}
288#endif /* POLARSSL_AES_C && POLARSSL_DHM_C && POLARSSL_ENTROPY_C &&
289          POLARSSL_NET_C && POLARSSL_RSA_C && POLARSSL_SHA1_C &&
290          POLARSSL_FS_IO && POLARSSL_CTR_DRBG_C */
Note: See TracBrowser for help on using the repository browser.

What are you looking for?