Merge lp:~rene-hummen/hipl/puzzle-fixes into lp:hipl
- puzzle-fixes
- Merge into trunk
Status: | Merged |
---|---|
Merge reported by: | René Hummen |
Merged at revision: | not available |
Proposed branch: | lp:~rene-hummen/hipl/puzzle-fixes |
Merge into: | lp:hipl |
Diff against target: |
882 lines (+363/-154) 17 files modified
Makefile.am (+1/-0) hipd/cookie.c (+15/-9) hipd/cookie.h (+2/-2) hipd/input.c (+18/-9) hipd/keymat.c (+10/-11) hipd/keymat.h (+3/-1) hipd/output.c (+4/-5) lib/core/builder.c (+8/-5) lib/core/builder.h (+6/-6) lib/core/protodefs.h (+7/-3) lib/core/solve.c (+115/-88) lib/core/solve.h (+24/-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 (+136/-0) test/lib/core/test_suites.h (+1/-0) |
To merge this branch: | bzr merge lp:~rene-hummen/hipl/puzzle-fixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Diego Biurrun | Needs Fixing | ||
Christof Mroz | Approve | ||
Stefan Götz (community) | Approve | ||
Miika Komu | Pending | ||
Review via email: mp+57446@code.launchpad.net |
This proposal supersedes a proposal from 2011-04-12.
Commit message
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.
Additionally, I now changed the data types for the puzzle and solution values from uint64_t to uint8_t[8]. Also addressed remaining review comments.
Addressed Stefan's latest comments.
Christof Mroz (christof-mroz) wrote : Posted in a previous version of this proposal | # |
Christof Mroz (christof-mroz) wrote : Posted in a previous version of this proposal | # |
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[
>> 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).
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal | # |
The algorithm seems changed. Did you test it against the old, interoperable implementation?
René Hummen (rene-hummen) wrote : Posted in a previous version of this proposal | # |
On 07.04.2011, at 21:59, Christof Mroz wrote:
> Review: Needs Fixing
> 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_
>> + unsigned char sha_digest[
>> + 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(
>> - (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(
>> -
>> - if (mode == HIP_VERIFY_PUZZLE) {
>> - ipv6_addr_
>> - ipv6_addr_
>> - randval = u->sl.J;
>> - maxtries = 1;
>> - } else if (mode == HIP_SOLVE_PUZZLE) {
>> - ipv6_addr_
>> - ipv6_addr_
>> - maxtries = 1ULL << (u->pz.K + 3);
>> - get_random_
>> + uint32_t truncated_digest = 0;
>> + int err = -1;
>> +
>> + HIP_IFEL(difficulty > max_puzzle_
>> + 1, "difficulty exceeds max. configured difficulty\n");
>> +
>> + HIP_IFEL(
>> + 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.
Done. I don't see your point in adding an assertion here.
>> + /* we are interested in the 8 least significant bytes */
>> + truncated_digest = *(uint32_t *) &sha_digest[
>
> The 8 least significant bytes have index 0..7. Also, sizeof(uint32_t) is 4, not 8.
>
>> +int hip_solve_
>> + const int difficulty,
>> + const hip_hit_t...
René Hummen (rene-hummen) wrote : Posted in a previous version of this proposal | # |
On 08.04.2011, at 06:35, Miika Komu wrote:
> Review: Needs Information
> The algorithm seems changed. Did you test it against the old, interoperable implementation?
I had already tested the following scenarios:
1.) puzzle-fixes <-> trunk
2.) trunk <-> puzzle-fixes
3.) puzzle-fixes <-> puzzle-fixes
All worked fine for me.
--
Dipl.-Inform. Rene Hummen, Ph.D. Student
Chair of Communication and Distributed Systems
RWTH Aachen University, Germany
tel: +49 241 80 20772
web: http://
Diego Biurrun (diego-biurrun) wrote : Posted in a previous version of this proposal | # |
review abstain
I have no opinion on this merge request, just some minor comments
that you may wish to ignore or adapt at your discretion...
On Fri, Apr 08, 2011 at 03:41:24PM +0000, René Hummen wrote:
>
> --- lib/core/solve.c 2011-01-24 10:21:17 +0000
> +++ lib/core/solve.c 2011-04-08 15:41:17 +0000
> @@ -28,11 +28,14 @@
>
> #include <errno.h>
> +#include <openssl/rand.h>
> #include <stdint.h>
> #include <string.h>
> +#include <strings.h>
nit:
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <openssl/rand.h>
> @@ -43,104 +46,170 @@
> +static int hip_calculate_
> + unsigned char sha_digest[
> + const int difficulty)
> {
> + HIP_IFEL(difficulty > max_puzzle_
> + -1, "difficulty exceeds max. configured difficulty\n");
> +
> + HIP_IFEL(
> + compute_puzzle,
> + sizeof(struct puzzle_common),
> + sha_digest),
> + -1, "failed to compute hash digest\n");
> +
> + /* check if position of first least significant 1-bit is higher than
> + * difficulty */
> + if (ffs(truncated_
> + err = 0;
> } else {
> + err = 1;
> + }
> +
> +out_err:
> + return err;
> +}
I would suggest doing that without HIP_IFEL, that would even save two
lines in the if/else clause.
> +/**
> + * Solve a computational puzzle for HIP
> + *
> + * @param puzzle puzzle to be solved
> + * @param difficulty difficulty of the puzzle
> + * @param initiator_hit initiator HIT of the message exchange
> + * @param responder_hit responder HIT of the message exchange
> + * @param solution computed puzzle solution
> + * @return 0 when solution was found, 1 in case no solution was found after
> + * MAX_PUZZLE_
> + */
> +int hip_solve_
> + const int difficulty,
> + const hip_hit_t initiator_hit,
> + const hip_hit_t responder_hit,
> + uint8_t solution[
Having solution as third parameter would feel more natural to me.
> +/**
> + * Verify a computational puzzle for HIP
> + *
> + * @param puzzle puzzle to be verified
> + * @param difficulty difficulty of the puzzle
> + * @param initiator_hit initiator HIT of the message exchange
> + * @param responder_hit responder HIT of the message exchange
> + * @param solution puzzle solution to be verified
> + * @return 0 when solution is correct, -1 otherwise
> + */
> +int hip_verify_
> + const uint8_t difficulty,
> + const hip_hit_t initiator_hit,
> + const hip_hit_t responder_hit,
> + const uint8_t solution[
Having solution as third paramete...
Christof Mroz (christof-mroz) wrote : Posted in a previous version of this proposal | # |
Looks good; feel free to address the following points.
> + * Computes a single iteration for a computational puzzle
> + *
> + * @param compute_puzzle puzzle to be solved or verified
> + * @param sha_digest buffer for hash digest
> + * @param difficulty difficulty of the puzzle (number of leading zeros)
> + * @return 0 when hash has >= #difficulty least significant bits as zeros, 1
> + * when hash has < #difficulty least significant bits as zeros,
> + * -1 in case of an error
> */
@a difficulty
> +/**
> + * Solve a computational puzzle for HIP
> + *
> + * @param puzzle puzzle to be solved
> + * @param difficulty difficulty of the puzzle
> + * @param initiator_hit initiator HIT of the message exchange
> + * @param responder_hit responder HIT of the message exchange
> + * @param solution computed puzzle solution
> + * @return 0 when solution was found, 1 in case no solution was found after
> + * MAX_PUZZLE_
> + */
Prepend :: to create a hyperlink to a global in doxygen, e.g.
::MAX_PUZZLE_
> + ipv6_addr_
> + ipv6_addr_
struct in6_addr can be copied using assignment AFAIK (there are more instances of this).
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
Hi René!
> === modified file 'hipd/cookie.c'
> --- hipd/cookie.c 2011-04-05 16:44:22 +0000
> +++ hipd/cookie.c 2011-04-08 15:41:17 +0000
> @@ -56,7 +56,7 @@
>
> #define HIP_R1TABLESIZE 3 /* precreate only this many R1s */
>
> -static int hip_cookie_
> +static int hip_cookie_
[L] 'cookie' and 'puzzle' seem to refer to the same thing. It would be
great if this ambiguity were removed from the code and only a single
name was used.
> @@ -77,9 +77,9 @@
> */
> static int hip_set_
[M] 'const int k' for const correctness and boyscouting
> {
> - if (k > HIP_PUZZLE_MAX_K || k < 1) {
> + if (k > max_puzzle_
[M] k is not ever supposed to be < 0, correct? If yes, please give it
an unsigned type.
> === modified file 'lib/core/
> --- lib/core/builder.c 2011-04-07 16:58:58 +0000
> +++ lib/core/builder.c 2011-04-08 15:41:17 +0000
> @@ -2385,7 +2385,8 @@
> * @return zero for success, or non-zero on error
> */
> int hip_build_
> - uint8_t lifetime, uint32_t opaque, uint64_t random_i)
> + uint8_t lifetime, uint32_t opaque,
> + const uint8_t random_
[M] const correctness for boyscouting
> === modified file 'lib/core/
> --- lib/core/builder.h 2011-04-02 20:38:36 +0000
> +++ lib/core/builder.h 2011-04-08 15:41:17 +0000
> @@ -130,7 +130,7 @@
> uint8_t,
> uint8_t,
> uint32_t,
> - uint64_t);
> + const uint8_t *);
[M] 'const uint8_t *const'?
> @@ -150,7 +150,7 @@
> uint8_t);
> int hip_build_
> const struct hip_puzzle *,
> - uint64_t);
> + uint8_t *);
[M] 'uint8_t *const'?
> === modified file 'lib/core/
> --- lib/core/
> +++ lib/core/
> @@ -737,13 +737,17 @@
> uint64_t generation;
> } __attribute__ ((packed));
>
> +
> +/* puzzle and solutions are defined to have a length of 8 bytes */
> +#define PUZZLE_LENGTH 8
[M] 'const unsigned PUZZLE_LENGTH = 8;'
> === modified file 'lib/core/solve.c'
> --- lib/core/solve.c 2011-01-24 10:21:17 +0000
> +++ lib/core/solve.c 2011-04-08 15:41:17 +0000
> @@ -43,104 +46,170 @@
> #include "protodefs.h"
> #include "solve.h"
>
> +struct puzzle_common {
> + uint8_t puzzle[
> + hip_hit_t initiator_hit;
> + hip_hit_t responder_hit;
> + uint8_t solution[
> +} __attribute__ ((packed));
[M] The type is undocumented.
[M] The name 'puzzle_common' is not very descriptive (its opposite
'puzzle_uncommon' would be similarly helpful in understanding the
struct's purpose)...
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
Forgot my verdict on this merge proposal.
René Hummen (rene-hummen) wrote : Posted in a previous version of this proposal | # |
On 08.04.2011, at 20:08, Christof Mroz wrote:
> Review: Approve
> Looks good; feel free to address the following points.
>
>> + ipv6_addr_
>> + ipv6_addr_
>
> struct in6_addr can be copied using assignment AFAIK (there are more instances of this).
I don't see why a simple assignment should be sufficient with the following struct definition:
/*
* IPv6 address
*/
struct in6_addr {
union {
__uint8_t __u6_addr8[16];
__uint16_t __u6_addr16[8];
__uint32_t __u6_addr32[4];
} __u6_addr; /* 128-bit IP6 address */
};
In each case, in6_addr contains array, so we would merely copy pointers, right?
Ciao,
René
--
Dipl.-Inform. Rene Hummen, Ph.D. Student
Chair of Communication and Distributed Systems
RWTH Aachen University, Germany
tel: +49 241 80 20772
web: http://
Christof Mroz (christof-mroz) wrote : Posted in a previous version of this proposal | # |
On Tue, 12 Apr 2011 13:15:56 +0200, René Hummen
<email address hidden> wrote:
>>> + ipv6_addr_
>>> + ipv6_addr_
>>
>> struct in6_addr can be copied using assignment AFAIK (there are more
>> instances of this).
>
> I don't see why a simple assignment should be sufficient with the
> following struct definition:
All I know is that the following works:
struct in6_addr a,b;
// ...
a = b;
I personally prefer this over an explicit byte copy... unless
ipv6_addr_copy does something extra. Assignment of structs is really
nothing else than a typesafe version of memcpy(&a, &b, sizeof(a)).
> In each case, in6_addr contains array, so we would merely copy pointers,
> right?
I'd say yes: an IPv6 address is essentially an opaque array of 16 bytes.
René Hummen (rene-hummen) wrote : Posted in a previous version of this proposal | # |
Thanks for this detailed review! Below the comments I did not address in the branch.
On 09.04.2011, at 02:04, Stefan Götz wrote:
> Hi René!
>
>> === modified file 'hipd/cookie.c'
>> --- hipd/cookie.c 2011-04-05 16:44:22 +0000
>> +++ hipd/cookie.c 2011-04-08 15:41:17 +0000
>> @@ -56,7 +56,7 @@
>>
>> #define HIP_R1TABLESIZE 3 /* precreate only this many R1s */
>>
>> -static int hip_cookie_
>> +static int hip_cookie_
>
> [L] 'cookie' and 'puzzle' seem to refer to the same thing. It would be
> great if this ambiguity were removed from the code and only a single
> name was used.
Agreed, but that's not in the focus of this branch. I wouldn't want to change hip_cookie_
>> === modified file 'lib/core/
>> --- lib/core/
>> +++ lib/core/
>> @@ -737,13 +737,17 @@
>> uint64_t generation;
>> } __attribute__ ((packed));
>>
>> +
>> +/* puzzle and solutions are defined to have a length of 8 bytes */
>> +#define PUZZLE_LENGTH 8
>
> [M] 'const unsigned PUZZLE_LENGTH = 8;'
This won't work as I'm using PUZZLE_LENGTH for array definitions in structs, etc.
>> +static int hip_calculate_
>> + unsigned char sha_digest[
>> + const int difficulty)
>> {
>
> [M] It seems that 'sha_digest' is accessed only within this function
> but never by any of its callers. Please declare it as a local variable
> instead of a function parameter.
It's called in a for loop by hip_solve_puzzle(). I don't want memory to be
allocated each time.
> [M] Since this function returns only two distinct values, please use
> 'bool' instead of 'int'
It returns -1, 0, and 1.
>> +int hip_verify_
>> + const uint8_t difficulty,
>> + const hip_hit_t initiator_hit,
>> + const hip_hit_t responder_hit,
>> + const uint8_t solution[
>
> [M] This function only returns two distinct values. Please use 'bool'
> as the return type instead.
It's done like this everywhere in HIPL for notifying about errors. I don't want to introduce a "new way" of doing that in this branch.
> Btw. I like it that hip_hit_t's are passed around by value as opposed
> by error-prone reference.
Me too :)
>> === modified file 'lib/core/solve.h'
>> --- lib/core/solve.h 2010-10-15 15:29:14 +0000
>> +++ lib/core/solve.h 2011-04-08 15:41:17 +0000
>> @@ -30,10 +30,20 @@
>>
>> #include "protodefs.h"
>>
>> -#define HIP_PUZZLE_MAX_K 28
>> -
>> -uint64_t hip_solve_
>> - ...
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
>> struct in6_addr can be copied using assignment AFAIK (there are more instances of this).
>
> I don't see why a simple assignment should be sufficient with the following struct definition:
>
> /*
> * IPv6 address
> */
> struct in6_addr {
> union {
> __uint8_t __u6_addr8[16];
> __uint16_t __u6_addr16[8];
> __uint32_t __u6_addr32[4];
> } __u6_addr; /* 128-bit IP6 address */
> };
>
> In each case, in6_addr contains array, so we would merely copy pointers, right?
No. The struct contains the actual array data. If you have the following:
int a[2];
Then you can use 'a' as if it was a pointer. However, the memory for
two integers is definitely allocated through this statement, be it in
a struct or as a variable.
Another way to look at it: if you really want a struct to contain an
array of uint32_t's (maybe plus some other data), there simply is no
other way of doing that than saying:
struct x {
uint32_t a[4];
};
That array is 16 bytes long - sizeof will say the same.
Due to that: in6_addr should be assignable without a problem.
Yet another reason why it is possible: you can pass in6_addr structs
as function parameters by value. That implies that they can be copied
by assignment.
Stefan
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
Hi Rene!
Anything I haven't commented on I agree with and consider my previous
comments to be void.
>>> +static int hip_calculate_
>>> + unsigned char sha_digest[
>>> + const int difficulty)
>>> {
>>
>> [M] It seems that 'sha_digest' is accessed only within this function
>> but never by any of its callers. Please declare it as a local variable
>> instead of a function parameter.
>
> It's called in a for loop by hip_solve_puzzle(). I don't want memory to be
> allocated each time.
Ok - please fix this, nevertheless:
1) If malloc() were to be used in each iteration, I'd agree. But as a
local variable, there is zero allocation overhead. The 'allocation'
happens on the stack and is essentially taken care of by the compiler
at compile time, as with any other local variable.
2) The next best option would be to declare sha_digest as a static
local variable - then that memory would be kept around in a fixed
location between calls. I'm pretty sure though that this solution is
still inferior to a non-static local variable because the non-static
local variable on the stack has better chances of being in the cache
and fewer chances for hash collisions.
>>> +/* right now we only support difficulties up to sizeof(int), as only ffs
>>> + * is available on OpenWRT */
>>
>> [M] 'difficulties of up to sizeof(int)' is incorrect because in fact
>> it is 'MIN(28, sizeof(int))'.
>
> Nope, the difficulty can be max sizeof(int). It might be any lower value though.
>
>>> +static const int max_puzzle_
Hm - maybe we misunderstand each other. What I'm trying to say is that
I read the code as follows:
if (sizeof(int) * 8) is greater than or equal to 28, then mpd is set to 28.
if (sizeof(int) * 8) is less than 28, then mpd is set to (sizeof(int)
* 8), i.e., a number smaller than 28.
So on 32-bit and 64-bit machines, we end up with 28. 16-bit machine: 16.
My complaint is the following: the comment says that a difficulty of
up to sizeof(int) [*8 I guess] is supported. On 32-bit and 64-bit
machines, that is incorrect as the maximum supported difficulty is 28
bits, not 32 or 64.
I guess the code is alright - it's the comment that bugs me, because
to me, it contradicts the code.
Stefan
Christof Mroz (christof-mroz) wrote : Posted in a previous version of this proposal | # |
Looks good to me.
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal | # |
Seems ok to me.
René Hummen (rene-hummen) wrote : | # |
If there are no further comments, I will merge this branch tomorrow.
Diego Biurrun (diego-biurrun) wrote : | # |
review needs-fixing
On Wed, Apr 13, 2011 at 08:50:53AM +0000, René Hummen wrote:
> René Hummen has proposed merging lp:~rene-hummen/hipl/puzzle-fixes into lp:hipl.
>
> --- lib/core/builder.h 2011-04-02 20:38:36 +0000
> +++ lib/core/builder.h 2011-04-13 08:50:40 +0000
> @@ -126,11 +126,11 @@
> -int hip_build_
> - uint8_t,
> - uint8_t,
> - uint32_t,
> - uint64_t);
> +int hip_build_
> + const uint8_t val_K,
> + const uint8_t lifetime,
> + const uint32_t opaque,
> + const uint8_t *const random_i);
nit:
Maybe you could add the parameter names while you're changing those
lines anyway? That one of the most important headers in HIPL lacks
parameter names in function declarations is extremely annoying.
> --- lib/core/solve.c 2011-01-24 10:21:17 +0000
> +++ lib/core/solve.c 2011-04-13 08:50:40 +0000
> @@ -43,108 +46,183 @@
>
> +static int hip_single_
> + const uint8_t difficulty)
> {
> + unsigned char sha_digest[
> + uint32_t truncated_digest = 0;
> + int err = -1;
> +
> + if (difficulty == 0) {
> + return 0;
> + }
> +
> + HIP_IFEL(difficulty > MAX_PUZZLE_
> + -1, "difficulty exceeds max. configured difficulty\n");
> +
> + HIP_IFEL(
> + puzzle_input,
> + sizeof(struct puzzle_hash_input),
> + sha_digest),
> + -1, "failed to compute hash digest\n");
> +
> + if (ffs(truncated_
> + err = 0;
> + } else {
> + err = 1;
> + }
> +
> +out_err:
> + return err;
> +}
You seem to insist on writing this with HIP_IFEL, but just compare how
much neater this is with plain if-return (slightly redacted):
static int hip_single_
{
unsigned char sha_digest[
uint32_t truncated_digest = 0;
if (difficulty == 0) {
return 0;
}
if (difficulty > MAX_PUZZLE_
return -1;
}
if (hip_build_
return -1;
}
if (ffs(truncated_
return 0;
}
return 1;
}
If this does not convince you, I can quote the relevant heuristics from
"Clean Code" at you :)
You can also make it slightly more compact by merging the if blocks with
else statements if you prefer.
> +int hip_solve_pu...
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
Hi René!
review:
> === modified file 'hipd/cookie.c'
> --- hipd/cookie.c 2011-04-05 16:44:22 +0000
> +++ hipd/cookie.c 2011-04-12 17:04:30 +0000
> @@ -56,7 +56,7 @@
>
> #define HIP_R1TABLESIZE 3 /* precreate only this many R1s */
>
> -static int hip_cookie_
> +static uint8_t hip_cookie_
[M] The change from int to uint8_t is a step backwards in my opinion
for two reasons:
1) built-in types should be used in preference to defined types,
unless specifically required to, e.g., achieve a guaranteed data
layout. In this case this means that 'unsigned short' is preferable to
'uint8_t'.
2) I assume that uint8_t was chosen to limit the range of supported
values to 256 instead of 2^32, correct? Is 256 indeed a useful
limitation? I thought it should not be greater than 32 due to the
limitations of OpenWRT, right? So if 'hip_cookie_
it's just as bad as if it was 257, right? If that is so, it seems to
me that the change to 'uint8_t' does not have an advantage.
It has a disadvantage though: 'uint8_t' is less efficient to handle
than 'int' or 'unsigned int'.
Thus, I'd recommend to change the type to 'unsigned int' or leave it
at 'int'. The same goes for all related 'uint8_t' variables and
function arguments.
> +static int hip_single_
> + unsigned char sha_digest[
> + const uint8_t difficulty)
[M] I guess the fact that 'sha_digest' is still a function parameter
instead of a local variable is due to our bad review/fix timing
yesterday?
> +int hip_solve_
> + const uint8_t difficulty,
> + const hip_hit_t initiator_hit,
> + const hip_hit_t responder_hit,
> + uint8_t solution[
> +{
> + struct puzzle_hash_input compute_puzzle;
> + unsigned char sha_digest[
> + int err = -1;
> + unsigned long long i = 0;
> +
> + /* solution must reference allocated memory here */
> + HIP_ASSERT(
> +
> + HIP_IFEL(difficulty > MAX_PUZZLE_
> + "Cookie (K = %i) is higher than we are willing to calculate"
> + " (current max K = %i)\n", difficulty, MAX_PUZZLE_
> +
> + /* solution is correct iff:
> + * 0 == V := Ltrunc( RHASH( I2.I | I2.hit_i | I2.hit_r | I2.J ), K )
> + * (RFC 5201 - Appendix A) */
> + memcpy(
> + ipv6_addr_
> + ipv6_addr_
[L] Could these be assigned directly?
Stefan
René Hummen (rene-hummen) wrote : | # |
On 13.04.2011, at 19:15, Diego Biurrun wrote:
> Review: Needs Fixing
> review needs-fixing
>
> On Wed, Apr 13, 2011 at 08:50:53AM +0000, René Hummen wrote:
>> René Hummen has proposed merging lp:~rene-hummen/hipl/puzzle-fixes into lp:hipl.
>>
>> --- lib/core/builder.h 2011-04-02 20:38:36 +0000
>> +++ lib/core/builder.h 2011-04-13 08:50:40 +0000
>> @@ -126,11 +126,11 @@
>> -int hip_build_
>> - uint8_t,
>> - uint8_t,
>> - uint32_t,
>> - uint64_t);
>> +int hip_build_
>> + const uint8_t val_K,
>> + const uint8_t lifetime,
>> + const uint32_t opaque,
>> + const uint8_t *const random_i);
>
> nit:
> Maybe you could add the parameter names while you're changing those
> lines anyway? That one of the most important headers in HIPL lacks
> parameter names in function declarations is extremely annoying.
No, I'm not going to fix builder.h here.
>> --- lib/core/solve.c 2011-01-24 10:21:17 +0000
>> +++ lib/core/solve.c 2011-04-13 08:50:40 +0000
>> @@ -43,108 +46,183 @@
>>
>> +static int hip_single_
>> + const uint8_t difficulty)
>> {
>> + unsigned char sha_digest[
>> + uint32_t truncated_digest = 0;
>> + int err = -1;
>> +
>> + if (difficulty == 0) {
>> + return 0;
>> + }
>> +
>> + HIP_IFEL(difficulty > MAX_PUZZLE_
>> + -1, "difficulty exceeds max. configured difficulty\n");
>> +
>> + HIP_IFEL(
>> + puzzle_input,
>> + sizeof(struct puzzle_hash_input),
>> + sha_digest),
>> + -1, "failed to compute hash digest\n");
>> +
>> + if (ffs(truncated_
>> + err = 0;
>> + } else {
>> + err = 1;
>> + }
>> +
>> +out_err:
>> + return err;
>> +}
>
> You seem to insist on writing this with HIP_IFEL, but just compare how
> much neater this is with plain if-return (slightly redacted):
>
> static int hip_single_
> const uint8_t difficulty)
> {
> unsigned char sha_digest[
> uint32_t truncated_digest = 0;
>
> if (difficulty == 0) {
> return 0;
> }
>
> if (difficulty > MAX_PUZZLE_
> HIP_ERROR(
> return -1;
> }
>
> if (hip_build_
> sizeof(struct puzzle_hash_input), sha_digest) {
> HIP_ERROR("failed to compute hash digest\n");
> return -1;
> }
>
> if (ffs(truncated_
> return 0;
> }
>
> return 1;
> }
>
> If this doe...
René Hummen (rene-hummen) wrote : Posted in a previous version of this proposal | # |
On 14.04.2011, at 08:21, Stefan Götz wrote:
> Hi René!
>
> review:needs_fixing
>
>> === modified file 'hipd/cookie.c'
>> --- hipd/cookie.c 2011-04-05 16:44:22 +0000
>> +++ hipd/cookie.c 2011-04-12 17:04:30 +0000
>> @@ -56,7 +56,7 @@
>>
>> #define HIP_R1TABLESIZE 3 /* precreate only this many R1s */
>>
>> -static int hip_cookie_
>> +static uint8_t hip_cookie_
>
> [M] The change from int to uint8_t is a step backwards in my opinion
> for two reasons:
>
> 1) built-in types should be used in preference to defined types,
> unless specifically required to, e.g., achieve a guaranteed data
> layout. In this case this means that 'unsigned short' is preferable to
> 'uint8_t'.
I don't mind the data type so much as long as it is unsigned. However, the difficulty will never be higher than 256 (see below).
> 2) I assume that uint8_t was chosen to limit the range of supported
> values to 256 instead of 2^32, correct? Is 256 indeed a useful
> limitation? I thought it should not be greater than 32 due to the
> limitations of OpenWRT, right? So if 'hip_cookie_
> it's just as bad as if it was 257, right? If that is so, it seems to
> me that the change to 'uint8_t' does not have an advantage.
> It has a disadvantage though: 'uint8_t' is less efficient to handle
> than 'int' or 'unsigned int'.
> Thus, I'd recommend to change the type to 'unsigned int' or leave it
> at 'int'. The same goes for all related 'uint80_t' variables and
> function arguments.
uint8_t is simply the length of the header field on the wire. That seems like a natural limitation for me. The fact that we only support difficulties up to 32 is just an implementation issue of one function and might change in the future.
>> +static int hip_single_
>> + unsigned char sha_digest[
>> + const uint8_t difficulty)
>
> [M] I guess the fact that 'sha_digest' is still a function parameter
> instead of a local variable is due to our bad review/fix timing
> yesterday?
Hmm, that's a bit strange. The merge proposal on launchpad already show my change here.
René
--
Dipl.-Inform. Rene Hummen, Ph.D. Student
Chair of Communication and Distributed Systems
RWTH Aachen University, Germany
tel: +49 241 80 20772
web: http://
- 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
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : | # |
I'm fine with the current version.
Christof Mroz (christof-mroz) wrote : | # |
Looks good; just some comments.
You don't renew your merge proposal if you address any of these, as far as I'm concerned (to speed things up).
> + * Computes a single iteration for a computational puzzle
> + *
> + * @param compute_puzzle puzzle to be solved or verified
> + * @param sha_digest buffer for hash digest
> + * @param difficulty difficulty of the puzzle (number of leading zeros)
> + * @return 0 when hash has >= @a difficulty least significant bits as zeros, 1
> + * when hash has < @a difficulty least significant bits as zeros,
> + * -1 in case of an error
> */
> -uint64_t hip_solve_
> - const struct hip_common *hdr,
> - int mode)
> +static int hip_single_
> + const uint8_t difficulty)
> {
Parameter documentation is out of sync (run `make doxygen` to catch all other instances).
> + HIP_IFEL(difficulty > MAX_PUZZLE_
> + "Cookie (K = %i) is higher than we are willing to calculate"
> + " (current max K = %i)\n", difficulty, MAX_PUZZLE_
Use %u for unsigned integers.
> +
> + /* solution is correct iff:
> + * 0 == V := Ltrunc( RHASH( I2.I | I2.hit_i | I2.hit_r | I2.J ), K )
> + * (RFC 5201 - Appendix A) */
> + memcpy(
> + compute_
> + compute_
> + RAND_bytes(
> +
> + // any puzzle solution is acceptable for difficulty 0
> + if (difficulty == 0) {
> + return 0;
> + }
This should be the very first thing to check, to avoid copying at all.
> + /* If max_puzzle_
> + * Hence, no solution will be found for these cases. */
> + HIP_ASSERT(
If you're trying to avoid MAX_PUZZLE_
> +/**
> + * Verify a computational puzzle for HIP
> + *
> + * @param puzzle puzzle to be verified
> + * @param solution puzzle solution to be verified
> + * @param difficulty difficulty of the puzzle
> + * @param initiator_hit initiator HIT of the message exchange
> + * @param responder_hit responder HIT of the message exchange
> + * @return 0 when solution is correct, -1 otherwise
> + */
> +int hip_verify_
> + const uint8_t solution[
> + const uint8_t difficulty,
> + const hip_hit_t initiator_hit,
> + const hip_hit_t responder_hit)
> +{
> + struct puzzle_hash_input compute_puzzle;
> +
> + // any puzzle solution is acceptable for difficulty 0
> + if (difficulty == 0) {
> + return 0;
> + }
> +
> + /* solution is correct iff:
> + * 0 == V := Ltrunc( ...
Diego Biurrun (diego-biurrun) wrote : | # |
On Thu, Apr 14, 2011 at 09:24:22AM +0000, René Hummen wrote:
>
> On 13.04.2011, at 19:15, Diego Biurrun wrote:
>
> > On Wed, Apr 13, 2011 at 08:50:53AM +0000, René Hummen wrote:
> >> René Hummen has proposed merging lp:~rene-hummen/hipl/puzzle-fixes into lp:hipl.
> >>
> HIP_IFEL is the way errors are handled throughout the code. I won't
> change this here.
Unfortunately you missed our analysis of HIP_IFEL during the code review
session from Friday. Clearly, HIP_IFEL is something that must go away.
Period.
Of course elimating all HIP_IFE* from HIPL is a large task and I am not
asking anyone to do it here. What I am asking of you is not to make the
problem worse by introducing more instances of the problem, which I
consider reasonable.
Consistency is all nice and dandy if you have to choose between equal
alternatives. But if you have a problem, then consistency can never
be an argument for introducing more problem instances.
> >> +int hip_solve_
> >> + const uint8_t difficulty,
> >> + const hip_hit_t initiator_hit,
> >> + const hip_hit_t responder_hit,
> >> + uint8_t solution[
> >> +{
> >> + struct puzzle_hash_input compute_puzzle;
> >> +
> >> + /* solution is correct iff:
> >> + * 0 == V := Ltrunc( RHASH( I2.I | I2.hit_i | I2.hit_r | I2.J ), K )
> >> + * (RFC 5201 - Appendix A) */
> >> + memcpy(
> >> + compute_
> >> + compute_
> >
> > Replace the memcpy by an assignment.
>
> Wouldn't that just copy references?
Yes, you are right, that will not work.
> >> --- lib/tool/pk.c 2011-04-04 13:59:21 +0000
> >> +++ lib/tool/pk.c 2011-04-13 08:50:40 +0000
> >> @@ -146,11 +146,13 @@
> >>
> >> HIP_IFEL(!(pz = hip_get_
> >> -ENOENT, "Illegal R1 packet (puzzle missing)\n");
> >> - memcpy(opaque, pz->opaque, sizeof(
> >> - randi = pz->I;
> >>
> >> - memset(pz->opaque, 0, sizeof(
> >> - pz->I = 0;
> >> + /* temporarily store original puzzle values */
> >> + memcpy(opaque, pz->opaque, HIP_PUZZLE_
> >> + memcpy(rand_i, pz->I, PUZZLE_LENGTH);
> >> + /* R1 signature is computed over zero values */
> >> + memset(pz->opaque, 0, HIP_PUZZLE_
> >> + memset(pz->I, 0, PUZZLE_LENGTH);
> >
> > It seems these could be replaced by assignments as well...
>
> Same here.
pz->opaque is an array, but pz->I is a uint64_t, so at least the latter
could simply be assigned.
> >> --- test/lib/
> >> +++ test/lib/
> >
> > This file did not pass through uncrustify.
>
> Of course it did not. Did you have a look recently at what the output
> would look like?
Sure, but it's not hard to undo the merging of the macros onto single
lines...
> >> @@ -0,0 +1,200 @@
> >> +START_
> >> +{
> >> + uint8_...
Diego Biurrun (diego-biurrun) wrote : | # |
review needs-fixing
On Wed, Apr 13, 2011 at 08:50:53AM +0000, René Hummen wrote:
> René Hummen has proposed merging lp:~rene-hummen/hipl/puzzle-fixes into lp:hipl.
>
> --- lib/core/solve.c 2011-01-24 10:21:17 +0000
> +++ lib/core/solve.c 2011-04-13 08:50:40 +0000
> @@ -43,108 +46,183 @@
>
> +/** This data type represents the ordered input for the hash function used to
> + * solve a given puzzle challenge as defined in RFC 5201 - Appendix A */
> +struct puzzle_hash_input {
> + uint8_t puzzle[
> + hip_hit_t initiator_hit;
> + hip_hit_t responder_hit;
> + uint8_t solution[
> +} __attribute__ ((packed));
> +
> +int hip_solve_
> + const uint8_t difficulty,
> + const hip_hit_t initiator_hit,
> + const hip_hit_t responder_hit,
> + uint8_t solution[
> +{
Just pass a puzzle_hash_input struct to the function and you go down
from five to two parameters.
> +int hip_verify_
> + const uint8_t solution[
> + const uint8_t difficulty,
> + const hip_hit_t initiator_hit,
> + const hip_hit_t responder_hit)
> +{
same
Diego
Diego Biurrun (diego-biurrun) wrote : | # |
On Mon, Apr 18, 2011 at 01:22:04PM +0200, Diego Biurrun wrote:
> On Thu, Apr 14, 2011 at 09:24:22AM +0000, René Hummen wrote:
> >
> > On 13.04.2011, at 19:15, Diego Biurrun wrote:
> >
> > > On Wed, Apr 13, 2011 at 08:50:53AM +0000, René Hummen wrote:
> > >> René Hummen has proposed merging lp:~rene-hummen/hipl/puzzle-fixes into lp:hipl.
> > >>
> > >> --- lib/tool/pk.c 2011-04-04 13:59:21 +0000
> > >> +++ lib/tool/pk.c 2011-04-13 08:50:40 +0000
> > >> @@ -146,11 +146,13 @@
> > >>
> > >> HIP_IFEL(!(pz = hip_get_
> > >> -ENOENT, "Illegal R1 packet (puzzle missing)\n");
> > >> - memcpy(opaque, pz->opaque, sizeof(
> > >> - randi = pz->I;
> > >>
> > >> - memset(pz->opaque, 0, sizeof(
> > >> - pz->I = 0;
> > >> + /* temporarily store original puzzle values */
> > >> + memcpy(opaque, pz->opaque, HIP_PUZZLE_
> > >> + memcpy(rand_i, pz->I, PUZZLE_LENGTH);
> > >> + /* R1 signature is computed over zero values */
> > >> + memset(pz->opaque, 0, HIP_PUZZLE_
> > >> + memset(pz->I, 0, PUZZLE_LENGTH);
> > >
> > > It seems these could be replaced by assignments as well...
> >
> > Same here.
>
> pz->opaque is an array, but pz->I is a uint64_t, so at least the latter
> could simply be assigned.
Scratch that comment, I forgot that you modified that struct..
Diego
- 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
René Hummen (rene-hummen) wrote : | # |
Merged to trunk in revision 5879.
Preview Diff
1 | === modified file 'Makefile.am' |
2 | --- Makefile.am 2011-04-06 15:52:33 +0000 |
3 | +++ Makefile.am 2011-04-19 15:56:06 +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-19 15:56:06 +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 uint8_t 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 | @@ -75,11 +75,11 @@ |
26 | * @param k the new puzzle difficulty |
27 | * @return the k value on success or negative on error |
28 | */ |
29 | -static int hip_set_cookie_difficulty(int k) |
30 | +static int hip_set_cookie_difficulty(const uint8_t k) |
31 | { |
32 | - if (k > HIP_PUZZLE_MAX_K || k < 1) { |
33 | + if (k > MAX_PUZZLE_DIFFICULTY) { |
34 | HIP_ERROR("Bad cookie value (%d), min=%d, max=%d\n", |
35 | - k, 1, HIP_PUZZLE_MAX_K); |
36 | + k, 1, MAX_PUZZLE_DIFFICULTY); |
37 | return -1; |
38 | } |
39 | hip_cookie_difficulty = k; |
40 | @@ -322,7 +322,8 @@ |
41 | const struct hip_puzzle *puzzle = NULL; |
42 | struct hip_r1entry *result = NULL; |
43 | struct hip_host_id_entry *hid = NULL; |
44 | - int err = 0; |
45 | + struct puzzle_hash_input puzzle_input; |
46 | + int err = 0; |
47 | |
48 | /* Find the proper R1 table */ |
49 | HIP_IFEL(!(hid = hip_get_hostid_entry_by_lhi_and_algo(HIP_DB_LOCAL_HID, |
50 | @@ -347,7 +348,7 @@ |
51 | |
52 | HIP_IFEL(solution->K != result->Ck, -1, |
53 | "Solution's K did not match any sent Ks.\n"); |
54 | - HIP_IFEL(solution->I != result->Ci, -1, |
55 | + HIP_IFEL(memcmp(solution->I, result->Ci, PUZZLE_LENGTH), -1, |
56 | "Solution's I did not match the sent I\n"); |
57 | HIP_IFEL(memcmp(solution->opaque, result->Copaque, |
58 | HIP_PUZZLE_OPAQUE_LEN), -1, |
59 | @@ -356,15 +357,20 @@ |
60 | } else { |
61 | HIP_HEXDUMP("solution", solution, sizeof(*solution)); |
62 | HIP_HEXDUMP("puzzle", puzzle, sizeof(*puzzle)); |
63 | - HIP_IFEL(solution->I != puzzle->I, -1, |
64 | + HIP_IFEL(memcmp(solution->I, puzzle->I, PUZZLE_LENGTH), -1, |
65 | "Solution's I did not match the sent I\n"); |
66 | HIP_IFEL(memcmp(solution->opaque, puzzle->opaque, |
67 | HIP_PUZZLE_OPAQUE_LEN), -1, |
68 | "Solution's opaque data does not match the opaque data sent\n"); |
69 | } |
70 | |
71 | - HIP_IFEL(!hip_solve_puzzle(solution, hdr, HIP_VERIFY_PUZZLE), -1, |
72 | - "Puzzle incorrectly solved.\n"); |
73 | + memcpy(puzzle_input.puzzle, solution->I, PUZZLE_LENGTH); |
74 | + puzzle_input.initiator_hit = hdr->hits; |
75 | + puzzle_input.responder_hit = hdr->hitr; |
76 | + memcpy(puzzle_input.solution, solution->J, PUZZLE_LENGTH); |
77 | + |
78 | + HIP_IFEL(hip_verify_puzzle_solution(&puzzle_input, solution->K), |
79 | + -1, "Puzzle incorrectly solved.\n"); |
80 | |
81 | out_err: |
82 | return err; |
83 | |
84 | === modified file 'hipd/cookie.h' |
85 | --- hipd/cookie.h 2011-01-10 13:12:17 +0000 |
86 | +++ hipd/cookie.h 2011-04-19 15:56:06 +0000 |
87 | @@ -34,9 +34,9 @@ |
88 | struct hip_r1entry { |
89 | struct hip_common *r1; |
90 | uint32_t generation; |
91 | - uint64_t Ci; |
92 | + uint8_t Ci[PUZZLE_LENGTH]; |
93 | uint8_t Ck; |
94 | - uint8_t Copaque[3]; |
95 | + uint8_t Copaque[HIP_PUZZLE_OPAQUE_LEN]; |
96 | }; |
97 | |
98 | struct hip_common *hip_get_r1(struct in6_addr *ip_i, |
99 | |
100 | === modified file 'hipd/input.c' |
101 | --- hipd/input.c 2011-04-14 08:55:31 +0000 |
102 | +++ hipd/input.c 2011-04-19 15:56:06 +0000 |
103 | @@ -50,6 +50,7 @@ |
104 | #include <arpa/inet.h> |
105 | #include <netinet/in.h> |
106 | #include <openssl/lhash.h> |
107 | +#include <openssl/rand.h> |
108 | #include <sys/types.h> |
109 | |
110 | #include "lib/core/builder.h" |
111 | @@ -234,8 +235,8 @@ |
112 | * @return zero on success, or negative on error. |
113 | */ |
114 | static int hip_produce_keying_material(struct hip_packet_context *ctx, |
115 | - uint64_t I, |
116 | - uint64_t J) |
117 | + const uint8_t I[PUZZLE_LENGTH], |
118 | + const uint8_t J[PUZZLE_LENGTH]) |
119 | { |
120 | char *dh_shared_key = NULL; |
121 | int hip_transf_length, hmac_transf_length; |
122 | @@ -794,6 +795,7 @@ |
123 | { |
124 | int err = 0, retransmission = 0; |
125 | const struct hip_r1_counter *r1cntr = NULL; |
126 | + struct puzzle_hash_input puzzle_input; |
127 | |
128 | if (ha_state == HIP_STATE_I2_SENT) { |
129 | HIP_DEBUG("Retransmission\n"); |
130 | @@ -828,16 +830,23 @@ |
131 | /* Solve puzzle: if this is a retransmission, we have to preserve |
132 | * the old solution. */ |
133 | if (!retransmission) { |
134 | - const struct hip_puzzle *pz2 = NULL; |
135 | + const struct hip_puzzle *pz = NULL; |
136 | |
137 | - HIP_IFEL(!(pz2 = hip_get_param(ctx->input_msg, HIP_PARAM_PUZZLE)), -EINVAL, |
138 | + HIP_IFEL(!(pz = hip_get_param(ctx->input_msg, HIP_PARAM_PUZZLE)), -EINVAL, |
139 | "Malformed R1 packet. PUZZLE parameter missing\n"); |
140 | - HIP_IFEL((ctx->hadb_entry->puzzle_solution = |
141 | - hip_solve_puzzle(pz2, |
142 | - ctx->input_msg, |
143 | - HIP_SOLVE_PUZZLE)) == 0, |
144 | + |
145 | + memcpy(puzzle_input.puzzle, pz->I, PUZZLE_LENGTH); |
146 | + puzzle_input.initiator_hit = ctx->input_msg->hitr; |
147 | + puzzle_input.responder_hit = ctx->input_msg->hits; |
148 | + RAND_bytes(puzzle_input.solution, PUZZLE_LENGTH); |
149 | + |
150 | + HIP_IFEL(hip_solve_puzzle(&puzzle_input, pz->K), |
151 | -EINVAL, "Solving of puzzle failed\n"); |
152 | - ctx->hadb_entry->puzzle_i = pz2->I; |
153 | + |
154 | + memcpy(ctx->hadb_entry->puzzle_i, pz->I, PUZZLE_LENGTH); |
155 | + memcpy(ctx->hadb_entry->puzzle_solution, |
156 | + puzzle_input.solution, |
157 | + PUZZLE_LENGTH); |
158 | } |
159 | |
160 | HIP_DEBUG("Build normal I2.\n"); |
161 | |
162 | === modified file 'hipd/keymat.c' |
163 | --- hipd/keymat.c 2011-01-11 13:59:46 +0000 |
164 | +++ hipd/keymat.c 2011-04-19 15:56:06 +0000 |
165 | @@ -58,19 +58,18 @@ |
166 | static uint8_t *hip_create_keymat_buffer(char *kij, size_t kij_len, size_t hash_len, |
167 | struct in6_addr *smaller_hit, |
168 | struct in6_addr *bigger_hit, |
169 | - uint64_t I, uint64_t J) |
170 | + const uint8_t I[PUZZLE_LENGTH], |
171 | + const uint8_t J[PUZZLE_LENGTH]) |
172 | |
173 | { |
174 | uint8_t *buffer = NULL, *cur = NULL; |
175 | size_t requiredmem; |
176 | |
177 | - HIP_DEBUG("\n"); |
178 | - /* 2*sizeof(uint64_t) added to take care of I and J. */ |
179 | if (2 * sizeof(struct in6_addr) < hash_len) { |
180 | - requiredmem = kij_len + hash_len + sizeof(uint8_t) + 2 * sizeof(uint64_t); |
181 | + requiredmem = kij_len + hash_len + sizeof(uint8_t) + 2 * PUZZLE_LENGTH; |
182 | } else { |
183 | requiredmem = kij_len + 2 * sizeof(struct in6_addr) + |
184 | - sizeof(uint8_t) + 2 * sizeof(uint64_t); |
185 | + sizeof(uint8_t) + 2 * PUZZLE_LENGTH; |
186 | } |
187 | buffer = malloc(requiredmem); |
188 | if (!buffer) { |
189 | @@ -85,10 +84,10 @@ |
190 | cur += sizeof(struct in6_addr); |
191 | memcpy(cur, (uint8_t *) bigger_hit, sizeof(struct in6_addr)); |
192 | cur += sizeof(struct in6_addr); |
193 | - memcpy(cur, &I, sizeof(uint64_t)); // XX CHECK: network byte order? |
194 | - cur += sizeof(uint64_t); |
195 | - memcpy(cur, &J, sizeof(uint64_t)); // XX CHECK: network byte order? |
196 | - cur += sizeof(uint64_t); |
197 | + memcpy(cur, I, PUZZLE_LENGTH); |
198 | + cur += PUZZLE_LENGTH; |
199 | + memcpy(cur, J, PUZZLE_LENGTH); |
200 | + cur += PUZZLE_LENGTH; |
201 | *(cur) = 1; |
202 | cur += sizeof(uint8_t); |
203 | |
204 | @@ -138,8 +137,8 @@ |
205 | struct in6_addr *hit1, |
206 | struct in6_addr *hit2, |
207 | uint8_t *calc_index, |
208 | - uint64_t I, |
209 | - uint64_t J) |
210 | + const uint8_t I[PUZZLE_LENGTH], |
211 | + const uint8_t J[PUZZLE_LENGTH]) |
212 | { |
213 | int bufsize; |
214 | uint8_t index_nbr = 1; |
215 | |
216 | === modified file 'hipd/keymat.h' |
217 | --- hipd/keymat.h 2010-10-15 15:29:14 +0000 |
218 | +++ hipd/keymat.h 2011-04-19 15:56:06 +0000 |
219 | @@ -37,7 +37,9 @@ |
220 | void hip_make_keymat(char *kij, size_t kij_len, |
221 | struct hip_keymat_keymat *keymat, |
222 | void *dstbuf, size_t dstbuflen, struct in6_addr *hit1, |
223 | - struct in6_addr *hit2, uint8_t *calc_index, uint64_t I, uint64_t J); |
224 | + struct in6_addr *hit2, uint8_t *calc_index, |
225 | + const uint8_t I[PUZZLE_LENGTH], |
226 | + const uint8_t J[PUZZLE_LENGTH]); |
227 | int hip_keymat_draw_and_copy(unsigned char *dst, |
228 | struct hip_keymat_keymat *keymat, |
229 | int len); |
230 | |
231 | === modified file 'hipd/output.c' |
232 | --- hipd/output.c 2011-04-11 12:56:12 +0000 |
233 | +++ hipd/output.c 2011-04-19 15:56:06 +0000 |
234 | @@ -652,8 +652,10 @@ |
235 | /********** R1_COUNTER (OPTIONAL) *********/ |
236 | |
237 | /********** PUZZLE ************/ |
238 | + const uint8_t zero_i[PUZZLE_LENGTH] = { 0 }; |
239 | + |
240 | HIP_IFEL(hip_build_param_puzzle(err, cookie_k, |
241 | - 42 /* 2^(42-32) sec lifetime */, 0, 0), |
242 | + 42 /* 2^(42-32) sec lifetime */, 0, zero_i), |
243 | NULL, "Cookies were burned. Bummer!\n"); |
244 | |
245 | /* Parameter Diffie-Hellman */ |
246 | @@ -718,7 +720,6 @@ |
247 | /* Fill puzzle parameters */ |
248 | { |
249 | struct hip_puzzle *pz; |
250 | - uint64_t random_i; |
251 | |
252 | HIP_IFEL(!(pz = hip_get_param_readwrite(err, HIP_PARAM_PUZZLE)), NULL, |
253 | "Internal error\n"); |
254 | @@ -727,9 +728,7 @@ |
255 | pz->opaque[0] = 'H'; |
256 | pz->opaque[1] = 'I'; |
257 | //pz->opaque[2] = 'P'; |
258 | - /** @todo Remove random_i variable. */ |
259 | - get_random_bytes(&random_i, sizeof(random_i)); |
260 | - pz->I = random_i; |
261 | + get_random_bytes(pz->I, PUZZLE_LENGTH); |
262 | } |
263 | |
264 | /* Packet ready */ |
265 | |
266 | === modified file 'lib/core/builder.c' |
267 | --- lib/core/builder.c 2011-04-07 16:58:58 +0000 |
268 | +++ lib/core/builder.c 2011-04-19 15:56:06 +0000 |
269 | @@ -2384,8 +2384,11 @@ |
270 | * |
271 | * @return zero for success, or non-zero on error |
272 | */ |
273 | -int hip_build_param_puzzle(struct hip_common *msg, uint8_t val_K, |
274 | - uint8_t lifetime, uint32_t opaque, uint64_t random_i) |
275 | +int hip_build_param_puzzle(struct hip_common *const msg, |
276 | + const uint8_t val_K, |
277 | + const uint8_t lifetime, |
278 | + const uint32_t opaque, |
279 | + const uint8_t random_i[PUZZLE_LENGTH]) |
280 | { |
281 | struct hip_puzzle puzzle; |
282 | int err = 0; |
283 | @@ -2402,7 +2405,7 @@ |
284 | puzzle.lifetime = lifetime; |
285 | puzzle.opaque[0] = opaque & 0xFF; |
286 | puzzle.opaque[1] = (opaque & 0xFF00) >> 8; |
287 | - puzzle.I = random_i; |
288 | + memcpy(puzzle.I, random_i, PUZZLE_LENGTH); |
289 | |
290 | err = hip_build_generic_param(msg, &puzzle, |
291 | sizeof(struct hip_tlv_common), |
292 | @@ -2515,7 +2518,7 @@ |
293 | */ |
294 | int hip_build_param_solution(struct hip_common *msg, |
295 | const struct hip_puzzle *pz, |
296 | - uint64_t val_J) |
297 | + uint8_t val_J[PUZZLE_LENGTH]) |
298 | { |
299 | struct hip_solution cookie; |
300 | int err = 0; |
301 | @@ -2527,7 +2530,7 @@ |
302 | /* Type 2 (in R1) or 3 (in I2) */ |
303 | hip_set_param_type((struct hip_tlv_common *) &cookie, HIP_PARAM_SOLUTION); |
304 | |
305 | - cookie.J = val_J; |
306 | + memcpy(cookie.J, val_J, PUZZLE_LENGTH); |
307 | memcpy(&cookie.K, &pz->K, 12); /* copy: K (1), reserved (1), |
308 | * opaque (2) and I (8 bytes). */ |
309 | cookie.reserved = 0; |
310 | |
311 | === modified file 'lib/core/builder.h' |
312 | --- lib/core/builder.h 2011-04-02 20:38:36 +0000 |
313 | +++ lib/core/builder.h 2011-04-19 15:56:06 +0000 |
314 | @@ -126,11 +126,11 @@ |
315 | uint8_t, |
316 | void *, |
317 | size_t); |
318 | -int hip_build_param_puzzle(struct hip_common *, |
319 | - uint8_t, |
320 | - uint8_t, |
321 | - uint32_t, |
322 | - uint64_t); |
323 | +int hip_build_param_puzzle(struct hip_common *const msg, |
324 | + const uint8_t val_K, |
325 | + const uint8_t lifetime, |
326 | + const uint32_t opaque, |
327 | + const uint8_t *const random_i); |
328 | |
329 | int hip_build_param_challenge_request(struct hip_common *, |
330 | uint8_t, |
331 | @@ -150,7 +150,7 @@ |
332 | uint8_t); |
333 | int hip_build_param_solution(struct hip_common *, |
334 | const struct hip_puzzle *, |
335 | - uint64_t); |
336 | + uint8_t *const); |
337 | |
338 | int hip_build_param_challenge_response(struct hip_common *, |
339 | const struct hip_challenge_request *, |
340 | |
341 | === modified file 'lib/core/protodefs.h' |
342 | --- lib/core/protodefs.h 2011-02-04 14:44:37 +0000 |
343 | +++ lib/core/protodefs.h 2011-04-19 15:56:06 +0000 |
344 | @@ -737,13 +737,17 @@ |
345 | uint64_t generation; |
346 | } __attribute__ ((packed)); |
347 | |
348 | + |
349 | +/* puzzle and solutions are defined to have a length of 8 bytes */ |
350 | +#define PUZZLE_LENGTH 8 |
351 | + |
352 | struct hip_puzzle { |
353 | hip_tlv type; |
354 | hip_tlv_len length; |
355 | uint8_t K; |
356 | uint8_t lifetime; |
357 | uint8_t opaque[HIP_PUZZLE_OPAQUE_LEN]; |
358 | - uint64_t I; |
359 | + uint8_t I[PUZZLE_LENGTH]; |
360 | } __attribute__ ((packed)); |
361 | |
362 | struct hip_solution { |
363 | @@ -752,8 +756,8 @@ |
364 | uint8_t K; |
365 | uint8_t reserved; |
366 | uint8_t opaque[HIP_PUZZLE_OPAQUE_LEN]; |
367 | - uint64_t I; |
368 | - uint64_t J; |
369 | + uint8_t I[PUZZLE_LENGTH]; |
370 | + uint8_t J[PUZZLE_LENGTH]; |
371 | } __attribute__ ((packed)); |
372 | |
373 | |
374 | |
375 | === modified file 'lib/core/solve.c' |
376 | --- lib/core/solve.c 2011-04-18 11:59:17 +0000 |
377 | +++ lib/core/solve.c 2011-04-19 15:56:06 +0000 |
378 | @@ -28,11 +28,13 @@ |
379 | * @brief HIP computation puzzle solving algorithms |
380 | * |
381 | * @author Miika Komu <miika@iki.fi> |
382 | + * @author Rene Hummen |
383 | */ |
384 | |
385 | #include <errno.h> |
386 | #include <stdint.h> |
387 | #include <string.h> |
388 | +#include <strings.h> |
389 | |
390 | #include "config.h" |
391 | #include "builder.h" |
392 | @@ -42,109 +44,134 @@ |
393 | #include "protodefs.h" |
394 | #include "solve.h" |
395 | |
396 | +// max. 2^max_puzzle_difficulty tries to solve a puzzle |
397 | +#define MAX_PUZZLE_SOLUTION_TRIES (1ULL << MAX_PUZZLE_DIFFICULTY) |
398 | + |
399 | /** |
400 | - * solve a computational puzzle for HIP |
401 | - * |
402 | - * @param puzzle_or_solution Either a pointer to hip_puzzle or hip_solution structure |
403 | - * @param hdr The incoming R1/I2 packet header. |
404 | - * @param mode Either HIP_VERIFY_PUZZLE of HIP_SOLVE_PUZZLE |
405 | - * |
406 | - * @note The K and I is read from the @c puzzle_or_solution. |
407 | - * @note Regarding to return value of zero, I don't see why 0 couldn't solve the |
408 | - * puzzle too, but since the odds are 1/2^64 to try 0, I don't see the point |
409 | - * in improving this now. |
410 | - * @return The J that solves the puzzle is returned, or 0 to indicate an error. |
411 | + * Computes a single iteration for a computational puzzle |
412 | + * |
413 | + * @param puzzle_input puzzle to be solved or verified |
414 | + * @param difficulty difficulty of the puzzle (number of leading zeros) |
415 | + * @return 0 when hash has >= @a difficulty least significant bits as zeros, 1 |
416 | + * when hash has < @a difficulty least significant bits as zeros, |
417 | + * -1 in case of an error |
418 | */ |
419 | -uint64_t hip_solve_puzzle(const void *puzzle_or_solution, |
420 | - const struct hip_common *hdr, |
421 | - int mode) |
422 | +static int hip_single_puzzle_computation(const struct puzzle_hash_input *const puzzle_input, |
423 | + const uint8_t difficulty) |
424 | { |
425 | - uint64_t mask = 0; |
426 | - uint64_t randval = 0; |
427 | - uint64_t maxtries = 0; |
428 | - uint64_t digest = 0; |
429 | - uint8_t cookie[48]; |
430 | - const union { |
431 | - struct hip_puzzle pz; |
432 | - struct hip_solution sl; |
433 | - } *u; |
434 | - |
435 | - HIP_HEXDUMP("puzzle", puzzle_or_solution, |
436 | - (mode == HIP_VERIFY_PUZZLE ? sizeof(struct hip_solution) : |
437 | - sizeof(struct hip_puzzle))); |
438 | - |
439 | - /* pre-create cookie */ |
440 | - u = puzzle_or_solution; |
441 | - |
442 | - if (u->pz.K > HIP_PUZZLE_MAX_K) { |
443 | - HIP_ERROR("Cookie K %u is higher than we are willing to calculate" |
444 | - " (current max K=%d)\n", u->pz.K, HIP_PUZZLE_MAX_K); |
445 | + unsigned char sha_digest[SHA_DIGEST_LENGTH]; |
446 | + uint32_t truncated_digest = 0; |
447 | + int err = -1; |
448 | + |
449 | + /* any puzzle solution is acceptable for difficulty 0 */ |
450 | + if (difficulty == 0) { |
451 | return 0; |
452 | } |
453 | |
454 | - mask = hton64((1ULL << u->pz.K) - 1); |
455 | - memcpy(cookie, &u->pz.I, sizeof(uint64_t)); |
456 | - |
457 | - HIP_DEBUG("(u->pz.I: 0x%llx\n", u->pz.I); |
458 | - |
459 | - if (mode == HIP_VERIFY_PUZZLE) { |
460 | - ipv6_addr_copy((hip_hit_t *) (cookie + 8), &hdr->hits); |
461 | - ipv6_addr_copy((hip_hit_t *) (cookie + 24), &hdr->hitr); |
462 | - randval = u->sl.J; |
463 | - maxtries = 1; |
464 | - } else if (mode == HIP_SOLVE_PUZZLE) { |
465 | - ipv6_addr_copy((hip_hit_t *) (cookie + 8), &hdr->hitr); |
466 | - ipv6_addr_copy((hip_hit_t *) (cookie + 24), &hdr->hits); |
467 | - maxtries = 1ULL << (u->pz.K + 3); |
468 | - get_random_bytes(&randval, sizeof(uint64_t)); |
469 | + HIP_IFEL(difficulty > MAX_PUZZLE_DIFFICULTY, |
470 | + -1, "difficulty exceeds max. configured difficulty\n"); |
471 | + |
472 | + HIP_IFEL(hip_build_digest(HIP_DIGEST_SHA1, |
473 | + puzzle_input, |
474 | + sizeof(struct puzzle_hash_input), |
475 | + sha_digest), |
476 | + -1, "failed to compute hash digest\n"); |
477 | + |
478 | + /* In reference to RFC 5201, we need to interpret the hash digest as an |
479 | + * integer in network byte-order. We are interested in least significant |
480 | + * bits here. */ |
481 | + truncated_digest = *(uint32_t *) &sha_digest[SHA_DIGEST_LENGTH - sizeof(truncated_digest)]; |
482 | + |
483 | + /* Make sure to interpret the solution equally across platforms |
484 | + * (i.e., network byte-order), when calculating the puzzle solution. |
485 | + * |
486 | + * The problem is that ffs() interprets its input not as a byte array |
487 | + * but as an integer with an encoding that depends on the host byte order. |
488 | + * htonl() ensures that ffs() performs the check in network byte order |
489 | + * independent from the actual host byte order. */ |
490 | + truncated_digest = htonl(truncated_digest); |
491 | + |
492 | + /* check if position of first least significant 1-bit is higher than |
493 | + * difficulty */ |
494 | + if (ffs(truncated_digest) > difficulty) { |
495 | + err = 0; |
496 | } else { |
497 | - HIP_ERROR("Unknown mode: %d\n", mode); |
498 | + err = 1; |
499 | + } |
500 | + |
501 | +out_err: |
502 | + return err; |
503 | +} |
504 | + |
505 | +/** |
506 | + * Solve a computational puzzle for HIP |
507 | + * |
508 | + * @param puzzle_input puzzle to be solved or verified |
509 | + * @param difficulty difficulty of the puzzle |
510 | + * @return 0 when solution was found, 1 in case no solution was found after |
511 | + * ::MAX_PUZZLE_SOLUTION_TRIES, -1 in case of an error |
512 | + * |
513 | + * @note provide data for all members of puzzle_input when calling this function |
514 | + * @note puzzle_input will contain the solution on successful exit |
515 | + */ |
516 | +int hip_solve_puzzle(struct puzzle_hash_input *const puzzle_input, |
517 | + const uint8_t difficulty) |
518 | +{ |
519 | + int err = -1; |
520 | + |
521 | + // any puzzle solution is acceptable for difficulty 0 |
522 | + if (difficulty == 0) { |
523 | return 0; |
524 | } |
525 | |
526 | - HIP_DEBUG("K=%u, maxtries (with k+2)=%llu\n", u->pz.K, maxtries); |
527 | - /* while loops should work even if the maxtries is unsigned |
528 | - * if maxtries = 1 ---> while(1 > 0) [maxtries == 0 now]... |
529 | - * the next round while (0 > 0) [maxtries > 0 now] |
530 | - */ |
531 | - while (maxtries-- > 0) { |
532 | - uint8_t sha_digest[HIP_AH_SHA_LEN]; |
533 | - |
534 | - /* must be 8 */ |
535 | - memcpy(cookie + 40, (uint8_t *) &randval, sizeof(uint64_t)); |
536 | - |
537 | - hip_build_digest(HIP_DIGEST_SHA1, cookie, 48, sha_digest); |
538 | - |
539 | - /* copy the last 8 bytes for checking */ |
540 | - memcpy(&digest, sha_digest + 12, sizeof(uint64_t)); |
541 | - |
542 | - /* now, in order to be able to do correctly the bitwise |
543 | - * AND-operation we have to remember that little endian |
544 | - * processors will interpret the digest and mask reversely. |
545 | - * digest is the last 64 bits of the sha1-digest.. how that is |
546 | - * ordered in processors registers etc.. does not matter to us. |
547 | - * If the last 64 bits of the sha1-digest is |
548 | - * 0x12345678DEADBEEF, whether we have 0xEFBEADDE78563412 |
549 | - * doesn't matter because the mask matters... if the mask is |
550 | - * 0x000000000000FFFF (or in other endianness |
551 | - * 0xFFFF000000000000). Either ways... the result is |
552 | - * 0x000000000000BEEF or 0xEFBE000000000000, which the cpu |
553 | - * interprets as 0xBEEF. The mask is converted to network byte |
554 | - * order (above). |
555 | - */ |
556 | - if ((digest & mask) == 0) { |
557 | - return randval; |
558 | - } |
559 | - |
560 | - /* It seems like the puzzle was not correctly solved */ |
561 | - if (mode == HIP_VERIFY_PUZZLE) { |
562 | - HIP_ERROR("Puzzle incorrect\n"); |
563 | + /* If max_puzzle_difficulty >= 64, MAX_PUZZLE_SOLUTION_TRIES will be 0. |
564 | + * Hence, no solution will be found for these cases. */ |
565 | + HIP_ASSERT(MAX_PUZZLE_DIFFICULTY < sizeof(unsigned long long) * 8); |
566 | + |
567 | + if (difficulty > MAX_PUZZLE_DIFFICULTY) { |
568 | + HIP_ERROR("Cookie (K = %u) is higher than we are willing to calculate " |
569 | + "(current max K = %u)\n", difficulty, MAX_PUZZLE_DIFFICULTY); |
570 | + return -1; |
571 | + } |
572 | + |
573 | + for (unsigned long long i = 0; i < MAX_PUZZLE_SOLUTION_TRIES; i++) { |
574 | + err = hip_single_puzzle_computation(puzzle_input, |
575 | + difficulty); |
576 | + if (err == 0) { |
577 | return 0; |
578 | + } else if (err > 0) { |
579 | + // increase random value by one and try again |
580 | + (*(uint64_t *) puzzle_input->solution)++; |
581 | + } else { |
582 | + HIP_ERROR("error while computing the puzzle solution\n"); |
583 | + memset(puzzle_input, 0, PUZZLE_LENGTH); |
584 | + return -1; |
585 | } |
586 | - randval++; |
587 | } |
588 | |
589 | HIP_ERROR("Could not solve the puzzle, no solution found\n"); |
590 | + return 1; |
591 | +} |
592 | + |
593 | +/** |
594 | + * Verify a computational puzzle for HIP |
595 | + * |
596 | + * @param puzzle_input puzzle to be solved or verified |
597 | + * @param difficulty difficulty of the puzzle |
598 | + * @return 0 when solution is correct, -1 otherwise |
599 | + */ |
600 | +int hip_verify_puzzle_solution(const struct puzzle_hash_input *const puzzle_input, |
601 | + const uint8_t difficulty) |
602 | +{ |
603 | + // any puzzle solution is acceptable for difficulty 0 |
604 | + if (difficulty == 0) { |
605 | + return 0; |
606 | + } |
607 | + |
608 | + if (hip_single_puzzle_computation(puzzle_input, difficulty)) { |
609 | + HIP_ERROR("failed to verify puzzle solution\n"); |
610 | + return -1; |
611 | + } |
612 | |
613 | return 0; |
614 | } |
615 | |
616 | === modified file 'lib/core/solve.h' |
617 | --- lib/core/solve.h 2010-10-15 15:29:14 +0000 |
618 | +++ lib/core/solve.h 2011-04-19 15:56:06 +0000 |
619 | @@ -30,10 +30,29 @@ |
620 | |
621 | #include "protodefs.h" |
622 | |
623 | -#define HIP_PUZZLE_MAX_K 28 |
624 | - |
625 | -uint64_t hip_solve_puzzle(const void *puzzle, |
626 | - const struct hip_common *hdr, int mode); |
627 | -int hip_solve_puzzle_m(struct hip_common *out, struct hip_common *in); |
628 | +/* ensure that the max puzzle difficulty (here 28) is limited by sizeof(int), |
629 | + * as ffs() is working on int type. |
630 | + * |
631 | + * NOTE: ffsll() allowing for sizeof(long long int) is currently not available |
632 | + * on OpenWRT. */ |
633 | +static const uint8_t MAX_PUZZLE_DIFFICULTY = sizeof(int) * 8 >= 28 ? 28 : sizeof(int) * 8; |
634 | + |
635 | +/** This data type represents the ordered input for the hash function used to |
636 | + * solve a given puzzle challenge as defined in RFC 5201 - Appendix A |
637 | + * |
638 | + * solution is correct iff: |
639 | + * 0 == V := Ltrunc( RHASH( I2.I | I2.hit_i | I2.hit_r | I2.J ), K ) */ |
640 | +struct puzzle_hash_input { |
641 | + uint8_t puzzle[PUZZLE_LENGTH]; |
642 | + hip_hit_t initiator_hit; |
643 | + hip_hit_t responder_hit; |
644 | + uint8_t solution[PUZZLE_LENGTH]; |
645 | +} __attribute__ ((packed)); |
646 | + |
647 | +int hip_solve_puzzle(struct puzzle_hash_input *puzzle_input, |
648 | + const uint8_t difficulty); |
649 | + |
650 | +int hip_verify_puzzle_solution(const struct puzzle_hash_input *const puzzle_input, |
651 | + const uint8_t difficulty); |
652 | |
653 | #endif /* HIP_LIB_CORE_SOLVE_H */ |
654 | |
655 | === modified file 'lib/core/state.h' |
656 | --- lib/core/state.h 2011-02-06 09:03:39 +0000 |
657 | +++ lib/core/state.h 2011-04-19 15:56:06 +0000 |
658 | @@ -294,13 +294,13 @@ |
659 | /** A function pointer to a function that verifies peer's host identity. */ |
660 | int (*verify)(void *, struct hip_common *); |
661 | /** For retransmission. */ |
662 | - uint64_t puzzle_solution; |
663 | + uint8_t puzzle_solution[PUZZLE_LENGTH]; |
664 | /** LOCATOR parameter. Just tmp save if sent in R1 no @c esp_info so |
665 | * keeping it here 'till the hip_update_locator_parameter can be done. |
666 | * @todo Remove this kludge. */ |
667 | struct hip_locator *locator; |
668 | /** For retransmission. */ |
669 | - uint64_t puzzle_i; |
670 | + uint8_t puzzle_i[PUZZLE_LENGTH]; |
671 | /** Used for UPDATE and CLOSE. When we sent multiple identical UPDATE |
672 | * packets between different address combinations, we don't modify |
673 | * the opaque data. */ |
674 | |
675 | === modified file 'lib/tool/pk.c' |
676 | --- lib/tool/pk.c 2011-04-04 13:59:21 +0000 |
677 | +++ lib/tool/pk.c 2011-04-19 15:56:06 +0000 |
678 | @@ -131,8 +131,8 @@ |
679 | uint8_t sha1_digest[HIP_AH_SHA_LEN]; |
680 | struct in6_addr tmpaddr; |
681 | struct hip_puzzle *pz = NULL; |
682 | - uint8_t opaque[3]; |
683 | - uint64_t randi = 0; |
684 | + uint8_t opaque[HIP_PUZZLE_OPAQUE_LEN]; |
685 | + uint8_t rand_i[PUZZLE_LENGTH]; |
686 | |
687 | ipv6_addr_copy(&tmpaddr, &msg->hitr); /* so update is handled, too */ |
688 | |
689 | @@ -146,11 +146,13 @@ |
690 | |
691 | HIP_IFEL(!(pz = hip_get_param_readwrite(msg, HIP_PARAM_PUZZLE)), |
692 | -ENOENT, "Illegal R1 packet (puzzle missing)\n"); |
693 | - memcpy(opaque, pz->opaque, sizeof(pz->opaque)); |
694 | - randi = pz->I; |
695 | |
696 | - memset(pz->opaque, 0, sizeof(pz->opaque)); |
697 | - pz->I = 0; |
698 | + /* temporarily store original puzzle values */ |
699 | + memcpy(opaque, pz->opaque, HIP_PUZZLE_OPAQUE_LEN); |
700 | + memcpy(rand_i, pz->I, PUZZLE_LENGTH); |
701 | + /* R1 signature is computed over zero values */ |
702 | + memset(pz->opaque, 0, HIP_PUZZLE_OPAQUE_LEN); |
703 | + memset(pz->I, 0, PUZZLE_LENGTH); |
704 | } else { |
705 | HIP_IFEL(!(sig = hip_get_param_readwrite(msg, HIP_PARAM_HIP_SIGNATURE)), |
706 | -ENOENT, "Could not find signature\n"); |
707 | @@ -182,8 +184,8 @@ |
708 | #endif |
709 | |
710 | if (hip_get_msg_type(msg) == HIP_R1) { |
711 | - memcpy(pz->opaque, opaque, sizeof(pz->opaque)); |
712 | - pz->I = randi; |
713 | + memcpy(pz->opaque, opaque, HIP_PUZZLE_OPAQUE_LEN); |
714 | + memcpy(pz->I, rand_i, PUZZLE_LENGTH); |
715 | } |
716 | |
717 | ipv6_addr_copy(&msg->hitr, &tmpaddr); |
718 | |
719 | === modified file 'test/check_lib_core.c' |
720 | --- test/check_lib_core.c 2011-02-18 14:39:38 +0000 |
721 | +++ test/check_lib_core.c 2011-04-19 15:56:06 +0000 |
722 | @@ -38,6 +38,7 @@ |
723 | { |
724 | int number_failed; |
725 | SRunner *sr = srunner_create(lib_core_hit()); |
726 | + srunner_add_suite(sr, lib_core_solve()); |
727 | srunner_add_suite(sr, lib_core_straddr()); |
728 | |
729 | srunner_run_all(sr, CK_NORMAL); |
730 | |
731 | === added file 'test/lib/core/solve.c' |
732 | --- test/lib/core/solve.c 1970-01-01 00:00:00 +0000 |
733 | +++ test/lib/core/solve.c 2011-04-19 15:56:06 +0000 |
734 | @@ -0,0 +1,136 @@ |
735 | +/* |
736 | + * Copyright (c) 2011 Aalto University and RWTH Aachen University. |
737 | + * |
738 | + * Permission is hereby granted, free of charge, to any person |
739 | + * obtaining a copy of this software and associated documentation |
740 | + * files (the "Software"), to deal in the Software without |
741 | + * restriction, including without limitation the rights to use, |
742 | + * copy, modify, merge, publish, distribute, sublicense, and/or sell |
743 | + * copies of the Software, and to permit persons to whom the |
744 | + * Software is furnished to do so, subject to the following |
745 | + * conditions: |
746 | + * |
747 | + * The above copyright notice and this permission notice shall be |
748 | + * included in all copies or substantial portions of the Software. |
749 | + * |
750 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
751 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
752 | + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
753 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
754 | + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
755 | + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
756 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
757 | + * OTHER DEALINGS IN THE SOFTWARE. |
758 | + */ |
759 | + |
760 | +/** |
761 | + * @file |
762 | + * @author Rene Hummen |
763 | + */ |
764 | + |
765 | +#include <check.h> |
766 | +#include <stdint.h> |
767 | +#include <stdio.h> |
768 | +#include <arpa/inet.h> |
769 | +#include <netinet/in.h> |
770 | +#include <openssl/rand.h> |
771 | + |
772 | +#include "lib/core/solve.h" |
773 | +#include "config.h" |
774 | +#include "test_suites.h" |
775 | + |
776 | + |
777 | +START_TEST(test_hip_solve_puzzle_0_K) |
778 | +{ |
779 | + struct puzzle_hash_input puzzle_input = { { 0 } }; |
780 | + uint8_t difficulty = 0; |
781 | + |
782 | + RAND_bytes(puzzle_input.puzzle, sizeof(PUZZLE_LENGTH)); |
783 | + |
784 | + fail_unless(hip_solve_puzzle(&puzzle_input, difficulty) == 0, NULL); |
785 | +} |
786 | +END_TEST |
787 | + |
788 | +START_TEST(test_hip_solve_puzzle_5_K) |
789 | +{ |
790 | + struct puzzle_hash_input puzzle_input = { { 0 } }; |
791 | + uint8_t difficulty = 5; |
792 | + |
793 | + RAND_bytes(puzzle_input.puzzle, sizeof(PUZZLE_LENGTH)); |
794 | + |
795 | + fail_unless(hip_solve_puzzle(&puzzle_input, difficulty) == 0, NULL); |
796 | +} |
797 | +END_TEST |
798 | + |
799 | +START_TEST(test_hip_solve_puzzle_exceeding_K) |
800 | +{ |
801 | + struct puzzle_hash_input puzzle_input = { { 0 } }; |
802 | + uint8_t difficulty = MAX_PUZZLE_DIFFICULTY + 1; |
803 | + |
804 | + RAND_bytes(puzzle_input.puzzle, sizeof(PUZZLE_LENGTH)); |
805 | + |
806 | + fail_unless(hip_solve_puzzle(&puzzle_input, difficulty) == -1, NULL); |
807 | +} |
808 | +END_TEST |
809 | + |
810 | +START_TEST(test_hip_verify_puzzle_solution_invalid) |
811 | +{ |
812 | + struct puzzle_hash_input puzzle_input = { { 0 } }; |
813 | + uint8_t difficulty = 5; |
814 | + |
815 | + memset(puzzle_input.puzzle, 1, PUZZLE_LENGTH); |
816 | + |
817 | + fail_unless(hip_verify_puzzle_solution(&puzzle_input, difficulty) == -1, NULL); |
818 | +} |
819 | +END_TEST |
820 | + |
821 | +START_TEST(test_hip_verify_puzzle_solution_against_ourselves) |
822 | +{ |
823 | + struct puzzle_hash_input puzzle_input = { { 0 } }; |
824 | + uint8_t difficulty = 5; |
825 | + |
826 | + RAND_bytes(puzzle_input.puzzle, sizeof(PUZZLE_LENGTH)); |
827 | + |
828 | + fail_unless(hip_solve_puzzle(&puzzle_input, difficulty) == 0, NULL); |
829 | + fail_unless(hip_verify_puzzle_solution(&puzzle_input, difficulty) == 0, NULL); |
830 | +} |
831 | +END_TEST |
832 | + |
833 | +START_TEST(test_hip_test_hip_verify_puzzle_solution_against_real_solution) |
834 | +{ |
835 | + char solution_dump[] = "\x01\x41\x00\x14\x05\x00\x48\x49\x0b\xbd\xd0\xb4" |
836 | + "\x92\xbb\xea\xe3\xa9\x71\x97\xdf\x12\xe1\x2c\x9f"; |
837 | + struct hip_solution *solution = (struct hip_solution *) solution_dump; |
838 | + const char *initiator_hit_str = "2001:1b:d8b0:77f0:c617:7170:ded7:f320"; |
839 | + const char *responder_hit_str = "2001:17:5df8:c426:98e5:5fa2:286d:2847"; |
840 | + struct in6_addr initiator_hit; |
841 | + struct in6_addr responder_hit; |
842 | + struct puzzle_hash_input puzzle_input; |
843 | + |
844 | + inet_pton(AF_INET6, initiator_hit_str, &initiator_hit); |
845 | + inet_pton(AF_INET6, responder_hit_str, &responder_hit); |
846 | + |
847 | + memcpy(puzzle_input.puzzle, solution->I, PUZZLE_LENGTH); |
848 | + puzzle_input.initiator_hit = initiator_hit; |
849 | + puzzle_input.responder_hit = responder_hit; |
850 | + memcpy(puzzle_input.solution, solution->J, PUZZLE_LENGTH); |
851 | + |
852 | + fail_unless(hip_verify_puzzle_solution(&puzzle_input, solution->K) == 0, NULL); |
853 | +} |
854 | +END_TEST |
855 | + |
856 | +Suite *lib_core_solve(void) |
857 | +{ |
858 | + Suite *s = suite_create("lib/core/solve"); |
859 | + |
860 | + TCase *tc_core = tcase_create("Core"); |
861 | + tcase_add_test(tc_core, test_hip_solve_puzzle_0_K); |
862 | + tcase_add_test(tc_core, test_hip_solve_puzzle_5_K); |
863 | + tcase_add_test(tc_core, test_hip_solve_puzzle_exceeding_K); |
864 | + tcase_add_test(tc_core, test_hip_verify_puzzle_solution_invalid); |
865 | + tcase_add_test(tc_core, test_hip_verify_puzzle_solution_against_ourselves); |
866 | + tcase_add_test(tc_core, test_hip_test_hip_verify_puzzle_solution_against_real_solution); |
867 | + suite_add_tcase(s, tc_core); |
868 | + |
869 | + return s; |
870 | +} |
871 | |
872 | === modified file 'test/lib/core/test_suites.h' |
873 | --- test/lib/core/test_suites.h 2011-02-18 14:39:38 +0000 |
874 | +++ test/lib/core/test_suites.h 2011-04-19 15:56:06 +0000 |
875 | @@ -29,6 +29,7 @@ |
876 | #include <check.h> |
877 | |
878 | Suite *lib_core_hit(void); |
879 | +Suite *lib_core_solve(void); |
880 | Suite *lib_core_straddr(void); |
881 | |
882 | #endif /* HIP_TEST_LIB_CORE_TEST_SUITES_H */ |
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, SHA_DIGEST_ LENGTH] , "puzzle" , puzzle_or_solution, "(u->pz. I: 0x%llx\n", u->pz.I); copy((hip_ hit_t *) (cookie + 8), &hdr->hits); copy((hip_ hit_t *) (cookie + 24), &hdr->hitr); copy((hip_ hit_t *) (cookie + 8), &hdr->hitr); copy((hip_ hit_t *) (cookie + 24), &hdr->hits); bytes(& randval, sizeof(uint64_t)); difficulty, hip_build_ digest( HIP_DIGEST_ SHA1,
> + unsigned char sha_digest[
> + 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(
> - (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(
> -
> - if (mode == HIP_VERIFY_PUZZLE) {
> - ipv6_addr_
> - ipv6_addr_
> - randval = u->sl.J;
> - maxtries = 1;
> - } else if (mode == HIP_SOLVE_PUZZLE) {
> - ipv6_addr_
> - ipv6_addr_
> - maxtries = 1ULL << (u->pz.K + 3);
> - get_random_
> + uint32_t truncated_digest = 0;
> + int err = -1;
> +
> + HIP_IFEL(difficulty > max_puzzle_
> + 1, "difficulty exceeds max. configured difficulty\n");
> +
> + HIP_IFEL(
> + 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 */ SHA_DIGEST_ LENGTH - sizeof(uint32_t)];
> + truncated_digest = *(uint32_t *) &sha_digest[
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...