Merge lp:~rene-hummen/hipl/puzzle-fixes into lp:hipl

Proposed by René Hummen
Status: Superseded
Proposed branch: lp:~rene-hummen/hipl/puzzle-fixes
Merge into: lp:hipl
Diff against target: 901 lines (+416/-152)
17 files modified
Makefile.am (+1/-0)
hipd/cookie.c (+11/-7)
hipd/cookie.h (+2/-2)
hipd/input.c (+10/-9)
hipd/keymat.c (+10/-11)
hipd/keymat.h (+3/-1)
hipd/output.c (+4/-5)
lib/core/builder.c (+5/-4)
lib/core/builder.h (+2/-2)
lib/core/protodefs.h (+7/-3)
lib/core/solve.c (+162/-93)
lib/core/solve.h (+15/-5)
lib/core/state.h (+2/-2)
lib/tool/pk.c (+10/-8)
test/check_lib_core.c (+1/-0)
test/lib/core/solve.c (+170/-0)
test/lib/core/test_suites.h (+1/-0)
To merge this branch: bzr merge lp:~rene-hummen/hipl/puzzle-fixes
Reviewer Review Type Date Requested Status
Miika Komu Needs Information
Christof Mroz Needs Fixing
Review via email: mp+56811@code.launchpad.net

This proposal has been superseded by a proposal from 2011-04-08.

Description of the change

This branch refactors HIPL's puzzle handling functionality and generalizes the API for use with the midauth extension. It has been tested with unit tests and on virtual machines.

To post a comment you must log in.
Revision history for this message
Christof Mroz (christof-mroz) wrote :
Download full text (4.4 KiB)

Overall, this is definately cleaner than the old code.

There is one piece of code that does not match its corresponding comment; as soon as this is clarified (or fixed), I'll approve.
Would be nice if you could address the other points too (mainly missing documentation for newly added functions).

> +static int hip_calculate_puzzle_solution(const struct puzzle_common *const compute_puzzle,
> + unsigned char sha_digest[SHA_DIGEST_LENGTH],
> + const int difficulty)
> {
> - uint64_t mask = 0;
> - uint64_t randval = 0;
> - uint64_t maxtries = 0;
> - uint64_t digest = 0;
> - uint8_t cookie[48];
> - int err = 0;
> - const union {
> - struct hip_puzzle pz;
> - struct hip_solution sl;
> - } *u;
> -
> - HIP_HEXDUMP("puzzle", puzzle_or_solution,
> - (mode == HIP_VERIFY_PUZZLE ? sizeof(struct hip_solution) :
> - sizeof(struct hip_puzzle)));
> -
> - /* pre-create cookie */
> - u = puzzle_or_solution;
> -
> - HIP_IFEL(u->pz.K > HIP_PUZZLE_MAX_K, 0,
> - "Cookie K %u is higher than we are willing to calculate"
> - " (current max K=%d)\n", u->pz.K, HIP_PUZZLE_MAX_K);
> -
> - mask = hton64((1ULL << u->pz.K) - 1);
> - memcpy(cookie, &u->pz.I, sizeof(uint64_t));
> -
> - HIP_DEBUG("(u->pz.I: 0x%llx\n", u->pz.I);
> -
> - if (mode == HIP_VERIFY_PUZZLE) {
> - ipv6_addr_copy((hip_hit_t *) (cookie + 8), &hdr->hits);
> - ipv6_addr_copy((hip_hit_t *) (cookie + 24), &hdr->hitr);
> - randval = u->sl.J;
> - maxtries = 1;
> - } else if (mode == HIP_SOLVE_PUZZLE) {
> - ipv6_addr_copy((hip_hit_t *) (cookie + 8), &hdr->hitr);
> - ipv6_addr_copy((hip_hit_t *) (cookie + 24), &hdr->hits);
> - maxtries = 1ULL << (u->pz.K + 3);
> - get_random_bytes(&randval, sizeof(uint64_t));
> + uint32_t truncated_digest = 0;
> + int err = -1;
> +
> + HIP_IFEL(difficulty > max_puzzle_difficulty,
> + 1, "difficulty exceeds max. configured difficulty\n");
> +
> + HIP_IFEL(hip_build_digest(HIP_DIGEST_SHA1,
> + compute_puzzle,
> + sizeof(struct puzzle_common),
> + sha_digest),
> + -1, "failed to compute hash digest\n");

You could return early with a (successful) solution of zero if difficulty == 0.
If the caller is responsible of taking that shortcut, I'd add an assertion here to catch future callers who forget about this.

> + /* we are interested in the 8 least significant bytes */
> + truncated_digest = *(uint32_t *) &sha_digest[SHA_DIGEST_LENGTH - sizeof(uint32_t)];

The 8 least significant bytes have index 0..7. Also, sizeof(uint32_t) is 4, not 8.

> +int hip_solve_puzzle(const uint64_t puzzle,
> + const int difficulty,
> + const hip_hit_t initiator_hit,
> + const hip_hit_t responder_hit,
> + uint64_t *solution)
> +{
> + struct puzzle_common compute_puzzle;
> + unsigned char sha_digest[SHA...

Read more...

review: Needs Fixing
Revision history for this message
Christof Mroz (christof-mroz) wrote :

On Thu, 07 Apr 2011 21:59:22 +0200, Christof Mroz
<email address hidden> wrote:

>> + /* we are interested in the 8 least significant bytes */
>> + truncated_digest = *(uint32_t *) &sha_digest[SHA_DIGEST_LENGTH -
>> sizeof(uint32_t)];
>
> The 8 least significant bytes have index 0..7. Also, sizeof(uint32_t) is
> 4, not 8.

Note: I'm aware that things look differently if you interpret the digest
as a big-endian number with SHA_DIGEST_LENGTH * 8 bits; what I'm trying to
say here is: if that's what you meant in the comment, then you should
state it more verbosely (i.e. mention byte order).

Revision history for this message
Miika Komu (miika-iki) wrote :

The algorithm seems changed. Did you test it against the old, interoperable implementation?

review: Needs Information
lp:~rene-hummen/hipl/puzzle-fixes updated
5855. By René Hummen

remove write-only variables solved_puzzle and I

5859. By René Hummen

fix forward declaration in unit-tests for lib/core/solve.c

5860. By René Hummen

make difficulty > max_puzzle_difficulty an error

5861. By René Hummen

add missing doxygen documentation

5862. By René Hummen

replace uint64_t by uint8_t[8] for puzzle and solution values

puzzle and solution values are bit.fields and do not need to be
interpreted. Hence, uint64_t is not the correct data type and
leads to endianess problems for these values.

5863. By René Hummen

allow for early exit for puzzle difficulty 0

5864. By René Hummen

reflect API changes in unit-tests

5865. By René Hummen

clarify comments of on endianness

5866. By René Hummen

merged with trunk revision 5854

5867. By René Hummen

fix comparison of solution and puzzle values

5868. By René Hummen

reorder includes as suggested by Diego

5869. By René Hummen

fix doxygen comments

5870. By René Hummen

convert HIP_IFEL into if statement

5871. By René Hummen

reorder parameters of hip_verify_puzzle_solution()

5872. By René Hummen

change type of puzzle difficulty from int to uint8_t

The puzzle difficulty is transported as uint8_t on the wire.

5873. By René Hummen

address comments and improvements by Stefan

5874. By René Hummen

fix unit-tests according to previous changes

5875. By René Hummen

add solution verification unit-test for real/captured solution

5876. By René Hummen

replace ipv6_addr_copy() by simple assignment

5877. By René Hummen

declare sha_digest as a local variable

5878. By René Hummen

improve documentation of MAX_PUZZLE_DIFFICULTY

5879. By René Hummen

replace ipv6_addr_copy() by an assignment

5880. By René Hummen

minor change in local var ordering

5881. By René Hummen

change year of copyright

5882. By René Hummen

use struct puzzle_hash_input in puzzle api

5883. By René Hummen

fix doxygen

5884. By René Hummen

change output type from int to uint

5885. By René Hummen

directly exit hip_solve_puzzle instead of using break indirection

5886. By René Hummen

merge trunk revision 5878

Unmerged revisions

5886. By René Hummen

merge trunk revision 5878

5885. By René Hummen

directly exit hip_solve_puzzle instead of using break indirection

5884. By René Hummen

change output type from int to uint

5883. By René Hummen

fix doxygen

5882. By René Hummen

use struct puzzle_hash_input in puzzle api

5881. By René Hummen

change year of copyright

5880. By René Hummen

minor change in local var ordering

5879. By René Hummen

replace ipv6_addr_copy() by an assignment

5878. By René Hummen

improve documentation of MAX_PUZZLE_DIFFICULTY

5877. By René Hummen

declare sha_digest as a local variable

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile.am'
2--- Makefile.am 2011-04-06 15:52:33 +0000
3+++ Makefile.am 2011-04-08 15:38:33 +0000
4@@ -207,6 +207,7 @@
5
6 test_check_lib_core_SOURCES = test/check_lib_core.c \
7 test/lib/core/hit.c \
8+ test/lib/core/solve.c \
9 test/lib/core/straddr.c
10
11 test_check_lib_tool_SOURCES = test/check_lib_tool.c \
12
13=== modified file 'hipd/cookie.c'
14--- hipd/cookie.c 2011-04-05 16:44:22 +0000
15+++ hipd/cookie.c 2011-04-08 15:38:33 +0000
16@@ -56,7 +56,7 @@
17
18 #define HIP_R1TABLESIZE 3 /* precreate only this many R1s */
19
20-static int hip_cookie_difficulty = 1ULL; /* a difficulty of i leads to approx. 2^(i-1) hash computations during BEX */
21+static int hip_cookie_difficulty = 0; /* a difficulty of i leads to approx. 2^(i-1) hash computations during BEX */
22
23 /**
24 * query for current puzzle difficulty
25@@ -77,9 +77,9 @@
26 */
27 static int hip_set_cookie_difficulty(int k)
28 {
29- if (k > HIP_PUZZLE_MAX_K || k < 1) {
30+ if (k > max_puzzle_difficulty || k < 0) {
31 HIP_ERROR("Bad cookie value (%d), min=%d, max=%d\n",
32- k, 1, HIP_PUZZLE_MAX_K);
33+ k, 1, max_puzzle_difficulty);
34 return -1;
35 }
36 hip_cookie_difficulty = k;
37@@ -347,7 +347,7 @@
38
39 HIP_IFEL(solution->K != result->Ck, -1,
40 "Solution's K did not match any sent Ks.\n");
41- HIP_IFEL(solution->I != result->Ci, -1,
42+ HIP_IFEL(memcmp(solution->I, result->Ci, PUZZLE_LENGTH), -1,
43 "Solution's I did not match the sent I\n");
44 HIP_IFEL(memcmp(solution->opaque, result->Copaque,
45 HIP_PUZZLE_OPAQUE_LEN), -1,
46@@ -356,15 +356,19 @@
47 } else {
48 HIP_HEXDUMP("solution", solution, sizeof(*solution));
49 HIP_HEXDUMP("puzzle", puzzle, sizeof(*puzzle));
50- HIP_IFEL(solution->I != puzzle->I, -1,
51+ HIP_IFEL(memcmp(solution->I, puzzle->I, PUZZLE_LENGTH), -1,
52 "Solution's I did not match the sent I\n");
53 HIP_IFEL(memcmp(solution->opaque, puzzle->opaque,
54 HIP_PUZZLE_OPAQUE_LEN), -1,
55 "Solution's opaque data does not match the opaque data sent\n");
56 }
57
58- HIP_IFEL(!hip_solve_puzzle(solution, hdr, HIP_VERIFY_PUZZLE), -1,
59- "Puzzle incorrectly solved.\n");
60+ HIP_IFEL(hip_verify_puzzle_solution(solution->I,
61+ solution->K,
62+ hdr->hits,
63+ hdr->hitr,
64+ solution->J),
65+ -1, "Puzzle incorrectly solved.\n");
66
67 out_err:
68 return err;
69
70=== modified file 'hipd/cookie.h'
71--- hipd/cookie.h 2011-01-10 13:12:17 +0000
72+++ hipd/cookie.h 2011-04-08 15:38:33 +0000
73@@ -34,9 +34,9 @@
74 struct hip_r1entry {
75 struct hip_common *r1;
76 uint32_t generation;
77- uint64_t Ci;
78+ uint8_t Ci[PUZZLE_LENGTH];
79 uint8_t Ck;
80- uint8_t Copaque[3];
81+ uint8_t Copaque[HIP_PUZZLE_OPAQUE_LEN];
82 };
83
84 struct hip_common *hip_get_r1(struct in6_addr *ip_i,
85
86=== modified file 'hipd/input.c'
87--- hipd/input.c 2011-04-08 08:47:50 +0000
88+++ hipd/input.c 2011-04-08 15:38:33 +0000
89@@ -235,8 +235,8 @@
90 * @return zero on success, or negative on error.
91 */
92 static int hip_produce_keying_material(struct hip_packet_context *ctx,
93- uint64_t I,
94- uint64_t J)
95+ const uint8_t I[PUZZLE_LENGTH],
96+ const uint8_t J[PUZZLE_LENGTH])
97 {
98 char *dh_shared_key = NULL;
99 int hip_transf_length, hmac_transf_length;
100@@ -868,16 +868,17 @@
101 /* Solve puzzle: if this is a retransmission, we have to preserve
102 * the old solution. */
103 if (!retransmission) {
104- const struct hip_puzzle *pz2 = NULL;
105+ const struct hip_puzzle *pz = NULL;
106
107- HIP_IFEL(!(pz2 = hip_get_param(ctx->input_msg, HIP_PARAM_PUZZLE)), -EINVAL,
108+ HIP_IFEL(!(pz = hip_get_param(ctx->input_msg, HIP_PARAM_PUZZLE)), -EINVAL,
109 "Malformed R1 packet. PUZZLE parameter missing\n");
110- HIP_IFEL((ctx->hadb_entry->puzzle_solution =
111- hip_solve_puzzle(pz2,
112- ctx->input_msg,
113- HIP_SOLVE_PUZZLE)) == 0,
114+ HIP_IFEL(hip_solve_puzzle(pz->I,
115+ pz->K,
116+ ctx->input_msg->hitr,
117+ ctx->input_msg->hits,
118+ ctx->hadb_entry->puzzle_solution),
119 -EINVAL, "Solving of puzzle failed\n");
120- ctx->hadb_entry->puzzle_i = pz2->I;
121+ memcpy(ctx->hadb_entry->puzzle_i, pz->I, PUZZLE_LENGTH);
122 }
123
124 HIP_DEBUG("Build normal I2.\n");
125
126=== modified file 'hipd/keymat.c'
127--- hipd/keymat.c 2011-01-11 13:59:46 +0000
128+++ hipd/keymat.c 2011-04-08 15:38:33 +0000
129@@ -58,19 +58,18 @@
130 static uint8_t *hip_create_keymat_buffer(char *kij, size_t kij_len, size_t hash_len,
131 struct in6_addr *smaller_hit,
132 struct in6_addr *bigger_hit,
133- uint64_t I, uint64_t J)
134+ const uint8_t I[PUZZLE_LENGTH],
135+ const uint8_t J[PUZZLE_LENGTH])
136
137 {
138 uint8_t *buffer = NULL, *cur = NULL;
139 size_t requiredmem;
140
141- HIP_DEBUG("\n");
142- /* 2*sizeof(uint64_t) added to take care of I and J. */
143 if (2 * sizeof(struct in6_addr) < hash_len) {
144- requiredmem = kij_len + hash_len + sizeof(uint8_t) + 2 * sizeof(uint64_t);
145+ requiredmem = kij_len + hash_len + sizeof(uint8_t) + 2 * PUZZLE_LENGTH;
146 } else {
147 requiredmem = kij_len + 2 * sizeof(struct in6_addr) +
148- sizeof(uint8_t) + 2 * sizeof(uint64_t);
149+ sizeof(uint8_t) + 2 * PUZZLE_LENGTH;
150 }
151 buffer = malloc(requiredmem);
152 if (!buffer) {
153@@ -85,10 +84,10 @@
154 cur += sizeof(struct in6_addr);
155 memcpy(cur, (uint8_t *) bigger_hit, sizeof(struct in6_addr));
156 cur += sizeof(struct in6_addr);
157- memcpy(cur, &I, sizeof(uint64_t)); // XX CHECK: network byte order?
158- cur += sizeof(uint64_t);
159- memcpy(cur, &J, sizeof(uint64_t)); // XX CHECK: network byte order?
160- cur += sizeof(uint64_t);
161+ memcpy(cur, I, PUZZLE_LENGTH);
162+ cur += PUZZLE_LENGTH;
163+ memcpy(cur, J, PUZZLE_LENGTH);
164+ cur += PUZZLE_LENGTH;
165 *(cur) = 1;
166 cur += sizeof(uint8_t);
167
168@@ -138,8 +137,8 @@
169 struct in6_addr *hit1,
170 struct in6_addr *hit2,
171 uint8_t *calc_index,
172- uint64_t I,
173- uint64_t J)
174+ const uint8_t I[PUZZLE_LENGTH],
175+ const uint8_t J[PUZZLE_LENGTH])
176 {
177 int bufsize;
178 uint8_t index_nbr = 1;
179
180=== modified file 'hipd/keymat.h'
181--- hipd/keymat.h 2010-10-15 15:29:14 +0000
182+++ hipd/keymat.h 2011-04-08 15:38:33 +0000
183@@ -37,7 +37,9 @@
184 void hip_make_keymat(char *kij, size_t kij_len,
185 struct hip_keymat_keymat *keymat,
186 void *dstbuf, size_t dstbuflen, struct in6_addr *hit1,
187- struct in6_addr *hit2, uint8_t *calc_index, uint64_t I, uint64_t J);
188+ struct in6_addr *hit2, uint8_t *calc_index,
189+ const uint8_t I[PUZZLE_LENGTH],
190+ const uint8_t J[PUZZLE_LENGTH]);
191 int hip_keymat_draw_and_copy(unsigned char *dst,
192 struct hip_keymat_keymat *keymat,
193 int len);
194
195=== modified file 'hipd/output.c'
196--- hipd/output.c 2011-04-06 09:07:51 +0000
197+++ hipd/output.c 2011-04-08 15:38:33 +0000
198@@ -636,8 +636,10 @@
199 /********** R1_COUNTER (OPTIONAL) *********/
200
201 /********** PUZZLE ************/
202+ const uint8_t zero_i[PUZZLE_LENGTH] = { 0 };
203+
204 HIP_IFEL(hip_build_param_puzzle(err, cookie_k,
205- 42 /* 2^(42-32) sec lifetime */, 0, 0),
206+ 42 /* 2^(42-32) sec lifetime */, 0, zero_i),
207 NULL, "Cookies were burned. Bummer!\n");
208
209 /* Parameter Diffie-Hellman */
210@@ -702,7 +704,6 @@
211 /* Fill puzzle parameters */
212 {
213 struct hip_puzzle *pz;
214- uint64_t random_i;
215
216 HIP_IFEL(!(pz = hip_get_param_readwrite(err, HIP_PARAM_PUZZLE)), NULL,
217 "Internal error\n");
218@@ -711,9 +712,7 @@
219 pz->opaque[0] = 'H';
220 pz->opaque[1] = 'I';
221 //pz->opaque[2] = 'P';
222- /** @todo Remove random_i variable. */
223- get_random_bytes(&random_i, sizeof(random_i));
224- pz->I = random_i;
225+ get_random_bytes(pz->I, PUZZLE_LENGTH);
226 }
227
228 /* Packet ready */
229
230=== modified file 'lib/core/builder.c'
231--- lib/core/builder.c 2011-04-07 16:58:58 +0000
232+++ lib/core/builder.c 2011-04-08 15:38:33 +0000
233@@ -2385,7 +2385,8 @@
234 * @return zero for success, or non-zero on error
235 */
236 int hip_build_param_puzzle(struct hip_common *msg, uint8_t val_K,
237- uint8_t lifetime, uint32_t opaque, uint64_t random_i)
238+ uint8_t lifetime, uint32_t opaque,
239+ const uint8_t random_i[PUZZLE_LENGTH])
240 {
241 struct hip_puzzle puzzle;
242 int err = 0;
243@@ -2402,7 +2403,7 @@
244 puzzle.lifetime = lifetime;
245 puzzle.opaque[0] = opaque & 0xFF;
246 puzzle.opaque[1] = (opaque & 0xFF00) >> 8;
247- puzzle.I = random_i;
248+ memcpy(puzzle.I, random_i, PUZZLE_LENGTH);
249
250 err = hip_build_generic_param(msg, &puzzle,
251 sizeof(struct hip_tlv_common),
252@@ -2515,7 +2516,7 @@
253 */
254 int hip_build_param_solution(struct hip_common *msg,
255 const struct hip_puzzle *pz,
256- uint64_t val_J)
257+ uint8_t val_J[PUZZLE_LENGTH])
258 {
259 struct hip_solution cookie;
260 int err = 0;
261@@ -2527,7 +2528,7 @@
262 /* Type 2 (in R1) or 3 (in I2) */
263 hip_set_param_type((struct hip_tlv_common *) &cookie, HIP_PARAM_SOLUTION);
264
265- cookie.J = val_J;
266+ memcpy(cookie.J, val_J, PUZZLE_LENGTH);
267 memcpy(&cookie.K, &pz->K, 12); /* copy: K (1), reserved (1),
268 * opaque (2) and I (8 bytes). */
269 cookie.reserved = 0;
270
271=== modified file 'lib/core/builder.h'
272--- lib/core/builder.h 2011-04-02 20:38:36 +0000
273+++ lib/core/builder.h 2011-04-08 15:38:33 +0000
274@@ -130,7 +130,7 @@
275 uint8_t,
276 uint8_t,
277 uint32_t,
278- uint64_t);
279+ const uint8_t *);
280
281 int hip_build_param_challenge_request(struct hip_common *,
282 uint8_t,
283@@ -150,7 +150,7 @@
284 uint8_t);
285 int hip_build_param_solution(struct hip_common *,
286 const struct hip_puzzle *,
287- uint64_t);
288+ uint8_t *);
289
290 int hip_build_param_challenge_response(struct hip_common *,
291 const struct hip_challenge_request *,
292
293=== modified file 'lib/core/protodefs.h'
294--- lib/core/protodefs.h 2011-02-04 14:44:37 +0000
295+++ lib/core/protodefs.h 2011-04-08 15:38:33 +0000
296@@ -737,13 +737,17 @@
297 uint64_t generation;
298 } __attribute__ ((packed));
299
300+
301+/* puzzle and solutions are defined to have a length of 8 bytes */
302+#define PUZZLE_LENGTH 8
303+
304 struct hip_puzzle {
305 hip_tlv type;
306 hip_tlv_len length;
307 uint8_t K;
308 uint8_t lifetime;
309 uint8_t opaque[HIP_PUZZLE_OPAQUE_LEN];
310- uint64_t I;
311+ uint8_t I[PUZZLE_LENGTH];
312 } __attribute__ ((packed));
313
314 struct hip_solution {
315@@ -752,8 +756,8 @@
316 uint8_t K;
317 uint8_t reserved;
318 uint8_t opaque[HIP_PUZZLE_OPAQUE_LEN];
319- uint64_t I;
320- uint64_t J;
321+ uint8_t I[PUZZLE_LENGTH];
322+ uint8_t J[PUZZLE_LENGTH];
323 } __attribute__ ((packed));
324
325
326
327=== modified file 'lib/core/solve.c'
328--- lib/core/solve.c 2011-01-24 10:21:17 +0000
329+++ lib/core/solve.c 2011-04-08 15:38:33 +0000
330@@ -28,11 +28,14 @@
331 * @brief HIP computation puzzle solving algorithms
332 *
333 * @author Miika Komu <miika@iki.fi>
334+ * @author Rene Hummen
335 */
336
337 #include <errno.h>
338+#include <openssl/rand.h>
339 #include <stdint.h>
340 #include <string.h>
341+#include <strings.h>
342
343 #include "config.h"
344 #include "builder.h"
345@@ -43,104 +46,170 @@
346 #include "protodefs.h"
347 #include "solve.h"
348
349+struct puzzle_common {
350+ uint8_t puzzle[PUZZLE_LENGTH];
351+ hip_hit_t initiator_hit;
352+ hip_hit_t responder_hit;
353+ uint8_t solution[PUZZLE_LENGTH];
354+} __attribute__ ((packed));
355+
356+// max. 2^max_puzzle_difficulty tries to solve a puzzle
357+#define MAX_PUZZLE_SOLUTION_TRIES 1ULL << max_puzzle_difficulty
358+
359 /**
360- * solve a computational puzzle for HIP
361- *
362- * @param puzzle_or_solution Either a pointer to hip_puzzle or hip_solution structure
363- * @param hdr The incoming R1/I2 packet header.
364- * @param mode Either HIP_VERIFY_PUZZLE of HIP_SOLVE_PUZZLE
365- *
366- * @note The K and I is read from the @c puzzle_or_solution.
367- * @note Regarding to return value of zero, I don't see why 0 couldn't solve the
368- * puzzle too, but since the odds are 1/2^64 to try 0, I don't see the point
369- * in improving this now.
370- * @return The J that solves the puzzle is returned, or 0 to indicate an error.
371+ * Computes a single iteration for a computational puzzle
372+ *
373+ * @param compute_puzzle puzzle to be solved or verified
374+ * @param sha_digest buffer for hash digest
375+ * @param difficulty difficulty of the puzzle (number of leading zeros)
376+ * @return 0 when hash has >= #difficulty least significant bits as zeros, 1
377+ * when hash has < #difficulty least significant bits as zeros,
378+ * -1 in case of an error
379 */
380-uint64_t hip_solve_puzzle(const void *puzzle_or_solution,
381- const struct hip_common *hdr,
382- int mode)
383+static int hip_calculate_puzzle_solution(const struct puzzle_common *const compute_puzzle,
384+ unsigned char sha_digest[SHA_DIGEST_LENGTH],
385+ const int difficulty)
386 {
387- uint64_t mask = 0;
388- uint64_t randval = 0;
389- uint64_t maxtries = 0;
390- uint64_t digest = 0;
391- uint8_t cookie[48];
392- int err = 0;
393- const union {
394- struct hip_puzzle pz;
395- struct hip_solution sl;
396- } *u;
397-
398- HIP_HEXDUMP("puzzle", puzzle_or_solution,
399- (mode == HIP_VERIFY_PUZZLE ? sizeof(struct hip_solution) :
400- sizeof(struct hip_puzzle)));
401-
402- /* pre-create cookie */
403- u = puzzle_or_solution;
404-
405- HIP_IFEL(u->pz.K > HIP_PUZZLE_MAX_K, 0,
406- "Cookie K %u is higher than we are willing to calculate"
407- " (current max K=%d)\n", u->pz.K, HIP_PUZZLE_MAX_K);
408-
409- mask = hton64((1ULL << u->pz.K) - 1);
410- memcpy(cookie, &u->pz.I, sizeof(uint64_t));
411-
412- HIP_DEBUG("(u->pz.I: 0x%llx\n", u->pz.I);
413-
414- if (mode == HIP_VERIFY_PUZZLE) {
415- ipv6_addr_copy((hip_hit_t *) (cookie + 8), &hdr->hits);
416- ipv6_addr_copy((hip_hit_t *) (cookie + 24), &hdr->hitr);
417- randval = u->sl.J;
418- maxtries = 1;
419- } else if (mode == HIP_SOLVE_PUZZLE) {
420- ipv6_addr_copy((hip_hit_t *) (cookie + 8), &hdr->hitr);
421- ipv6_addr_copy((hip_hit_t *) (cookie + 24), &hdr->hits);
422- maxtries = 1ULL << (u->pz.K + 3);
423- get_random_bytes(&randval, sizeof(uint64_t));
424+ uint32_t truncated_digest = 0;
425+ int err = -1;
426+
427+ /* any puzzle solution is acceptable for difficulty 0 */
428+ if (difficulty == 0) {
429+ return 0;
430+ }
431+
432+ HIP_IFEL(difficulty > max_puzzle_difficulty,
433+ -1, "difficulty exceeds max. configured difficulty\n");
434+
435+ HIP_IFEL(hip_build_digest(HIP_DIGEST_SHA1,
436+ compute_puzzle,
437+ sizeof(struct puzzle_common),
438+ sha_digest),
439+ -1, "failed to compute hash digest\n");
440+
441+ /* we are interested in least significant bytes in network byte-order */
442+ truncated_digest = *(uint32_t *) &sha_digest[SHA_DIGEST_LENGTH - sizeof(uint32_t)];
443+
444+ /* make sure to interpret the solution equally across platforms
445+ * (i.e., network byte-order), when calculating puzzle solution */
446+ truncated_digest = htonl(truncated_digest);
447+
448+ /* check if position of first least significant 1-bit is higher than
449+ * difficulty */
450+ if (ffs(truncated_digest) > difficulty) {
451+ err = 0;
452 } else {
453- HIP_OUT_ERR(0, "Unknown mode: %d\n", mode);
454- }
455-
456- HIP_DEBUG("K=%u, maxtries (with k+2)=%llu\n", u->pz.K, maxtries);
457- /* while loops should work even if the maxtries is unsigned
458- * if maxtries = 1 ---> while(1 > 0) [maxtries == 0 now]...
459- * the next round while (0 > 0) [maxtries > 0 now]
460- */
461- while (maxtries-- > 0) {
462- uint8_t sha_digest[HIP_AH_SHA_LEN];
463-
464- /* must be 8 */
465- memcpy(cookie + 40, (uint8_t *) &randval, sizeof(uint64_t));
466-
467- hip_build_digest(HIP_DIGEST_SHA1, cookie, 48, sha_digest);
468-
469- /* copy the last 8 bytes for checking */
470- memcpy(&digest, sha_digest + 12, sizeof(uint64_t));
471-
472- /* now, in order to be able to do correctly the bitwise
473- * AND-operation we have to remember that little endian
474- * processors will interpret the digest and mask reversely.
475- * digest is the last 64 bits of the sha1-digest.. how that is
476- * ordered in processors registers etc.. does not matter to us.
477- * If the last 64 bits of the sha1-digest is
478- * 0x12345678DEADBEEF, whether we have 0xEFBEADDE78563412
479- * doesn't matter because the mask matters... if the mask is
480- * 0x000000000000FFFF (or in other endianness
481- * 0xFFFF000000000000). Either ways... the result is
482- * 0x000000000000BEEF or 0xEFBE000000000000, which the cpu
483- * interprets as 0xBEEF. The mask is converted to network byte
484- * order (above).
485- */
486- if ((digest & mask) == 0) {
487- return randval;
488+ err = 1;
489+ }
490+
491+out_err:
492+ return err;
493+}
494+
495+/**
496+ * Solve a computational puzzle for HIP
497+ *
498+ * @param puzzle puzzle to be solved
499+ * @param difficulty difficulty of the puzzle
500+ * @param initiator_hit initiator HIT of the message exchange
501+ * @param responder_hit responder HIT of the message exchange
502+ * @param solution computed puzzle solution
503+ * @return 0 when solution was found, 1 in case no solution was found after
504+ * MAX_PUZZLE_SOLUTION_TRIES, -1 in case of an error
505+ */
506+int hip_solve_puzzle(const uint8_t puzzle[PUZZLE_LENGTH],
507+ const int difficulty,
508+ const hip_hit_t initiator_hit,
509+ const hip_hit_t responder_hit,
510+ uint8_t solution[PUZZLE_LENGTH])
511+{
512+ struct puzzle_common compute_puzzle;
513+ unsigned char sha_digest[SHA_DIGEST_LENGTH];
514+ int err = -1;
515+ uint32_t i = 0;
516+
517+ HIP_IFEL(!solution, -1, "invalid parameter passed (NULL)\n");
518+
519+ HIP_IFEL(difficulty > max_puzzle_difficulty, -1,
520+ "Cookie (K = %i) is higher than we are willing to calculate"
521+ " (current max K = %i)\n", difficulty, max_puzzle_difficulty);
522+
523+ /* solution is correct iff:
524+ * 0 == V := Ltrunc( RHASH( I2.I | I2.hit_i | I2.hit_r | I2.J ), K )
525+ * (RFC 5201 - Appendix A) */
526+ memcpy(compute_puzzle.puzzle, puzzle, PUZZLE_LENGTH);
527+ ipv6_addr_copy(&compute_puzzle.initiator_hit, &initiator_hit);
528+ ipv6_addr_copy(&compute_puzzle.responder_hit, &responder_hit);
529+ RAND_bytes(compute_puzzle.solution, PUZZLE_LENGTH);
530+
531+ // any puzzle solution is acceptable for difficulty 0
532+ if (difficulty == 0) {
533+ return 0;
534+ }
535+
536+ for (i = 0; i < MAX_PUZZLE_SOLUTION_TRIES; i++) {
537+ // now do the computations
538+ err = hip_calculate_puzzle_solution(&compute_puzzle,
539+ sha_digest,
540+ difficulty);
541+ if (err == 0) {
542+ memcpy(solution, compute_puzzle.solution, PUZZLE_LENGTH);
543+ break;
544+ } else if (err > 0) {
545+ // increase random value by one and try again
546+ (*(uint64_t *) compute_puzzle.solution)++;
547+ } else {
548+ memset(solution, 0, PUZZLE_LENGTH);
549+ break;
550 }
551-
552- /* It seems like the puzzle was not correctly solved */
553- HIP_IFEL(mode == HIP_VERIFY_PUZZLE, 0, "Puzzle incorrect\n");
554- randval++;
555- }
556-
557- HIP_ERROR("Could not solve the puzzle, no solution found\n");
558+ }
559+
560+out_err:
561+ if (i == MAX_PUZZLE_SOLUTION_TRIES) {
562+ HIP_ERROR("Could not solve the puzzle, no solution found\n");
563+ }
564+
565+ return err;
566+}
567+
568+/**
569+ * Verify a computational puzzle for HIP
570+ *
571+ * @param puzzle puzzle to be verified
572+ * @param difficulty difficulty of the puzzle
573+ * @param initiator_hit initiator HIT of the message exchange
574+ * @param responder_hit responder HIT of the message exchange
575+ * @param solution puzzle solution to be verified
576+ * @return 0 when solution is correct, -1 otherwise
577+ */
578+int hip_verify_puzzle_solution(const uint8_t puzzle[PUZZLE_LENGTH],
579+ const uint8_t difficulty,
580+ const hip_hit_t initiator_hit,
581+ const hip_hit_t responder_hit,
582+ const uint8_t solution[PUZZLE_LENGTH])
583+{
584+ struct puzzle_common compute_puzzle;
585+ unsigned char sha_digest[SHA_DIGEST_LENGTH];
586+ int err = 0;
587+
588+ // any puzzle solution is acceptable for difficulty 0
589+ if (difficulty == 0) {
590+ return 0;
591+ }
592+
593+ /* solution is correct iff:
594+ * 0 == V := Ltrunc( RHASH( I2.I | I2.hit_i | I2.hit_r | I2.J ), K )
595+ * (RFC 5201 - Appendix A) */
596+ memcpy(compute_puzzle.puzzle, puzzle, PUZZLE_LENGTH);
597+ ipv6_addr_copy(&compute_puzzle.initiator_hit, &initiator_hit);
598+ ipv6_addr_copy(&compute_puzzle.responder_hit, &responder_hit);
599+ memcpy(compute_puzzle.solution, solution, PUZZLE_LENGTH);
600+
601+ HIP_IFEL(hip_calculate_puzzle_solution(&compute_puzzle,
602+ sha_digest,
603+ difficulty),
604+ -1, "failed to verify puzzle solution\n");
605+
606 out_err:
607 return err;
608 }
609
610=== modified file 'lib/core/solve.h'
611--- lib/core/solve.h 2010-10-15 15:29:14 +0000
612+++ lib/core/solve.h 2011-04-08 15:38:33 +0000
613@@ -30,10 +30,20 @@
614
615 #include "protodefs.h"
616
617-#define HIP_PUZZLE_MAX_K 28
618-
619-uint64_t hip_solve_puzzle(const void *puzzle,
620- const struct hip_common *hdr, int mode);
621-int hip_solve_puzzle_m(struct hip_common *out, struct hip_common *in);
622+/* right now we only support difficulties up to sizeof(int), as only ffs
623+ * is available on OpenWRT */
624+static const int max_puzzle_difficulty = sizeof(int) * 8 >= 28 ? 28 : sizeof(int) * 8;
625+
626+int hip_solve_puzzle(const uint8_t puzzle[PUZZLE_LENGTH],
627+ const int difficulty,
628+ const hip_hit_t initiator_hit,
629+ const hip_hit_t responder_hit,
630+ uint8_t solution[PUZZLE_LENGTH]);
631+
632+int hip_verify_puzzle_solution(const uint8_t puzzle[PUZZLE_LENGTH],
633+ const uint8_t difficulty,
634+ const hip_hit_t initiator_hit,
635+ const hip_hit_t responder_hit,
636+ const uint8_t solution[PUZZLE_LENGTH]);
637
638 #endif /* HIP_LIB_CORE_SOLVE_H */
639
640=== modified file 'lib/core/state.h'
641--- lib/core/state.h 2011-02-06 09:03:39 +0000
642+++ lib/core/state.h 2011-04-08 15:38:33 +0000
643@@ -294,13 +294,13 @@
644 /** A function pointer to a function that verifies peer's host identity. */
645 int (*verify)(void *, struct hip_common *);
646 /** For retransmission. */
647- uint64_t puzzle_solution;
648+ uint8_t puzzle_solution[PUZZLE_LENGTH];
649 /** LOCATOR parameter. Just tmp save if sent in R1 no @c esp_info so
650 * keeping it here 'till the hip_update_locator_parameter can be done.
651 * @todo Remove this kludge. */
652 struct hip_locator *locator;
653 /** For retransmission. */
654- uint64_t puzzle_i;
655+ uint8_t puzzle_i[PUZZLE_LENGTH];
656 /** Used for UPDATE and CLOSE. When we sent multiple identical UPDATE
657 * packets between different address combinations, we don't modify
658 * the opaque data. */
659
660=== modified file 'lib/tool/pk.c'
661--- lib/tool/pk.c 2011-04-04 13:59:21 +0000
662+++ lib/tool/pk.c 2011-04-08 15:38:33 +0000
663@@ -131,8 +131,8 @@
664 uint8_t sha1_digest[HIP_AH_SHA_LEN];
665 struct in6_addr tmpaddr;
666 struct hip_puzzle *pz = NULL;
667- uint8_t opaque[3];
668- uint64_t randi = 0;
669+ uint8_t opaque[HIP_PUZZLE_OPAQUE_LEN];
670+ uint8_t rand_i[PUZZLE_LENGTH];
671
672 ipv6_addr_copy(&tmpaddr, &msg->hitr); /* so update is handled, too */
673
674@@ -146,11 +146,13 @@
675
676 HIP_IFEL(!(pz = hip_get_param_readwrite(msg, HIP_PARAM_PUZZLE)),
677 -ENOENT, "Illegal R1 packet (puzzle missing)\n");
678- memcpy(opaque, pz->opaque, sizeof(pz->opaque));
679- randi = pz->I;
680
681- memset(pz->opaque, 0, sizeof(pz->opaque));
682- pz->I = 0;
683+ /* temporarily store original puzzle values */
684+ memcpy(opaque, pz->opaque, HIP_PUZZLE_OPAQUE_LEN);
685+ memcpy(rand_i, pz->I, PUZZLE_LENGTH);
686+ /* R1 signature is computed over zero values */
687+ memset(pz->opaque, 0, HIP_PUZZLE_OPAQUE_LEN);
688+ memset(pz->I, 0, PUZZLE_LENGTH);
689 } else {
690 HIP_IFEL(!(sig = hip_get_param_readwrite(msg, HIP_PARAM_HIP_SIGNATURE)),
691 -ENOENT, "Could not find signature\n");
692@@ -182,8 +184,8 @@
693 #endif
694
695 if (hip_get_msg_type(msg) == HIP_R1) {
696- memcpy(pz->opaque, opaque, sizeof(pz->opaque));
697- pz->I = randi;
698+ memcpy(pz->opaque, opaque, HIP_PUZZLE_OPAQUE_LEN);
699+ memcpy(pz->I, rand_i, PUZZLE_LENGTH);
700 }
701
702 ipv6_addr_copy(&msg->hitr, &tmpaddr);
703
704=== modified file 'test/check_lib_core.c'
705--- test/check_lib_core.c 2011-02-18 14:39:38 +0000
706+++ test/check_lib_core.c 2011-04-08 15:38:33 +0000
707@@ -38,6 +38,7 @@
708 {
709 int number_failed;
710 SRunner *sr = srunner_create(lib_core_hit());
711+ srunner_add_suite(sr, lib_core_solve());
712 srunner_add_suite(sr, lib_core_straddr());
713
714 srunner_run_all(sr, CK_NORMAL);
715
716=== added file 'test/lib/core/solve.c'
717--- test/lib/core/solve.c 1970-01-01 00:00:00 +0000
718+++ test/lib/core/solve.c 2011-04-08 15:38:33 +0000
719@@ -0,0 +1,170 @@
720+/*
721+ * Copyright (c) 2010 Aalto University and RWTH Aachen University.
722+ *
723+ * Permission is hereby granted, free of charge, to any person
724+ * obtaining a copy of this software and associated documentation
725+ * files (the "Software"), to deal in the Software without
726+ * restriction, including without limitation the rights to use,
727+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
728+ * copies of the Software, and to permit persons to whom the
729+ * Software is furnished to do so, subject to the following
730+ * conditions:
731+ *
732+ * The above copyright notice and this permission notice shall be
733+ * included in all copies or substantial portions of the Software.
734+ *
735+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
736+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
737+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
738+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
739+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
740+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
741+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
742+ * OTHER DEALINGS IN THE SOFTWARE.
743+ */
744+
745+/**
746+ * @file
747+ * @author Rene Hummen
748+ */
749+
750+#include <check.h>
751+#include <openssl/rand.h>
752+#include <stdint.h>
753+
754+#include "lib/core/solve.h"
755+#include "test_suites.h"
756+
757+START_TEST(test_hip_solve_puzzle_NULL_solution)
758+{
759+ uint8_t puzzle[PUZZLE_LENGTH] = { 0 };
760+ int difficulty = 0;
761+ hip_hit_t initiator;
762+ hip_hit_t responder;
763+
764+ RAND_bytes((unsigned char *)&puzzle, sizeof(uint64_t));
765+
766+ fail_unless(hip_solve_puzzle(puzzle,
767+ difficulty,
768+ initiator,
769+ responder,
770+ NULL) == -1,
771+ NULL);
772+}
773+END_TEST
774+
775+START_TEST(test_hip_solve_puzzle_0_K)
776+{
777+ uint8_t puzzle[PUZZLE_LENGTH] = { 0 };
778+ int difficulty = 0;
779+ hip_hit_t initiator;
780+ hip_hit_t responder;
781+ uint8_t solution[PUZZLE_LENGTH] = { 0 };
782+
783+ RAND_bytes((unsigned char *)&puzzle, sizeof(PUZZLE_LENGTH));
784+
785+ fail_unless(hip_solve_puzzle(puzzle,
786+ difficulty,
787+ initiator,
788+ responder,
789+ solution) == 0,
790+ NULL);
791+}
792+END_TEST
793+
794+START_TEST(test_hip_solve_puzzle_5_K)
795+{
796+ uint8_t puzzle[PUZZLE_LENGTH] = { 0 };
797+ int difficulty = 5;
798+ hip_hit_t initiator;
799+ hip_hit_t responder;
800+ uint8_t solution[PUZZLE_LENGTH] = { 0 };
801+
802+ RAND_bytes((unsigned char *)&puzzle, sizeof(uint64_t));
803+
804+ fail_unless(hip_solve_puzzle(puzzle,
805+ difficulty,
806+ initiator,
807+ responder,
808+ solution) == 0,
809+ NULL);
810+}
811+END_TEST
812+
813+START_TEST(test_hip_solve_puzzle_exceeding_K)
814+{
815+ uint8_t puzzle[PUZZLE_LENGTH] = { 0 };
816+ int difficulty = max_puzzle_difficulty + 1;
817+ hip_hit_t initiator;
818+ hip_hit_t responder;
819+ uint8_t solution[PUZZLE_LENGTH] = { 0 };
820+
821+ RAND_bytes((unsigned char *)&puzzle, sizeof(uint64_t));
822+
823+ fail_unless(hip_solve_puzzle(puzzle,
824+ difficulty,
825+ initiator,
826+ responder,
827+ solution) == -1,
828+ NULL);
829+}
830+END_TEST
831+
832+START_TEST(test_hip_solve_puzzle_invalid)
833+{
834+ uint8_t puzzle[PUZZLE_LENGTH] = { 1 };
835+ int difficulty = 20;
836+ hip_hit_t initiator;
837+ hip_hit_t responder;
838+ uint8_t solution[PUZZLE_LENGTH] = { 0 };
839+
840+ fail_unless(hip_verify_puzzle_solution(puzzle,
841+ difficulty,
842+ initiator,
843+ responder,
844+ solution) == -1,
845+ NULL);
846+}
847+END_TEST
848+
849+START_TEST(test_hip_solve_puzzle_valid)
850+{
851+ uint8_t puzzle[PUZZLE_LENGTH] = { 0 };
852+ int difficulty = 8;
853+ hip_hit_t initiator;
854+ hip_hit_t responder;
855+ uint8_t solution[PUZZLE_LENGTH] = { 0 };
856+
857+ RAND_bytes((unsigned char *)&puzzle, sizeof(uint64_t));
858+
859+ fail_unless(hip_solve_puzzle(puzzle,
860+ difficulty,
861+ initiator,
862+ responder,
863+ solution) == 0,
864+ NULL);
865+
866+ fail_unless(hip_verify_puzzle_solution(puzzle,
867+ difficulty,
868+ initiator,
869+ responder,
870+ solution) == 0,
871+ NULL);
872+}
873+END_TEST
874+
875+Suite *lib_core_solve(void)
876+{
877+ Suite *s = suite_create("lib/core/solve");
878+
879+ TCase *tc_core = tcase_create("Core");
880+ tcase_add_test(tc_core, test_hip_solve_puzzle_NULL_solution);
881+ tcase_add_test(tc_core, test_hip_solve_puzzle_0_K);
882+ tcase_add_test(tc_core, test_hip_solve_puzzle_5_K);
883+ tcase_add_test(tc_core, test_hip_solve_puzzle_exceeding_K);
884+ tcase_add_test(tc_core, test_hip_solve_puzzle_invalid);
885+ tcase_add_test(tc_core, test_hip_solve_puzzle_valid);
886+ suite_add_tcase(s, tc_core);
887+
888+ return s;
889+}
890
891=== modified file 'test/lib/core/test_suites.h'
892--- test/lib/core/test_suites.h 2011-02-18 14:39:38 +0000
893+++ test/lib/core/test_suites.h 2011-04-08 15:38:33 +0000
894@@ -29,6 +29,7 @@
895 #include <check.h>
896
897 Suite *lib_core_hit(void);
898+Suite *lib_core_solve(void);
899 Suite *lib_core_straddr(void);
900
901 #endif /* HIP_TEST_LIB_CORE_TEST_SUITES_H */

Subscribers

People subscribed via source and target branches

to all changes: