bignum: make mpi_init() and mpi_free() accept a single argument
[tropicssl.git] / programs / pkey / dh_client.c
blobf3026ce0adafd7093da7a344f067703e7bd6e21a
1 /*
2 * Diffie-Hellman-Merkle key exchange (client 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_NAME "localhost"
51 #define SERVER_PORT 11999
53 int main(void)
55 FILE *f;
57 int ret, n, buflen;
58 int server_fd = -1;
60 unsigned char *p, *end;
61 unsigned char buf[1024];
62 unsigned char hash[20];
64 havege_state hs;
65 rsa_context rsa;
66 dhm_context dhm;
67 aes_context aes;
69 memset(&rsa, 0, sizeof(rsa));
70 memset(&dhm, 0, sizeof(dhm));
73 * 1. Setup the RNG
75 printf("\n . Seeding the random number generator");
76 fflush(stdout);
78 havege_init(&hs);
81 * 2. Read the server's public RSA key
83 printf("\n . Reading public key from rsa_pub.txt");
84 fflush(stdout);
86 if ((f = fopen("rsa_pub.txt", "rb")) == NULL) {
87 ret = 1;
88 printf(" failed\n ! Could not open rsa_pub.txt\n"
89 " ! Please run rsa_genkey first\n\n");
90 goto exit;
93 rsa_init(&rsa, RSA_PKCS_V15, 0, NULL, NULL);
95 if ((ret = mpi_read_file(&rsa.N, 16, f)) != 0 ||
96 (ret = mpi_read_file(&rsa.E, 16, f)) != 0) {
97 printf(" failed\n ! mpi_read_file returned %d\n\n", ret);
98 goto exit;
101 rsa.len = (mpi_msb(&rsa.N) + 7) >> 3;
103 fclose(f);
106 * 3. Initiate the connection
108 printf("\n . Connecting to tcp/%s/%d", SERVER_NAME, SERVER_PORT);
109 fflush(stdout);
111 if ((ret = net_connect(&server_fd, SERVER_NAME, SERVER_PORT)) != 0) {
112 printf(" failed\n ! net_connect returned %d\n\n", ret);
113 goto exit;
117 * 4a. First get the buffer length
119 printf("\n . Receiving the server's DH parameters");
120 fflush(stdout);
122 memset(buf, 0, sizeof(buf));
124 if ((ret = net_recv(&server_fd, buf, 2)) != 2) {
125 printf(" failed\n ! net_recv returned %d\n\n", ret);
126 goto exit;
129 n = buflen = (buf[0] << 8) | buf[1];
130 if (buflen < 1 || buflen > (int)sizeof(buf)) {
131 printf(" failed\n ! Got an invalid buffer length\n\n");
132 goto exit;
136 * 4b. Get the DHM parameters: P, G and Ys = G^Xs mod P
138 memset(buf, 0, sizeof(buf));
140 if ((ret = net_recv(&server_fd, buf, n)) != n) {
141 printf(" failed\n ! net_recv returned %d\n\n", ret);
142 goto exit;
145 p = buf, end = buf + buflen;
147 if ((ret = dhm_read_params(&dhm, &p, end)) != 0) {
148 printf(" failed\n ! dhm_read_params returned %d\n\n", ret);
149 goto exit;
152 if (dhm.len < 64 || dhm.len > 256) {
153 ret = 1;
154 printf(" failed\n ! Invalid DHM modulus size\n\n");
155 goto exit;
159 * 5. Check that the server's RSA signature matches
160 * the SHA-1 hash of (P,G,Ys)
162 printf("\n . Verifying the server's RSA signature");
163 fflush(stdout);
165 if ((n = (int)(end - p)) != rsa.len) {
166 ret = 1;
167 printf(" failed\n ! Invalid RSA signature size\n\n");
168 goto exit;
171 sha1(buf, (int)(p - 2 - buf), hash);
173 if ((ret = rsa_pkcs1_verify(&rsa, RSA_PUBLIC, RSA_SHA1,
174 0, hash, p)) != 0) {
175 printf(" failed\n ! rsa_pkcs1_verify returned %d\n\n", ret);
176 goto exit;
180 * 6. Send our public value: Yc = G ^ Xc mod P
182 printf("\n . Sending own public value to server");
183 fflush(stdout);
185 n = dhm.len;
186 if ((ret = dhm_make_public(&dhm, 256, buf, n, havege_rand, &hs)) != 0) {
187 printf(" failed\n ! dhm_make_public returned %d\n\n", ret);
188 goto exit;
191 if ((ret = net_send(&server_fd, buf, n)) != n) {
192 printf(" failed\n ! net_send returned %d\n\n", ret);
193 goto exit;
197 * 7. Derive the shared secret: K = Ys ^ Xc mod P
199 printf("\n . Shared secret: ");
200 fflush(stdout);
202 n = dhm.len;
203 if ((ret = dhm_calc_secret(&dhm, buf, &n)) != 0) {
204 printf(" failed\n ! dhm_calc_secret returned %d\n\n", ret);
205 goto exit;
208 for (n = 0; n < 16; n++)
209 printf("%02x", buf[n]);
212 * 8. Setup the AES-256 decryption key
214 * This is an overly simplified example; best practice is
215 * to hash the shared secret with a random value to derive
216 * the keying material for the encryption/decryption keys,
217 * IVs and MACs.
219 printf("...\n . Receiving and decrypting the ciphertext");
220 fflush(stdout);
222 aes_setkey_dec(&aes, buf, 256);
224 memset(buf, 0, sizeof(buf));
226 if ((ret = net_recv(&server_fd, buf, 16)) != 16) {
227 printf(" failed\n ! net_recv returned %d\n\n", ret);
228 goto exit;
231 aes_crypt_ecb(&aes, AES_DECRYPT, buf, buf);
232 buf[16] = '\0';
233 printf("\n . Plaintext is \"%s\"\n\n", (char *)buf);
235 exit:
237 net_close(server_fd);
238 rsa_free(&rsa);
239 dhm_free(&dhm);
241 #ifdef WIN32
242 printf(" + Press Enter to exit this program.\n");
243 fflush(stdout);
244 getchar();
245 #endif
247 return (ret);