blob: 18485aa800172b1add1020943ea5aab27c24a819 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Diffie-Hellman-Merkle key exchange (client side)
3 *
Paul Bakker84f12b72010-07-18 10:13:04 +00004 * Copyright (C) 2006-2010, Brainspark B.V.
5 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
Paul Bakker77b385e2009-07-28 17:23:11 +00006 * All rights reserved.
Paul Bakkere0ccd0a2009-01-04 16:27:10 +00007 *
Paul Bakker5121ce52009-01-03 21:22:43 +00008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#ifndef _CRT_SECURE_NO_DEPRECATE
24#define _CRT_SECURE_NO_DEPRECATE 1
25#endif
26
27#include <string.h>
28#include <stdio.h>
29
Paul Bakker40e46942009-01-03 21:51:57 +000030#include "polarssl/net.h"
31#include "polarssl/aes.h"
32#include "polarssl/dhm.h"
33#include "polarssl/rsa.h"
34#include "polarssl/sha1.h"
35#include "polarssl/havege.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000036
37#define SERVER_NAME "localhost"
38#define SERVER_PORT 11999
39
40int main( void )
41{
42 FILE *f;
43
44 int ret, n, buflen;
45 int server_fd = -1;
46
47 unsigned char *p, *end;
48 unsigned char buf[1024];
49 unsigned char hash[20];
50
51 havege_state hs;
52 rsa_context rsa;
53 dhm_context dhm;
54 aes_context aes;
55
56 memset( &rsa, 0, sizeof( rsa ) );
57 memset( &dhm, 0, sizeof( dhm ) );
58
59 /*
60 * 1. Setup the RNG
61 */
62 printf( "\n . Seeding the random number generator" );
63 fflush( stdout );
64
65 havege_init( &hs );
66
67 /*
68 * 2. Read the server's public RSA key
69 */
70 printf( "\n . Reading public key from rsa_pub.txt" );
71 fflush( stdout );
72
73 if( ( f = fopen( "rsa_pub.txt", "rb" ) ) == NULL )
74 {
75 ret = 1;
76 printf( " failed\n ! Could not open rsa_pub.txt\n" \
77 " ! Please run rsa_genkey first\n\n" );
78 goto exit;
79 }
80
81 rsa_init( &rsa, RSA_PKCS_V15, 0, NULL, NULL );
82
83 if( ( ret = mpi_read_file( &rsa.N, 16, f ) ) != 0 ||
84 ( ret = mpi_read_file( &rsa.E, 16, f ) ) != 0 )
85 {
86 printf( " failed\n ! mpi_read_file returned %d\n\n", ret );
87 goto exit;
88 }
89
90 rsa.len = ( mpi_msb( &rsa.N ) + 7 ) >> 3;
91
92 fclose( f );
93
94 /*
95 * 3. Initiate the connection
96 */
97 printf( "\n . Connecting to tcp/%s/%d", SERVER_NAME,
98 SERVER_PORT );
99 fflush( stdout );
100
101 if( ( ret = net_connect( &server_fd, SERVER_NAME,
102 SERVER_PORT ) ) != 0 )
103 {
104 printf( " failed\n ! net_connect returned %d\n\n", ret );
105 goto exit;
106 }
107
108 /*
109 * 4a. First get the buffer length
110 */
111 printf( "\n . Receiving the server's DH parameters" );
112 fflush( stdout );
113
114 memset( buf, 0, sizeof( buf ) );
115
116 if( ( ret = net_recv( &server_fd, buf, 2 ) ) != 2 )
117 {
118 printf( " failed\n ! net_recv returned %d\n\n", ret );
119 goto exit;
120 }
121
122 n = buflen = ( buf[0] << 8 ) | buf[1];
123 if( buflen < 1 || buflen > (int) sizeof( buf ) )
124 {
125 printf( " failed\n ! Got an invalid buffer length\n\n" );
126 goto exit;
127 }
128
129 /*
130 * 4b. Get the DHM parameters: P, G and Ys = G^Xs mod P
131 */
132 memset( buf, 0, sizeof( buf ) );
133
134 if( ( ret = net_recv( &server_fd, buf, n ) ) != n )
135 {
136 printf( " failed\n ! net_recv returned %d\n\n", ret );
137 goto exit;
138 }
139
140 p = buf, end = buf + buflen;
141
142 if( ( ret = dhm_read_params( &dhm, &p, end ) ) != 0 )
143 {
144 printf( " failed\n ! dhm_read_params returned %d\n\n", ret );
145 goto exit;
146 }
147
148 if( dhm.len < 64 || dhm.len > 256 )
149 {
150 ret = 1;
151 printf( " failed\n ! Invalid DHM modulus size\n\n" );
152 goto exit;
153 }
154
155 /*
156 * 5. Check that the server's RSA signature matches
157 * the SHA-1 hash of (P,G,Ys)
158 */
159 printf( "\n . Verifying the server's RSA signature" );
160 fflush( stdout );
161
162 if( ( n = (int)( end - p ) ) != rsa.len )
163 {
164 ret = 1;
165 printf( " failed\n ! Invalid RSA signature size\n\n" );
166 goto exit;
167 }
168
169 sha1( buf, (int)( p - 2 - buf ), hash );
170
Paul Bakker4593aea2009-02-09 22:32:35 +0000171 if( ( ret = rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1,
Paul Bakker5121ce52009-01-03 21:22:43 +0000172 0, hash, p ) ) != 0 )
173 {
174 printf( " failed\n ! rsa_pkcs1_verify returned %d\n\n", ret );
175 goto exit;
176 }
177
178 /*
179 * 6. Send our public value: Yc = G ^ Xc mod P
180 */
181 printf( "\n . Sending own public value to server" );
182 fflush( stdout );
183
184 n = dhm.len;
185 if( ( ret = dhm_make_public( &dhm, 256, buf, n,
186 havege_rand, &hs ) ) != 0 )
187 {
188 printf( " failed\n ! dhm_make_public returned %d\n\n", ret );
189 goto exit;
190 }
191
192 if( ( ret = net_send( &server_fd, buf, n ) ) != n )
193 {
194 printf( " failed\n ! net_send returned %d\n\n", ret );
195 goto exit;
196 }
197
198 /*
199 * 7. Derive the shared secret: K = Ys ^ Xc mod P
200 */
201 printf( "\n . Shared secret: " );
202 fflush( stdout );
203
204 n = dhm.len;
205 if( ( ret = dhm_calc_secret( &dhm, buf, &n ) ) != 0 )
206 {
207 printf( " failed\n ! dhm_calc_secret returned %d\n\n", ret );
208 goto exit;
209 }
210
211 for( n = 0; n < 16; n++ )
212 printf( "%02x", buf[n] );
213
214 /*
215 * 8. Setup the AES-256 decryption key
216 *
217 * This is an overly simplified example; best practice is
218 * to hash the shared secret with a random value to derive
219 * the keying material for the encryption/decryption keys,
220 * IVs and MACs.
221 */
222 printf( "...\n . Receiving and decrypting the ciphertext" );
223 fflush( stdout );
224
225 aes_setkey_dec( &aes, buf, 256 );
226
227 memset( buf, 0, sizeof( buf ) );
228
229 if( ( ret = net_recv( &server_fd, buf, 16 ) ) != 16 )
230 {
231 printf( " failed\n ! net_recv returned %d\n\n", ret );
232 goto exit;
233 }
234
235 aes_crypt_ecb( &aes, AES_DECRYPT, buf, buf );
236 buf[16] = '\0';
237 printf( "\n . Plaintext is \"%s\"\n\n", (char *) buf );
238
239exit:
240
241 net_close( server_fd );
242 rsa_free( &rsa );
243 dhm_free( &dhm );
244
245#ifdef WIN32
246 printf( " + Press Enter to exit this program.\n" );
247 fflush( stdout ); getchar();
248#endif
249
250 return( ret );
251}