00001 /* 00002 * Diffie-Hellman-Merkle key exchange (server side) 00003 * 00004 * Copyright (C) 2006-2007 Christophe Devine 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License along 00017 * with this program; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00019 */ 00020 00021 #ifndef _CRT_SECURE_NO_DEPRECATE 00022 #define _CRT_SECURE_NO_DEPRECATE 1 00023 #endif 00024 00025 #include <string.h> 00026 #include <stdio.h> 00027 00028 #include "xyssl/net.h" 00029 #include "xyssl/aes.h" 00030 #include "xyssl/dhm.h" 00031 #include "xyssl/rsa.h" 00032 #include "xyssl/sha1.h" 00033 #include "xyssl/havege.h" 00034 00035 #define SERVER_PORT 11999 00036 #define PLAINTEXT "==Hello there!==" 00037 00038 int main( void ) 00039 { 00040 FILE *f; 00041 00042 int ret, n, buflen; 00043 int listen_fd = -1; 00044 int client_fd = -1; 00045 00046 unsigned char buf[1024]; 00047 unsigned char hash[20]; 00048 unsigned char buf2[2]; 00049 00050 havege_state hs; 00051 rsa_context rsa; 00052 dhm_context dhm; 00053 aes_context aes; 00054 00055 memset( &rsa, 0, sizeof( rsa ) ); 00056 memset( &dhm, 0, sizeof( dhm ) ); 00057 00058 /* 00059 * 1. Setup the RNG 00060 */ 00061 printf( "\n . Seeding the random number generator" ); 00062 fflush( stdout ); 00063 00064 havege_init( &hs ); 00065 00066 /* 00067 * 2a. Read the server's private RSA key 00068 */ 00069 printf( "\n . Reading private key from rsa_priv.txt" ); 00070 fflush( stdout ); 00071 00072 if( ( f = fopen( "rsa_priv.txt", "rb" ) ) == NULL ) 00073 { 00074 ret = 1; 00075 printf( " failed\n ! Could not open rsa_priv.txt\n" \ 00076 " ! Please run rsa_genkey first\n\n" ); 00077 goto exit; 00078 } 00079 00080 rsa_init( &rsa, RSA_PKCS_V15, 0, NULL, NULL ); 00081 00082 if( ( ret = mpi_read_file( &rsa.N , 16, f ) ) != 0 || 00083 ( ret = mpi_read_file( &rsa.E , 16, f ) ) != 0 || 00084 ( ret = mpi_read_file( &rsa.D , 16, f ) ) != 0 || 00085 ( ret = mpi_read_file( &rsa.P , 16, f ) ) != 0 || 00086 ( ret = mpi_read_file( &rsa.Q , 16, f ) ) != 0 || 00087 ( ret = mpi_read_file( &rsa.DP, 16, f ) ) != 0 || 00088 ( ret = mpi_read_file( &rsa.DQ, 16, f ) ) != 0 || 00089 ( ret = mpi_read_file( &rsa.QP, 16, f ) ) != 0 ) 00090 { 00091 printf( " failed\n ! mpi_read_file returned %d\n\n", ret ); 00092 goto exit; 00093 } 00094 00095 rsa.len = ( mpi_msb( &rsa.N ) + 7 ) >> 3; 00096 00097 fclose( f ); 00098 00099 /* 00100 * 2b. Get the DHM modulus and generator 00101 */ 00102 printf( "\n . Reading DH parameters from dh_prime.txt" ); 00103 fflush( stdout ); 00104 00105 if( ( f = fopen( "dh_prime.txt", "rb" ) ) == NULL ) 00106 { 00107 ret = 1; 00108 printf( " failed\n ! Could not open dh_prime.txt\n" \ 00109 " ! Please run dh_genprime first\n\n" ); 00110 goto exit; 00111 } 00112 00113 if( mpi_read_file( &dhm.P, 16, f ) != 0 || 00114 mpi_read_file( &dhm.G, 16, f ) != 0 ) 00115 { 00116 printf( " failed\n ! Invalid DH parameter file\n\n" ); 00117 goto exit; 00118 } 00119 00120 fclose( f ); 00121 00122 /* 00123 * 3. Wait for a client to connect 00124 */ 00125 printf( "\n . Waiting for a remote connection" ); 00126 fflush( stdout ); 00127 00128 if( ( ret = net_bind( &listen_fd, NULL, SERVER_PORT ) ) != 0 ) 00129 { 00130 printf( " failed\n ! net_bind returned %d\n\n", ret ); 00131 goto exit; 00132 } 00133 00134 if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 ) 00135 { 00136 printf( " failed\n ! net_accept returned %d\n\n", ret ); 00137 goto exit; 00138 } 00139 00140 /* 00141 * 4. Setup the DH parameters (P,G,Ys) 00142 */ 00143 printf( "\n . Sending the server's DH parameters" ); 00144 fflush( stdout ); 00145 00146 memset( buf, 0, sizeof( buf ) ); 00147 00148 if( ( ret = dhm_make_params( &dhm, 256, buf, &n, 00149 havege_rand, &hs ) ) != 0 ) 00150 { 00151 printf( " failed\n ! dhm_make_params returned %d\n\n", ret ); 00152 goto exit; 00153 } 00154 00155 /* 00156 * 5. Sign the parameters and send them 00157 */ 00158 sha1( buf, n, hash ); 00159 00160 buf[n ] = (unsigned char)( rsa.len >> 8 ); 00161 buf[n + 1] = (unsigned char)( rsa.len ); 00162 00163 if( ( ret = rsa_pkcs1_sign( &rsa, RSA_PRIVATE, RSA_SHA1, 00164 0, hash, buf + n + 2 ) ) != 0 ) 00165 { 00166 printf( " failed\n ! rsa_pkcs1_sign returned %d\n\n", ret ); 00167 goto exit; 00168 } 00169 00170 buflen = n + 2 + rsa.len; 00171 buf2[0] = (unsigned char)( buflen >> 8 ); 00172 buf2[1] = (unsigned char)( buflen ); 00173 00174 if( ( ret = net_send( &client_fd, buf2, 2 ) ) != 2 || 00175 ( ret = net_send( &client_fd, buf, buflen ) ) != buflen ) 00176 { 00177 printf( " failed\n ! net_send returned %d\n\n", ret ); 00178 goto exit; 00179 } 00180 00181 /* 00182 * 6. Get the client's public value: Yc = G ^ Xc mod P 00183 */ 00184 printf( "\n . Receiving the client's public value" ); 00185 fflush( stdout ); 00186 00187 memset( buf, 0, sizeof( buf ) ); 00188 n = dhm.len; 00189 00190 if( ( ret = net_recv( &client_fd, buf, n ) ) != n ) 00191 { 00192 printf( " failed\n ! net_recv returned %d\n\n", ret ); 00193 goto exit; 00194 } 00195 00196 if( ( ret = dhm_read_public( &dhm, buf, dhm.len ) ) != 0 ) 00197 { 00198 printf( " failed\n ! dhm_read_public returned %d\n\n", ret ); 00199 goto exit; 00200 } 00201 00202 /* 00203 * 7. Derive the shared secret: K = Ys ^ Xc mod P 00204 */ 00205 printf( "\n . Shared secret: " ); 00206 fflush( stdout ); 00207 00208 if( ( ret = dhm_calc_secret( &dhm, buf, &n ) ) != 0 ) 00209 { 00210 printf( " failed\n ! dhm_calc_secret returned %d\n\n", ret ); 00211 goto exit; 00212 } 00213 00214 for( n = 0; n < 16; n++ ) 00215 printf( "%02x", buf[n] ); 00216 00217 /* 00218 * 8. Setup the AES-256 encryption key 00219 * 00220 * This is an overly simplified example; best practice is 00221 * to hash the shared secret with a random value to derive 00222 * the keying material for the encryption/decryption keys 00223 * and MACs. 00224 */ 00225 printf( "...\n . Encrypting and sending the ciphertext" ); 00226 fflush( stdout ); 00227 00228 aes_setkey_enc( &aes, buf, 256 ); 00229 memcpy( buf, PLAINTEXT, 16 ); 00230 aes_crypt_ecb( &aes, AES_ENCRYPT, buf, buf ); 00231 00232 if( ( ret = net_send( &client_fd, buf, 16 ) ) != 16 ) 00233 { 00234 printf( " failed\n ! net_send returned %d\n\n", ret ); 00235 goto exit; 00236 } 00237 00238 printf( "\n\n" ); 00239 00240 exit: 00241 00242 net_close( client_fd ); 00243 rsa_free( &rsa ); 00244 dhm_free( &dhm ); 00245 00246 #ifdef WIN32 00247 printf( " + Press Enter to exit this program.\n" ); 00248 fflush( stdout ); getchar(); 00249 #endif 00250 00251 return( ret ); 00252 }