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>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
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
60 unsigned char *p
, *end
;
61 unsigned char buf
[1024];
62 unsigned char hash
[20];
69 memset(&rsa
, 0, sizeof(rsa
));
70 memset(&dhm
, 0, sizeof(dhm
));
75 printf("\n . Seeding the random number generator");
81 * 2. Read the server's public RSA key
83 printf("\n . Reading public key from rsa_pub.txt");
86 if ((f
= fopen("rsa_pub.txt", "rb")) == NULL
) {
88 printf(" failed\n ! Could not open rsa_pub.txt\n"
89 " ! Please run rsa_genkey first\n\n");
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
);
101 rsa
.len
= (mpi_msb(&rsa
.N
) + 7) >> 3;
106 * 3. Initiate the connection
108 printf("\n . Connecting to tcp/%s/%d", SERVER_NAME
, SERVER_PORT
);
111 if ((ret
= net_connect(&server_fd
, SERVER_NAME
, SERVER_PORT
)) != 0) {
112 printf(" failed\n ! net_connect returned %d\n\n", ret
);
117 * 4a. First get the buffer length
119 printf("\n . Receiving the server's DH parameters");
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
);
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");
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
);
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
);
152 if (dhm
.len
< 64 || dhm
.len
> 256) {
154 printf(" failed\n ! Invalid DHM modulus size\n\n");
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");
165 if ((n
= (int)(end
- p
)) != rsa
.len
) {
167 printf(" failed\n ! Invalid RSA signature size\n\n");
171 sha1(buf
, (int)(p
- 2 - buf
), hash
);
173 if ((ret
= rsa_pkcs1_verify(&rsa
, RSA_PUBLIC
, RSA_SHA1
,
175 printf(" failed\n ! rsa_pkcs1_verify returned %d\n\n", ret
);
180 * 6. Send our public value: Yc = G ^ Xc mod P
182 printf("\n . Sending own public value to server");
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
);
191 if ((ret
= net_send(&server_fd
, buf
, n
)) != n
) {
192 printf(" failed\n ! net_send returned %d\n\n", ret
);
197 * 7. Derive the shared secret: K = Ys ^ Xc mod P
199 printf("\n . Shared secret: ");
203 if ((ret
= dhm_calc_secret(&dhm
, buf
, &n
)) != 0) {
204 printf(" failed\n ! dhm_calc_secret returned %d\n\n", ret
);
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,
219 printf("...\n . Receiving and decrypting the ciphertext");
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
);
231 aes_crypt_ecb(&aes
, AES_DECRYPT
, buf
, buf
);
233 printf("\n . Plaintext is \"%s\"\n\n", (char *)buf
);
237 net_close(server_fd
);
242 printf(" + Press Enter to exit this program.\n");