bignum: make mpi_init() and mpi_free() accept a single argument
[tropicssl.git] / programs / pkey / dh_server.c
blob3715b39dde4f19c6d159d09ce485084b3f91fc74
1 /*
2 * Diffie-Hellman-Merkle key exchange (server side)
4 * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
6 * Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * * Neither the names of PolarSSL or XySSL nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #ifndef _CRT_SECURE_NO_DEPRECATE
37 #define _CRT_SECURE_NO_DEPRECATE 1
38 #endif
40 #include <string.h>
41 #include <stdio.h>
43 #include "tropicssl/net.h"
44 #include "tropicssl/aes.h"
45 #include "tropicssl/dhm.h"
46 #include "tropicssl/rsa.h"
47 #include "tropicssl/sha1.h"
48 #include "tropicssl/havege.h"
50 #define SERVER_PORT 11999
51 #define PLAINTEXT "==Hello there!=="
53 int main(void)
55 FILE *f;
57 int ret, n, buflen;
58 int listen_fd = -1;
59 int client_fd = -1;
61 unsigned char buf[1024];
62 unsigned char hash[20];
63 unsigned char buf2[2];
65 havege_state hs;
66 rsa_context rsa;
67 dhm_context dhm;
68 aes_context aes;
70 memset(&rsa, 0, sizeof(rsa));
71 memset(&dhm, 0, sizeof(dhm));
74 * 1. Setup the RNG
76 printf("\n . Seeding the random number generator");
77 fflush(stdout);
79 havege_init(&hs);
82 * 2a. Read the server's private RSA key
84 printf("\n . Reading private key from rsa_priv.txt");
85 fflush(stdout);
87 if ((f = fopen("rsa_priv.txt", "rb")) == NULL) {
88 ret = 1;
89 printf(" failed\n ! Could not open rsa_priv.txt\n"
90 " ! Please run rsa_genkey first\n\n");
91 goto exit;
94 rsa_init(&rsa, RSA_PKCS_V15, 0, NULL, NULL);
96 if ((ret = mpi_read_file(&rsa.N, 16, f)) != 0 ||
97 (ret = mpi_read_file(&rsa.E, 16, f)) != 0 ||
98 (ret = mpi_read_file(&rsa.D, 16, f)) != 0 ||
99 (ret = mpi_read_file(&rsa.P, 16, f)) != 0 ||
100 (ret = mpi_read_file(&rsa.Q, 16, f)) != 0 ||
101 (ret = mpi_read_file(&rsa.DP, 16, f)) != 0 ||
102 (ret = mpi_read_file(&rsa.DQ, 16, f)) != 0 ||
103 (ret = mpi_read_file(&rsa.QP, 16, f)) != 0) {
104 printf(" failed\n ! mpi_read_file returned %d\n\n", ret);
105 goto exit;
108 rsa.len = (mpi_msb(&rsa.N) + 7) >> 3;
110 fclose(f);
113 * 2b. Get the DHM modulus and generator
115 printf("\n . Reading DH parameters from dh_prime.txt");
116 fflush(stdout);
118 if ((f = fopen("dh_prime.txt", "rb")) == NULL) {
119 ret = 1;
120 printf(" failed\n ! Could not open dh_prime.txt\n"
121 " ! Please run dh_genprime first\n\n");
122 goto exit;
125 if (mpi_read_file(&dhm.P, 16, f) != 0 ||
126 mpi_read_file(&dhm.G, 16, f) != 0) {
127 printf(" failed\n ! Invalid DH parameter file\n\n");
128 goto exit;
131 fclose(f);
134 * 3. Wait for a client to connect
136 printf("\n . Waiting for a remote connection");
137 fflush(stdout);
139 if ((ret = net_bind(&listen_fd, NULL, SERVER_PORT)) != 0) {
140 printf(" failed\n ! net_bind returned %d\n\n", ret);
141 goto exit;
144 if ((ret = net_accept(listen_fd, &client_fd, NULL)) != 0) {
145 printf(" failed\n ! net_accept returned %d\n\n", ret);
146 goto exit;
150 * 4. Setup the DH parameters (P,G,Ys)
152 printf("\n . Sending the server's DH parameters");
153 fflush(stdout);
155 memset(buf, 0, sizeof(buf));
157 if ((ret = dhm_make_params(&dhm, 256, buf, &n, havege_rand, &hs)) != 0) {
158 printf(" failed\n ! dhm_make_params returned %d\n\n", ret);
159 goto exit;
163 * 5. Sign the parameters and send them
165 sha1(buf, n, hash);
167 buf[n] = (unsigned char)(rsa.len >> 8);
168 buf[n + 1] = (unsigned char)(rsa.len);
170 if ((ret = rsa_pkcs1_sign(&rsa, RSA_PRIVATE, RSA_SHA1,
171 0, hash, buf + n + 2)) != 0) {
172 printf(" failed\n ! rsa_pkcs1_sign returned %d\n\n", ret);
173 goto exit;
176 buflen = n + 2 + rsa.len;
177 buf2[0] = (unsigned char)(buflen >> 8);
178 buf2[1] = (unsigned char)(buflen);
180 if ((ret = net_send(&client_fd, buf2, 2)) != 2 ||
181 (ret = net_send(&client_fd, buf, buflen)) != buflen) {
182 printf(" failed\n ! net_send returned %d\n\n", ret);
183 goto exit;
187 * 6. Get the client's public value: Yc = G ^ Xc mod P
189 printf("\n . Receiving the client's public value");
190 fflush(stdout);
192 memset(buf, 0, sizeof(buf));
193 n = dhm.len;
195 if ((ret = net_recv(&client_fd, buf, n)) != n) {
196 printf(" failed\n ! net_recv returned %d\n\n", ret);
197 goto exit;
200 if ((ret = dhm_read_public(&dhm, buf, dhm.len)) != 0) {
201 printf(" failed\n ! dhm_read_public returned %d\n\n", ret);
202 goto exit;
206 * 7. Derive the shared secret: K = Ys ^ Xc mod P
208 printf("\n . Shared secret: ");
209 fflush(stdout);
211 if ((ret = dhm_calc_secret(&dhm, buf, &n)) != 0) {
212 printf(" failed\n ! dhm_calc_secret returned %d\n\n", ret);
213 goto exit;
216 for (n = 0; n < 16; n++)
217 printf("%02x", buf[n]);
220 * 8. Setup the AES-256 encryption key
222 * This is an overly simplified example; best practice is
223 * to hash the shared secret with a random value to derive
224 * the keying material for the encryption/decryption keys
225 * and MACs.
227 printf("...\n . Encrypting and sending the ciphertext");
228 fflush(stdout);
230 aes_setkey_enc(&aes, buf, 256);
231 memcpy(buf, PLAINTEXT, 16);
232 aes_crypt_ecb(&aes, AES_ENCRYPT, buf, buf);
234 if ((ret = net_send(&client_fd, buf, 16)) != 16) {
235 printf(" failed\n ! net_send returned %d\n\n", ret);
236 goto exit;
239 printf("\n\n");
241 exit:
243 net_close(client_fd);
244 rsa_free(&rsa);
245 dhm_free(&dhm);
247 #ifdef WIN32
248 printf(" + Press Enter to exit this program.\n");
249 fflush(stdout);
250 getchar();
251 #endif
253 return (ret);