From anakin at pobox.com Tue Jun 25 18:44:34 2013 From: anakin at pobox.com (Simon Tatham) Date: Tue, 25 Jun 2013 18:44:34 +0100 Subject: secnet robustness: tolerate SLIP decoding errors Message-ID: As discussed with Ian on Sunday, I attach a patch to secnet which makes it stop treating SLIP decoding failures as fatal error conditions worthy of assertion failure or secnet termination, and instead logs them and resynchronises at the next packet boundary. (I've recently been running secnet with gdb attached in order to track down a behavioural oddity, and have noticed that gdb suspending the secnet process tends to have the side effect that corruptions can appear in the SLIP stream after it's restarted; presumably some data got lost when the kernel got impatient. Therefore, Ian suggested that such corruption should no longer be an assertion-failure condition.) Cheers, Simon -- Simon Tatham "A cynic is a person who smells flowers and immediately looks around for a coffin." -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-slip-tolerate-SLIP-decoding-errors.patch Type: text/x-diff Size: 3732 bytes Desc: not available URL: From ijackson at chiark.greenend.org.uk Wed Jul 3 23:02:42 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 3 Jul 2013 23:02:42 +0100 Subject: secnet bug: tun and mobile sites [and 1 more messages] In-Reply-To: , References: Message-ID: <20948.40834.530863.275060@chiark.greenend.org.uk> Simon Tatham writes ("secnet bug: tun and mobile sites"): > secnet's 'tun' netlink will add and remove kernel routing table > entries during PHASE_RUN if the OPT_SOFTROUTE option is set. > However, at startup during PHASE_GETRESOURCES it will set up routes > for a site only if that site lists an address. So if you have a site > in your sites file with no address but also haven't enabled > OPT_SOFTROUTE (e.g. because you run secnet so that it drops privs), > then no route for that site will _ever_ be set up. Thanks for this patch. I have applied it. I included your explanation of the bug in the commit message. > (See also bdd4351ff2fc6dc8b1dad689f751ac46347636cf, which seems to > be fixing the analogous bug for userv-ipif.) That seems to be an empty commit, which seems to have been incorporated due to some kind of vcs glitch. The actual code change is in the earlier commit 04f92904ea6c41517ff7154910c16ef4c3bc646b which has an identical commit message. Simon Tatham writes ("Re: secnet bug: tun and mobile sites"): > Oh, I've just noticed a previous mailing list message muttering > about Signed-off-by lines. If my patch is acceptable, please feel > free to add to my commit message the line > > Signed-off-by: Simon Tatham Thanks, done. Ian. From ijackson at chiark.greenend.org.uk Wed Jul 3 23:20:19 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 3 Jul 2013 23:20:19 +0100 Subject: secnet robustness: tolerate SLIP decoding errors In-Reply-To: References: Message-ID: <20948.41891.690701.75500@chiark.greenend.org.uk> Simon Tatham writes ("secnet robustness: tolerate SLIP decoding errors"): > As discussed with Ian on Sunday, I attach a patch to secnet which > makes it stop treating SLIP decoding failures as fatal error > conditions worthy of assertion failure or secnet termination, and > instead logs them and resynchronises at the next packet boundary. Cor, this is quite a complicated way of doing this. It makes what did seem quite a simple (but fragile) function into quite a fiddly one. Perhaps it would have been easier to rewrite this function but perhaps not. Anyway I have decided not to push this quibble. I have applied the patch, and fixed the trailing whitespace on this line: } else if (outputchr != OUTPUT_NOTHING) { which git-am warned me about. BTW, I'm not sure how useful the distinction is that you're making between your covering notes and your commit messages. In some cases you seem to be writing the same thing twice and in your previous patch I found myself copying some of the covering note into the commit message. In general I don't think you need to explain again in the covering note what's already said in the commit message. If that means you don't end up with a covering note then that's less bureaucracy :-). Ian. From ijackson at chiark.greenend.org.uk Wed Jul 3 23:24:47 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 3 Jul 2013 23:24:47 +0100 Subject: secnet status Message-ID: <20948.42159.375677.357139@chiark.greenend.org.uk> Before doing another beta, and then a release, there are some things that need to be fixed: * We need to get rid of CBC-MAC, really! We don't have much algorithm agility, but we do need at the least to have some kind of sites-fragment-based capability computation mechanism. And we need a new transform. I propose to implement a simple one using HMAC-SHA-512 truncated to 128 bits, and Serpent in Counter mode (using the packet sequence number concatenated with the block number within the packet as the counter). * We need to replace some of our memcmps with a constant time version. I have code to do this. * There is an annoying tendency for a restarted secnet not to be quite functional; in particular restarting the fixed site can cause trouble for mobile sites. I have a patch series half-written to fix this. Ian. From ijackson at chiark.greenend.org.uk Wed Jul 17 14:02:54 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:02:54 +0100 Subject: [RFC PATCH 0/5] Security-relevant fixes, transform agility Message-ID: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> This is a preview of a work-in-progress series I have in development to fix some security problems in secnet. The biggest problem is that we are using CBC-MAC, which is known to be broken. I plan to fix this by replace our CBC+CBC-MAC transform with EAX. Unfortunately we are lacking algorithm agility. Looking at the NOTES and the code, it is difficult to retrofit this because we're lacking an officially approved space for future expansion covered by the signatures. However, bug to the rescue! It turns out that the string comparison used for checking site names is broken in a way that we can exploit. We therefore perpetrate an awful bodge, and enshrine and document it. Ideally we would like also to abandon PKCS#1 in favour of OAEP. But I think this is less urgent and wants to be combined with a general public key (and public algorithm) rollover mechanism, which we are currently lacking. So far in this series, we make a start on using a constant-time memcmp and providing a capability field for future expansion: 1/5 memcmp: Introduce and use consttime_memcmp 2/5 transform: Do not look at any bytes of PKCS#5 padding other than the last 3/5 NOTES: Remove unimplemented protocol negotiation 4/5 site: fix site name checking leaving room for expansion 5/5 site: interpret first two bytes of extrainfo as capabilities NB that this series is an RFC. It compiles but HAS NOT BEEN EXECUTED. From ijackson at chiark.greenend.org.uk Wed Jul 17 14:02:55 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:02:55 +0100 Subject: [PATCH 1/5] memcmp: Introduce and use consttime_memcmp In-Reply-To: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066179-8129-2-git-send-email-ijackson@chiark.greenend.org.uk> We need to use a constant-time memcmp in MAC checking, to avoid leaking (to an adversary) how much of the MAC is right. (This would be especially dangerous if our MAC was outside the encryption, which thankfully it isn't.) Signed-off-by: Ian Jackson --- site.c | 2 +- transform.c | 2 +- util.c | 23 +++++++++++++++++++++++ util.h | 2 ++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/site.c b/site.c index db65bd8..e96d6f4 100644 --- a/site.c +++ b/site.c @@ -463,7 +463,7 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, return False; } if (type==LABEL_MSG2) return True; - if (memcmp(m->nR,st->remoteN,NONCELEN)!=0) { + if (consttime_memcmp(m->nR,st->remoteN,NONCELEN)!=0) { *error="wrong remotely-generated nonce"; return False; } diff --git a/transform.c b/transform.c index 289b02e..893f41c 100644 --- a/transform.c +++ b/transform.c @@ -220,7 +220,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, serpent_encrypt(&ti->mackey,macplain,macacc); } serpent_encrypt(&ti->mackey,macacc,macacc); - if (memcmp(macexpected,macacc,16)!=0) { + if (consttime_memcmp(macexpected,macacc,16)!=0) { *errmsg="invalid MAC"; return 1; } diff --git a/util.c b/util.c index f5f3d75..e50218c 100644 --- a/util.c +++ b/util.c @@ -363,7 +363,30 @@ static list_t *buffer_apply(closure_t *self, struct cloc loc, dict_t *context, return new_closure(&st->cl); } +static FILE *devnull; + +int consttime_memcmp(const void *s1in, const void *s2in, size_t n) +{ + const uint8_t *s1=s1in, *s2=s2in; + size_t accumulator=0; + + assert(n <= SIZE_MAX/255); + + while (n-- > 0) { + accumulator += (*s1++ ^ *s2++); + } + /* This forces the compiler to actually compute all of the bits of + * accumulator. Hopefully that's enough to stop it shortcutting + * the loop. */ + fwrite(&accumulator,1,sizeof(accumulator),devnull); + + return !!accumulator; +} + void util_module(dict_t *dict) { + devnull=fopen("/dev/null","wb"); + if (!devnull) fatal_perror("could not open /dev/null (for util)"); + add_closure(dict,"sysbuffer",buffer_apply); } diff --git a/util.h b/util.h index af19363..2491fd5 100644 --- a/util.h +++ b/util.h @@ -39,4 +39,6 @@ extern int32_t write_mpbin(MP_INT *a, uint8_t *buffer, int32_t buflen); extern struct log_if *init_log(list_t *loglist); +extern int consttime_memcmp(const void *s1, const void *s2, size_t n); + #endif /* util_h */ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:02:56 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:02:56 +0100 Subject: [PATCH 2/5] transform: Do not look at any bytes of PKCS#5 padding other than the last In-Reply-To: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066179-8129-3-git-send-email-ijackson@chiark.greenend.org.uk> This might avoid some timing-related information leaks. In principle this is a protocol change: we now no longer use actual PKCS#5 padding; instead, we use a padding scheme where all but the last byte of the padding may be sent as anything and are ignored by the receiver. Signed-off-by: Ian Jackson --- transform.c | 8 +------- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/transform.c b/transform.c index 893f41c..9ee0df0 100644 --- a/transform.c +++ b/transform.c @@ -234,13 +234,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, return 1; } - padp=buf_unappend(buf,padlen-1); - for (i=0; i References: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066179-8129-4-git-send-email-ijackson@chiark.greenend.org.uk> The protocol negotiation mechanism documented in NOTES is not implemented. Remove it from the document. Signed-off-by: Ian Jackson --- NOTES | 20 +++++--------------- 1 files changed, 5 insertions(+), 15 deletions(-) diff --git a/NOTES b/NOTES index 84453df..f22818c 100644 --- a/NOTES +++ b/NOTES @@ -193,21 +193,18 @@ i? is appropriate index for receiver Note that 'i' may be re-used from one session to the next, whereas 'n' is always fresh. -The protocol version selection stuff is not yet implemented: I'm not -yet convinced it's a good idea. Instead, the initiator could try -using its preferred protocol (which starts with a different magic -number) and fall back if there's no reply. +The protocol version selection stuff is not yet implemented. Messages: -1) A->B: *,iA,msg1,A,B,protorange-A,nA +1) A->B: *,iA,msg1,A,B,,nA -2) B->A: iA,iB,msg2,B,A,chosen-protocol,nB,nA +2) B->A: iA,iB,msg2,B,A,nB,nA (The order of B and A reverses in alternate messages so that the same code can be used to construct them...) -3) A->B: {iB,iA,msg3,A,B,protorange-A,chosen-protocol,nA,nB,g^x mod m}_PK_A^-1 +3) A->B: {iB,iA,msg3,A,B,nA,nB,g^x mod m}_PK_A^-1 If message 1 was a replay then A will not generate message 3, because it doesn't recognise nA. @@ -215,18 +212,11 @@ it doesn't recognise nA. If message 2 was from an attacker then B will not generate message 4, because it doesn't recognise nB. -If an attacker is trying to manipulate the chosen protocol, B can spot -this when it sees A's message 3. - -4) B->A: {iA,iB,msg4,B,A,protorange-B,chosen-protocol,nB,nA,g^y mod m}_PK_B^-1 +4) B->A: {iA,iB,msg4,B,A,nB,nA,g^y mod m}_PK_B^-1 At this point, A and B share a key, k. B must keep retransmitting message 4 until it receives a packet encrypted using key k. -A can abandon the exchange if the chosen protocol is not the one that -it would have chosen knowing the acceptable protocol ranges of A and -B. - 5) A: iB,iA,msg5,(ping/msg5)_k 6) B: iA,iB,msg6,(pong/msg6)_k -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:02:58 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:02:58 +0100 Subject: [PATCH 4/5] site: fix site name checking leaving room for expansion In-Reply-To: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066179-8129-5-git-send-email-ijackson@chiark.greenend.org.uk> Previously, secnet would only check that the site names sent by the peer had the expected site names as prefixes. This would be a security bug on a vpn where one site name is the prefix of another site name. In fact, if the peer sends a short name, secnet will suffer a buffer read overrun and maybe crash - although this is exploitable only for DoS at worst, and not as an information leak. (With reasonable peers, it won't cause packets to be mishandled, because the next field after each name string is a 16-byte integer giving a name or public key byte count, which would have to contain a value greater than 8000 to look like printable characters.) Fix this bug. However, we use this as an opportunity to provide some space (in the signed part of MSG2..4) for future extensions. (At present there is nothing in the parts of MSG3 and MSG4 covered by the signature which is not supposedly entirely fixed - apart from the amount of zero-padding at the MS end of our DH public exponent. This is bad because it provides no way to do transport protocol upgrade/downgrade negotiation without leaving open a protocol version downgrade attack.) After this change the name fields in MSG2..4 are, following the 16-bit length, either just the characters of the name, or the name, followed by a nul byte, followed by zero or more bytes of additional data. Additional data beyond what the receiver expects (which currently means any additional data), is to be ignored. Let us work through some examples. Suppose the expected site name is "expected". Here are the behaviours in relation to various names being transmitted in the packet. (This applies both to the local name, and to the remote name; "rejected" means other instances of the protocol engine get a go, and perhaps the instance with the correct names will accept the message.) MSG Sent name Old secnet New secnet 1 expected ok ok 1 expected\0extra rejected rejected 1 expected/suffix rejected rejected 1 expect rejected rejected 2-4 expected ok ok 2-4 expected\0extra ok, extra ignored ok, extra data 2-4 expected/suffix wrongly accepted rejected 2-4 expect read overrun rejected Signed-off-by: Ian Jackson --- NOTES | 11 ++++++----- site.c | 53 +++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/NOTES b/NOTES index f22818c..5adea50 100644 --- a/NOTES +++ b/NOTES @@ -174,8 +174,9 @@ quite stable so the feature doesn't gain us much. Definitions: -A is the originating gateway machine -B is the destination gateway machine +A is the originating gateway machine name +B is the destination gateway machine name +A+ and B+ are the names with optional additional data, currently ignored PK_A is the public RSA key of A PK_B is the public RSA key of B PK_A^-1 is the private RSA key of A @@ -199,12 +200,12 @@ Messages: 1) A->B: *,iA,msg1,A,B,,nA -2) B->A: iA,iB,msg2,B,A,nB,nA +2) B->A: iA,iB,msg2,B+,A+,nB,nA (The order of B and A reverses in alternate messages so that the same code can be used to construct them...) -3) A->B: {iB,iA,msg3,A,B,nA,nB,g^x mod m}_PK_A^-1 +3) A->B: {iB,iA,msg3,A+,B+,nA,nB,g^x mod m}_PK_A^-1 If message 1 was a replay then A will not generate message 3, because it doesn't recognise nA. @@ -212,7 +213,7 @@ it doesn't recognise nA. If message 2 was from an attacker then B will not generate message 4, because it doesn't recognise nB. -4) B->A: {iA,iB,msg4,B,A,nB,nA,g^y mod m}_PK_B^-1 +4) B->A: {iA,iB,msg4,B+,A+,nB,nA,g^y mod m}_PK_B^-1 At this point, A and B share a key, k. B must keep retransmitting message 4 until it receives a packet encrypted using key k. diff --git a/site.c b/site.c index e96d6f4..261052a 100644 --- a/site.c +++ b/site.c @@ -346,14 +346,19 @@ static bool_t current_valid(struct site *st) type=buf_unprepend_uint32((b)); \ if (type!=(t)) return False; } while(0) +struct parsedname { + int32_t len; + uint8_t *name; + int32_t extrainfo_len; + uint8_t *extrainfo; +}; + struct msg { uint8_t *hashstart; uint32_t dest; uint32_t source; - int32_t remlen; - uint8_t *remote; - int32_t loclen; - uint8_t *local; + struct parsedname remote; + struct parsedname local; uint8_t *nR; uint8_t *nL; int32_t pklen; @@ -401,6 +406,24 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) return True; } +static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm) +{ + CHECK_AVAIL(msg,2); + nm->len=buf_unprepend_uint16(msg); + CHECK_AVAIL(msg,nm->len); + nm->name=buf_unprepend(msg,nm->len); + uint8_t *nul=memchr(nm->name,0,nm->len); + if (!nul) { + nm->extrainfo_len=0; + nm->extrainfo=0; + } else { + nm->extrainfo=nul+1; + nm->extrainfo_len=msg->start-nm->extrainfo; + nm->len=nul-nm->name; + } + return True; +} + static bool_t unpick_msg(struct site *st, uint32_t type, struct buffer_if *msg, struct msg *m) { @@ -410,14 +433,8 @@ static bool_t unpick_msg(struct site *st, uint32_t type, CHECK_AVAIL(msg,4); m->source=buf_unprepend_uint32(msg); CHECK_TYPE(msg,type); - CHECK_AVAIL(msg,2); - m->remlen=buf_unprepend_uint16(msg); - CHECK_AVAIL(msg,m->remlen); - m->remote=buf_unprepend(msg,m->remlen); - CHECK_AVAIL(msg,2); - m->loclen=buf_unprepend_uint16(msg); - CHECK_AVAIL(msg,m->loclen); - m->local=buf_unprepend(msg,m->loclen); + if (!unpick_name(msg,&m->remote)) return False; + if (!unpick_name(msg,&m->local)) return False; CHECK_AVAIL(msg,NONCELEN); m->nR=buf_unprepend(msg,NONCELEN); if (type==LABEL_MSG1) { @@ -443,6 +460,14 @@ static bool_t unpick_msg(struct site *st, uint32_t type, return True; } +static bool_t name_matches(const struct parsedname *nm, const char *expected) +{ + int expected_len=strlen(expected); + return + nm->len == expected_len && + !memcmp(nm->name, expected, expected_len); +} + static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, cstring_t *error) { @@ -450,11 +475,11 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, /* Check that the site names and our nonce have been sent back correctly, and then store our peer's nonce. */ - if (memcmp(m->remote,st->remotename,strlen(st->remotename)!=0)) { + if (!name_matches(&m->remote,st->remotename)) { *error="wrong remote site name"; return False; } - if (memcmp(m->local,st->localname,strlen(st->localname)!=0)) { + if (!name_matches(&m->local,st->localname)) { *error="wrong local site name"; return False; } -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:02:59 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:02:59 +0100 Subject: [PATCH 5/5] site: interpret first two bytes of extrainfo as capabilities In-Reply-To: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066179-8129-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066179-8129-6-git-send-email-ijackson@chiark.greenend.org.uk> Define the first two bytes of the additional data (after the nul in site names in MSG2..4) in the sender's name field to be a capability bitmask. Currently no capability flags are defined. To support this, replace extrainfo and its _len in struct parsedname with a struct buffer_if. We invent a new kind of buffer_if which is a readonly view of another buffer; such a view can be initialised with buffer_view_readonly. This makes it convenient to parse the extrainfo using our existing macros etc. Signed-off-by: Ian Jackson --- NOTES | 11 +++++++++-- site.c | 15 +++++++++------ util.c | 11 +++++++++++ util.h | 5 +++++ 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/NOTES b/NOTES index 5adea50..777ba7e 100644 --- a/NOTES +++ b/NOTES @@ -176,7 +176,7 @@ Definitions: A is the originating gateway machine name B is the destination gateway machine name -A+ and B+ are the names with optional additional data, currently ignored +A+ and B+ are the names with optional additional data, see below PK_A is the public RSA key of A PK_B is the public RSA key of B PK_A^-1 is the private RSA key of A @@ -194,7 +194,14 @@ i? is appropriate index for receiver Note that 'i' may be re-used from one session to the next, whereas 'n' is always fresh. -The protocol version selection stuff is not yet implemented. +The optional additional data after the sender's name consists of some +initial subset of the following list of items: + * A 16-bit integer with a set of capability flags, representing the + abilities of the sender. No such flags are currently defined. + +The optional additional data after the receiver's name is not +currently used. + Messages: diff --git a/site.c b/site.c index 261052a..0264f23 100644 --- a/site.c +++ b/site.c @@ -349,8 +349,7 @@ static bool_t current_valid(struct site *st) struct parsedname { int32_t len; uint8_t *name; - int32_t extrainfo_len; - uint8_t *extrainfo; + struct buffer_if extrainfo; }; struct msg { @@ -359,6 +358,7 @@ struct msg { uint32_t source; struct parsedname remote; struct parsedname local; + uint16_t remote_capabilities; uint8_t *nR; uint8_t *nL; int32_t pklen; @@ -408,17 +408,16 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm) { + struct buffer_if extrainfo; CHECK_AVAIL(msg,2); nm->len=buf_unprepend_uint16(msg); CHECK_AVAIL(msg,nm->len); nm->name=buf_unprepend(msg,nm->len); uint8_t *nul=memchr(nm->name,0,nm->len); if (!nul) { - nm->extrainfo_len=0; - nm->extrainfo=0; + buffer_readonly_view(&extrainfo,0,0); } else { - nm->extrainfo=nul+1; - nm->extrainfo_len=msg->start-nm->extrainfo; + buffer_readonly_view(&extrainfo, nul+1, msg->start-(nul+1)); nm->len=nul-nm->name; } return True; @@ -434,6 +433,10 @@ static bool_t unpick_msg(struct site *st, uint32_t type, m->source=buf_unprepend_uint32(msg); CHECK_TYPE(msg,type); if (!unpick_name(msg,&m->remote)) return False; + if (m->remote.extrainfo.len) { + CHECK_AVAIL(&m->remote.extrainfo,2); + m->remote_capabilities=buf_unprepend_uint16(&m->remote.extrainfo); + } if (!unpick_name(msg,&m->local)) return False; CHECK_AVAIL(msg,NONCELEN); m->nR=buf_unprepend(msg,NONCELEN); diff --git a/util.c b/util.c index e50218c..d47b944 100644 --- a/util.c +++ b/util.c @@ -301,6 +301,17 @@ void buffer_new(struct buffer_if *buf, int32_t len) buf->base=safe_malloc(len,"buffer_new"); } +void buffer_readonly_view(struct buffer_if *buf, const void *data, int32_t len) +{ + buf->free=False; + buf->owner="READONLY"; + buf->flags=0; + buf->loc.file=NULL; + buf->loc.line=0; + buf->size=buf->len=len; + buf->base=buf->start=(uint8_t*)data; +} + void buffer_copy(struct buffer_if *dst, const struct buffer_if *src) { if (dst->len < src->len) { diff --git a/util.h b/util.h index 2491fd5..451d749 100644 --- a/util.h +++ b/util.h @@ -29,6 +29,11 @@ extern void *buf_prepend(struct buffer_if *buf, int32_t amount); extern void *buf_unappend(struct buffer_if *buf, int32_t amount); extern void *buf_unprepend(struct buffer_if *buf, int32_t amount); +extern void buffer_readonly_view(struct buffer_if*, const void*, int32_t len); + /* Caller must only use unappend, unprepend et al. + * buffer state before this can be undefined. After use, + * it must NOT be freed. */ + extern void buf_append_string(struct buffer_if *buf, cstring_t s); extern void read_mpbin(MP_INT *a, uint8_t *bin, int binsize); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:07:47 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:07:47 +0100 Subject: [RFC PATCH 0/6] NAKs and PRODs Message-ID: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> Currently, there are situations where secnet won't recover properly after a restart of one of the ends. In this series we (mostly) fix this. We also tidy up some of the documentation relating to NAKs. 1/6 magic: Introduce LABEL_NAK 2/6 site: Send NAKs for undecryptable data packets (msg0) 3/6 NOTES: Improve documentation of NAKs. 4/6 NOTES: Remove paragraph about slow-to-prepare messages 5/6 site: Clearer processing for name-addressed packets 6/6 site: New PROD message NB that this series is an RFC. It compiles but HAS NOT BEEN EXECUTED. From ijackson at chiark.greenend.org.uk Wed Jul 17 14:07:48 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:07:48 +0100 Subject: [PATCH 1/6] magic: Introduce LABEL_NAK In-Reply-To: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066473-9095-2-git-send-email-ijackson@chiark.greenend.org.uk> Replace ad-hoc comments on the message number of NAK packets with an explicit #define. No functional change. Signed-off-by: Ian Jackson --- magic.h | 1 + site.c | 2 +- udp.c | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/magic.h b/magic.h index 5ac1e34..c2503a0c 100644 --- a/magic.h +++ b/magic.h @@ -3,6 +3,7 @@ #ifndef magic_h #define magic_h +#define LABEL_NAK 0x00000000 #define LABEL_MSG0 0x00020200 #define LABEL_MSG1 0x01010101 #define LABEL_MSG2 0x02020202 diff --git a/site.c b/site.c index e96d6f4..b995e52 100644 --- a/site.c +++ b/site.c @@ -1285,7 +1285,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, uint32_t msgtype=ntohl(get_uint32(buf->start+8)); if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); switch (msgtype) { - case 0: /* NAK */ + case LABEL_NAK: /* If the source is our current peer then initiate a key setup, because our peer's forgotten the key */ if (get_uint32(buf->start+4)==st->current.remote_session_id) { diff --git a/udp.c b/udp.c index bbf8c64..77be5b1 100644 --- a/udp.c +++ b/udp.c @@ -21,6 +21,7 @@ #include "util.h" #include "unaligned.h" #include "ipaddr.h" +#include "magic.h" static beforepoll_fn udp_beforepoll; static afterpoll_fn udp_afterpoll; @@ -140,7 +141,7 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds) buffer_init(st->rbuf,0); buf_append_uint32(st->rbuf,dest); buf_append_uint32(st->rbuf,source); - buf_append_uint32(st->rbuf,0); /* NAK is msg type 0 */ + buf_append_uint32(st->rbuf,LABEL_NAK); sendto(st->fd, st->rbuf->start, st->rbuf->size, 0, (struct sockaddr *)&from, sizeof(from)); BUF_FREE(st->rbuf); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:07:49 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:07:49 +0100 Subject: [PATCH 2/6] site: Send NAKs for undecryptable data packets (msg0) In-Reply-To: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066473-9095-3-git-send-email-ijackson@chiark.greenend.org.uk> Packets which are not understood are supposed in general to produce NAKs, to let the peer know that we don't have the key they were using. However, previously this would only happen if the incoming packet had a local site index which was not in use. But it can happen that a particular index value is reused by a recently restarted secnet. Previously, in this case, data packets would simply be thrown away undecryptable. With this change, undecryptable data packets always generate a NAK. This is particularly relevant for mobile sites, as it can happen that the fixed site doesn't have an address for the mobile site - so the association will remain stuck in a broken state until the mobile site is also restarted. There is still a potential problem when a site is restarted mid key exchange. The peer will refuse to start a new key exchange (because of the retry timeout) and the restarted site may not know it's necessary. This will be dealt with in a later patch. Signed-off-by: Ian Jackson --- site.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/site.c b/site.c index b995e52..5c73533 100644 --- a/site.c +++ b/site.c @@ -1226,6 +1226,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, const struct comm_addr *source) { struct site *st=sst; + bool_t ok=True; if (buf->size < 12) return False; @@ -1295,7 +1296,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, } break; case LABEL_MSG0: - process_msg0(st,buf,source); + ok=process_msg0(st,buf,source); break; case LABEL_MSG1: /* Setup packet: should not have been explicitly addressed @@ -1382,7 +1383,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, break; } BUF_FREE(buf); - return True; + return ok; } return False; -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:07:50 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:07:50 +0100 Subject: [PATCH 3/6] NOTES: Improve documentation of NAKs. In-Reply-To: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066473-9095-4-git-send-email-ijackson@chiark.greenend.org.uk> Improve the description of the function of NAK packets. Document an ancient form of NAK, MSG8. Add a missing heading "Other messages" and put the description of the NAK message and of the obsolete NAK in it. Signed-off-by: Ian Jackson --- NOTES | 41 +++++++++++++++++++++-------------------- 1 files changed, 21 insertions(+), 20 deletions(-) diff --git a/NOTES b/NOTES index 84453df..6a245ec 100644 --- a/NOTES +++ b/NOTES @@ -247,32 +247,33 @@ retransmit or confirm reception. It is suggested that this message be sent when a key times out, or the tunnel is forcibly terminated for some reason. -8) i?,i?,NAK (encoded as zero) +**** Protocol sub-goal 3: send a packet -If the link-layer can't work out what to do with a packet (session has -gone away, etc.) it can transmit a NAK back to the sender. The sender -can then try to verify whether the session is alive by sending ping -packets, and forget the key if it isn't. Potential denial-of-service -if the attacker can stop the ping/pong packets getting through (the -key will be forgotten and another key setup must take place), but if -they can delete packets then we've lost anyway... +8) i?,i?,msg0,(send-packet/msg9,packet)_k -The attacker can of course forge NAKs since they aren't protected. But -if they can only forge packets then they won't be able to stop the -ping/pong working. Trust in NAKs can be rate-limited... +Some messages may take a long time to prepare (software modexp on slow +machines); this is a "please wait" message to indicate that a message +is in preparation. -Alternative idea (which is actually implemented): if you receive a -packet you can't decode, because there's no key established, then -initiate key setup... +**** Other messages -Keepalives are probably a good idea. +9) i?,i?,NAK (NAK is encoded as zero) -**** Protocol sub-goal 3: send a packet +If the link-layer can't work out what to do with a packet (session has +gone away, etc.) it can transmit a NAK back to the sender. -9) i?,i?,msg0,(send-packet/msg9,packet)_k +This can alert the sender to the situation where the sender has a key +but the receiver doesn't (eg because it has been restarted). The +sender, on receiving the NAK, will try to initiate a key exchange. -Some messages may take a long time to prepare (software modexp on slow -machines); this is a "please wait" message to indicate that a message -is in preparation. +Forged (or overly delayed) NAKs can cause wasted resources due to +spurious key exchange initiation, but there is a limit on this because +of the key exchange retry timeout. 10) i?,i?,msg8,A,B,nA,nB,msg? + +This is an obsolete form of NAK packet which is not sent by any even +vaguely recent version of secnet. (In fact, there is no evidence in +the git history of it ever being sent.) + +This message number is reserved. -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:07:51 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:07:51 +0100 Subject: [PATCH 4/6] NOTES: Remove paragraph about slow-to-prepare messages In-Reply-To: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066473-9095-5-git-send-email-ijackson@chiark.greenend.org.uk> NOTES contained this paragraph: Some messages may take a long time to prepare (software modexp on slow machines); this is a "please wait" message to indicate that a message is in preparation. This paragraph was immediately after the description of the msg0(msg9) packet - ie, the ordinary data packet. It is therefore at the very least misplaced. In the git history this paragraph was introduced in "Import release 0.1.14" (4f5e39ec). However, the diff for that commit (ie the diff between 0.1.13 and 0.1.4) does not show any code which might correspond to this comment. There is not currently any code in site.c which responds to a message of this kind. I have had a quick look for code which sends such a message and failed to find any. So I think this paragraph represents a never-implemented intent, and should be removed. It certainly predates the "hacky parallelism" by a long way. Signed-off-by: Ian Jackson --- NOTES | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/NOTES b/NOTES index 6a245ec..09c083e 100644 --- a/NOTES +++ b/NOTES @@ -251,10 +251,6 @@ some reason. 8) i?,i?,msg0,(send-packet/msg9,packet)_k -Some messages may take a long time to prepare (software modexp on slow -machines); this is a "please wait" message to indicate that a message -is in preparation. - **** Other messages 9) i?,i?,NAK (NAK is encoded as zero) -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:07:52 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:07:52 +0100 Subject: [PATCH 5/6] site: Clearer processing for name-addressed packets In-Reply-To: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066473-9095-6-git-send-email-ijackson@chiark.greenend.org.uk> We are going to introduce a new packet which (like MSG1) is addressed by name rather than the site id. To make this easier: * Change st->setupsig and st->setupsiglen to st->namesig and st->namesiglen, which contain only the portion of the packet with the local and remote site names, and no longer the type. * Break out a function named_for_us which does the length check and name addressing comparison. * Make site_incoming extract the message type earlier, and use the message type to choose how to check the address. * Eliminate checking dest==0 for name-addressed packets. This last point constitutes a change to the implemented protocol. The old code would treat a packet as name-addressed iff the destination "index" was zero. However, the requirement to send a zero in this field is not documented. After this patch, peers which send MSG1 with a non-zero destination index will have their messages honoured rather than discarded. But we do document the restriction. There is no other significant functional change: peers which send non-MSG1s with zero destination index will have their packets rejected both before and afterwards (although there may be a change in whether a NAK is sent and in logging) but anyway those peers are broken because all of our generated indexes are nonzero. Signed-off-by: Ian Jackson --- NOTES | 3 ++ site.c | 107 +++++++++++++++++++++++++++++++++------------------------------ 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/NOTES b/NOTES index 09c083e..477104f 100644 --- a/NOTES +++ b/NOTES @@ -202,6 +202,9 @@ Messages: 1) A->B: *,iA,msg1,A,B,protorange-A,nA +i* must be encoded as 0. (However, it is permitted for a site to use +zero as its "index" for another site.) + 2) B->A: iA,iB,msg2,B,A,chosen-protocol,nB,nA (The order of B and A reverses in alternate messages so that the same diff --git a/site.c b/site.c index 5c73533..aecd64d 100644 --- a/site.c +++ b/site.c @@ -253,9 +253,9 @@ struct site { after this time, initiate a new key exchange */ - uint8_t *setupsig; /* Expected signature of incoming MSG1 packets */ - int32_t setupsiglen; /* Allows us to discard packets quickly if - they are not for us */ + uint8_t *namedsig; /* Names section of MSG1 packets */ + int32_t namedsiglen; /* Allows us to discard name-addressed packets + quickly if they are not for us */ bool_t setup_priority; /* Do we have precedence if both sites emit message 1 simultaneously? */ uint32_t log_events; @@ -1220,6 +1220,18 @@ static void site_outgoing(void *sst, struct buffer_if *buf) initiate_key_setup(st,"outgoing packet"); } +static bool_t named_for_us(struct site *st, struct buffer_if *buf, + int extralen) + /* For packets which are identified by the local and remote names. + * If it has our name and our peer's name in it it's for us. */ +{ + if (buf->size<(st->namedsiglen+12+extralen)) + return False; + if (memcmp(buf->start+12,st->namedsig,st->namedsiglen)) + return False; + return True; +} + /* This function is called by the communication device to deliver packets from our peers. */ static bool_t site_incoming(void *sst, struct buffer_if *buf, @@ -1230,60 +1242,54 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, if (buf->size < 12) return False; + uint32_t msgtype=ntohl(get_uint32(buf->start+8)); uint32_t dest=ntohl(*(uint32_t *)buf->start); - if (dest==0) { - /* It could be for any site - it should have LABEL_MSG1 and - might have our name and our peer's name in it */ - if (buf->size<(st->setupsiglen+8+NONCELEN)) return False; - if (memcmp(buf->start+8,st->setupsig,st->setupsiglen)==0) { - /* It's addressed to us. Decide what to do about it. */ - dump_packet(st,buf,source,True); - if (st->state==SITE_RUN || st->state==SITE_RESOLVE || - st->state==SITE_WAIT) { - /* We should definitely process it */ + if (msgtype==LABEL_MSG1 && named_for_us(st,buf,NONCELEN)) { + /* It's a MSG1 addressed to us. Decide what to do about it. */ + dump_packet(st,buf,source,True); + if (st->state==SITE_RUN || st->state==SITE_RESOLVE || + st->state==SITE_WAIT) { + /* We should definitely process it */ + if (process_msg1(st,buf,source)) { + slog(st,LOG_SETUP_INIT,"key setup initiated by peer"); + enter_new_state(st,SITE_SENTMSG2); + } else { + slog(st,LOG_ERROR,"failed to process incoming msg1"); + } + BUF_FREE(buf); + return True; + } else if (st->state==SITE_SENTMSG1) { + /* We've just sent a message 1! They may have crossed on + the wire. If we have priority then we ignore the + incoming one, otherwise we process it as usual. */ + if (st->setup_priority) { + BUF_FREE(buf); + slog(st,LOG_DUMP,"crossed msg1s; we are higher " + "priority => ignore incoming msg1"); + return True; + } else { + slog(st,LOG_DUMP,"crossed msg1s; we are lower " + "priority => use incoming msg1"); if (process_msg1(st,buf,source)) { - slog(st,LOG_SETUP_INIT,"key setup initiated by peer"); + BUF_FREE(&st->buffer); /* Free our old message 1 */ enter_new_state(st,SITE_SENTMSG2); } else { - slog(st,LOG_ERROR,"failed to process incoming msg1"); + slog(st,LOG_ERROR,"failed to process an incoming " + "crossed msg1 (we have low priority)"); } BUF_FREE(buf); return True; - } else if (st->state==SITE_SENTMSG1) { - /* We've just sent a message 1! They may have crossed on - the wire. If we have priority then we ignore the - incoming one, otherwise we process it as usual. */ - if (st->setup_priority) { - BUF_FREE(buf); - slog(st,LOG_DUMP,"crossed msg1s; we are higher " - "priority => ignore incoming msg1"); - return True; - } else { - slog(st,LOG_DUMP,"crossed msg1s; we are lower " - "priority => use incoming msg1"); - if (process_msg1(st,buf,source)) { - BUF_FREE(&st->buffer); /* Free our old message 1 */ - enter_new_state(st,SITE_SENTMSG2); - } else { - slog(st,LOG_ERROR,"failed to process an incoming " - "crossed msg1 (we have low priority)"); - } - BUF_FREE(buf); - return True; - } } - /* The message 1 was received at an unexpected stage of the - key setup. XXX POLICY - what do we do? */ - slog(st,LOG_UNEXPECTED,"unexpected incoming message 1"); - BUF_FREE(buf); - return True; } - return False; /* Not for us. */ + /* The message 1 was received at an unexpected stage of the + key setup. XXX POLICY - what do we do? */ + slog(st,LOG_UNEXPECTED,"unexpected incoming message 1"); + BUF_FREE(buf); + return True; } if (dest==st->index) { /* Explicitly addressed to us */ - uint32_t msgtype=ntohl(get_uint32(buf->start+8)); if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); switch (msgtype) { case LABEL_NAK: @@ -1532,13 +1538,12 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, /* The information we expect to see in incoming messages of type 1 */ /* fixme: lots of unchecked overflows here, but the results are only corrupted packets rather than undefined behaviour */ - st->setupsiglen=strlen(st->remotename)+strlen(st->localname)+8; - st->setupsig=safe_malloc(st->setupsiglen,"site_apply"); - put_uint32(st->setupsig+0,LABEL_MSG1); - put_uint16(st->setupsig+4,strlen(st->remotename)); - memcpy(&st->setupsig[6],st->remotename,strlen(st->remotename)); - put_uint16(st->setupsig+(6+strlen(st->remotename)),strlen(st->localname)); - memcpy(&st->setupsig[8+strlen(st->remotename)],st->localname, + st->namedsiglen=strlen(st->remotename)+strlen(st->localname)+4; + st->namedsig=safe_malloc(st->namedsiglen,"site_apply"); + put_uint16(st->namedsig+0,strlen(st->remotename)); + memcpy(&st->namedsig[2],st->remotename,strlen(st->remotename)); + put_uint16(st->namedsig+(2+strlen(st->remotename)),strlen(st->localname)); + memcpy(&st->namedsig[4+strlen(st->remotename)],st->localname, strlen(st->localname)); st->setup_priority=(strcmp(st->localname,st->remotename)>0); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:07:53 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:07:53 +0100 Subject: [PATCH 6/6] site: New PROD message In-Reply-To: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374066473-9095-7-git-send-email-ijackson@chiark.greenend.org.uk> We introduce a new message PROD which requests that the peer initiate a key exchange with us, if it doesn't already have a key. This helps significantly reduce a possible "dead period" when one end of a connection is restarted during key exchange. The dead period is now limited to the time taken for the interrupted key exchange to time out. Signed-off-by: Ian Jackson --- NOTES | 34 +++++++++++++++++++++++ magic.h | 1 + site.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- udp.c | 1 + 4 files changed, 113 insertions(+), 15 deletions(-) diff --git a/NOTES b/NOTES index 477104f..a4e6b21 100644 --- a/NOTES +++ b/NOTES @@ -276,3 +276,37 @@ vaguely recent version of secnet. (In fact, there is no evidence in the git history of it ever being sent.) This message number is reserved. + +11) *,*,PROD,A,B + +Sent in response to a NAK from B to A. Requests that B initiates a +key exchange with A, if B is willing and lacks a transport key for A. +(If B doesn't have A's address configured, implicitly supplies A's +public address.) + +This is necessary because if one end of a link (B) is restarted while +a key exchange is in progress, the following bad state can persist: +the non-restarted end (A) thinks that the key is still valid and keeps +sending packets, but B either doesn't realise that a key exchange with +A is necessary or (if A is a mobile site) doesn't know A's public IP +address. + +Normally in these circumstances B would send NAKs to A, causing A to +initiate a key exchange. However if A and B were already in the +middle of a key exchange then A will not want to try another one until +the first one has timed out ("setup-time" x "setup-retries") and then +the key exchange retry timeout ("wait-time") has elapsed. + +However if B's setup has timed out, B would be willing to participate +in a key exchange initiated by A, if A could be induced to do so. +This is the purpose of the PROD packet. + +We send no more PRODs than we would want to send data packets, to +avoid a traffic amplification attack. We also send them only in state +WAIT, as in other states we wouldn't respond favourably. And we only +honour them if we don't already have a key. + +With PROD, the period of broken communication due to a key exchange +interrupted by a restart is limited to the key exchange total +retransmission timeout, rather than also including the key exchange +retry timeout. diff --git a/magic.h b/magic.h index c2503a0c..7d2f427 100644 --- a/magic.h +++ b/magic.h @@ -14,5 +14,6 @@ #define LABEL_MSG7 0x07070707 #define LABEL_MSG8 0x08080808 #define LABEL_MSG9 0x09090909 +#define LABEL_PROD 0x0a0a0a0a #endif /* magic_h */ diff --git a/site.c b/site.c index aecd64d..8de482b 100644 --- a/site.c +++ b/site.c @@ -204,7 +204,8 @@ static void transport_peers_copy(struct site *st, transport_peers *dst, static void transport_setup_msgok(struct site *st, const struct comm_addr *a); static void transport_data_msgok(struct site *st, const struct comm_addr *a); static bool_t transport_compute_setupinit_peers(struct site *st, - const struct comm_addr *configured_addr /* 0 if none or not found */); + const struct comm_addr *configured_addr /* 0 if none or not found */, + const struct comm_addr *prod_hint_addr /* 0 if none */); static void transport_record_peer(struct site *st, transport_peers *peers, const struct comm_addr *addr, const char *m); @@ -263,6 +264,7 @@ struct site { /* runtime information */ uint32_t state; uint64_t now; /* Most recently seen time */ + bool_t allow_send_prod; /* The currently established session */ struct data_key current; @@ -327,7 +329,8 @@ static void delete_one_key(struct site *st, struct data_key *key, const char *reason /* may be 0 meaning don't log*/, const char *which /* ignored if !reasonn */, uint32_t loglevel /* ignored if !reasonn */); -static bool_t initiate_key_setup(struct site *st, cstring_t reason); +static bool_t initiate_key_setup(struct site *st, cstring_t reason, + const struct comm_addr *prod_hint); static void enter_state_run(struct site *st); static bool_t enter_state_resolve(struct site *st); static bool_t enter_new_state(struct site *st,uint32_t next); @@ -418,6 +421,10 @@ static bool_t unpick_msg(struct site *st, uint32_t type, m->loclen=buf_unprepend_uint16(msg); CHECK_AVAIL(msg,m->loclen); m->local=buf_unprepend(msg,m->loclen); + if (type==LABEL_PROD) { + CHECK_EMPTY(msg); + return True; + } CHECK_AVAIL(msg,NONCELEN); m->nR=buf_unprepend(msg,NONCELEN); if (type==LABEL_MSG1) { @@ -794,7 +801,7 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0) slog(st,LOG_SEC,"transform: %s (aux: %s, new: %s)", transform_err,auxkey_err,newkey_err); - initiate_key_setup(st,"incoming message would not decrypt"); + initiate_key_setup(st,"incoming message would not decrypt",0); return False; } @@ -819,7 +826,7 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0, transport_data_msgok(st,src); /* See whether we should start negotiating a new key */ if (st->now > st->renegotiate_key_time) - initiate_key_setup(st,"incoming packet in renegotiation window"); + initiate_key_setup(st,"incoming packet in renegotiation window",0); return True; default: slog(st,LOG_SEC,"incoming encrypted message of type %08x " @@ -900,7 +907,7 @@ static void site_resolve_callback(void *sst, struct in_addr *address) slog(st,LOG_ERROR,"resolution of %s failed",st->address); ca_use=0; } - if (transport_compute_setupinit_peers(st,ca_use)) { + if (transport_compute_setupinit_peers(st,ca_use,0)) { enter_new_state(st,SITE_SENTMSG1); } else { /* Can't figure out who to try to to talk to */ @@ -909,14 +916,15 @@ static void site_resolve_callback(void *sst, struct in_addr *address) } } -static bool_t initiate_key_setup(struct site *st, cstring_t reason) +static bool_t initiate_key_setup(struct site *st, cstring_t reason, + const struct comm_addr *prod_hint) { if (st->state!=SITE_RUN) return False; slog(st,LOG_SETUP_INIT,"initiating key exchange (%s)",reason); if (st->address) { slog(st,LOG_SETUP_INIT,"resolving peer address"); return enter_state_resolve(st); - } else if (transport_compute_setupinit_peers(st,0)) { + } else if (transport_compute_setupinit_peers(st,0,prod_hint)) { return enter_new_state(st,SITE_SENTMSG1); } slog(st,LOG_SETUP_INIT,"key exchange failed: no address for peer"); @@ -1126,6 +1134,30 @@ static void enter_state_wait(struct site *st) /* XXX Erase keys etc. */ } +static void generate_prod(struct site *st, struct buffer_if *buf) +{ + buffer_init(buf,0); + buf_append_uint32(buf,0); + buf_append_uint32(buf,0); + buf_append_uint32(buf,LABEL_PROD); + buf_append_string(buf,st->localname); + buf_append_string(buf,st->remotename); +} + +static void generate_send_prod(struct site *st, + const struct comm_addr *source) +{ + if (!st->allow_send_prod) return; /* too soon */ + if (!(st->state==SITE_RUN || st->state==SITE_RESOLVE || + st->state==SITE_WAIT)) return; /* we'd ignore peer's MSG1 */ + + slog(st,LOG_SETUP_INIT,"prodding peer for key exchange)"); + st->allow_send_prod=0; + generate_prod(st,&st->scratch); + dump_packet(st,&st->scratch,source,False); + source->comm->sendmsg(source->comm->st, &st->scratch, source); +} + static inline void site_settimeout(uint64_t timeout, int *timeout_io) { if (timeout) { @@ -1198,6 +1230,8 @@ static void site_outgoing(void *sst, struct buffer_if *buf) return; } + st->allow_send_prod=1; + /* In all other states we consider delivering the packet if we have a valid key and a valid address to send it to. */ if (current_valid(st) && transport_peers_valid(&st->peers)) { @@ -1217,7 +1251,7 @@ static void site_outgoing(void *sst, struct buffer_if *buf) slog(st,LOG_DROP,"discarding outgoing packet of size %d",buf->size); BUF_FREE(buf); - initiate_key_setup(st,"outgoing packet"); + initiate_key_setup(st,"outgoing packet",0); } static bool_t named_for_us(struct site *st, struct buffer_if *buf, @@ -1233,7 +1267,10 @@ static bool_t named_for_us(struct site *st, struct buffer_if *buf, } /* This function is called by the communication device to deliver - packets from our peers. */ + packets from our peers. + It should return True if the packet is recognised as being for + this current site instance (and should therefore not be processed + by other sites), even if the packet was otherwise ignored. */ static bool_t site_incoming(void *sst, struct buffer_if *buf, const struct comm_addr *source) { @@ -1288,6 +1325,20 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, BUF_FREE(buf); return True; } + if (msgtype==LABEL_PROD && named_for_us(st,buf,0)) { + struct msg m; + dump_packet(st,buf,source,True); + if (!unpick_msg(st,LABEL_PROD,buf,&m)) { + slog(st,LOG_ERROR,"failed to unpick incoming PROD"); + } else if (st->state!=SITE_RUN) { + slog(st,LOG_DROP,"ignoring PROD when not in state RUN"); + } else if (current_valid(st)) { + slog(st,LOG_DROP,"ignoring PROD when we think we have a key"); + } else { + initiate_key_setup(st,"peer sent PROD packet",source); + } + return True; + } if (dest==st->index) { /* Explicitly addressed to us */ if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); @@ -1296,7 +1347,9 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, /* If the source is our current peer then initiate a key setup, because our peer's forgotten the key */ if (get_uint32(buf->start+4)==st->current.remote_session_id) { - initiate_key_setup(st,"received a NAK"); + bool_t initiated; + initiated = initiate_key_setup(st,"received a NAK",0); + if (!initiated) generate_send_prod(st,source); } else { slog(st,LOG_SEC,"bad incoming NAK"); } @@ -1531,6 +1584,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->log_events=string_list_to_word(dict_lookup(dict,"log-events"), log_event_table,"site"); + st->allow_send_prod=0; + st->tunname=safe_malloc(strlen(st->localname)+strlen(st->remotename)+5, "site_apply"); sprintf(st->tunname,"%s<->%s",st->localname,st->remotename); @@ -1687,23 +1742,30 @@ static void transport_record_peer(struct site *st, transport_peers *peers, } static bool_t transport_compute_setupinit_peers(struct site *st, - const struct comm_addr *configured_addr /* 0 if none or not found */) { + const struct comm_addr *configured_addr /* 0 if none or not found */, + const struct comm_addr *prod_hint_addr /* 0 if none */) { - if (!configured_addr && !transport_peers_valid(&st->peers)) + if (!configured_addr && !prod_hint_addr && + !transport_peers_valid(&st->peers)) return False; slog(st,LOG_SETUP_INIT, - (!configured_addr ? "using only %d old peer address(es)" - : "using configured address, and/or perhaps %d old peer address(es)"), + "using:%s%s %d old peer address(es)", + configured_addr ? " configured address;" : "", + prod_hint_addr ? " PROD hint address;" : "", st->peers); /* Non-mobile peers havve st->peers.npeers==0 or ==1, since they * have transport_peers_max==1. The effect is that this code * always uses the configured address if supplied, or otherwise - * the existing data peer if one exists; this is as desired. */ + * the address of the incoming PROD, or the existing data peer if + * one exists; this is as desired. */ transport_peers_copy(st,&st->setup_peers,&st->peers); + if (prod_hint_addr) + transport_record_peer(st,&st->setup_peers,prod_hint_addr,"prod"); + if (configured_addr) transport_record_peer(st,&st->setup_peers,configured_addr,"setupinit"); diff --git a/udp.c b/udp.c index 77be5b1..5d1ef7c 100644 --- a/udp.c +++ b/udp.c @@ -19,6 +19,7 @@ #include #include #include "util.h" +#include "magic.h" #include "unaligned.h" #include "ipaddr.h" #include "magic.h" -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 17 14:36:11 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 17 Jul 2013 14:36:11 +0100 Subject: [PATCH 5/6] site: Clearer processing for name-addressed packets In-Reply-To: <1374066473-9095-6-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374066473-9095-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374066473-9095-6-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <20966.40395.986054.363379@chiark.greenend.org.uk> Ian Jackson writes ("[PATCH 5/6] site: Clearer processing for name-addressed packets"): > We are going to introduce a new packet which (like MSG1) is addressed > by name rather than the site id. To make this easier: The diff here is inflated by a reindent. Here is a copy of it prepared with "diff -b": diff --git a/NOTES b/NOTES index 09c083e..477104f 100644 --- a/NOTES +++ b/NOTES @@ -202,6 +202,9 @@ Messages: 1) A->B: *,iA,msg1,A,B,protorange-A,nA +i* must be encoded as 0. (However, it is permitted for a site to use +zero as its "index" for another site.) + 2) B->A: iA,iB,msg2,B,A,chosen-protocol,nB,nA (The order of B and A reverses in alternate messages so that the same diff --git a/site.c b/site.c index 5c73533..aecd64d 100644 --- a/site.c +++ b/site.c @@ -253,9 +253,9 @@ struct site { after this time, initiate a new key exchange */ - uint8_t *setupsig; /* Expected signature of incoming MSG1 packets */ - int32_t setupsiglen; /* Allows us to discard packets quickly if - they are not for us */ + uint8_t *namedsig; /* Names section of MSG1 packets */ + int32_t namedsiglen; /* Allows us to discard name-addressed packets + quickly if they are not for us */ bool_t setup_priority; /* Do we have precedence if both sites emit message 1 simultaneously? */ uint32_t log_events; @@ -1220,6 +1220,18 @@ static void site_outgoing(void *sst, struct buffer_if *buf) initiate_key_setup(st,"outgoing packet"); } +static bool_t named_for_us(struct site *st, struct buffer_if *buf, + int extralen) + /* For packets which are identified by the local and remote names. + * If it has our name and our peer's name in it it's for us. */ +{ + if (buf->size<(st->namedsiglen+12+extralen)) + return False; + if (memcmp(buf->start+12,st->namedsig,st->namedsiglen)) + return False; + return True; +} + /* This function is called by the communication device to deliver packets from our peers. */ static bool_t site_incoming(void *sst, struct buffer_if *buf, @@ -1230,14 +1242,11 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, if (buf->size < 12) return False; + uint32_t msgtype=ntohl(get_uint32(buf->start+8)); uint32_t dest=ntohl(*(uint32_t *)buf->start); - if (dest==0) { - /* It could be for any site - it should have LABEL_MSG1 and - might have our name and our peer's name in it */ - if (buf->size<(st->setupsiglen+8+NONCELEN)) return False; - if (memcmp(buf->start+8,st->setupsig,st->setupsiglen)==0) { - /* It's addressed to us. Decide what to do about it. */ + if (msgtype==LABEL_MSG1 && named_for_us(st,buf,NONCELEN)) { + /* It's a MSG1 addressed to us. Decide what to do about it. */ dump_packet(st,buf,source,True); if (st->state==SITE_RUN || st->state==SITE_RESOLVE || st->state==SITE_WAIT) { @@ -1279,11 +1288,8 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, BUF_FREE(buf); return True; } - return False; /* Not for us. */ - } if (dest==st->index) { /* Explicitly addressed to us */ - uint32_t msgtype=ntohl(get_uint32(buf->start+8)); if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); switch (msgtype) { case LABEL_NAK: @@ -1532,13 +1538,12 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, /* The information we expect to see in incoming messages of type 1 */ /* fixme: lots of unchecked overflows here, but the results are only corrupted packets rather than undefined behaviour */ - st->setupsiglen=strlen(st->remotename)+strlen(st->localname)+8; - st->setupsig=safe_malloc(st->setupsiglen,"site_apply"); - put_uint32(st->setupsig+0,LABEL_MSG1); - put_uint16(st->setupsig+4,strlen(st->remotename)); - memcpy(&st->setupsig[6],st->remotename,strlen(st->remotename)); - put_uint16(st->setupsig+(6+strlen(st->remotename)),strlen(st->localname)); - memcpy(&st->setupsig[8+strlen(st->remotename)],st->localname, + st->namedsiglen=strlen(st->remotename)+strlen(st->localname)+4; + st->namedsig=safe_malloc(st->namedsiglen,"site_apply"); + put_uint16(st->namedsig+0,strlen(st->remotename)); + memcpy(&st->namedsig[2],st->remotename,strlen(st->remotename)); + put_uint16(st->namedsig+(2+strlen(st->remotename)),strlen(st->localname)); + memcpy(&st->namedsig[4+strlen(st->remotename)],st->localname, strlen(st->localname)); st->setup_priority=(strcmp(st->localname,st->remotename)>0); From ijackson at chiark.greenend.org.uk Fri Jul 19 01:25:11 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:25:11 +0100 Subject: [RFC PATCH 0/7] EAX transform Message-ID: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Here is another RFC series for review. Here, I provide a new transform using EAX, Serpent (and SHA512 to hash the DH key). 1/7 serpent: const-correct 2/7 crypto: Copy an AES (Rijndael) implementation into tree 3/7 EAX: provide an implementation of EAX 4/7 transform: split out transform-common.h 5/7 transform: Allow DH to set the key size 6/7 transform: Pass a direction flag to the transform 7/7 transform: Provide Serpment-EAX transform Most of these are quite uninteresting, but the final patch could do with some proper review. The SHA512 implementation comes from coreutils, so we inherit its GPL3+ licence. From ijackson at chiark.greenend.org.uk Fri Jul 19 01:25:12 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:25:12 +0100 Subject: [PATCH 1/8] serpent: const-correct In-Reply-To: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374193519-19262-2-git-send-email-ijackson@chiark.greenend.org.uk> Decorate serpent_encrypt, serpent_decrypt and serpent_makekey with appropriate consts in their arguments. Signed-off-by: Ian Jackson --- serpent.c | 6 +++--- serpent.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/serpent.c b/serpent.c index ce91854..34ef6aa 100644 --- a/serpent.c +++ b/serpent.c @@ -26,7 +26,7 @@ #include "serpentsboxes.h" void serpent_makekey(struct keyInstance *key, int keyLen, - uint8_t *keyMaterial) + const uint8_t *keyMaterial) { int i; uint32_t j; @@ -86,7 +86,7 @@ void serpent_makekey(struct keyInstance *key, int keyLen, } void serpent_encrypt(struct keyInstance *key, - uint8_t plaintext[16], + const uint8_t plaintext[16], uint8_t ciphertext[16]) { register uint32_t x0, x1, x2, x3; @@ -204,7 +204,7 @@ void serpent_encrypt(struct keyInstance *key, } void serpent_decrypt(struct keyInstance *key, - uint8_t ciphertext[16], + const uint8_t ciphertext[16], uint8_t plaintext[16]) { register uint32_t x0, x1, x2, x3; diff --git a/serpent.h b/serpent.h index 07176d7..19c01fe 100644 --- a/serpent.h +++ b/serpent.h @@ -8,12 +8,12 @@ struct keyInstance { /* Function protoypes */ void serpent_makekey(struct keyInstance *key, int keyLen, - uint8_t *keyMaterial); + const uint8_t *keyMaterial); -void serpent_encrypt(struct keyInstance *key, uint8_t plaintext[16], +void serpent_encrypt(struct keyInstance *key, const uint8_t plaintext[16], uint8_t ciphertext[16]); -void serpent_decrypt(struct keyInstance *key, uint8_t ciphertext[16], +void serpent_decrypt(struct keyInstance *key, const uint8_t ciphertext[16], uint8_t plaintext[16]); #endif /* serpent_h */ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Fri Jul 19 01:25:13 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:25:13 +0100 Subject: [PATCH 2/8] crypto: Copy an AES (Rijndael) implementation into tree In-Reply-To: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374193519-19262-3-git-send-email-ijackson@chiark.greenend.org.uk> We are going to want an implementation of AES so that we can run publicly-provided test vectors of our EAX implementation. qemu seem to have a version with a fairly convenient shape, so lift it wholesale into our tree, from upstream qemu (their git commit 55616505876d6683130076b810a27c7889321560). The files in this patch are _exactly_ as copied from that qemu tree, so that we can separate out our own changes. Signed-off-by: Ian Jackson --- aes.c | 1314 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ aes.h | 26 ++ 2 files changed, 1340 insertions(+), 0 deletions(-) create mode 100644 aes.c create mode 100644 aes.h diff --git a/aes.c b/aes.c new file mode 100644 index 0000000..eb37adb --- /dev/null +++ b/aes.c @@ -0,0 +1,1314 @@ +/** + * + * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project. + */ +/* + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "qemu-common.h" +#include "aes.h" + +#ifndef NDEBUG +#define NDEBUG +#endif + +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +/* This controls loop-unrolling in aes_core.c */ +#undef FULL_UNROLL +# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) +# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +static const u32 Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +static const u32 Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +static const u32 Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +static const u32 Te3[256] = { + + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; +static const u32 Te4[256] = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; +static const u32 Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +static const u32 Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; +static const u32 Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; +static const u32 Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; +static const u32 Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; +static const u32 rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +/** + * Expand the cipher key into the encryption key schedule. + */ +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) { + + u32 *rk; + int i = 0; + u32 temp; + + if (!userKey || !key) + return -1; + if (bits != 128 && bits != 192 && bits != 256) + return -2; + + rk = key->rd_key; + + if (bits==128) + key->rounds = 10; + else if (bits==192) + key->rounds = 12; + else + key->rounds = 14; + + rk[0] = GETU32(userKey ); + rk[1] = GETU32(userKey + 4); + rk[2] = GETU32(userKey + 8); + rk[3] = GETU32(userKey + 12); + if (bits == 128) { + while (1) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 0; + } + rk += 4; + } + } + rk[4] = GETU32(userKey + 16); + rk[5] = GETU32(userKey + 20); + if (bits == 192) { + while (1) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + return 0; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(userKey + 24); + rk[7] = GETU32(userKey + 28); + if (bits == 256) { + while (1) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + return 0; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +/** + * Expand the cipher key into the decryption key schedule. + */ +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) { + + u32 *rk; + int i, j, status; + u32 temp; + + /* first, start with an encryption schedule */ + status = AES_set_encrypt_key(userKey, bits, key); + if (status < 0) + return status; + + rk = key->rd_key; + + /* invert the order of the round keys: */ + for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < (key->rounds); i++) { + rk += 4; + rk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + return 0; +} + +#ifndef AES_ASM +/* + * Encrypt a single block + * in and out can overlap + */ +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) { + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +/* + * Decrypt a single block + * in and out can overlap + */ +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) { + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out , s0); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +#endif /* AES_ASM */ + +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc) +{ + + unsigned long n; + unsigned long len = length; + unsigned char tmp[AES_BLOCK_SIZE]; + + assert(in && out && key && ivec); + + if (enc) { + while (len >= AES_BLOCK_SIZE) { + for(n=0; n < AES_BLOCK_SIZE; ++n) + tmp[n] = in[n] ^ ivec[n]; + AES_encrypt(tmp, out, key); + memcpy(ivec, out, AES_BLOCK_SIZE); + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (len) { + for(n=0; n < len; ++n) + tmp[n] = in[n] ^ ivec[n]; + for(n=len; n < AES_BLOCK_SIZE; ++n) + tmp[n] = ivec[n]; + AES_encrypt(tmp, tmp, key); + memcpy(out, tmp, AES_BLOCK_SIZE); + memcpy(ivec, tmp, AES_BLOCK_SIZE); + } + } else { + while (len >= AES_BLOCK_SIZE) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(in, out, key); + for(n=0; n < AES_BLOCK_SIZE; ++n) + out[n] ^= ivec[n]; + memcpy(ivec, tmp, AES_BLOCK_SIZE); + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (len) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(tmp, tmp, key); + for(n=0; n < len; ++n) + out[n] = tmp[n] ^ ivec[n]; + memcpy(ivec, tmp, AES_BLOCK_SIZE); + } + } +} diff --git a/aes.h b/aes.h new file mode 100644 index 0000000..a0167eb --- /dev/null +++ b/aes.h @@ -0,0 +1,26 @@ +#ifndef QEMU_AES_H +#define QEMU_AES_H + +#define AES_MAXNR 14 +#define AES_BLOCK_SIZE 16 + +struct aes_key_st { + uint32_t rd_key[4 *(AES_MAXNR + 1)]; + int rounds; +}; +typedef struct aes_key_st AES_KEY; + +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); + +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc); + +#endif -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Fri Jul 19 01:25:14 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:25:14 +0100 Subject: [PATCH 3/8] EAX: provide an implementation of EAX In-Reply-To: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374193519-19262-4-git-send-email-ijackson@chiark.greenend.org.uk> EAX is a reasonably well-regarded Authenticated Encryption block cipher mode. We intend to replace the existing CBC and CBC-MAC transform with EAX. EAX can be used with any block cipher, but we will use it with Serpent. In this patch we provide an implementation of EAX itself. This primary consists of eax.c, the actual implementation of the EAX mode. To test that our implementation is correct, we use aes.[ch], which we copied from qemu in the previous commit, to run the EAX-AES test vectors. These are cut-and-pasted out of the EAX paper. (To do this we need to make aes.[ch] compile in our environment - but the changes are minimal. We also improve the copyright notices.) Then for completeness we also provide a set of EAX-Serpent test vectors and the corresponding test code. The EAX-Serpent test vectors were generated by this very code, so aren't independently verified. (The implementation of what is now consttime_curious_multiply, and the comment preeding it, were provided by Mark. I have lightly edited it to conform to the coding style etc. of the rest of the file.) Signed-off-by: Ian Jackson Signed-off-by: Mark Wooding --- .gitignore | 2 + Makefile.in | 21 +++- aes.c | 5 +- aes.h | 59 +++++++- eax-aes-test.c | 41 ++++++ eax-aes-test.vectors | 59 ++++++++ eax-serpent-test.c | 41 ++++++ eax-serpent-test.vectors | 59 ++++++++ eax-test.c | 154 ++++++++++++++++++++ eax-test.h | 52 +++++++ eax.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 842 insertions(+), 8 deletions(-) create mode 100644 eax-aes-test.c create mode 100644 eax-aes-test.vectors create mode 100644 eax-serpent-test.c create mode 100644 eax-serpent-test.vectors create mode 100644 eax-test.c create mode 100644 eax-test.h create mode 100644 eax.c diff --git a/.gitignore b/.gitignore index b7f6187..a445369 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ conffile.tab.[ch] conffile.yy.[ch] /version.c /secnet +/eax-*-test +/eax-*-test.confirm /config.log /config.h diff --git a/Makefile.in b/Makefile.in index 182204b..6f36e4f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -58,6 +58,8 @@ OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ process.o @LIBOBJS@ \ hackypar.o +TEST_OBJECTS=eax-aes-test.o eax-serpent-test.o eax-test.o aes.o + %.c: %.y %.yy.c: %.fl @@ -69,7 +71,7 @@ OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ %.o: %.c $(CC) $(CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@ -all: $(TARGETS) +all: $(TARGETS) check # Automatic remaking of configuration files, from autoconf documentation ${srcdir}/configure: configure.in @@ -93,8 +95,8 @@ config.status: configure # End of config file remaking rules # C and header file dependency rules -SOURCES:=$(OBJECTS:.o=.c) -DEPENDS:=$(OBJECTS:.o=.d) +SOURCES:=$(OBJECTS:.o=.c) $(TEST_OBJECTS:.o=.c) +DEPENDS:=$(OBJECTS:.o=.d) $(TEST_OBJECTS:.o=.d) $(DEPENDS): ${srcdir}/depend.sh @@ -112,11 +114,22 @@ conffile.tab.c: conffile.y secnet: $(OBJECTS) $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $(OBJECTS) $(LDLIBS) +check: eax-aes-test.confirm eax-serpent-test.confirm + version.c: Makefile echo "#include \"secnet.h\"" >$@.new echo "char version[]=\"secnet $(VERSION)\";" >>$@.new mv -f $@.new $@ +eax-%-test: eax-%-test.o eax-test.o %.o + $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $^ + +eax-%-test.confirm: eax-%-test eax-%-test.vectors + ./$< $@.new + mv -f $@.new $@ + +.PRECIOUS: eax-%-test + installdirs: $(INSTALL) -d $(prefix)/share/secnet $(sbindir) $(INSTALL) -d $(mandir)/man8 @@ -129,7 +142,7 @@ install: installdirs clean: $(RM) -f *.o *.yy.c *.tab.[ch] $(TARGETS) core version.c - $(RM) -f *.d *~ + $(RM) -f *.d *~ eax-*-test.confirm eax-*-test realclean: clean $(RM) -f *~ Makefile config.h *.d \ diff --git a/aes.c b/aes.c index eb37adb..4e155ab 100644 --- a/aes.c +++ b/aes.c @@ -1,6 +1,10 @@ /** * * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project. + * + * Copied to the secnet tree by Ian Jackson from the upstream qemu git + * tree revision 55616505876d6683130076b810a27c7889321560 + * and modified only to remove the include of qemu-common.h. */ /* * rijndael-alg-fst.c @@ -27,7 +31,6 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "qemu-common.h" #include "aes.h" #ifndef NDEBUG diff --git a/aes.h b/aes.h index a0167eb..fc69356 100644 --- a/aes.h +++ b/aes.h @@ -1,5 +1,58 @@ -#ifndef QEMU_AES_H -#define QEMU_AES_H +/* + * aes.h + * + * Header file declaring AES functions. + * + * Copied from the upstream qemu git tree revision + * 55616505876d6683130076b810a27c7889321560 + * but was introduced there by Fabrice Bellard in + * e4d4fe3c34cdd6e26f9b9975efec7d1e81ad00b6 + * AES crypto support + * git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk at 1036 \ + * c046a42c-6fe2-441c-8c8c-71466251a162 + * + * Modified by Ian Jackson to change the guard #define from + * QEMU_AES_H to AES_H and to add some needed system #include's. + * + * The header file doesn't appear to have a separate copyright notice + * but is clearly a lightly edited (by Bellard) version of code from + * Rijmen, Bosselaers and Barreto. + * + * The original is from rijndael-alg-fst.c, with this copyright + * notice: + * + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef AES_H +#define AES_H + +#include +#include +#include #define AES_MAXNR 14 #define AES_BLOCK_SIZE 16 @@ -23,4 +76,4 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, const unsigned long length, const AES_KEY *key, unsigned char *ivec, const int enc); -#endif +#endif /* AES_H */ diff --git a/eax-aes-test.c b/eax-aes-test.c new file mode 100644 index 0000000..d8ad027 --- /dev/null +++ b/eax-aes-test.c @@ -0,0 +1,41 @@ +/* + * eax-aes-test.c: test harness glue for EAX-AES (EAX-Rijndael) + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "eax-test.h" +#include "aes.h" + +#define BLOCK_SIZE AES_BLOCK_SIZE +static AES_KEY key; + +EAX_SOME_TEST; + +void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes) +{ + AES_set_encrypt_key(keydata, bytes*8, &key); +} + +static void BLOCK_ENCRYPT(uint8_t dst[BLOCK_SIZE], + const uint8_t src[BLOCK_SIZE]) +{ + AES_encrypt((const void*)src, (void*)dst, &key); +} + +#include "eax.c" diff --git a/eax-aes-test.vectors b/eax-aes-test.vectors new file mode 100644 index 0000000..f6bf3f4 --- /dev/null +++ b/eax-aes-test.vectors @@ -0,0 +1,59 @@ +MSG: +KEY: 233952DEE4D5ED5F9B9C6D6FF80FF478 +NONCE: 62EC67F9C3A4A407FCB2A8C49031A8B3 +HEADER: 6BFB914FD07EAE6B +CIPHER: E037830E8389F27B025A2D6527E79D01 + +MSG: F7FB +KEY: 91945D3F4DCBEE0BF45EF52255F095A4 +NONCE: BECAF043B0A23D843194BA972C66DEBD +HEADER: FA3BFD4806EB53FA +CIPHER: 19DD5C4C9331049D0BDAB0277408F67967E5 + +MSG: 1A47CB4933 +KEY: 01F74AD64077F2E704C0F60ADA3DD523 +NONCE: 70C3DB4F0D26368400A10ED05D2BFF5E +HEADER: 234A3463C1264AC6 +CIPHER: D851D5BAE03A59F238A23E39199DC9266626C40F80 + +MSG: 481C9E39B1 +KEY: D07CF6CBB7F313BDDE66B727AFD3C5E8 +NONCE: 8408DFFF3C1A2B1292DC199E46B7D617 +HEADER: 33CCE2EABFF5A79D +CIPHER: 632A9D131AD4C168A4225D8E1FF755939974A7BEDE + +MSG: 40D0C07DA5E4 +KEY: 35B6D0580005BBC12B0587124557D2C2 +NONCE: FDB6B06676EEDC5C61D74276E1F8E816 +HEADER: AEB96EAEBE2970E9 +CIPHER: 071DFE16C675CB0677E536F73AFE6A14B74EE49844DD + +MSG: 4DE3B35C3FC039245BD1FB7D +KEY: BD8E6E11475E60B268784C38C62FEB22 +NONCE: 6EAC5C93072D8E8513F750935E46DA1B +HEADER: D4482D1CA78DCE0F +CIPHER: 835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F + +MSG: 8B0A79306C9CE7ED99DAE4F87F8DD61636 +KEY: 7C77D6E813BED5AC98BAA417477A2E7D +NONCE: 1A8C98DCD73D38393B2BF1569DEEFC19 +HEADER: 65D2017990D62528 +CIPHER: 02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2 + +MSG: 1BDA122BCE8A8DBAF1877D962B8592DD2D56 +KEY: 5FFF20CAFAB119CA2FC73549E20F5B0D +NONCE: DDE59B97D722156D4D9AFF2BC7559826 +HEADER: 54B9F04E6A09189A +CIPHER: 2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A + +MSG: 6CF36720872B8513F6EAB1A8A44438D5EF11 +KEY: A4A4782BCFFD3EC5E7EF6D8C34A56123 +NONCE: B781FCF2F75FA5A8DE97A9CA48E522EC +HEADER: 899A175897561D7E +CIPHER: 0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700 + +MSG: CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7 +KEY: 8395FCF1E95BEBD697BD010BC766AAC3 +NONCE: 22E7ADD93CFC6393C57EC0B3C17D6B44 +HEADER: 126735FCC320D25A +CIPHER: CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E diff --git a/eax-serpent-test.c b/eax-serpent-test.c new file mode 100644 index 0000000..9e8d951 --- /dev/null +++ b/eax-serpent-test.c @@ -0,0 +1,41 @@ +/* + * eax-serpent-test.c: test harness glue for EAX-Serpent + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "eax-test.h" +#include "serpent.h" + +#define BLOCK_SIZE 16 +static struct keyInstance key; + +EAX_SOME_TEST; + +void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes) +{ + serpent_makekey(&key, bytes*8, keydata); +} + +static void BLOCK_ENCRYPT(uint8_t dst[BLOCK_SIZE], + const uint8_t src[BLOCK_SIZE]) +{ + serpent_encrypt(&key, src, dst); +} + +#include "eax.c" diff --git a/eax-serpent-test.vectors b/eax-serpent-test.vectors new file mode 100644 index 0000000..d7e4e6e --- /dev/null +++ b/eax-serpent-test.vectors @@ -0,0 +1,59 @@ +MSG: +KEY: 233952DEE4D5ED5F9B9C6D6FF80FF478 +NONCE: 62EC67F9C3A4A407FCB2A8C49031A8B3 +HEADER: 6BFB914FD07EAE6B +CIPHER: E667316E3FC40DF234575E203EA06EA0 + +MSG: F7FB +KEY: 91945D3F4DCBEE0BF45EF52255F095A4 +NONCE: BECAF043B0A23D843194BA972C66DEBD +HEADER: FA3BFD4806EB53FA +CIPHER: D6D0A45C2A76EEB6AD20C3DB5CE100A2AEC4 + +MSG: 1A47CB4933 +KEY: 01F74AD64077F2E704C0F60ADA3DD523 +NONCE: 70C3DB4F0D26368400A10ED05D2BFF5E +HEADER: 234A3463C1264AC6 +CIPHER: FD8218F8987B7CCEBE4D521F4374D40B2F85794B31 + +MSG: 481C9E39B1 +KEY: D07CF6CBB7F313BDDE66B727AFD3C5E8 +NONCE: 8408DFFF3C1A2B1292DC199E46B7D617 +HEADER: 33CCE2EABFF5A79D +CIPHER: 529951EDB28B9557667E88ED360EB51256DEC0F056 + +MSG: 40D0C07DA5E4 +KEY: 35B6D0580005BBC12B0587124557D2C2 +NONCE: FDB6B06676EEDC5C61D74276E1F8E816 +HEADER: AEB96EAEBE2970E9 +CIPHER: F46A8BFED3B22A6E4388659FF1C39B3D49AAD8ADEA74 + +MSG: 4DE3B35C3FC039245BD1FB7D +KEY: BD8E6E11475E60B268784C38C62FEB22 +NONCE: 6EAC5C93072D8E8513F750935E46DA1B +HEADER: D4482D1CA78DCE0F +CIPHER: C3C7281CE5790F14D4CD666E8494D4911D528548F200014C32B86719 + +MSG: 8B0A79306C9CE7ED99DAE4F87F8DD61636 +KEY: 7C77D6E813BED5AC98BAA417477A2E7D +NONCE: 1A8C98DCD73D38393B2BF1569DEEFC19 +HEADER: 65D2017990D62528 +CIPHER: 1DD9A93ACD19F0C3FB7A3B431DFCFB96D2B899FA2285AEC7DCA504AF75B97A58A3 + +MSG: 1BDA122BCE8A8DBAF1877D962B8592DD2D56 +KEY: 5FFF20CAFAB119CA2FC73549E20F5B0D +NONCE: DDE59B97D722156D4D9AFF2BC7559826 +HEADER: 54B9F04E6A09189A +CIPHER: 2BA4C477F2927210ADCA26DF72E2BEF81BF3D6B03160E7BFE7FD3EB57D255D66713F + +MSG: 6CF36720872B8513F6EAB1A8A44438D5EF11 +KEY: A4A4782BCFFD3EC5E7EF6D8C34A56123 +NONCE: B781FCF2F75FA5A8DE97A9CA48E522EC +HEADER: 899A175897561D7E +CIPHER: A17D854BA33FDBDF0BA86ADC9152D40B4EA01E1A8FAB1E0A80B19E73784219B29446 + +MSG: CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7 +KEY: 8395FCF1E95BEBD697BD010BC766AAC3 +NONCE: 22E7ADD93CFC6393C57EC0B3C17D6B44 +HEADER: 126735FCC320D25A +CIPHER: 9F30626B590A0A6E2F6CE0ED8835031654B3FCCF311BD7A6C6089AF1C7373D22CB80D4AFEE diff --git a/eax-test.c b/eax-test.c new file mode 100644 index 0000000..c29a51f --- /dev/null +++ b/eax-test.c @@ -0,0 +1,154 @@ +/* + * eax-test.c: test harness for EAX, implementation + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * usages: + * ./eax-foo-test len; i++) { + perturb->v[i] ^= delta; + trydecrypt(0); + perturb->v[i] ^= delta; + } +} + +static void something(void) +{ + if (!msg.got) return; + assert(key.got); + assert(nonce.got); + assert(header.got); + eaxtest_blockcipher_key_setup(V(key)); + eax_setup(-1); + if (cipher.got) { + assert(cipher.len > msg.len); + tau = cipher.len - msg.len; + assert(tau <= blocksize); + } else { + assert(msg.len + blocksize < sizeof(ourcipher.v)); + tau = blocksize; + } + ourcipher.len = msg.len + tau; + eax_encrypt(-1, V(nonce), V(header), V(msg), tau, ourcipher.v); + if (cipher.got) { + assert(ourcipher.len == cipher.len); + assert(!memcmp(ourcipher.v, cipher.v, cipher.len)); + trydecrypt(1); + negtest(&ourcipher); + negtest(&header); + } else { + size_t i; + printf("CIPHER: "); + for (i=0; igot = 1; + cv->len = 0; + for (;;) { + c = getputchar(); + if (c == ':') break; + assert(isalpha(c)); + } + for (;;) { + char hbuf[3], *ep; + c = getputchar(); + if (c == '\n') break; + if (isspace(c)) continue; + assert(isprint(c)); + hbuf[0] = c; + c = getputchar(); + assert(isprint(c)); + hbuf[1] = c; + hbuf[2] = 0; + assert(cv->len < sizeof(cv->v)); + cv->v[cv->len++] = strtoul(hbuf,&ep,16); + assert(!*ep); + } + } + assert(!ferror(stdin)); + assert(feof(stdin)); + assert(!ferror(stdout)); + assert(!fflush(stdout)); + return 0; +} diff --git a/eax-test.h b/eax-test.h new file mode 100644 index 0000000..14aa010 --- /dev/null +++ b/eax-test.h @@ -0,0 +1,52 @@ +/* + * eax-test.c: test harness for EAX, common declarations + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef EAX_TEST_H +#define EAX_TEST_H + +#include +#include +#include +#include +#include +#include +#include + +#define INFO int dummy_info +#define I dummy_info +#define EAX_ENTRYPOINT_DECL /* empty */ + +#define EAX_DECLARATIONS_ONLY +#include "eax.c" +#undef EAX_DECLARATIONS_ONLY + +void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes); + +#define consttime_memcmp memcmp /* fine for running test vectors */ + +extern const size_t blocksize; + +#define EAX_SOME_TEST \ + const size_t blocksize = BLOCK_SIZE; \ + static uint8_t INFO_B[BLOCK_SIZE], INFO_P[BLOCK_SIZE] + +#endif /* EAX_TEST_H */ diff --git a/eax.c b/eax.c new file mode 100644 index 0000000..8c07fac --- /dev/null +++ b/eax.c @@ -0,0 +1,357 @@ +/* + * eax.c: implementation of the EAX authenticated encryption block cipher mode + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * This file is designed to be #included into another .c file which + * sets up the environment. It will declare or define three + * functions, eax_setup, eax_encrypt and eax_decrypt. + * + * Manifest constants which are expected to be defined: + * + * INFO One or more formal parameter definitions. + * Used in all relevant function declarations. Typically + * the application will use this for its context pointer, + * key schedule structure, etc. + * + * I Corresponding actual parameters for chaining onto + * sub-functions declared to take INFO parameters + * + * EAX_ENTRYPOINT_DECL + * Declarator decoration for the three entry points. + * Typically either "static" or the empty string; + * + * EAX_DECLARATIONS_ONLY + * Tested with #ifdef, so should be #defined to 1, or left + * undefined. If defined, #including eax.c will produces + * only the function prototypes for the three entrypoints. + * Otherwise it will produce the implementation. + * + * BLOCK_SIZE + * Constant expresion of integer type. + * + * void BLOCK_ENCRYPT(uint8_t dst[n], const uint8_t src[n]); + * + * Function to encrypt with the selected key. The block + * cipher's key schedule (ie, the key) to be used is + * implicit; uses of BLOCK_ENCRYPT always occur in a + * context where the parameters defined by INFO are + * available. + * + * So in a real application which wants to use more than + * one key at a time, BLOCK_ENCRYPT must be a macro which + * accesses the block cipher's key schedule via one of the + * INFO parameters. + * + * BLOCK_ENCRYPT must tolerate dst==src. + * + * EAX does not need to use the block cipher's decryption + * function. + * + * uint8_t INFO_B[n], INFO_P[n]; + * + * Buffers used by the algorithm; they are written by + * eax_setup and used by eax_encrypt and eax_decrypt. + * + * That is, effectively they are the part of the key + * schedule specific to EAX. + * + * An application which wants to use more than one key at + * a time must define these as macros which refer to + * key-specific variables via one of the INFO parameters. + * + * int consttime_memcmp(const void *s1, const void *s2, size_t n); + * + * Like memcmp but takes the same amount of time no matter + * where the discrepancy is. + * + * The entrypoints which are then defined are: + * + * void eax_setup(INFO) + * + * Does the EAX-specific part of the key setup. The block + * cipher key schedule must already have been done, as + * eax_setup uses BLOCK_ENCRYPT. + * + * void eax_encrypt(INFO, const uint8_t nonce[nonce_len], size_t nonce_len, + * const uint8_t h[h_len], size_t h_len, + * const uint8_t m[m_len], size_t m_len, + * uint8_t tau, + * uint8_t ct[m_len+tau]) + * + * Does a single EAX authenticated encryption, providing + * confidentiality and integrity to the message m[0..m_len-1]. + * + * The output message is longer than m by tau bytes and is stored + * in the array ct which must be big enough. + * + * nonce must never be repeated with the same key or the security + * of the system is destroyed, but it does not need to be secret. + * It is OK to transmit the nonce with the message along with the + * ciphertext and have the receiver recover it. + * + * h is the "header" - it is some extra data which should be + * covered by the authentication, but not the encryption. The + * output message does not contain a representation of h: it is + * expected to be transmitted separately (perhaps even in a + * different format). (If h_len==0, h may be a NULL pointer.) + * + * tau is the tag length - that is, the length of the message + * authentication code. It should be chosen for the right + * tradeoff between message expansion and security (resistence to + * forgery). It must be no longer than the block cipher block + * size. + * + * For any particular key. the tag length should be fixed. (The + * tag length should NOT be encoded into the packet along with + * the ciphertext and extracted by the receiver! Rather, the + * receiver must know what tag length to expect.) + * + * It is permissible for ct==m, or for the arrays to be disjoint. + * They must not overlap more subtly. + * + * _Bool eax_decrypt(INFO, const uint8_t nonce[nonce_len], size_t nonce_len, + * const uint8_t h[h_len], size_t h_len, + * const uint8_t ct[ct_len], size_t ct_len, + * uint8_t tau, + * uint8_t m[ct_len-tau]) + * + * Does a single EAX authenticated decryption. + * + * On successful return, the plaintext message is written to m + * and eax_decrypt returns true. The length of the plaintext + * message is always ct_len-tau. + * + * If the message did not decrypt correctly, returns false. + * (There is no further indication of the nature of the error.) + * In this case the buffer m may contain arbitrary contents which + * should not be revealed to attackers. + * + * nonce, h, tau are as above. + * + * It is permissible to call eax_decrypt with an input message + * which is too short (i.e. shorter than tau) (notwithstanding + * the notation m[ct_len-tau] in the faux prototype above). + * In this case it will return false without touching m. + * + * As with eax_decrypt, ct==m is permissible. + */ + +/***** IMPLEMENTATION *****/ + +/* + * We use the notation from the EAX paper, mostly. + * (We write xscr for "x in fancy mathsy curly script".) + * + * See: + * Mihir Bellare, Phillip Rogaway, and David Wagner + * + * _The EAX Mode of Operation + * (A Two-Pass Authenticated Encryption Scheme + * Optimized for Simplicity and Efficiency)_ + * + * Preliminary version in: + * Fast Software Encryption (FSE) 2004. Lecture Notes in Computer Science, + * vol. ??, pp. ??--??. + * + * Full version at: + * http://www.cs.ucdavis.edu/~rogaway/papers/eax.html + */ +/* + * In general, all functions tolerate their destination arrays being + * the same pointer to their source arrays, or totally distinct. + * (Just like BLOCK_ENCRYPT and the public eax entrypoints.) + * They must not overlap in more subtle ways. + */ + +#define n ((size_t)BLOCK_SIZE) + +#ifndef EAX_DECLARATIONS_ONLY + +static void xor(uint8_t *dst, const uint8_t *a, const uint8_t *b, size_t l) + /* simple block xor */ +{ + while (l--) + *dst++ = *a++ ^ *b++; +} + +static void increment(uint8_t *value) + /* value is a single block; incremented (BE) mod 256^n */ +{ + uint8_t *p; + for (p=value+n; p>value; ) + if ((*--p)++) break; +} + +static void alg_ctr(INFO, uint8_t *c, const uint8_t *nscr, + const uint8_t *m, size_t m_len) +{ + uint8_t blocknonce[n], cipher[n]; + size_t in; + + memcpy(blocknonce, nscr, n); + for (in=0; in0 && remain> 7) - 1u) & POLY; + unsigned i, mm; + + for (i = n - 1; i < n; i--) { + mm = (v[i] >> 7) & 1u; + o[i] = (v[i] << 1) ^ m; + m = mm; + } + +#undef POLY +} + +#endif /* not EAX_DECLARATIONS_ONLY */ + +EAX_ENTRYPOINT_DECL +void eax_setup(INFO) +#ifndef EAX_DECLARATIONS_ONLY +{ + uint8_t work[n]; + memset(work,0,n); + BLOCK_ENCRYPT(work,work); + consttime_curious_multiply(I, INFO_B, work); + consttime_curious_multiply(I, INFO_P, INFO_B); +} +#endif /* not EAX_DECLARATIONS_ONLY */ +; + +EAX_ENTRYPOINT_DECL +void eax_encrypt(INFO, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *h, size_t h_len, + const uint8_t *m, size_t m_len, uint8_t tau, uint8_t *ct) +#ifndef EAX_DECLARATIONS_ONLY +{ + assert(tau <= n); + uint8_t nscr[n], hscr[n], cscr[n]; + alg_omac_t_k(I, nscr, 0, nonce,nonce_len); + alg_omac_t_k(I, hscr, 1, h,h_len); + alg_ctr(I, ct, nscr, m, m_len); + alg_omac_t_k(I, cscr, 2, ct, m_len); + uint8_t *t = ct + m_len; + xor(t, nscr, cscr, tau); + xor(t, t, hscr, tau); +} +#endif /* not EAX_DECLARATIONS_ONLY */ +; + +EAX_ENTRYPOINT_DECL +_Bool eax_decrypt(INFO, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *h, size_t h_len, + const uint8_t *ct, size_t ct_len, uint8_t tau, uint8_t *m) +#ifndef EAX_DECLARATIONS_ONLY +{ + assert(tau <= n); + const uint8_t *t; + uint8_t nscr[n], hscr[n], cscr[n], tprime[tau]; + if (ct_len < tau) return 0; + size_t m_len = ct_len - tau; + t = ct + m_len; + alg_omac_t_k(I, nscr, 0, nonce,nonce_len); + alg_omac_t_k(I, hscr, 1, h,h_len); + alg_omac_t_k(I, cscr, 2, ct,m_len); + xor(tprime, nscr, cscr, tau); + xor(tprime, tprime, hscr, tau); + if (consttime_memcmp(tprime, t, tau)) return 0; + alg_ctr(I, m, nscr, ct, m_len); + return 1; +} +#endif /* not EAX_DECLARATIONS_ONLY */ +; + +#undef n -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Fri Jul 19 01:25:15 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:25:15 +0100 Subject: [PATCH 4/8] transform: split out transform-common.h In-Reply-To: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374193519-19262-5-git-send-email-ijackson@chiark.greenend.org.uk> To avoid too much duplication, some boilerplate and helpful code from transport.c is now brought out into macros in transport-common.h. It will be reused in the later commits introducing the EAX transform. Also, rename transform.c to transform-cbcmac.c, etc. Signed-off-by: Ian Jackson --- Makefile.in | 3 +- README | 2 +- modules.c | 2 +- secnet.h | 2 +- transform-cbcmac.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++ transform-common.h | 51 +++++++ transform.c | 394 ---------------------------------------------------- 7 files changed, 415 insertions(+), 398 deletions(-) create mode 100644 transform-cbcmac.c create mode 100644 transform-common.h delete mode 100644 transform.c diff --git a/Makefile.in b/Makefile.in index 6f36e4f..22f9de4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,7 +53,8 @@ mandir:=@mandir@ TARGETS:=secnet OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ - resolver.o random.o udp.o site.o transform.o netlink.o rsa.o dh.o \ + resolver.o random.o udp.o site.o transform-cbcmac.o \ + netlink.o rsa.o dh.o \ serpent.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ process.o @LIBOBJS@ \ hackypar.o diff --git a/README b/README index 84bb392..93730e9 100644 --- a/README +++ b/README @@ -336,7 +336,7 @@ setup but more relaxed about using old keys. These are noted with "mobile:", above, and apply whether the mobile peer is local or remote. -** transform +** transform-cbcmac Defines: serpent256-cbc (closure => transform closure) diff --git a/modules.c b/modules.c index 9b94e25..0290cd4 100644 --- a/modules.c +++ b/modules.c @@ -7,7 +7,7 @@ void init_builtin_modules(dict_t *dict) udp_module(dict); util_module(dict); site_module(dict); - transform_module(dict); + transform_cbcmac_module(dict); netlink_module(dict); rsa_module(dict); dh_module(dict); diff --git a/secnet.h b/secnet.h index 6ac64e3..1a5aaad 100644 --- a/secnet.h +++ b/secnet.h @@ -232,7 +232,7 @@ extern init_module random_module; extern init_module udp_module; extern init_module util_module; extern init_module site_module; -extern init_module transform_module; +extern init_module transform_cbcmac_module; extern init_module netlink_module; extern init_module rsa_module; extern init_module dh_module; diff --git a/transform-cbcmac.c b/transform-cbcmac.c new file mode 100644 index 0000000..7b97ce9 --- /dev/null +++ b/transform-cbcmac.c @@ -0,0 +1,359 @@ +/* Transform module - bulk data transformation */ + +/* For now it's hard-coded to do sequence + number/pkcs5/serpent-cbcmac/serpent with a 256 bit key for each + instance of serpent. We also require key material for the IVs for + cbcmac and cbc. Hack: we're not using full 128-bit IVs, we're just + using 32 bits and encrypting to get the full IV to save space in + the packets sent over the wire. */ + +#include +#include +#include "secnet.h" +#include "util.h" +#include "serpent.h" +#include "unaligned.h" + +/* Required key length in bytes */ +#define REQUIRED_KEYLEN ((512+64+32)/8) + +struct transform { + closure_t cl; + struct transform_if ops; + uint32_t max_seq_skew; +}; + +struct transform_inst { + struct transform_inst_if ops; + struct keyInstance cryptkey; + struct keyInstance mackey; + uint32_t cryptiv; + uint32_t maciv; + uint32_t sendseq; + uint32_t lastrecvseq; + uint32_t max_skew; + bool_t keyed; +}; + +#include "transform-common.h" + +#define PKCS5_MASK 15 + +static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) +{ + struct transform_inst *ti=sst; + + if (keylencryptkey,256,key); + serpent_makekey(&ti->mackey,256,key+32); + ti->cryptiv=GET_32BIT_MSB_FIRST(key+64); + ti->maciv=GET_32BIT_MSB_FIRST(key+68); + ti->sendseq=GET_32BIT_MSB_FIRST(key+72); + ti->lastrecvseq=ti->sendseq; + ti->keyed=True; + + return True; +} + +TRANSFORM_VALID; + +static void transform_delkey(void *sst) +{ + struct transform_inst *ti=sst; + + FILLZERO(ti->cryptkey); + FILLZERO(ti->mackey); + ti->keyed=False; +} + +static uint32_t transform_forward(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + uint8_t *padp; + int padlen; + uint8_t iv[16]; + uint8_t macplain[16]; + uint8_t macacc[16]; + uint8_t *p, *n; + int i; + + KEYED_CHECK; + + /* Sequence number */ + buf_prepend_uint32(buf,ti->sendseq); + ti->sendseq++; + + /* PKCS5, stolen from IWJ */ + /* eg with blocksize=4 mask=3 mask+2=5 */ + /* msgsize 20 21 22 23 24 */ + padlen= PKCS5_MASK-buf->size; /* -17 -18 -19 -16 -17 */ + padlen &= PKCS5_MASK; /* 3 2 1 0 3 */ + padlen++; /* 4 3 2 1 4 */ + + padp=buf_append(buf,padlen); + memset(padp,padlen,padlen); + + /* Serpent-CBCMAC. We expand the IV from 32-bit to 128-bit using + one encryption. Then we do the MAC and append the result. We don't + bother sending the IV - it's the same each time. (If we wanted to send + it we've have to add 16 bytes to each message, not 4, so that the + message stays a multiple of 16 bytes long.) */ + memset(iv,0,16); + PUT_32BIT_MSB_FIRST(iv, ti->maciv); + serpent_encrypt(&ti->mackey,iv,macacc); + + /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted + block encrypted once again. */ + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + macplain[i] = macacc[i] ^ n[i]; + serpent_encrypt(&ti->mackey,macplain,macacc); + } + serpent_encrypt(&ti->mackey,macacc,macacc); + memcpy(buf_append(buf,16),macacc,16); + + /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption, + and prepend the IV before increasing it. */ + memset(iv,0,16); + PUT_32BIT_MSB_FIRST(iv, ti->cryptiv); + serpent_encrypt(&ti->cryptkey,iv,iv); + + /* CBC: each block is XORed with the previous encrypted block (or the IV) + before being encrypted. */ + p=iv; + + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + n[i] ^= p[i]; + serpent_encrypt(&ti->cryptkey,n,n); + p=n; + } + + buf_prepend_uint32(buf,ti->cryptiv); + ti->cryptiv++; + return 0; +} + +static uint32_t transform_reverse(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + uint8_t *padp; + int padlen; + int i; + uint32_t seqnum; + uint8_t iv[16]; + uint8_t pct[16]; + uint8_t macplain[16]; + uint8_t macacc[16]; + uint8_t *n; + uint8_t *macexpected; + + KEYED_CHECK; + + if (buf->size < 4 + 16 + 16) { + *errmsg="msg too short"; + return 1; + } + + /* CBC */ + memset(iv,0,16); + { + uint32_t ivword = buf_unprepend_uint32(buf); + PUT_32BIT_MSB_FIRST(iv, ivword); + } + /* Assert bufsize is multiple of blocksize */ + if (buf->size&0xf) { + *errmsg="msg not multiple of cipher blocksize"; + return 1; + } + serpent_encrypt(&ti->cryptkey,iv,iv); + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + pct[i] = n[i]; + serpent_decrypt(&ti->cryptkey,n,n); + for (i = 0; i < 16; i++) + n[i] ^= iv[i]; + memcpy(iv, pct, 16); + } + + /* CBCMAC */ + macexpected=buf_unappend(buf,16); + memset(iv,0,16); + PUT_32BIT_MSB_FIRST(iv, ti->maciv); + serpent_encrypt(&ti->mackey,iv,macacc); + + /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted + block encrypted once again. */ + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + macplain[i] = macacc[i] ^ n[i]; + serpent_encrypt(&ti->mackey,macplain,macacc); + } + serpent_encrypt(&ti->mackey,macacc,macacc); + if (consttime_memcmp(macexpected,macacc,16)!=0) { + *errmsg="invalid MAC"; + return 1; + } + + /* PKCS5, stolen from IWJ */ + + padp=buf_unappend(buf,1); + padlen=*padp; + if (!padlen || (padlen > PKCS5_MASK+1)) { + *errmsg="pkcs5: invalid length"; + return 1; + } + + buf_unappend(buf,padlen-1); + + /* Sequence number must be within max_skew of lastrecvseq; lastrecvseq + is only allowed to increase. */ + seqnum=buf_unprepend_uint32(buf); + SEQNUM_CHECK(seqnum, ti->max_skew); + + return 0; +} + +TRANSFORM_DESTROY; + +static struct transform_inst_if *transform_create(void *sst) +{ + struct transform *st=sst; + + TRANSFORM_CREATE_CORE; + + ti->max_skew=st->max_seq_skew; + + return &ti->ops; +} + +static list_t *transform_apply(closure_t *self, struct cloc loc, + dict_t *context, list_t *args) +{ + struct transform *st; + item_t *item; + dict_t *dict; + + st=safe_malloc(sizeof(*st),"serpent"); + st->cl.description="serpent-cbc256"; + st->cl.type=CL_TRANSFORM; + st->cl.apply=NULL; + st->cl.interface=&st->ops; + st->ops.st=st; + st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV, + 4byte IV */ + st->ops.max_end_pad=16; /* 16byte CBCMAC */ + + /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits + for CBCMAC-IV, and 32 bits for init sequence number */ + st->ops.keylen=REQUIRED_KEYLEN; + st->ops.create=transform_create; + + /* First parameter must be a dict */ + item=list_elem(args,0); + if (!item || item->type!=t_dict) + cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n"); + + dict=item->data.dict; + st->max_seq_skew=dict_read_number(dict, "max-sequence-skew", + False, "serpent-cbc256", loc, 10); + + return new_closure(&st->cl); +} + +void transform_cbcmac_module(dict_t *dict) +{ + struct keyInstance k; + uint8_t data[32]; + uint8_t plaintext[16]; + uint8_t ciphertext[16]; + + /* + * Serpent self-test. + * + * This test pattern is taken directly from the Serpent test + * vectors, to ensure we have all endianness issues correct. -sgt + */ + + /* Serpent self-test */ + memcpy(data, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" + "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00", + 32); + serpent_makekey(&k,256,data); + + memcpy(plaintext, + "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10", + 16); + serpent_encrypt(&k,plaintext,ciphertext); + + if (memcmp(ciphertext, "\xca\x7f\xa1\x93\xe3\xeb\x9e\x99" + "\xbd\x87\xe3\xaf\x3c\x9a\xdf\x93", 16)) { + fatal("transform_module: serpent failed self-test (encrypt)"); + } + serpent_decrypt(&k,ciphertext,plaintext); + if (memcmp(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\xfe\xdc\xba\x98\x76\x54\x32\x10", 16)) { + fatal("transform_module: serpent failed self-test (decrypt)"); + } + + add_closure(dict,"serpent256-cbc",transform_apply); + +#ifdef TEST_WHOLE_TRANSFORM + { + struct transform *tr; + void *ti; + struct buffer_if buf; + const char text[] = "This is a piece of test text."; + char keymaterial[76] = + "Seventy-six bytes i" + "n four rows of 19; " + "this looks almost l" + "ike a poem but not."; + const char *errmsg; + int i; + + tr = malloc(sizeof(struct transform)); + tr->max_seq_skew = 20; + ti = transform_create(tr); + + transform_setkey(ti, keymaterial, 76); + + buf.base = malloc(4096); + buffer_init(&buf, 2048); + memcpy(buf_append(&buf, sizeof(text)), text, sizeof(text)); + if (transform_forward(ti, &buf, &errmsg)) { + fatal("transform_forward test: %s", errmsg); + } + printf("transformed text is:\n"); + for (i = 0; i < buf.size; i++) + printf("%02x%c", buf.start[i], + (i%16==15 || i==buf.size-1 ? '\n' : ' ')); + if (transform_reverse(ti, &buf, &errmsg)) { + fatal("transform_reverse test: %s", errmsg); + } + printf("transform reversal worked OK\n"); + } +#endif +} diff --git a/transform-common.h b/transform-common.h new file mode 100644 index 0000000..dd18b2f --- /dev/null +++ b/transform-common.h @@ -0,0 +1,51 @@ + +#define KEYED_CHECK do{ \ + if (!ti->keyed) { \ + *errmsg="transform unkeyed"; \ + return 1; \ + } \ + }while(0) + +#define SEQNUM_CHECK(seqnum, max_skew) do{ \ + uint32_t skew=seqnum-ti->lastrecvseq; \ + if (skew<0x8fffffff) { \ + /* Ok */ \ + ti->lastrecvseq=seqnum; \ + } else if ((0-skew)keyed; \ + } + +#define TRANSFORM_DESTROY \ + static void transform_destroy(void *sst) \ + { \ + struct transform_inst *st=sst; \ + \ + FILLZERO(*st); /* Destroy key material */ \ + free(st); \ + } + +#define TRANSFORM_CREATE_CORE \ + struct transform_inst *ti; \ + ti=safe_malloc(sizeof(*ti),"transform_create"); \ + /* mlock XXX */ \ + ti->ops.st=ti; \ + ti->ops.setkey=transform_setkey; \ + ti->ops.valid=transform_valid; \ + ti->ops.delkey=transform_delkey; \ + ti->ops.forwards=transform_forward; \ + ti->ops.reverse=transform_reverse; \ + ti->ops.destroy=transform_destroy; \ + ti->keyed=False; diff --git a/transform.c b/transform.c deleted file mode 100644 index 9ee0df0..0000000 --- a/transform.c +++ /dev/null @@ -1,394 +0,0 @@ -/* Transform module - bulk data transformation */ - -/* For now it's hard-coded to do sequence - number/pkcs5/serpent-cbcmac/serpent with a 256 bit key for each - instance of serpent. We also require key material for the IVs for - cbcmac and cbc. Hack: we're not using full 128-bit IVs, we're just - using 32 bits and encrypting to get the full IV to save space in - the packets sent over the wire. */ - -#include -#include -#include "secnet.h" -#include "util.h" -#include "serpent.h" -#include "unaligned.h" - -/* Required key length in bytes */ -#define REQUIRED_KEYLEN ((512+64+32)/8) - -struct transform { - closure_t cl; - struct transform_if ops; - uint32_t max_seq_skew; -}; - -struct transform_inst { - struct transform_inst_if ops; - struct keyInstance cryptkey; - struct keyInstance mackey; - uint32_t cryptiv; - uint32_t maciv; - uint32_t sendseq; - uint32_t lastrecvseq; - uint32_t max_skew; - bool_t keyed; -}; - -#define PKCS5_MASK 15 - -static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) -{ - struct transform_inst *ti=sst; - - if (keylencryptkey,256,key); - serpent_makekey(&ti->mackey,256,key+32); - ti->cryptiv=GET_32BIT_MSB_FIRST(key+64); - ti->maciv=GET_32BIT_MSB_FIRST(key+68); - ti->sendseq=GET_32BIT_MSB_FIRST(key+72); - ti->lastrecvseq=ti->sendseq; - ti->keyed=True; - - return True; -} - -static bool_t transform_valid(void *sst) -{ - struct transform_inst *ti=sst; - - return ti->keyed; -} - -static void transform_delkey(void *sst) -{ - struct transform_inst *ti=sst; - - FILLZERO(ti->cryptkey); - FILLZERO(ti->mackey); - ti->keyed=False; -} - -static uint32_t transform_forward(void *sst, struct buffer_if *buf, - const char **errmsg) -{ - struct transform_inst *ti=sst; - uint8_t *padp; - int padlen; - uint8_t iv[16]; - uint8_t macplain[16]; - uint8_t macacc[16]; - uint8_t *p, *n; - int i; - - if (!ti->keyed) { - *errmsg="transform unkeyed"; - return 1; - } - - /* Sequence number */ - buf_prepend_uint32(buf,ti->sendseq); - ti->sendseq++; - - /* PKCS5, stolen from IWJ */ - /* eg with blocksize=4 mask=3 mask+2=5 */ - /* msgsize 20 21 22 23 24 */ - padlen= PKCS5_MASK-buf->size; /* -17 -18 -19 -16 -17 */ - padlen &= PKCS5_MASK; /* 3 2 1 0 3 */ - padlen++; /* 4 3 2 1 4 */ - - padp=buf_append(buf,padlen); - memset(padp,padlen,padlen); - - /* Serpent-CBCMAC. We expand the IV from 32-bit to 128-bit using - one encryption. Then we do the MAC and append the result. We don't - bother sending the IV - it's the same each time. (If we wanted to send - it we've have to add 16 bytes to each message, not 4, so that the - message stays a multiple of 16 bytes long.) */ - memset(iv,0,16); - PUT_32BIT_MSB_FIRST(iv, ti->maciv); - serpent_encrypt(&ti->mackey,iv,macacc); - - /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted - block encrypted once again. */ - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - macplain[i] = macacc[i] ^ n[i]; - serpent_encrypt(&ti->mackey,macplain,macacc); - } - serpent_encrypt(&ti->mackey,macacc,macacc); - memcpy(buf_append(buf,16),macacc,16); - - /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption, - and prepend the IV before increasing it. */ - memset(iv,0,16); - PUT_32BIT_MSB_FIRST(iv, ti->cryptiv); - serpent_encrypt(&ti->cryptkey,iv,iv); - - /* CBC: each block is XORed with the previous encrypted block (or the IV) - before being encrypted. */ - p=iv; - - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - n[i] ^= p[i]; - serpent_encrypt(&ti->cryptkey,n,n); - p=n; - } - - buf_prepend_uint32(buf,ti->cryptiv); - ti->cryptiv++; - return 0; -} - -static uint32_t transform_reverse(void *sst, struct buffer_if *buf, - const char **errmsg) -{ - struct transform_inst *ti=sst; - uint8_t *padp; - int padlen; - int i; - uint32_t seqnum, skew; - uint8_t iv[16]; - uint8_t pct[16]; - uint8_t macplain[16]; - uint8_t macacc[16]; - uint8_t *n; - uint8_t *macexpected; - - if (!ti->keyed) { - *errmsg="transform unkeyed"; - return 1; - } - - if (buf->size < 4 + 16 + 16) { - *errmsg="msg too short"; - return 1; - } - - /* CBC */ - memset(iv,0,16); - { - uint32_t ivword = buf_unprepend_uint32(buf); - PUT_32BIT_MSB_FIRST(iv, ivword); - } - /* Assert bufsize is multiple of blocksize */ - if (buf->size&0xf) { - *errmsg="msg not multiple of cipher blocksize"; - return 1; - } - serpent_encrypt(&ti->cryptkey,iv,iv); - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - pct[i] = n[i]; - serpent_decrypt(&ti->cryptkey,n,n); - for (i = 0; i < 16; i++) - n[i] ^= iv[i]; - memcpy(iv, pct, 16); - } - - /* CBCMAC */ - macexpected=buf_unappend(buf,16); - memset(iv,0,16); - PUT_32BIT_MSB_FIRST(iv, ti->maciv); - serpent_encrypt(&ti->mackey,iv,macacc); - - /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted - block encrypted once again. */ - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - macplain[i] = macacc[i] ^ n[i]; - serpent_encrypt(&ti->mackey,macplain,macacc); - } - serpent_encrypt(&ti->mackey,macacc,macacc); - if (consttime_memcmp(macexpected,macacc,16)!=0) { - *errmsg="invalid MAC"; - return 1; - } - - /* PKCS5, stolen from IWJ */ - - padp=buf_unappend(buf,1); - padlen=*padp; - if (!padlen || (padlen > PKCS5_MASK+1)) { - *errmsg="pkcs5: invalid length"; - return 1; - } - - buf_unappend(buf,padlen-1); - - /* Sequence number must be within max_skew of lastrecvseq; lastrecvseq - is only allowed to increase. */ - seqnum=buf_unprepend_uint32(buf); - skew=seqnum-ti->lastrecvseq; - if (skew<0x8fffffff) { - /* Ok */ - ti->lastrecvseq=seqnum; - } else if ((0-skew)max_skew) { - /* Ok */ - } else { - /* Too much skew */ - *errmsg="seqnum: too much skew"; - return 2; - } - - return 0; -} - -static void transform_destroy(void *sst) -{ - struct transform_inst *st=sst; - - FILLZERO(*st); /* Destroy key material */ - free(st); -} - -static struct transform_inst_if *transform_create(void *sst) -{ - struct transform_inst *ti; - struct transform *st=sst; - - ti=safe_malloc(sizeof(*ti),"transform_create"); - /* mlock XXX */ - - ti->ops.st=ti; - ti->ops.setkey=transform_setkey; - ti->ops.valid=transform_valid; - ti->ops.delkey=transform_delkey; - ti->ops.forwards=transform_forward; - ti->ops.reverse=transform_reverse; - ti->ops.destroy=transform_destroy; - ti->max_skew=st->max_seq_skew; - ti->keyed=False; - - return &ti->ops; -} - -static list_t *transform_apply(closure_t *self, struct cloc loc, - dict_t *context, list_t *args) -{ - struct transform *st; - item_t *item; - dict_t *dict; - - st=safe_malloc(sizeof(*st),"serpent"); - st->cl.description="serpent-cbc256"; - st->cl.type=CL_TRANSFORM; - st->cl.apply=NULL; - st->cl.interface=&st->ops; - st->ops.st=st; - st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV, - 4byte IV */ - st->ops.max_end_pad=16; /* 16byte CBCMAC */ - - /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits - for CBCMAC-IV, and 32 bits for init sequence number */ - st->ops.keylen=REQUIRED_KEYLEN; - st->ops.create=transform_create; - - /* First parameter must be a dict */ - item=list_elem(args,0); - if (!item || item->type!=t_dict) - cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n"); - - dict=item->data.dict; - st->max_seq_skew=dict_read_number(dict, "max-sequence-skew", - False, "serpent-cbc256", loc, 10); - - return new_closure(&st->cl); -} - -void transform_module(dict_t *dict) -{ - struct keyInstance k; - uint8_t data[32]; - uint8_t plaintext[16]; - uint8_t ciphertext[16]; - - /* - * Serpent self-test. - * - * This test pattern is taken directly from the Serpent test - * vectors, to ensure we have all endianness issues correct. -sgt - */ - - /* Serpent self-test */ - memcpy(data, - "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" - "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00", - 32); - serpent_makekey(&k,256,data); - - memcpy(plaintext, - "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10", - 16); - serpent_encrypt(&k,plaintext,ciphertext); - - if (memcmp(ciphertext, "\xca\x7f\xa1\x93\xe3\xeb\x9e\x99" - "\xbd\x87\xe3\xaf\x3c\x9a\xdf\x93", 16)) { - fatal("transform_module: serpent failed self-test (encrypt)"); - } - serpent_decrypt(&k,ciphertext,plaintext); - if (memcmp(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", 16)) { - fatal("transform_module: serpent failed self-test (decrypt)"); - } - - add_closure(dict,"serpent256-cbc",transform_apply); - -#ifdef TEST_WHOLE_TRANSFORM - { - struct transform *tr; - void *ti; - struct buffer_if buf; - const char text[] = "This is a piece of test text."; - char keymaterial[76] = - "Seventy-six bytes i" - "n four rows of 19; " - "this looks almost l" - "ike a poem but not."; - const char *errmsg; - int i; - - tr = malloc(sizeof(struct transform)); - tr->max_seq_skew = 20; - ti = transform_create(tr); - - transform_setkey(ti, keymaterial, 76); - - buf.base = malloc(4096); - buffer_init(&buf, 2048); - memcpy(buf_append(&buf, sizeof(text)), text, sizeof(text)); - if (transform_forward(ti, &buf, &errmsg)) { - fatal("transform_forward test: %s", errmsg); - } - printf("transformed text is:\n"); - for (i = 0; i < buf.size; i++) - printf("%02x%c", buf.start[i], - (i%16==15 || i==buf.size-1 ? '\n' : ' ')); - if (transform_reverse(ti, &buf, &errmsg)) { - fatal("transform_reverse test: %s", errmsg); - } - printf("transform reversal worked OK\n"); - } -#endif -} -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Fri Jul 19 01:25:16 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:25:16 +0100 Subject: [PATCH 5/8] transform: Allow DH to set the key size In-Reply-To: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374193519-19262-6-git-send-email-ijackson@chiark.greenend.org.uk> It turns out that the current Serpent CBC-MAC transform takes the raw DH shared secret, and parcels it up in byte ranges for the various uses (some of which are published). Well, obviously this is not a good idea. But also it means the interface isn't set up to allow the size of the key data provided to the transform to be determined by the size of the DH modulus. Fix this latter interface problem. Now a transform can set its keylen to 0, meaning it will be provided with the whole of the DH private value. We don't use this new feature yet. We can't make the existing transform use it without breaking compatibility, but it will be used by the new EAX-based transform. Signed-off-by: Ian Jackson --- dh.c | 4 ++++ secnet.h | 3 ++- site.c | 14 ++++++++------ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/dh.c b/dh.c index 2383192..c37b538 100644 --- a/dh.c +++ b/dh.c @@ -125,6 +125,10 @@ static list_t *dh_apply(closure_t *self, struct cloc loc, dict_t *context, st->ops.len=sz; + st->ops.ceil_len=(mpz_sizeinbase(&st->p,2)+7)/8; + /* According to the docs, mpz_sizeinbase(,256) is allowed to return + * an answer which is 1 too large. But mpz_sizeinbase(,2) isn't. */ + return new_closure(&st->cl); } diff --git a/secnet.h b/secnet.h index 1a5aaad..23d62ba 100644 --- a/secnet.h +++ b/secnet.h @@ -412,7 +412,7 @@ struct transform_if { void *st; int32_t max_start_pad; /* these three are all <<< INT_MAX */ int32_t max_end_pad; - int32_t keylen; + int32_t keylen; /* 0 means give the transform exactly as much as there is */ transform_createinstance_fn *create; }; @@ -459,6 +459,7 @@ typedef void dh_makeshared_fn(void *st, uint8_t *secret, struct dh_if { void *st; int32_t len; /* Approximate size of modulus in bytes */ + int32_t ceil_len; /* Number of bytes just sufficient to contain modulus */ dh_makepublic_fn *makepublic; dh_makeshared_fn *makeshared; }; diff --git a/site.c b/site.c index e96d6f4..12b2df2 100644 --- a/site.c +++ b/site.c @@ -288,6 +288,7 @@ struct site { uint64_t timeout; /* Timeout for current state */ uint8_t *dhsecret; uint8_t *sharedsecret; + uint32_t sharedsecretlen; struct transform_inst_if *new_transform; /* For key setup/verify */ }; @@ -561,11 +562,11 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, /* Generate the shared key */ st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->transform->keylen); + st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->transform->keylen); + st->sharedsecretlen); return True; } @@ -609,10 +610,10 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, m.pk[m.pklen]=0; /* Generate the shared key */ st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->transform->keylen); + st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->transform->keylen); + st->sharedsecretlen); return True; } @@ -1009,7 +1010,7 @@ static void enter_state_run(struct site *st) memset(st->remoteN,0,NONCELEN); st->new_transform->delkey(st->new_transform->st); memset(st->dhsecret,0,st->dh->len); - memset(st->sharedsecret,0,st->transform->keylen); + memset(st->sharedsecret,0,st->sharedsecretlen); set_link_quality(st); } @@ -1557,7 +1558,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, transport_peers_clear(st,&st->setup_peers); /* XXX mlock these */ st->dhsecret=safe_malloc(st->dh->len,"site:dhsecret"); - st->sharedsecret=safe_malloc(st->transform->keylen,"site:sharedsecret"); + st->sharedsecretlen=st->transform->keylen?:st->dh->ceil_len; + st->sharedsecret=safe_malloc(st->sharedsecretlen,"site:sharedsecret"); /* We need to compute some properties of our comms */ #define COMPUTE_WORST(pad) \ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Fri Jul 19 01:25:17 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:25:17 +0100 Subject: [PATCH 6/8] transform: Pass a direction flag to the transform In-Reply-To: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374193519-19262-7-git-send-email-ijackson@chiark.greenend.org.uk> The same transform is used for inbound and outbound packets. The transform should know which direction these packets are flowing in; that (a) allows a transform to reject packets which are "looping back" so to speak, and (b) makes it easier for a transform to generate unique nonces. This will be used by the forthcoming EAX transform. It is combined with the sequence number (the same values of which are used by both ends) to make the nonce, which must be unique across the single shared key, ie unique across both flows. Signed-off-by: Ian Jackson --- secnet.h | 7 +++++-- site.c | 4 ++-- transform-cbcmac.c | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/secnet.h b/secnet.h index 23d62ba..6ad8fc9 100644 --- a/secnet.h +++ b/secnet.h @@ -383,10 +383,13 @@ struct site_if { also depend on internal factors (eg. time) and keep internal state. A struct transform_if only represents a particular type of transformation; instances of the transformation (eg. with - particular key material) have a different C type. */ + particular key material) have a different C type. The same + secret key will be used in opposite directions between a pair of + secnets; one of these pairs will get direction==False, the other True. */ typedef struct transform_inst_if *transform_createinstance_fn(void *st); -typedef bool_t transform_setkey_fn(void *st, uint8_t *key, int32_t keylen); +typedef bool_t transform_setkey_fn(void *st, uint8_t *key, int32_t keylen, + bool_t direction); typedef bool_t transform_valid_fn(void *st); /* 0: no key; 1: ok */ typedef void transform_delkey_fn(void *st); typedef void transform_destroyinstance_fn(void *st); diff --git a/site.c b/site.c index 12b2df2..c48a1e5 100644 --- a/site.c +++ b/site.c @@ -566,7 +566,7 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen); + st->sharedsecretlen,st->setup_priority); return True; } @@ -613,7 +613,7 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen); + st->sharedsecretlen,st->setup_priority); return True; } diff --git a/transform-cbcmac.c b/transform-cbcmac.c index 7b97ce9..b163d33 100644 --- a/transform-cbcmac.c +++ b/transform-cbcmac.c @@ -39,7 +39,8 @@ struct transform_inst { #define PKCS5_MASK 15 -static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) +static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen, + bool_t direction) { struct transform_inst *ti=sst; -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Fri Jul 19 01:25:18 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:25:18 +0100 Subject: [PATCH 7/8] crypto: Copy a SHA512 implementation into tree In-Reply-To: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374193519-19262-8-git-send-email-ijackson@chiark.greenend.org.uk> We are going to want an implementation of SHA512 (initially for hashing DH secrets into EAX keys). Copy the version from coreutils 8.5, along with u64.h. In this patch, we commit exactly the files from coreutils. They will be made to compile later. Doing it this way means we can more easily isolate changes we have to make. Copying these files from coreutils makes secnet GPL-3+. Signed-off-by: Ian Jackson --- COPYING | 914 ++++++++++++++++++++++++++++++++++++++++++-------------------- sha512.c | 619 ++++++++++++++++++++++++++++++++++++++++++ sha512.h | 95 +++++++ u64.h | 159 +++++++++++ 4 files changed, 1497 insertions(+), 290 deletions(-) create mode 100644 sha512.c create mode 100644 sha512.h create mode 100644 u64.h diff --git a/COPYING b/COPYING index 60549be..94a9ed0 100644 --- a/COPYING +++ b/COPYING @@ -1,285 +1,626 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of this License. - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least +state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -304,37 +645,30 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/sha512.c b/sha512.c new file mode 100644 index 0000000..5c0b2ed --- /dev/null +++ b/sha512.c @@ -0,0 +1,619 @@ +/* sha512.c - Functions to compute SHA512 and SHA384 message digest of files or + memory blocks according to the NIST specification FIPS-180-2. + + Copyright (C) 2005, 2006, 2008, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by David Madore, considerably copypasting from + Scott G. Miller's sha1.c +*/ + +#include + +#include "sha512.h" + +#include +#include +#include + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + u64or (u64or (u64or (u64shl (n, 56), \ + u64shl (u64and (n, u64lo (0x0000ff00)), 40)), \ + u64or (u64shl (u64and (n, u64lo (0x00ff0000)), 24), \ + u64shl (u64and (n, u64lo (0xff000000)), 8))), \ + u64or (u64or (u64and (u64shr (n, 8), u64lo (0xff000000)), \ + u64and (u64shr (n, 24), u64lo (0x00ff0000))), \ + u64or (u64and (u64shr (n, 40), u64lo (0x0000ff00)), \ + u64shr (n, 56)))) +#endif + +#define BLOCKSIZE 32768 +#if BLOCKSIZE % 128 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 128-byte boundary. */ +static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 512 bit block of data (eight 64 bit ints) and + intializes it to the start constants of the SHA512 algorithm. This + must be called before using hash in the call to sha512_hash +*/ +void +sha512_init_ctx (struct sha512_ctx *ctx) +{ + ctx->state[0] = u64hilo (0x6a09e667, 0xf3bcc908); + ctx->state[1] = u64hilo (0xbb67ae85, 0x84caa73b); + ctx->state[2] = u64hilo (0x3c6ef372, 0xfe94f82b); + ctx->state[3] = u64hilo (0xa54ff53a, 0x5f1d36f1); + ctx->state[4] = u64hilo (0x510e527f, 0xade682d1); + ctx->state[5] = u64hilo (0x9b05688c, 0x2b3e6c1f); + ctx->state[6] = u64hilo (0x1f83d9ab, 0xfb41bd6b); + ctx->state[7] = u64hilo (0x5be0cd19, 0x137e2179); + + ctx->total[0] = ctx->total[1] = u64lo (0); + ctx->buflen = 0; +} + +void +sha384_init_ctx (struct sha512_ctx *ctx) +{ + ctx->state[0] = u64hilo (0xcbbb9d5d, 0xc1059ed8); + ctx->state[1] = u64hilo (0x629a292a, 0x367cd507); + ctx->state[2] = u64hilo (0x9159015a, 0x3070dd17); + ctx->state[3] = u64hilo (0x152fecd8, 0xf70e5939); + ctx->state[4] = u64hilo (0x67332667, 0xffc00b31); + ctx->state[5] = u64hilo (0x8eb44a87, 0x68581511); + ctx->state[6] = u64hilo (0xdb0c2e0d, 0x64f98fa7); + ctx->state[7] = u64hilo (0x47b5481d, 0xbefa4fa4); + + ctx->total[0] = ctx->total[1] = u64lo (0); + ctx->buflen = 0; +} + +/* Copy the value from V into the memory location pointed to by *CP, + If your architecture allows unaligned access, this is equivalent to + * (__typeof__ (v) *) cp = v */ +static inline void +set_uint64 (char *cp, u64 v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 64 bytes following RESBUF. + The result must be in little endian byte order. */ +void * +sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 8; i++) + set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +void * +sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 6; i++) + set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +static void +sha512_conclude_ctx (struct sha512_ctx *ctx) +{ + /* Take yet unprocessed bytes into account. */ + size_t bytes = ctx->buflen; + size_t size = (bytes < 112) ? 128 / 8 : 128 * 2 / 8; + + /* Now count remaining bytes. */ + ctx->total[0] = u64plus (ctx->total[0], u64lo (bytes)); + if (u64lt (ctx->total[0], u64lo (bytes))) + ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); + + /* Put the 128-bit file length in *bits* at the end of the buffer. + Use set_uint64 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint64 ((char *) &ctx->buffer[size - 2], + SWAP (u64or (u64shl (ctx->total[1], 3), + u64shr (ctx->total[0], 61)))); + set_uint64 ((char *) &ctx->buffer[size - 1], + SWAP (u64shl (ctx->total[0], 3))); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes); + + /* Process last bytes. */ + sha512_process_block (ctx->buffer, size * 8, ctx); +} + +void * +sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf) +{ + sha512_conclude_ctx (ctx); + return sha512_read_ctx (ctx, resbuf); +} + +void * +sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf) +{ + sha512_conclude_ctx (ctx); + return sha384_read_ctx (ctx, resbuf); +} + +/* Compute SHA512 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 64 bytes + beginning at RESBLOCK. */ +int +sha512_stream (FILE *stream, void *resblock) +{ + struct sha512_ctx ctx; + size_t sum; + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + /* Initialize the computation context. */ + sha512_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + { + free (buffer); + return 1; + } + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 128 == 0 + */ + sha512_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha512_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha512_finish_ctx (&ctx, resblock); + free (buffer); + return 0; +} + +/* FIXME: Avoid code duplication */ +int +sha384_stream (FILE *stream, void *resblock) +{ + struct sha512_ctx ctx; + size_t sum; + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + /* Initialize the computation context. */ + sha384_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + { + free (buffer); + return 1; + } + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 128 == 0 + */ + sha512_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha512_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha384_finish_ctx (&ctx, resblock); + free (buffer); + return 0; +} + +/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +sha512_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha512_ctx ctx; + + /* Initialize the computation context. */ + sha512_init_ctx (&ctx); + + /* Process whole buffer but last len % 128 bytes. */ + sha512_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha512_finish_ctx (&ctx, resblock); +} + +void * +sha384_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha512_ctx ctx; + + /* Initialize the computation context. */ + sha384_init_ctx (&ctx); + + /* Process whole buffer but last len % 128 bytes. */ + sha512_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha384_finish_ctx (&ctx, resblock); +} + +void +sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 256 - left_over > len ? len : 256 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 128) + { + sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx); + + ctx->buflen &= 127; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~127], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 128) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (u64) != 0) + if (UNALIGNED_P (buffer)) + while (len > 128) + { + sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128, ctx); + buffer = (const char *) buffer + 128; + len -= 128; + } + else +#endif + { + sha512_process_block (buffer, len & ~127, ctx); + buffer = (const char *) buffer + (len & ~127); + len &= 127; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 128) + { + sha512_process_block (ctx->buffer, 128, ctx); + left_over -= 128; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha512.c --- */ + +/* SHA512 round constants */ +#define K(I) sha512_round_constants[I] +static u64 const sha512_round_constants[80] = { + u64init (0x428a2f98, 0xd728ae22), u64init (0x71374491, 0x23ef65cd), + u64init (0xb5c0fbcf, 0xec4d3b2f), u64init (0xe9b5dba5, 0x8189dbbc), + u64init (0x3956c25b, 0xf348b538), u64init (0x59f111f1, 0xb605d019), + u64init (0x923f82a4, 0xaf194f9b), u64init (0xab1c5ed5, 0xda6d8118), + u64init (0xd807aa98, 0xa3030242), u64init (0x12835b01, 0x45706fbe), + u64init (0x243185be, 0x4ee4b28c), u64init (0x550c7dc3, 0xd5ffb4e2), + u64init (0x72be5d74, 0xf27b896f), u64init (0x80deb1fe, 0x3b1696b1), + u64init (0x9bdc06a7, 0x25c71235), u64init (0xc19bf174, 0xcf692694), + u64init (0xe49b69c1, 0x9ef14ad2), u64init (0xefbe4786, 0x384f25e3), + u64init (0x0fc19dc6, 0x8b8cd5b5), u64init (0x240ca1cc, 0x77ac9c65), + u64init (0x2de92c6f, 0x592b0275), u64init (0x4a7484aa, 0x6ea6e483), + u64init (0x5cb0a9dc, 0xbd41fbd4), u64init (0x76f988da, 0x831153b5), + u64init (0x983e5152, 0xee66dfab), u64init (0xa831c66d, 0x2db43210), + u64init (0xb00327c8, 0x98fb213f), u64init (0xbf597fc7, 0xbeef0ee4), + u64init (0xc6e00bf3, 0x3da88fc2), u64init (0xd5a79147, 0x930aa725), + u64init (0x06ca6351, 0xe003826f), u64init (0x14292967, 0x0a0e6e70), + u64init (0x27b70a85, 0x46d22ffc), u64init (0x2e1b2138, 0x5c26c926), + u64init (0x4d2c6dfc, 0x5ac42aed), u64init (0x53380d13, 0x9d95b3df), + u64init (0x650a7354, 0x8baf63de), u64init (0x766a0abb, 0x3c77b2a8), + u64init (0x81c2c92e, 0x47edaee6), u64init (0x92722c85, 0x1482353b), + u64init (0xa2bfe8a1, 0x4cf10364), u64init (0xa81a664b, 0xbc423001), + u64init (0xc24b8b70, 0xd0f89791), u64init (0xc76c51a3, 0x0654be30), + u64init (0xd192e819, 0xd6ef5218), u64init (0xd6990624, 0x5565a910), + u64init (0xf40e3585, 0x5771202a), u64init (0x106aa070, 0x32bbd1b8), + u64init (0x19a4c116, 0xb8d2d0c8), u64init (0x1e376c08, 0x5141ab53), + u64init (0x2748774c, 0xdf8eeb99), u64init (0x34b0bcb5, 0xe19b48a8), + u64init (0x391c0cb3, 0xc5c95a63), u64init (0x4ed8aa4a, 0xe3418acb), + u64init (0x5b9cca4f, 0x7763e373), u64init (0x682e6ff3, 0xd6b2b8a3), + u64init (0x748f82ee, 0x5defb2fc), u64init (0x78a5636f, 0x43172f60), + u64init (0x84c87814, 0xa1f0ab72), u64init (0x8cc70208, 0x1a6439ec), + u64init (0x90befffa, 0x23631e28), u64init (0xa4506ceb, 0xde82bde9), + u64init (0xbef9a3f7, 0xb2c67915), u64init (0xc67178f2, 0xe372532b), + u64init (0xca273ece, 0xea26619c), u64init (0xd186b8c7, 0x21c0c207), + u64init (0xeada7dd6, 0xcde0eb1e), u64init (0xf57d4f7f, 0xee6ed178), + u64init (0x06f067aa, 0x72176fba), u64init (0x0a637dc5, 0xa2c898a6), + u64init (0x113f9804, 0xbef90dae), u64init (0x1b710b35, 0x131c471b), + u64init (0x28db77f5, 0x23047d84), u64init (0x32caab7b, 0x40c72493), + u64init (0x3c9ebe0a, 0x15c9bebc), u64init (0x431d67c4, 0x9c100d4c), + u64init (0x4cc5d4be, 0xcb3e42b6), u64init (0x597f299c, 0xfc657e2a), + u64init (0x5fcb6fab, 0x3ad6faec), u64init (0x6c44198c, 0x4a475817), +}; + +/* Round functions. */ +#define F2(A, B, C) u64or (u64and (A, B), u64and (C, u64or (A, B))) +#define F1(E, F, G) u64xor (G, u64and (E, u64xor (F, G))) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 128 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void +sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx) +{ + u64 const *words = buffer; + u64 const *endp = words + len / sizeof (u64); + u64 x[16]; + u64 a = ctx->state[0]; + u64 b = ctx->state[1]; + u64 c = ctx->state[2]; + u64 d = ctx->state[3]; + u64 e = ctx->state[4]; + u64 f = ctx->state[5]; + u64 g = ctx->state[6]; + u64 h = ctx->state[7]; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^128 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] = u64plus (ctx->total[0], u64lo (len)); + if (u64lt (ctx->total[0], u64lo (len))) + ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); + +#define S0(x) u64xor (u64rol(x, 63), u64xor (u64rol (x, 56), u64shr (x, 7))) +#define S1(x) u64xor (u64rol (x, 45), u64xor (u64rol (x, 3), u64shr (x, 6))) +#define SS0(x) u64xor (u64rol (x, 36), u64xor (u64rol (x, 30), u64rol (x, 25))) +#define SS1(x) u64xor (u64rol(x, 50), u64xor (u64rol (x, 46), u64rol (x, 23))) + +#define M(I) (x[(I) & 15] \ + = u64plus (x[(I) & 15], \ + u64plus (S1 (x[((I) - 2) & 15]), \ + u64plus (x[((I) - 7) & 15], \ + S0 (x[((I) - 15) & 15]))))) + +#define R(A, B, C, D, E, F, G, H, K, M) \ + do \ + { \ + u64 t0 = u64plus (SS0 (A), F2 (A, B, C)); \ + u64 t1 = \ + u64plus (H, u64plus (SS1 (E), \ + u64plus (F1 (E, F, G), u64plus (K, M)))); \ + D = u64plus (D, t1); \ + H = u64plus (t0, t1); \ + } \ + while (0) + + while (words < endp) + { + int t; + /* FIXME: see sha1.c for a better implementation. */ + for (t = 0; t < 16; t++) + { + x[t] = SWAP (*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + R( a, b, c, d, e, f, g, h, K(64), M(64) ); + R( h, a, b, c, d, e, f, g, K(65), M(65) ); + R( g, h, a, b, c, d, e, f, K(66), M(66) ); + R( f, g, h, a, b, c, d, e, K(67), M(67) ); + R( e, f, g, h, a, b, c, d, K(68), M(68) ); + R( d, e, f, g, h, a, b, c, K(69), M(69) ); + R( c, d, e, f, g, h, a, b, K(70), M(70) ); + R( b, c, d, e, f, g, h, a, K(71), M(71) ); + R( a, b, c, d, e, f, g, h, K(72), M(72) ); + R( h, a, b, c, d, e, f, g, K(73), M(73) ); + R( g, h, a, b, c, d, e, f, K(74), M(74) ); + R( f, g, h, a, b, c, d, e, K(75), M(75) ); + R( e, f, g, h, a, b, c, d, K(76), M(76) ); + R( d, e, f, g, h, a, b, c, K(77), M(77) ); + R( c, d, e, f, g, h, a, b, K(78), M(78) ); + R( b, c, d, e, f, g, h, a, K(79), M(79) ); + + a = ctx->state[0] = u64plus (ctx->state[0], a); + b = ctx->state[1] = u64plus (ctx->state[1], b); + c = ctx->state[2] = u64plus (ctx->state[2], c); + d = ctx->state[3] = u64plus (ctx->state[3], d); + e = ctx->state[4] = u64plus (ctx->state[4], e); + f = ctx->state[5] = u64plus (ctx->state[5], f); + g = ctx->state[6] = u64plus (ctx->state[6], g); + h = ctx->state[7] = u64plus (ctx->state[7], h); + } +} diff --git a/sha512.h b/sha512.h new file mode 100644 index 0000000..ea85194 --- /dev/null +++ b/sha512.h @@ -0,0 +1,95 @@ +/* Declarations of functions and data types used for SHA512 and SHA384 sum + library functions. + Copyright (C) 2005, 2006, 2008, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef SHA512_H +# define SHA512_H 1 + +# include + +# include "u64.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/* Structure to save state of computation between the single steps. */ +struct sha512_ctx +{ + u64 state[8]; + + u64 total[2]; + size_t buflen; + u64 buffer[32]; +}; + +enum { SHA384_DIGEST_SIZE = 384 / 8 }; +enum { SHA512_DIGEST_SIZE = 512 / 8 }; + +/* Initialize structure containing state of computation. */ +extern void sha512_init_ctx (struct sha512_ctx *ctx); +extern void sha384_init_ctx (struct sha512_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 128!!! */ +extern void sha512_process_block (const void *buffer, size_t len, + struct sha512_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 128. */ +extern void sha512_process_bytes (const void *buffer, size_t len, + struct sha512_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 64 (48) bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf); +extern void *sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 64 (48) bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf); +extern void *sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf); + + +/* Compute SHA512 (SHA384) message digest for bytes read from STREAM. The + resulting message digest number will be written into the 64 (48) bytes + beginning at RESBLOCK. */ +extern int sha512_stream (FILE *stream, void *resblock); +extern int sha384_stream (FILE *stream, void *resblock); + +/* Compute SHA512 (SHA384) message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha512_buffer (const char *buffer, size_t len, void *resblock); +extern void *sha384_buffer (const char *buffer, size_t len, void *resblock); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/u64.h b/u64.h new file mode 100644 index 0000000..0d35c55 --- /dev/null +++ b/u64.h @@ -0,0 +1,159 @@ +/* uint64_t-like operations that work even on hosts lacking uint64_t + + Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert. */ + +#include +#include + +/* Return X rotated left by N bits, where 0 < N < 64. */ +#define u64rol(x, n) u64or (u64shl (x, n), u64shr (x, 64 - n)) + +#ifdef UINT64_MAX + +/* Native implementations are trivial. See below for comments on what + these operations do. */ +typedef uint64_t u64; +# define u64hilo(hi, lo) ((u64) (((u64) (hi) << 32) + (lo))) +# define u64init(hi, lo) u64hilo (hi, lo) +# define u64lo(x) ((u64) (x)) +# define u64lt(x, y) ((x) < (y)) +# define u64and(x, y) ((x) & (y)) +# define u64or(x, y) ((x) | (y)) +# define u64xor(x, y) ((x) ^ (y)) +# define u64plus(x, y) ((x) + (y)) +# define u64shl(x, n) ((x) << (n)) +# define u64shr(x, n) ((x) >> (n)) + +#else + +/* u64 is a 64-bit unsigned integer value. + u64init (HI, LO), is like u64hilo (HI, LO), but for use in + initializer contexts. */ +# ifdef WORDS_BIGENDIAN +typedef struct { uint32_t hi, lo; } u64; +# define u64init(hi, lo) { hi, lo } +# else +typedef struct { uint32_t lo, hi; } u64; +# define u64init(hi, lo) { lo, hi } +# endif + +/* Given the high and low-order 32-bit quantities HI and LO, return a u64 + value representing (HI << 32) + LO. */ +static inline u64 +u64hilo (uint32_t hi, uint32_t lo) +{ + u64 r; + r.hi = hi; + r.lo = lo; + return r; +} + +/* Return a u64 value representing LO. */ +static inline u64 +u64lo (uint32_t lo) +{ + u64 r; + r.hi = 0; + r.lo = lo; + return r; +} + +/* Return X < Y. */ +static inline int +u64lt (u64 x, u64 y) +{ + return x.hi < y.hi || (x.hi == y.hi && x.lo < y.lo); +} + +/* Return X & Y. */ +static inline u64 +u64and (u64 x, u64 y) +{ + u64 r; + r.hi = x.hi & y.hi; + r.lo = x.lo & y.lo; + return r; +} + +/* Return X | Y. */ +static inline u64 +u64or (u64 x, u64 y) +{ + u64 r; + r.hi = x.hi | y.hi; + r.lo = x.lo | y.lo; + return r; +} + +/* Return X ^ Y. */ +static inline u64 +u64xor (u64 x, u64 y) +{ + u64 r; + r.hi = x.hi ^ y.hi; + r.lo = x.lo ^ y.lo; + return r; +} + +/* Return X + Y. */ +static inline u64 +u64plus (u64 x, u64 y) +{ + u64 r; + r.lo = x.lo + y.lo; + r.hi = x.hi + y.hi + (r.lo < x.lo); + return r; +} + +/* Return X << N. */ +static inline u64 +u64shl (u64 x, int n) +{ + u64 r; + if (n < 32) + { + r.hi = (x.hi << n) | (x.lo >> (32 - n)); + r.lo = x.lo << n; + } + else + { + r.hi = x.lo << (n - 32); + r.lo = 0; + } + return r; +} + +/* Return X >> N. */ +static inline u64 +u64shr (u64 x, int n) +{ + u64 r; + if (n < 32) + { + r.hi = x.hi >> n; + r.lo = (x.hi << (32 - n)) | (x.lo >> n); + } + else + { + r.hi = 0; + r.lo = x.hi >> (n - 32); + } + return r; +} + +#endif -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Fri Jul 19 01:25:19 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:25:19 +0100 Subject: [PATCH 8/8] transform: Provide Serpment-EAX transform In-Reply-To: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374193519-19262-9-git-send-email-ijackson@chiark.greenend.org.uk> This provides an alternative to the (rather badly broken) serpent256-cbc transform. In this patch, there is not yet any algorith negotiation for a smooth upgrade, nor any changes to the example configurations. Signed-off-by: Ian Jackson --- Makefile.in | 4 +- README | 5 + modules.c | 1 + secnet.8 | 21 ++++- secnet.h | 3 + transform-eax.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 282 insertions(+), 4 deletions(-) create mode 100644 transform-eax.c diff --git a/Makefile.in b/Makefile.in index 22f9de4..1e4f670 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,9 +53,9 @@ mandir:=@mandir@ TARGETS:=secnet OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ - resolver.o random.o udp.o site.o transform-cbcmac.o \ + resolver.o random.o udp.o site.o transform-cbcmac.o transform-eax.o \ netlink.o rsa.o dh.o \ - serpent.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ + serpent.o md5.o sha512.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ process.o @LIBOBJS@ \ hackypar.o diff --git a/README b/README index 93730e9..fc3bf55 100644 --- a/README +++ b/README @@ -336,6 +336,11 @@ setup but more relaxed about using old keys. These are noted with "mobile:", above, and apply whether the mobile peer is local or remote. +** transform-eax + +Defines: + serpent-eax (closure => transform closure) + ** transform-cbcmac Defines: diff --git a/modules.c b/modules.c index 0290cd4..724ccbb 100644 --- a/modules.c +++ b/modules.c @@ -7,6 +7,7 @@ void init_builtin_modules(dict_t *dict) udp_module(dict); util_module(dict); site_module(dict); + transform_eax_module(dict); transform_cbcmac_module(dict); netlink_module(dict); rsa_module(dict); diff --git a/secnet.8 b/secnet.8 index 869d297..4b1fcff 100644 --- a/secnet.8 +++ b/secnet.8 @@ -415,8 +415,8 @@ A \fIrandomsource closure\fR is a source of random numbers. .PP Read the contents of the file \fIPATH\fR (a string) and return it as a string. -.SS serpent256-cbc -\fBserpent256-cbc(\fIDICT\fB)\fR => \fItransform closure\fR +.SS serpent-eax +\fBserpent-eax(\fIDICT\fB)\fR => \fItransform closure\fR .PP Valid keys in the \fIDICT\fR argument are: .TP @@ -425,11 +425,28 @@ The maximum acceptable difference between the sequence number in a received, decrypted message and the previous one. The default is 10. It may be necessary to increase this is if connectivity is poor. +.TP +.B tag-length-bytes +The length of the message authentication tag. The default is 16, +for a 128-bit tag length. It must be no longer than the Serpent +blocksize, 16. +.TP +.B padding-rounding +Messages are padded to a multiple of this many bytes. This +serves to obscure the exact length of messages. The default is 16, .PP A \fItransform closure\fR is a reversible means of transforming messages for transmission over a (presumably) insecure network. It is responsible for both confidentiality and integrity. +.SS serpent256-cbc +\fBserpent256-cbc(\fIDICT\fB)\fR => \fItransform closure\fR +.PP +Valid keys in the \fIDICT\fR argument are: +.TP +.B max-sequence-skew +As above. + .SS rsa-private \fBrsa-private(\fIPATH\fB\fR[, \fICHECK\fR]\fB)\fR => \fIrsaprivkey closure\fR .TP diff --git a/secnet.h b/secnet.h index 6ad8fc9..af0c1f7 100644 --- a/secnet.h +++ b/secnet.h @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -232,6 +234,7 @@ extern init_module random_module; extern init_module udp_module; extern init_module util_module; extern init_module site_module; +extern init_module transform_eax_module; extern init_module transform_cbcmac_module; extern init_module netlink_module; extern init_module rsa_module; diff --git a/transform-eax.c b/transform-eax.c new file mode 100644 index 0000000..506f05d --- /dev/null +++ b/transform-eax.c @@ -0,0 +1,252 @@ +/* + * eax-transform.c: EAX-Serpent bulk data transformation + * + * We use EAX with the following parameters: + * + * Plaintext: + * Concatenation of: + * Data packet as supplied to us + * Zero or more zero bytes ignored by receiver } padding + * One byte padding length } + * This is a bit like PKCS#5. It helps disguise message lengths. + * It also provides a further room for future expansion. When + * transmitting we pad the message to the next multiple of + * a configurable rounding factor, 16 bytes by default. + * + * Transmitted message: + * Concatenation of: + * EAX ciphertext + * 32-bit sequence number (initially zero) + * The sequence number allows us to discard far-too-old + * packets. + * + * Nonce: + * Concatenation of: + * 32-bit sequence number (big endian) starting at zero + * 1 byte: 0x01 if sender has setup priority, 0x00 if it doesn't + * (ie, the direction of data flow) + * + * Header: None + * + * Tag length: + * 16 bytes (128 bits) by default + * + * Key: + * The first 32 bytes of the SHA-512 hash of the shared secret + * from the DH key exchange (the latter being expressed as + * the shortest possible big-endian octet string). + */ + +#include "secnet.h" +#include "unaligned.h" +#include "util.h" +#include "serpent.h" +#include "sha512.h" +#include "transform-common.h" + +#define BLOCK_SIZE 16 +#define SEQLEN 4 + +struct transform_params { + uint32_t max_seq_skew, tag_length, padding_mask; +}; + +struct transform { + closure_t cl; + struct transform_if ops; + struct transform_params p; +}; + +struct transform_inst { + struct transform_inst_if ops; + struct transform_params p; + unsigned keyed:1; + /* remaining valid iff keyed */ + unsigned direction:1; + uint32_t sendseq; + uint32_t lastrecvseq; + struct keyInstance key; + uint8_t info_b[BLOCK_SIZE], info_p[BLOCK_SIZE]; +}; + +static void block_encrypt(struct transform_inst *transform_inst, + uint8_t dst[BLOCK_SIZE], + const uint8_t src[BLOCK_SIZE]) +{ + serpent_encrypt(&transform_inst->key, src, dst); +} + +#define INFO struct transform_inst *transform_inst +#define I transform_inst +#define EAX_ENTRYPOINT_DECL static +#define BLOCK_ENCRYPT(dst,src) block_encrypt(transform_inst,dst,src) +#define INFO_B (transform_inst->info_b) +#define INFO_P (transform_inst->info_p) + +#include "eax.c" + +static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen, + bool_t direction) +{ + struct transform_inst *ti=sst; + struct sha512_ctx hash_ctx; + uint8_t hash_out[64]; + + sha512_init_ctx(&hash_ctx); + sha512_process_bytes(key, keylen, &hash_ctx); + sha512_finish_ctx(&hash_ctx, hash_out); + + ti->direction=direction; + ti->sendseq=ti->lastrecvseq=0; + serpent_makekey(&ti->key, 32*8, hash_out); + eax_setup(ti); + ti->keyed=True; + + return True; +} + +TRANSFORM_VALID; + +TRANSFORM_DESTROY; + +static void transform_delkey(void *sst) +{ + struct transform_inst *ti=sst; + + FILLZERO(ti->key); + FILLZERO(ti->info_b); + FILLZERO(ti->info_p); + ti->keyed=False; +} + +static uint32_t transform_forward(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + + KEYED_CHECK; + + size_t padlen = ti->p.padding_mask - buf->size; + padlen &= ti->p.padding_mask; + padlen++; + + uint8_t *pad = buf_append(buf,padlen); + memset(pad, 0, padlen-1); + pad[padlen-1] = padlen; + + uint8_t nonce[SEQLEN+1]; + put_uint32(nonce,ti->sendseq); + nonce[SEQLEN] = ti->direction; + + assert(buf_append(buf,ti->p.tag_length)); + eax_encrypt(ti, nonce,sizeof(nonce), 0,0, buf->start,buf->size, + ti->p.tag_length, buf->start); + memcpy(buf_append(buf,SEQLEN), nonce, SEQLEN); + + ti->sendseq++; + + return 0; +} + +static uint32_t transform_reverse(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + + KEYED_CHECK; + + uint8_t nonce[SEQLEN+1]; + const uint8_t *seqp = buf_unappend(buf,SEQLEN); + if (!seqp) goto too_short; + + uint32_t seqnum = get_uint32(seqp); + SEQNUM_CHECK(seqnum, ti->p.max_seq_skew); + + memcpy(nonce,seqp,SEQLEN); + nonce[4] = !ti->direction; + + bool_t ok = eax_decrypt(ti, nonce,sizeof(nonce), 0,0, buf->start,buf->size, + ti->p.tag_length, buf->start); + if (!ok) { + *errmsg="EAX decryption failed"; + return 1; + } + assert(buf->size >= (int)ti->p.tag_length); + buf->size -= ti->p.tag_length; + + const uint8_t *padp = buf_unappend(buf,1); + if (!padp) goto too_short; + + size_t padlen = *padp; + if (!buf_unappend(buf,padlen-1)) goto too_short; + + return 0; + + too_short: + *errmsg="ciphertext or plaintext too short"; + return 1; +} + +static struct transform_inst_if *transform_create(void *sst) +{ + struct transform *st=sst; + + TRANSFORM_CREATE_CORE; + + ti->p=st->p; + + return &ti->ops; +} + +static list_t *transform_apply(closure_t *self, struct cloc loc, + dict_t *context, list_t *args) +{ + struct transform *st; + item_t *item; + dict_t *dict; + + st=safe_malloc(sizeof(*st),"eax-serpent"); + st->cl.description="eax-serpent"; + st->cl.type=CL_TRANSFORM; + st->cl.apply=NULL; + st->cl.interface=&st->ops; + st->ops.st=st; + + /* First parameter must be a dict */ + item=list_elem(args,0); + if (!item || item->type!=t_dict) + cfgfatal(loc,"eax-serpent","parameter must be a dictionary\n"); + dict=item->data.dict; + + st->p.max_seq_skew=dict_read_number(dict, "max-sequence-skew", + False, "eax-serpent", loc, 10); + + st->p.tag_length=dict_read_number(dict, "tag-length-bytes", + False, "eax-serpent", loc, 128/8); + if (st->p.tag_length<1 || st->p.tag_length>BLOCK_SIZE) + cfgfatal(loc,"eax-serpent","tag-length-bytes out of range 0..%d\n", + BLOCK_SIZE); + + uint32_t padding_round=dict_read_number(dict, "padding-rounding", + False, "eax-serpent", loc, 16); + if (padding_round & (padding_round-1)) + cfgfatal(loc,"eax-serpent","padding-round not a power of two\n"); + if (padding_round > 255) + cfgfatal(loc,"eax-serpent","padding-round must be 1..128\n"); + if (padding_round == 0) + padding_round = 1; + st->p.padding_mask = padding_round-1; + + st->ops.max_start_pad=0; + st->ops.max_end_pad= padding_round + st->p.tag_length + SEQLEN; + + st->ops.keylen=0; + st->ops.create=transform_create; + + return new_closure(&st->cl); +} + +void transform_eax_module(dict_t *dict) +{ + add_closure(dict,"serpent-eax",transform_apply); +} -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Fri Jul 19 01:29:04 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 19 Jul 2013 01:29:04 +0100 Subject: [RFC PATCH 0/7] EAX transform In-Reply-To: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374193519-19262-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <20968.34896.55219.460790@chiark.greenend.org.uk> Ian Jackson writes ("[RFC PATCH 0/7] EAX transform"): > Here is another RFC series for review. Here, I provide a new > transform using EAX, Serpent (and SHA512 to hash the DH key). > > 1/7 serpent: const-correct > 2/7 crypto: Copy an AES (Rijndael) implementation into tree > 3/7 EAX: provide an implementation of EAX > 4/7 transform: split out transform-common.h > 5/7 transform: Allow DH to set the key size > 6/7 transform: Pass a direction flag to the transform > 7/7 transform: Provide Serpment-EAX transform This list is wrong. There are eight patches, including: 7/8 crypto: Copy a SHA512 implementation into tree and the last one should be 8/8. > Most of these are quite uninteresting, but the final patch could do > with some proper review. The patch that could do with a proper review is > 8/8 transform: Provide Serpment-EAX transform Sorry, Ian. From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:44 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:44 +0100 Subject: [RFC PATCH v2 00/25] Algorithm agility, new transform, robustness Message-ID: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> This is a portmanteau of my previous three patch series. They have been extensively updated. I think these are mostly complete now, although they have still NOT BEEN TESTED. I'm particularly looking for review of these two patches: 19/25 transform: Provide Serpment-EAX transform I'd like someone to check that what I've implemented is a sane usage of EAX, and ideally that it's lacking in howlers. 11/25 site: interpret first 4 bytes of extrainfo as capabilities It would be good for someone else to double-check my forward-compatibility logic. (With a view not just to the new transform, which I'll test, but also looking forward to a future public key algorithm upgrade.) The biggest problem is that we are using CBC-MAC, which is known to be broken. I plan to fix this by replace our CBC+CBC-MAC transform with EAX. Unfortunately we are lacking algorithm agility. Looking at the NOTES and the code, it is difficult to retrofit this because we're lacking an officially approved space for future expansion covered by the signatures. However, bug to the rescue! It turns out that the string comparison used for checking site names is broken in a way that we can exploit. We therefore perpetrate an awful bodge, and enshrine and document it. This gives us the room to replace the badly broken existing transform with one based on EAX-Serpent. Ideally we would like also to abandon PKCS#1 in favour of OAEP. But I think this is less urgent and wants to be combined with a general public key (and public algorithm) rollover mechanism, which we are currently lacking. The capability mechanism is designed to be able to offer this in the future, but sadly both peers will have to upgrade to the capability-capable version first. Also, there are situations where secnet won't recover properly after a restart of one of the ends. In this series we (mostly) fix this. Due to the inclusion of coreutils's SHA512 implementation, this patch series makes secnet GPLv3+. 01/25 memcmp: Introduce and use consttime_memcmp 02/25 transform: Do not look at any bytes of PKCS#5 padding other than the last 03/25 magic: Introduce LABEL_NAK 04/25 site: Send NAKs for undecryptable data packets (msg0) 05/25 NOTES: Improve documentation of NAKs. 06/25 NOTES: Remove paragraph about slow-to-prepare messages 07/25 NOTES: Remove unimplemented protocol negotiation 08/25 site: fix site name checking leaving room for expansion 09/25 site: Extra info in name fields for MSG1, clearer processing 10/25 site: use unaligned.h's functions, not pointer cast and ntohl 11/25 site: interpret first 4 bytes of extrainfo as capabilities 12/25 serpent: const-correct 13/25 crypto: Copy a SHA512 implementation into tree 14/25 crypto: Copy an AES (Rijndael) implementation into tree 15/25 EAX: provide an implementation of EAX 16/25 transform: split out transform-common.h 17/25 transform: Allow DH to set the key size 18/25 transform: Pass a direction flag to the transform 19/25 transform: Provide Serpment-EAX transform 20/25 site: dynamically create and destroy transform instances 21/25 site, netlink: abolish max_end_pad and min_end_pad 22/25 site, transform: per-transform-instance max_start_pad 23/25 site: support multiple transforms 24/25 Use FORMAT everywhere, and fix up the errors it finds 25/25 site: New PROD message From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:45 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:45 +0100 Subject: [PATCH 01/25] memcmp: Introduce and use consttime_memcmp In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-2-git-send-email-ijackson@chiark.greenend.org.uk> We need to use a constant-time memcmp in MAC checking, to avoid leaking (to an adversary) how much of the MAC is right. (This would be especially dangerous if our MAC was outside the encryption, which thankfully it isn't.) Signed-off-by: Ian Jackson --- site.c | 2 +- transform.c | 2 +- util.c | 23 +++++++++++++++++++++++ util.h | 2 ++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/site.c b/site.c index db65bd8..e96d6f4 100644 --- a/site.c +++ b/site.c @@ -463,7 +463,7 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, return False; } if (type==LABEL_MSG2) return True; - if (memcmp(m->nR,st->remoteN,NONCELEN)!=0) { + if (consttime_memcmp(m->nR,st->remoteN,NONCELEN)!=0) { *error="wrong remotely-generated nonce"; return False; } diff --git a/transform.c b/transform.c index 289b02e..893f41c 100644 --- a/transform.c +++ b/transform.c @@ -220,7 +220,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, serpent_encrypt(&ti->mackey,macplain,macacc); } serpent_encrypt(&ti->mackey,macacc,macacc); - if (memcmp(macexpected,macacc,16)!=0) { + if (consttime_memcmp(macexpected,macacc,16)!=0) { *errmsg="invalid MAC"; return 1; } diff --git a/util.c b/util.c index f5f3d75..e50218c 100644 --- a/util.c +++ b/util.c @@ -363,7 +363,30 @@ static list_t *buffer_apply(closure_t *self, struct cloc loc, dict_t *context, return new_closure(&st->cl); } +static FILE *devnull; + +int consttime_memcmp(const void *s1in, const void *s2in, size_t n) +{ + const uint8_t *s1=s1in, *s2=s2in; + size_t accumulator=0; + + assert(n <= SIZE_MAX/255); + + while (n-- > 0) { + accumulator += (*s1++ ^ *s2++); + } + /* This forces the compiler to actually compute all of the bits of + * accumulator. Hopefully that's enough to stop it shortcutting + * the loop. */ + fwrite(&accumulator,1,sizeof(accumulator),devnull); + + return !!accumulator; +} + void util_module(dict_t *dict) { + devnull=fopen("/dev/null","wb"); + if (!devnull) fatal_perror("could not open /dev/null (for util)"); + add_closure(dict,"sysbuffer",buffer_apply); } diff --git a/util.h b/util.h index af19363..2491fd5 100644 --- a/util.h +++ b/util.h @@ -39,4 +39,6 @@ extern int32_t write_mpbin(MP_INT *a, uint8_t *buffer, int32_t buflen); extern struct log_if *init_log(list_t *loglist); +extern int consttime_memcmp(const void *s1, const void *s2, size_t n); + #endif /* util_h */ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:46 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:46 +0100 Subject: [PATCH 02/25] transform: Do not look at any bytes of PKCS#5 padding other than the last In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-3-git-send-email-ijackson@chiark.greenend.org.uk> This might avoid some timing-related information leaks. In principle this is a protocol change: we now no longer use actual PKCS#5 padding; instead, we use a padding scheme where all but the last byte of the padding may be sent as anything and are ignored by the receiver. Signed-off-by: Ian Jackson --- transform.c | 8 +------- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/transform.c b/transform.c index 893f41c..9ee0df0 100644 --- a/transform.c +++ b/transform.c @@ -234,13 +234,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, return 1; } - padp=buf_unappend(buf,padlen-1); - for (i=0; i References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-4-git-send-email-ijackson@chiark.greenend.org.uk> Replace ad-hoc comments on the message number of NAK packets with an explicit #define. No functional change. Signed-off-by: Ian Jackson --- magic.h | 1 + site.c | 2 +- udp.c | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/magic.h b/magic.h index 5ac1e34..c2503a0c 100644 --- a/magic.h +++ b/magic.h @@ -3,6 +3,7 @@ #ifndef magic_h #define magic_h +#define LABEL_NAK 0x00000000 #define LABEL_MSG0 0x00020200 #define LABEL_MSG1 0x01010101 #define LABEL_MSG2 0x02020202 diff --git a/site.c b/site.c index e96d6f4..b995e52 100644 --- a/site.c +++ b/site.c @@ -1285,7 +1285,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, uint32_t msgtype=ntohl(get_uint32(buf->start+8)); if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); switch (msgtype) { - case 0: /* NAK */ + case LABEL_NAK: /* If the source is our current peer then initiate a key setup, because our peer's forgotten the key */ if (get_uint32(buf->start+4)==st->current.remote_session_id) { diff --git a/udp.c b/udp.c index bbf8c64..77be5b1 100644 --- a/udp.c +++ b/udp.c @@ -21,6 +21,7 @@ #include "util.h" #include "unaligned.h" #include "ipaddr.h" +#include "magic.h" static beforepoll_fn udp_beforepoll; static afterpoll_fn udp_afterpoll; @@ -140,7 +141,7 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds) buffer_init(st->rbuf,0); buf_append_uint32(st->rbuf,dest); buf_append_uint32(st->rbuf,source); - buf_append_uint32(st->rbuf,0); /* NAK is msg type 0 */ + buf_append_uint32(st->rbuf,LABEL_NAK); sendto(st->fd, st->rbuf->start, st->rbuf->size, 0, (struct sockaddr *)&from, sizeof(from)); BUF_FREE(st->rbuf); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:48 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:48 +0100 Subject: [PATCH 04/25] site: Send NAKs for undecryptable data packets (msg0) In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-5-git-send-email-ijackson@chiark.greenend.org.uk> Packets which are not understood are supposed in general to produce NAKs, to let the peer know that we don't have the key they were using. However, previously this would only happen if the incoming packet had a local site index which was not in use. But it can happen that a particular index value is reused by a recently restarted secnet. Previously, in this case, data packets would simply be thrown away undecryptable. With this change, undecryptable data packets always generate a NAK. This is particularly relevant for mobile sites, as it can happen that the fixed site doesn't have an address for the mobile site - so the association will remain stuck in a broken state until the mobile site is also restarted. There is still a potential problem when a site is restarted mid key exchange. The peer will refuse to start a new key exchange (because of the retry timeout) and the restarted site may not know it's necessary. This will be dealt with in a later patch. Signed-off-by: Ian Jackson --- site.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/site.c b/site.c index b995e52..5c73533 100644 --- a/site.c +++ b/site.c @@ -1226,6 +1226,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, const struct comm_addr *source) { struct site *st=sst; + bool_t ok=True; if (buf->size < 12) return False; @@ -1295,7 +1296,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, } break; case LABEL_MSG0: - process_msg0(st,buf,source); + ok=process_msg0(st,buf,source); break; case LABEL_MSG1: /* Setup packet: should not have been explicitly addressed @@ -1382,7 +1383,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, break; } BUF_FREE(buf); - return True; + return ok; } return False; -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:49 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:49 +0100 Subject: [PATCH 05/25] NOTES: Improve documentation of NAKs. In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-6-git-send-email-ijackson@chiark.greenend.org.uk> Improve the description of the function of NAK packets. Document an ancient form of NAK, MSG8. Add a missing heading "Other messages" and put the description of the NAK message and of the obsolete NAK in it. Signed-off-by: Ian Jackson --- NOTES | 41 +++++++++++++++++++++-------------------- 1 files changed, 21 insertions(+), 20 deletions(-) diff --git a/NOTES b/NOTES index 84453df..6a245ec 100644 --- a/NOTES +++ b/NOTES @@ -247,32 +247,33 @@ retransmit or confirm reception. It is suggested that this message be sent when a key times out, or the tunnel is forcibly terminated for some reason. -8) i?,i?,NAK (encoded as zero) +**** Protocol sub-goal 3: send a packet -If the link-layer can't work out what to do with a packet (session has -gone away, etc.) it can transmit a NAK back to the sender. The sender -can then try to verify whether the session is alive by sending ping -packets, and forget the key if it isn't. Potential denial-of-service -if the attacker can stop the ping/pong packets getting through (the -key will be forgotten and another key setup must take place), but if -they can delete packets then we've lost anyway... +8) i?,i?,msg0,(send-packet/msg9,packet)_k -The attacker can of course forge NAKs since they aren't protected. But -if they can only forge packets then they won't be able to stop the -ping/pong working. Trust in NAKs can be rate-limited... +Some messages may take a long time to prepare (software modexp on slow +machines); this is a "please wait" message to indicate that a message +is in preparation. -Alternative idea (which is actually implemented): if you receive a -packet you can't decode, because there's no key established, then -initiate key setup... +**** Other messages -Keepalives are probably a good idea. +9) i?,i?,NAK (NAK is encoded as zero) -**** Protocol sub-goal 3: send a packet +If the link-layer can't work out what to do with a packet (session has +gone away, etc.) it can transmit a NAK back to the sender. -9) i?,i?,msg0,(send-packet/msg9,packet)_k +This can alert the sender to the situation where the sender has a key +but the receiver doesn't (eg because it has been restarted). The +sender, on receiving the NAK, will try to initiate a key exchange. -Some messages may take a long time to prepare (software modexp on slow -machines); this is a "please wait" message to indicate that a message -is in preparation. +Forged (or overly delayed) NAKs can cause wasted resources due to +spurious key exchange initiation, but there is a limit on this because +of the key exchange retry timeout. 10) i?,i?,msg8,A,B,nA,nB,msg? + +This is an obsolete form of NAK packet which is not sent by any even +vaguely recent version of secnet. (In fact, there is no evidence in +the git history of it ever being sent.) + +This message number is reserved. -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:50 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:50 +0100 Subject: [PATCH 06/25] NOTES: Remove paragraph about slow-to-prepare messages In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-7-git-send-email-ijackson@chiark.greenend.org.uk> NOTES contained this paragraph: Some messages may take a long time to prepare (software modexp on slow machines); this is a "please wait" message to indicate that a message is in preparation. This paragraph was immediately after the description of the msg0(msg9) packet - ie, the ordinary data packet. It is therefore at the very least misplaced. In the git history this paragraph was introduced in "Import release 0.1.14" (4f5e39ec). However, the diff for that commit (ie the diff between 0.1.13 and 0.1.4) does not show any code which might correspond to this comment. There is not currently any code in site.c which responds to a message of this kind. I have had a quick look for code which sends such a message and failed to find any. So I think this paragraph represents a never-implemented intent, and should be removed. It certainly predates the "hacky parallelism" by a long way. Signed-off-by: Ian Jackson --- NOTES | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/NOTES b/NOTES index 6a245ec..09c083e 100644 --- a/NOTES +++ b/NOTES @@ -251,10 +251,6 @@ some reason. 8) i?,i?,msg0,(send-packet/msg9,packet)_k -Some messages may take a long time to prepare (software modexp on slow -machines); this is a "please wait" message to indicate that a message -is in preparation. - **** Other messages 9) i?,i?,NAK (NAK is encoded as zero) -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:51 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:51 +0100 Subject: [PATCH 07/25] NOTES: Remove unimplemented protocol negotiation In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-8-git-send-email-ijackson@chiark.greenend.org.uk> The protocol negotiation mechanism documented in NOTES is not implemented. Remove it from the document. Signed-off-by: Ian Jackson --- NOTES | 20 +++++--------------- 1 files changed, 5 insertions(+), 15 deletions(-) diff --git a/NOTES b/NOTES index 09c083e..33c010e 100644 --- a/NOTES +++ b/NOTES @@ -193,21 +193,18 @@ i? is appropriate index for receiver Note that 'i' may be re-used from one session to the next, whereas 'n' is always fresh. -The protocol version selection stuff is not yet implemented: I'm not -yet convinced it's a good idea. Instead, the initiator could try -using its preferred protocol (which starts with a different magic -number) and fall back if there's no reply. +The protocol version selection stuff is not yet implemented. Messages: -1) A->B: *,iA,msg1,A,B,protorange-A,nA +1) A->B: *,iA,msg1,A,B,nA -2) B->A: iA,iB,msg2,B,A,chosen-protocol,nB,nA +2) B->A: iA,iB,msg2,B,A,nB,nA (The order of B and A reverses in alternate messages so that the same code can be used to construct them...) -3) A->B: {iB,iA,msg3,A,B,protorange-A,chosen-protocol,nA,nB,g^x mod m}_PK_A^-1 +3) A->B: {iB,iA,msg3,A,B,nA,nB,g^x mod m}_PK_A^-1 If message 1 was a replay then A will not generate message 3, because it doesn't recognise nA. @@ -215,18 +212,11 @@ it doesn't recognise nA. If message 2 was from an attacker then B will not generate message 4, because it doesn't recognise nB. -If an attacker is trying to manipulate the chosen protocol, B can spot -this when it sees A's message 3. - -4) B->A: {iA,iB,msg4,B,A,protorange-B,chosen-protocol,nB,nA,g^y mod m}_PK_B^-1 +4) B->A: {iA,iB,msg4,B,A,nB,nA,g^y mod m}_PK_B^-1 At this point, A and B share a key, k. B must keep retransmitting message 4 until it receives a packet encrypted using key k. -A can abandon the exchange if the chosen protocol is not the one that -it would have chosen knowing the acceptable protocol ranges of A and -B. - 5) A: iB,iA,msg5,(ping/msg5)_k 6) B: iA,iB,msg6,(pong/msg6)_k -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:52 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:52 +0100 Subject: [PATCH 08/25] site: fix site name checking leaving room for expansion In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-9-git-send-email-ijackson@chiark.greenend.org.uk> Previously, secnet would only check that the site names sent by the peer had the expected site names as prefixes. This would be a security bug on a vpn where one site name is the prefix of another site name. In fact, if the peer sends a short name, secnet will suffer a buffer read overrun and maybe crash - although this is exploitable only for DoS at worst, and not as an information leak. (With reasonable peers, it won't cause packets to be mishandled, because the next field after each name string is a 16-byte integer giving a name or public key byte count, which would have to contain a value greater than 8000 to look like printable characters.) Fix this bug. However, we use this as an opportunity to provide some space (in the signed part of MSG2..4) for future extensions. (At present there is nothing in the parts of MSG3 and MSG4 covered by the signature which is not supposedly entirely fixed - apart from the amount of zero-padding at the MS end of our DH public exponent. This is bad because it provides no way to do transport protocol upgrade/downgrade negotiation without leaving open a protocol version downgrade attack.) After this change the name fields in MSG2..4 are, following the 16-bit length, either just the characters of the name, or the name, followed by a nul byte, followed by zero or more bytes of additional data. Additional data beyond what the receiver expects (which currently means any additional data), is to be ignored. Let us work through some examples. Suppose the expected site name is "expected". Here are the behaviours in relation to various names being transmitted in the packet. (This applies both to the local name, and to the remote name; "rejected" means other instances of the protocol engine get a go, and perhaps the instance with the correct names will accept the message.) MSG Sent name Old secnet New secnet 1 expected ok ok 1 expected\0extra rejected rejected 1 expected/suffix rejected rejected 1 expect rejected rejected 2-4 expected ok ok 2-4 expected\0extra ok, extra ignored ok, extra data 2-4 expected/suffix wrongly accepted rejected 2-4 expect read overrun rejected We will do the same for MSG1 in a later commit. Signed-off-by: Ian Jackson --- NOTES | 11 ++++++----- site.c | 53 +++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/NOTES b/NOTES index 33c010e..ddd14a5 100644 --- a/NOTES +++ b/NOTES @@ -174,8 +174,9 @@ quite stable so the feature doesn't gain us much. Definitions: -A is the originating gateway machine -B is the destination gateway machine +A is the originating gateway machine name +B is the destination gateway machine name +A+ and B+ are the names with optional additional data, currently ignored PK_A is the public RSA key of A PK_B is the public RSA key of B PK_A^-1 is the private RSA key of A @@ -199,12 +200,12 @@ Messages: 1) A->B: *,iA,msg1,A,B,nA -2) B->A: iA,iB,msg2,B,A,nB,nA +2) B->A: iA,iB,msg2,B+,A+,nB,nA (The order of B and A reverses in alternate messages so that the same code can be used to construct them...) -3) A->B: {iB,iA,msg3,A,B,nA,nB,g^x mod m}_PK_A^-1 +3) A->B: {iB,iA,msg3,A+,B+,nA,nB,g^x mod m}_PK_A^-1 If message 1 was a replay then A will not generate message 3, because it doesn't recognise nA. @@ -212,7 +213,7 @@ it doesn't recognise nA. If message 2 was from an attacker then B will not generate message 4, because it doesn't recognise nB. -4) B->A: {iA,iB,msg4,B,A,nB,nA,g^y mod m}_PK_B^-1 +4) B->A: {iA,iB,msg4,B+,A+,nB,nA,g^y mod m}_PK_B^-1 At this point, A and B share a key, k. B must keep retransmitting message 4 until it receives a packet encrypted using key k. diff --git a/site.c b/site.c index 5c73533..cd053e2 100644 --- a/site.c +++ b/site.c @@ -346,14 +346,19 @@ static bool_t current_valid(struct site *st) type=buf_unprepend_uint32((b)); \ if (type!=(t)) return False; } while(0) +struct parsedname { + int32_t len; + uint8_t *name; + int32_t extrainfo_len; + uint8_t *extrainfo; +}; + struct msg { uint8_t *hashstart; uint32_t dest; uint32_t source; - int32_t remlen; - uint8_t *remote; - int32_t loclen; - uint8_t *local; + struct parsedname remote; + struct parsedname local; uint8_t *nR; uint8_t *nL; int32_t pklen; @@ -401,6 +406,24 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) return True; } +static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm) +{ + CHECK_AVAIL(msg,2); + nm->len=buf_unprepend_uint16(msg); + CHECK_AVAIL(msg,nm->len); + nm->name=buf_unprepend(msg,nm->len); + uint8_t *nul=memchr(nm->name,0,nm->len); + if (!nul) { + nm->extrainfo_len=0; + nm->extrainfo=0; + } else { + nm->extrainfo=nul+1; + nm->extrainfo_len=msg->start-nm->extrainfo; + nm->len=nul-nm->name; + } + return True; +} + static bool_t unpick_msg(struct site *st, uint32_t type, struct buffer_if *msg, struct msg *m) { @@ -410,14 +433,8 @@ static bool_t unpick_msg(struct site *st, uint32_t type, CHECK_AVAIL(msg,4); m->source=buf_unprepend_uint32(msg); CHECK_TYPE(msg,type); - CHECK_AVAIL(msg,2); - m->remlen=buf_unprepend_uint16(msg); - CHECK_AVAIL(msg,m->remlen); - m->remote=buf_unprepend(msg,m->remlen); - CHECK_AVAIL(msg,2); - m->loclen=buf_unprepend_uint16(msg); - CHECK_AVAIL(msg,m->loclen); - m->local=buf_unprepend(msg,m->loclen); + if (!unpick_name(msg,&m->remote)) return False; + if (!unpick_name(msg,&m->local)) return False; CHECK_AVAIL(msg,NONCELEN); m->nR=buf_unprepend(msg,NONCELEN); if (type==LABEL_MSG1) { @@ -443,6 +460,14 @@ static bool_t unpick_msg(struct site *st, uint32_t type, return True; } +static bool_t name_matches(const struct parsedname *nm, const char *expected) +{ + int expected_len=strlen(expected); + return + nm->len == expected_len && + !memcmp(nm->name, expected, expected_len); +} + static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, cstring_t *error) { @@ -450,11 +475,11 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, /* Check that the site names and our nonce have been sent back correctly, and then store our peer's nonce. */ - if (memcmp(m->remote,st->remotename,strlen(st->remotename)!=0)) { + if (!name_matches(&m->remote,st->remotename)) { *error="wrong remote site name"; return False; } - if (memcmp(m->local,st->localname,strlen(st->localname)!=0)) { + if (!name_matches(&m->local,st->localname)) { *error="wrong local site name"; return False; } -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:53 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:53 +0100 Subject: [PATCH 09/25] site: Extra info in name fields for MSG1, clearer processing In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-10-git-send-email-ijackson@chiark.greenend.org.uk> We change the parsing of the names in MSG1 packets to align it with that used for MSG2..4, abolishing the simple memcmp-based "setupsig" arrangement. This means that MSG1 packets, like MSG2..4, can contain extra information in the name fields. This results in the following table of behaviours (where "old secnet" is the version before we introduced additional data at all): MSG Sent name Old secnet New secnet 1 expected ok ok 1 expected\0extra rejected ok, extra data 1 expected/suffix rejected rejected 1 expect rejected rejected 2-4 expected ok ok 2-4 expected\0extra ok, extra ignored ok, extra data 2-4 expected/suffix wrongly accepted rejected 2-4 expect read overrun rejected After the new secnet is widely deployed, we will be able to use the extra data field in MSG1 for public key algorithm agility and public key rollover. Also, intend to introduce a new packet which (like MSG1) is addressed by name rather than the site id; this change makes that easier too. In detail, we: * Make site_incoming extract the message type earlier, and use the message type to choose how to check the address. * Abolish st->setupsig and st->setupsiglen; * Break out a function named_for_us, which uses unpick_msg and then checks the names; * Arrange to keep the unpicked message from named_for_us and reuse it in process_msg1. * Eliminate checking dest==0 for name-addressed packets. This last point constitutes a change to the implemented protocol. The old code would treat a packet as name-addressed iff the destination "index" was zero. However, the requirement to send a zero in this field is not documented. After this patch, peers which send MSG1 with a non-zero destination index will have their messages honoured rather than discarded. But we do document the restriction. There is no other significant functional implication of this last point. Peers which send non-MSG1s with zero destination index will have their packets rejected both before and afterwards (although there may be a change in whether a NAK is sent and in logging) but anyway those peers are broken because all of our generated indexes are nonzero. A downside of this change is that we will now unpick an incoming MSG1 repeatedly until we find which site instance wants it. But this unpicking is not particularly arduous. Signed-off-by: Ian Jackson --- NOTES | 5 ++- site.c | 114 +++++++++++++++++++++++++++++---------------------------------- 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/NOTES b/NOTES index ddd14a5..3e9d71d 100644 --- a/NOTES +++ b/NOTES @@ -198,7 +198,10 @@ The protocol version selection stuff is not yet implemented. Messages: -1) A->B: *,iA,msg1,A,B,nA +1) A->B: *,iA,msg1,A+,B+,nA + +i* must be encoded as 0. (However, it is permitted for a site to use +zero as its "index" for another site.) 2) B->A: iA,iB,msg2,B+,A+,nB,nA diff --git a/site.c b/site.c index cd053e2..7857956 100644 --- a/site.c +++ b/site.c @@ -253,9 +253,6 @@ struct site { after this time, initiate a new key exchange */ - uint8_t *setupsig; /* Expected signature of incoming MSG1 packets */ - int32_t setupsiglen; /* Allows us to discard packets quickly if - they are not for us */ bool_t setup_priority; /* Do we have precedence if both sites emit message 1 simultaneously? */ uint32_t log_events; @@ -505,19 +502,15 @@ static bool_t generate_msg1(struct site *st) } static bool_t process_msg1(struct site *st, struct buffer_if *msg1, - const struct comm_addr *src) + const struct comm_addr *src, struct msg *m) { - struct msg m; - /* We've already determined we're in an appropriate state to process an incoming MSG1, and that the MSG1 has correct values of A and B. */ - if (!unpick_msg(st,LABEL_MSG1,msg1,&m)) return False; - transport_record_peer(st,&st->setup_peers,src,"msg1"); - st->setup_session_id=m.source; - memcpy(st->remoteN,m.nR,NONCELEN); + st->setup_session_id=m->source; + memcpy(st->remoteN,m->nR,NONCELEN); return True; } @@ -1245,6 +1238,16 @@ static void site_outgoing(void *sst, struct buffer_if *buf) initiate_key_setup(st,"outgoing packet"); } +static bool_t named_for_us(struct site *st, struct buffer_if *buf, + uint32_t type, struct msg *m) + /* For packets which are identified by the local and remote names. + * If it has our name and our peer's name in it it's for us. */ +{ + return unpick_msg(st,type,buf,m) + && name_matches(&m->remote,st->remotename) + && name_matches(&m->local,st->localname); +} + /* This function is called by the communication device to deliver packets from our peers. */ static bool_t site_incoming(void *sst, struct buffer_if *buf, @@ -1255,60 +1258,57 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, if (buf->size < 12) return False; + uint32_t msgtype=ntohl(get_uint32(buf->start+8)); uint32_t dest=ntohl(*(uint32_t *)buf->start); - - if (dest==0) { - /* It could be for any site - it should have LABEL_MSG1 and - might have our name and our peer's name in it */ - if (buf->size<(st->setupsiglen+8+NONCELEN)) return False; - if (memcmp(buf->start+8,st->setupsig,st->setupsiglen)==0) { - /* It's addressed to us. Decide what to do about it. */ - dump_packet(st,buf,source,True); - if (st->state==SITE_RUN || st->state==SITE_RESOLVE || - st->state==SITE_WAIT) { - /* We should definitely process it */ - if (process_msg1(st,buf,source)) { - slog(st,LOG_SETUP_INIT,"key setup initiated by peer"); + struct msg named_msg; + + if (msgtype==LABEL_MSG1) { + if (!named_for_us(st,buf,msgtype,&named_msg)) + return False; + /* It's a MSG1 addressed to us. Decide what to do about it. */ + dump_packet(st,buf,source,True); + if (st->state==SITE_RUN || st->state==SITE_RESOLVE || + st->state==SITE_WAIT) { + /* We should definitely process it */ + if (process_msg1(st,buf,source,&named_msg)) { + slog(st,LOG_SETUP_INIT,"key setup initiated by peer"); + enter_new_state(st,SITE_SENTMSG2); + } else { + slog(st,LOG_ERROR,"failed to process incoming msg1"); + } + BUF_FREE(buf); + return True; + } else if (st->state==SITE_SENTMSG1) { + /* We've just sent a message 1! They may have crossed on + the wire. If we have priority then we ignore the + incoming one, otherwise we process it as usual. */ + if (st->setup_priority) { + BUF_FREE(buf); + slog(st,LOG_DUMP,"crossed msg1s; we are higher " + "priority => ignore incoming msg1"); + return True; + } else { + slog(st,LOG_DUMP,"crossed msg1s; we are lower " + "priority => use incoming msg1"); + if (process_msg1(st,buf,source,&named_msg)) { + BUF_FREE(&st->buffer); /* Free our old message 1 */ enter_new_state(st,SITE_SENTMSG2); } else { - slog(st,LOG_ERROR,"failed to process incoming msg1"); + slog(st,LOG_ERROR,"failed to process an incoming " + "crossed msg1 (we have low priority)"); } BUF_FREE(buf); return True; - } else if (st->state==SITE_SENTMSG1) { - /* We've just sent a message 1! They may have crossed on - the wire. If we have priority then we ignore the - incoming one, otherwise we process it as usual. */ - if (st->setup_priority) { - BUF_FREE(buf); - slog(st,LOG_DUMP,"crossed msg1s; we are higher " - "priority => ignore incoming msg1"); - return True; - } else { - slog(st,LOG_DUMP,"crossed msg1s; we are lower " - "priority => use incoming msg1"); - if (process_msg1(st,buf,source)) { - BUF_FREE(&st->buffer); /* Free our old message 1 */ - enter_new_state(st,SITE_SENTMSG2); - } else { - slog(st,LOG_ERROR,"failed to process an incoming " - "crossed msg1 (we have low priority)"); - } - BUF_FREE(buf); - return True; - } } - /* The message 1 was received at an unexpected stage of the - key setup. XXX POLICY - what do we do? */ - slog(st,LOG_UNEXPECTED,"unexpected incoming message 1"); - BUF_FREE(buf); - return True; } - return False; /* Not for us. */ + /* The message 1 was received at an unexpected stage of the + key setup. XXX POLICY - what do we do? */ + slog(st,LOG_UNEXPECTED,"unexpected incoming message 1"); + BUF_FREE(buf); + return True; } if (dest==st->index) { /* Explicitly addressed to us */ - uint32_t msgtype=ntohl(get_uint32(buf->start+8)); if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); switch (msgtype) { case LABEL_NAK: @@ -1557,14 +1557,6 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, /* The information we expect to see in incoming messages of type 1 */ /* fixme: lots of unchecked overflows here, but the results are only corrupted packets rather than undefined behaviour */ - st->setupsiglen=strlen(st->remotename)+strlen(st->localname)+8; - st->setupsig=safe_malloc(st->setupsiglen,"site_apply"); - put_uint32(st->setupsig+0,LABEL_MSG1); - put_uint16(st->setupsig+4,strlen(st->remotename)); - memcpy(&st->setupsig[6],st->remotename,strlen(st->remotename)); - put_uint16(st->setupsig+(6+strlen(st->remotename)),strlen(st->localname)); - memcpy(&st->setupsig[8+strlen(st->remotename)],st->localname, - strlen(st->localname)); st->setup_priority=(strcmp(st->localname,st->remotename)>0); buffer_new(&st->buffer,SETUP_BUFFER_LEN); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:05 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:05 +0100 Subject: [PATCH 21/25] site, netlink: abolish max_end_pad and min_end_pad In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-22-git-send-email-ijackson@chiark.greenend.org.uk> There is much code to compute these values, but they are never used anywhere. Signed-off-by: Ian Jackson --- netlink.c | 5 +---- netlink.h | 1 - secnet.h | 11 ++++------- site.c | 4 +--- transform-cbcmac.c | 1 - transform-eax.c | 1 - udp.c | 1 - 7 files changed, 6 insertions(+), 18 deletions(-) diff --git a/netlink.c b/netlink.c index 486df6f..f94058a 100644 --- a/netlink.c +++ b/netlink.c @@ -811,14 +811,12 @@ static void netlink_inst_set_mtu(void *sst, int32_t new_mtu) } static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver, - void *dst, int32_t max_start_pad, - int32_t max_end_pad) + void *dst, int32_t max_start_pad) { struct netlink_client *c=sst; struct netlink *st=c->nst; if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad; - if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad; c->deliver=deliver; c->dst=dst; } @@ -947,7 +945,6 @@ netlink_deliver_fn *netlink_init(struct netlink *st, st->cl.apply=netlink_inst_apply; st->cl.interface=st; st->max_start_pad=0; - st->max_end_pad=0; st->clients=NULL; st->routes=NULL; st->n_clients=0; diff --git a/netlink.h b/netlink.h index ffefd80..c89cc63 100644 --- a/netlink.h +++ b/netlink.h @@ -42,7 +42,6 @@ struct netlink { void *dst; /* Pointer to host interface state */ cstring_t name; int32_t max_start_pad; - int32_t max_end_pad; struct ipset *networks; /* Local networks */ struct subnet_list *subnets; /* Same as networks, for display */ struct ipset *remote_networks; /* Allowable remote networks */ diff --git a/secnet.h b/secnet.h index af0c1f7..41578b4 100644 --- a/secnet.h +++ b/secnet.h @@ -341,7 +341,6 @@ typedef const char *comm_addr_to_string_fn(void *commst, struct comm_if { void *st; int32_t min_start_pad; - int32_t min_end_pad; comm_request_notify_fn *request_notify; comm_release_notify_fn *release_notify; comm_sendmsg_fn *sendmsg; @@ -379,8 +378,8 @@ struct site_if { /* TRANSFORM interface */ /* A reversable transformation. Transforms buffer in-place; may add - data to start or end. Maximum amount of data to be added specified - in max_start_pad and max_end_pad. (Reverse transformations decrease + data to start or end. Maximum amount of data to be added before + the packet specified in max_start_pad. (Reverse transformations decrease length, of course.) Transformations may be key-dependent, in which case key material is passed in at initialisation time. They may also depend on internal factors (eg. time) and keep internal @@ -416,8 +415,7 @@ struct transform_inst_if { struct transform_if { void *st; - int32_t max_start_pad; /* these three are all <<< INT_MAX */ - int32_t max_end_pad; + int32_t max_start_pad; /* these two are both <<< INT_MAX */ int32_t keylen; /* 0 means give the transform exactly as much as there is */ transform_createinstance_fn *create; }; @@ -440,8 +438,7 @@ typedef void netlink_deliver_fn(void *st, struct buffer_if *buf); #define MAXIMUM_LINK_QUALITY 3 typedef void netlink_link_quality_fn(void *st, uint32_t quality); typedef void netlink_register_fn(void *st, netlink_deliver_fn *deliver, - void *dst, int32_t max_start_pad, - int32_t max_end_pad); + void *dst, int32_t max_start_pad); typedef void netlink_output_config_fn(void *st, struct buffer_if *buf); typedef bool_t netlink_check_config_fn(void *st, struct buffer_if *buf); typedef void netlink_set_mtu_fn(void *st, int32_t new_mtu); diff --git a/site.c b/site.c index eb8460a..817d5e4 100644 --- a/site.c +++ b/site.c @@ -1661,13 +1661,11 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, worst_##pad=thispad; \ } COMPUTE_WORST(min_start_pad) - COMPUTE_WORST(min_end_pad) /* We need to register the remote networks with the netlink device */ st->netlink->reg(st->netlink->st, site_outgoing, st, st->transform->max_start_pad+(4*4)+ - worst_min_start_pad, - st->transform->max_end_pad+worst_min_end_pad); + worst_min_start_pad); for (i=0; incomms; i++) st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming); diff --git a/transform-cbcmac.c b/transform-cbcmac.c index b163d33..5640ad8 100644 --- a/transform-cbcmac.c +++ b/transform-cbcmac.c @@ -264,7 +264,6 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, st->ops.st=st; st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV, 4byte IV */ - st->ops.max_end_pad=16; /* 16byte CBCMAC */ /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits for CBCMAC-IV, and 32 bits for init sequence number */ diff --git a/transform-eax.c b/transform-eax.c index 506f05d..f126408 100644 --- a/transform-eax.c +++ b/transform-eax.c @@ -238,7 +238,6 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, st->p.padding_mask = padding_round-1; st->ops.max_start_pad=0; - st->ops.max_end_pad= padding_round + st->p.tag_length + SEQLEN; st->ops.keylen=0; st->ops.create=transform_create; diff --git a/udp.c b/udp.c index 77be5b1..ba110fc 100644 --- a/udp.c +++ b/udp.c @@ -290,7 +290,6 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context, st->cl.interface=&st->ops; st->ops.st=st; st->ops.min_start_pad=0; - st->ops.min_end_pad=0; st->ops.request_notify=request_notify; st->ops.release_notify=release_notify; st->ops.sendmsg=udp_sendmsg; -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:02 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:02 +0100 Subject: [PATCH 18/25] transform: Pass a direction flag to the transform In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-19-git-send-email-ijackson@chiark.greenend.org.uk> The same transform is used for inbound and outbound packets. The transform should know which direction these packets are flowing in; that (a) allows a transform to reject packets which are "looping back" so to speak, and (b) makes it easier for a transform to generate unique nonces. This will be used by the forthcoming EAX transform. It is combined with the sequence number (the same values of which are used by both ends) to make the nonce, which must be unique across the single shared key, ie unique across both flows. Signed-off-by: Ian Jackson --- secnet.h | 7 +++++-- site.c | 4 ++-- transform-cbcmac.c | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/secnet.h b/secnet.h index 23d62ba..6ad8fc9 100644 --- a/secnet.h +++ b/secnet.h @@ -383,10 +383,13 @@ struct site_if { also depend on internal factors (eg. time) and keep internal state. A struct transform_if only represents a particular type of transformation; instances of the transformation (eg. with - particular key material) have a different C type. */ + particular key material) have a different C type. The same + secret key will be used in opposite directions between a pair of + secnets; one of these pairs will get direction==False, the other True. */ typedef struct transform_inst_if *transform_createinstance_fn(void *st); -typedef bool_t transform_setkey_fn(void *st, uint8_t *key, int32_t keylen); +typedef bool_t transform_setkey_fn(void *st, uint8_t *key, int32_t keylen, + bool_t direction); typedef bool_t transform_valid_fn(void *st); /* 0: no key; 1: ok */ typedef void transform_delkey_fn(void *st); typedef void transform_destroyinstance_fn(void *st); diff --git a/site.c b/site.c index a0416d8..5042af5 100644 --- a/site.c +++ b/site.c @@ -642,7 +642,7 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen); + st->sharedsecretlen,st->setup_priority); return True; } @@ -689,7 +689,7 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen); + st->sharedsecretlen,st->setup_priority); return True; } diff --git a/transform-cbcmac.c b/transform-cbcmac.c index 7b97ce9..b163d33 100644 --- a/transform-cbcmac.c +++ b/transform-cbcmac.c @@ -39,7 +39,8 @@ struct transform_inst { #define PKCS5_MASK 15 -static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) +static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen, + bool_t direction) { struct transform_inst *ti=sst; -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:57 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:57 +0100 Subject: [PATCH 13/25] crypto: Copy a SHA512 implementation into tree In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-14-git-send-email-ijackson@chiark.greenend.org.uk> We are going to want an implementation of SHA512 (initially for hashing DH secrets into EAX keys). Copy the version from coreutils 8.5, along with u64.h. In this patch, we commit exactly the files from coreutils. They will be made to compile later. Doing it this way means we can more easily isolate changes we have to make. Copying these files from coreutils makes secnet GPL-3+. Signed-off-by: Ian Jackson --- COPYING | 914 ++++++++++++++++++++++++++++++++++++++++++-------------------- sha512.c | 619 ++++++++++++++++++++++++++++++++++++++++++ sha512.h | 95 +++++++ u64.h | 159 +++++++++++ 4 files changed, 1497 insertions(+), 290 deletions(-) create mode 100644 sha512.c create mode 100644 sha512.h create mode 100644 u64.h diff --git a/COPYING b/COPYING index 60549be..94a9ed0 100644 --- a/COPYING +++ b/COPYING @@ -1,285 +1,626 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of this License. - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least +state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -304,37 +645,30 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/sha512.c b/sha512.c new file mode 100644 index 0000000..5c0b2ed --- /dev/null +++ b/sha512.c @@ -0,0 +1,619 @@ +/* sha512.c - Functions to compute SHA512 and SHA384 message digest of files or + memory blocks according to the NIST specification FIPS-180-2. + + Copyright (C) 2005, 2006, 2008, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by David Madore, considerably copypasting from + Scott G. Miller's sha1.c +*/ + +#include + +#include "sha512.h" + +#include +#include +#include + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + u64or (u64or (u64or (u64shl (n, 56), \ + u64shl (u64and (n, u64lo (0x0000ff00)), 40)), \ + u64or (u64shl (u64and (n, u64lo (0x00ff0000)), 24), \ + u64shl (u64and (n, u64lo (0xff000000)), 8))), \ + u64or (u64or (u64and (u64shr (n, 8), u64lo (0xff000000)), \ + u64and (u64shr (n, 24), u64lo (0x00ff0000))), \ + u64or (u64and (u64shr (n, 40), u64lo (0x0000ff00)), \ + u64shr (n, 56)))) +#endif + +#define BLOCKSIZE 32768 +#if BLOCKSIZE % 128 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 128-byte boundary. */ +static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 512 bit block of data (eight 64 bit ints) and + intializes it to the start constants of the SHA512 algorithm. This + must be called before using hash in the call to sha512_hash +*/ +void +sha512_init_ctx (struct sha512_ctx *ctx) +{ + ctx->state[0] = u64hilo (0x6a09e667, 0xf3bcc908); + ctx->state[1] = u64hilo (0xbb67ae85, 0x84caa73b); + ctx->state[2] = u64hilo (0x3c6ef372, 0xfe94f82b); + ctx->state[3] = u64hilo (0xa54ff53a, 0x5f1d36f1); + ctx->state[4] = u64hilo (0x510e527f, 0xade682d1); + ctx->state[5] = u64hilo (0x9b05688c, 0x2b3e6c1f); + ctx->state[6] = u64hilo (0x1f83d9ab, 0xfb41bd6b); + ctx->state[7] = u64hilo (0x5be0cd19, 0x137e2179); + + ctx->total[0] = ctx->total[1] = u64lo (0); + ctx->buflen = 0; +} + +void +sha384_init_ctx (struct sha512_ctx *ctx) +{ + ctx->state[0] = u64hilo (0xcbbb9d5d, 0xc1059ed8); + ctx->state[1] = u64hilo (0x629a292a, 0x367cd507); + ctx->state[2] = u64hilo (0x9159015a, 0x3070dd17); + ctx->state[3] = u64hilo (0x152fecd8, 0xf70e5939); + ctx->state[4] = u64hilo (0x67332667, 0xffc00b31); + ctx->state[5] = u64hilo (0x8eb44a87, 0x68581511); + ctx->state[6] = u64hilo (0xdb0c2e0d, 0x64f98fa7); + ctx->state[7] = u64hilo (0x47b5481d, 0xbefa4fa4); + + ctx->total[0] = ctx->total[1] = u64lo (0); + ctx->buflen = 0; +} + +/* Copy the value from V into the memory location pointed to by *CP, + If your architecture allows unaligned access, this is equivalent to + * (__typeof__ (v) *) cp = v */ +static inline void +set_uint64 (char *cp, u64 v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 64 bytes following RESBUF. + The result must be in little endian byte order. */ +void * +sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 8; i++) + set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +void * +sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 6; i++) + set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +static void +sha512_conclude_ctx (struct sha512_ctx *ctx) +{ + /* Take yet unprocessed bytes into account. */ + size_t bytes = ctx->buflen; + size_t size = (bytes < 112) ? 128 / 8 : 128 * 2 / 8; + + /* Now count remaining bytes. */ + ctx->total[0] = u64plus (ctx->total[0], u64lo (bytes)); + if (u64lt (ctx->total[0], u64lo (bytes))) + ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); + + /* Put the 128-bit file length in *bits* at the end of the buffer. + Use set_uint64 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint64 ((char *) &ctx->buffer[size - 2], + SWAP (u64or (u64shl (ctx->total[1], 3), + u64shr (ctx->total[0], 61)))); + set_uint64 ((char *) &ctx->buffer[size - 1], + SWAP (u64shl (ctx->total[0], 3))); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes); + + /* Process last bytes. */ + sha512_process_block (ctx->buffer, size * 8, ctx); +} + +void * +sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf) +{ + sha512_conclude_ctx (ctx); + return sha512_read_ctx (ctx, resbuf); +} + +void * +sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf) +{ + sha512_conclude_ctx (ctx); + return sha384_read_ctx (ctx, resbuf); +} + +/* Compute SHA512 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 64 bytes + beginning at RESBLOCK. */ +int +sha512_stream (FILE *stream, void *resblock) +{ + struct sha512_ctx ctx; + size_t sum; + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + /* Initialize the computation context. */ + sha512_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + { + free (buffer); + return 1; + } + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 128 == 0 + */ + sha512_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha512_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha512_finish_ctx (&ctx, resblock); + free (buffer); + return 0; +} + +/* FIXME: Avoid code duplication */ +int +sha384_stream (FILE *stream, void *resblock) +{ + struct sha512_ctx ctx; + size_t sum; + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + /* Initialize the computation context. */ + sha384_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + { + free (buffer); + return 1; + } + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 128 == 0 + */ + sha512_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha512_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha384_finish_ctx (&ctx, resblock); + free (buffer); + return 0; +} + +/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +sha512_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha512_ctx ctx; + + /* Initialize the computation context. */ + sha512_init_ctx (&ctx); + + /* Process whole buffer but last len % 128 bytes. */ + sha512_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha512_finish_ctx (&ctx, resblock); +} + +void * +sha384_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha512_ctx ctx; + + /* Initialize the computation context. */ + sha384_init_ctx (&ctx); + + /* Process whole buffer but last len % 128 bytes. */ + sha512_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha384_finish_ctx (&ctx, resblock); +} + +void +sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 256 - left_over > len ? len : 256 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 128) + { + sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx); + + ctx->buflen &= 127; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~127], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 128) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (u64) != 0) + if (UNALIGNED_P (buffer)) + while (len > 128) + { + sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128, ctx); + buffer = (const char *) buffer + 128; + len -= 128; + } + else +#endif + { + sha512_process_block (buffer, len & ~127, ctx); + buffer = (const char *) buffer + (len & ~127); + len &= 127; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 128) + { + sha512_process_block (ctx->buffer, 128, ctx); + left_over -= 128; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha512.c --- */ + +/* SHA512 round constants */ +#define K(I) sha512_round_constants[I] +static u64 const sha512_round_constants[80] = { + u64init (0x428a2f98, 0xd728ae22), u64init (0x71374491, 0x23ef65cd), + u64init (0xb5c0fbcf, 0xec4d3b2f), u64init (0xe9b5dba5, 0x8189dbbc), + u64init (0x3956c25b, 0xf348b538), u64init (0x59f111f1, 0xb605d019), + u64init (0x923f82a4, 0xaf194f9b), u64init (0xab1c5ed5, 0xda6d8118), + u64init (0xd807aa98, 0xa3030242), u64init (0x12835b01, 0x45706fbe), + u64init (0x243185be, 0x4ee4b28c), u64init (0x550c7dc3, 0xd5ffb4e2), + u64init (0x72be5d74, 0xf27b896f), u64init (0x80deb1fe, 0x3b1696b1), + u64init (0x9bdc06a7, 0x25c71235), u64init (0xc19bf174, 0xcf692694), + u64init (0xe49b69c1, 0x9ef14ad2), u64init (0xefbe4786, 0x384f25e3), + u64init (0x0fc19dc6, 0x8b8cd5b5), u64init (0x240ca1cc, 0x77ac9c65), + u64init (0x2de92c6f, 0x592b0275), u64init (0x4a7484aa, 0x6ea6e483), + u64init (0x5cb0a9dc, 0xbd41fbd4), u64init (0x76f988da, 0x831153b5), + u64init (0x983e5152, 0xee66dfab), u64init (0xa831c66d, 0x2db43210), + u64init (0xb00327c8, 0x98fb213f), u64init (0xbf597fc7, 0xbeef0ee4), + u64init (0xc6e00bf3, 0x3da88fc2), u64init (0xd5a79147, 0x930aa725), + u64init (0x06ca6351, 0xe003826f), u64init (0x14292967, 0x0a0e6e70), + u64init (0x27b70a85, 0x46d22ffc), u64init (0x2e1b2138, 0x5c26c926), + u64init (0x4d2c6dfc, 0x5ac42aed), u64init (0x53380d13, 0x9d95b3df), + u64init (0x650a7354, 0x8baf63de), u64init (0x766a0abb, 0x3c77b2a8), + u64init (0x81c2c92e, 0x47edaee6), u64init (0x92722c85, 0x1482353b), + u64init (0xa2bfe8a1, 0x4cf10364), u64init (0xa81a664b, 0xbc423001), + u64init (0xc24b8b70, 0xd0f89791), u64init (0xc76c51a3, 0x0654be30), + u64init (0xd192e819, 0xd6ef5218), u64init (0xd6990624, 0x5565a910), + u64init (0xf40e3585, 0x5771202a), u64init (0x106aa070, 0x32bbd1b8), + u64init (0x19a4c116, 0xb8d2d0c8), u64init (0x1e376c08, 0x5141ab53), + u64init (0x2748774c, 0xdf8eeb99), u64init (0x34b0bcb5, 0xe19b48a8), + u64init (0x391c0cb3, 0xc5c95a63), u64init (0x4ed8aa4a, 0xe3418acb), + u64init (0x5b9cca4f, 0x7763e373), u64init (0x682e6ff3, 0xd6b2b8a3), + u64init (0x748f82ee, 0x5defb2fc), u64init (0x78a5636f, 0x43172f60), + u64init (0x84c87814, 0xa1f0ab72), u64init (0x8cc70208, 0x1a6439ec), + u64init (0x90befffa, 0x23631e28), u64init (0xa4506ceb, 0xde82bde9), + u64init (0xbef9a3f7, 0xb2c67915), u64init (0xc67178f2, 0xe372532b), + u64init (0xca273ece, 0xea26619c), u64init (0xd186b8c7, 0x21c0c207), + u64init (0xeada7dd6, 0xcde0eb1e), u64init (0xf57d4f7f, 0xee6ed178), + u64init (0x06f067aa, 0x72176fba), u64init (0x0a637dc5, 0xa2c898a6), + u64init (0x113f9804, 0xbef90dae), u64init (0x1b710b35, 0x131c471b), + u64init (0x28db77f5, 0x23047d84), u64init (0x32caab7b, 0x40c72493), + u64init (0x3c9ebe0a, 0x15c9bebc), u64init (0x431d67c4, 0x9c100d4c), + u64init (0x4cc5d4be, 0xcb3e42b6), u64init (0x597f299c, 0xfc657e2a), + u64init (0x5fcb6fab, 0x3ad6faec), u64init (0x6c44198c, 0x4a475817), +}; + +/* Round functions. */ +#define F2(A, B, C) u64or (u64and (A, B), u64and (C, u64or (A, B))) +#define F1(E, F, G) u64xor (G, u64and (E, u64xor (F, G))) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 128 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void +sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx) +{ + u64 const *words = buffer; + u64 const *endp = words + len / sizeof (u64); + u64 x[16]; + u64 a = ctx->state[0]; + u64 b = ctx->state[1]; + u64 c = ctx->state[2]; + u64 d = ctx->state[3]; + u64 e = ctx->state[4]; + u64 f = ctx->state[5]; + u64 g = ctx->state[6]; + u64 h = ctx->state[7]; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^128 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] = u64plus (ctx->total[0], u64lo (len)); + if (u64lt (ctx->total[0], u64lo (len))) + ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); + +#define S0(x) u64xor (u64rol(x, 63), u64xor (u64rol (x, 56), u64shr (x, 7))) +#define S1(x) u64xor (u64rol (x, 45), u64xor (u64rol (x, 3), u64shr (x, 6))) +#define SS0(x) u64xor (u64rol (x, 36), u64xor (u64rol (x, 30), u64rol (x, 25))) +#define SS1(x) u64xor (u64rol(x, 50), u64xor (u64rol (x, 46), u64rol (x, 23))) + +#define M(I) (x[(I) & 15] \ + = u64plus (x[(I) & 15], \ + u64plus (S1 (x[((I) - 2) & 15]), \ + u64plus (x[((I) - 7) & 15], \ + S0 (x[((I) - 15) & 15]))))) + +#define R(A, B, C, D, E, F, G, H, K, M) \ + do \ + { \ + u64 t0 = u64plus (SS0 (A), F2 (A, B, C)); \ + u64 t1 = \ + u64plus (H, u64plus (SS1 (E), \ + u64plus (F1 (E, F, G), u64plus (K, M)))); \ + D = u64plus (D, t1); \ + H = u64plus (t0, t1); \ + } \ + while (0) + + while (words < endp) + { + int t; + /* FIXME: see sha1.c for a better implementation. */ + for (t = 0; t < 16; t++) + { + x[t] = SWAP (*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + R( a, b, c, d, e, f, g, h, K(64), M(64) ); + R( h, a, b, c, d, e, f, g, K(65), M(65) ); + R( g, h, a, b, c, d, e, f, K(66), M(66) ); + R( f, g, h, a, b, c, d, e, K(67), M(67) ); + R( e, f, g, h, a, b, c, d, K(68), M(68) ); + R( d, e, f, g, h, a, b, c, K(69), M(69) ); + R( c, d, e, f, g, h, a, b, K(70), M(70) ); + R( b, c, d, e, f, g, h, a, K(71), M(71) ); + R( a, b, c, d, e, f, g, h, K(72), M(72) ); + R( h, a, b, c, d, e, f, g, K(73), M(73) ); + R( g, h, a, b, c, d, e, f, K(74), M(74) ); + R( f, g, h, a, b, c, d, e, K(75), M(75) ); + R( e, f, g, h, a, b, c, d, K(76), M(76) ); + R( d, e, f, g, h, a, b, c, K(77), M(77) ); + R( c, d, e, f, g, h, a, b, K(78), M(78) ); + R( b, c, d, e, f, g, h, a, K(79), M(79) ); + + a = ctx->state[0] = u64plus (ctx->state[0], a); + b = ctx->state[1] = u64plus (ctx->state[1], b); + c = ctx->state[2] = u64plus (ctx->state[2], c); + d = ctx->state[3] = u64plus (ctx->state[3], d); + e = ctx->state[4] = u64plus (ctx->state[4], e); + f = ctx->state[5] = u64plus (ctx->state[5], f); + g = ctx->state[6] = u64plus (ctx->state[6], g); + h = ctx->state[7] = u64plus (ctx->state[7], h); + } +} diff --git a/sha512.h b/sha512.h new file mode 100644 index 0000000..ea85194 --- /dev/null +++ b/sha512.h @@ -0,0 +1,95 @@ +/* Declarations of functions and data types used for SHA512 and SHA384 sum + library functions. + Copyright (C) 2005, 2006, 2008, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef SHA512_H +# define SHA512_H 1 + +# include + +# include "u64.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/* Structure to save state of computation between the single steps. */ +struct sha512_ctx +{ + u64 state[8]; + + u64 total[2]; + size_t buflen; + u64 buffer[32]; +}; + +enum { SHA384_DIGEST_SIZE = 384 / 8 }; +enum { SHA512_DIGEST_SIZE = 512 / 8 }; + +/* Initialize structure containing state of computation. */ +extern void sha512_init_ctx (struct sha512_ctx *ctx); +extern void sha384_init_ctx (struct sha512_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 128!!! */ +extern void sha512_process_block (const void *buffer, size_t len, + struct sha512_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 128. */ +extern void sha512_process_bytes (const void *buffer, size_t len, + struct sha512_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 64 (48) bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf); +extern void *sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 64 (48) bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf); +extern void *sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf); + + +/* Compute SHA512 (SHA384) message digest for bytes read from STREAM. The + resulting message digest number will be written into the 64 (48) bytes + beginning at RESBLOCK. */ +extern int sha512_stream (FILE *stream, void *resblock); +extern int sha384_stream (FILE *stream, void *resblock); + +/* Compute SHA512 (SHA384) message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha512_buffer (const char *buffer, size_t len, void *resblock); +extern void *sha384_buffer (const char *buffer, size_t len, void *resblock); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/u64.h b/u64.h new file mode 100644 index 0000000..0d35c55 --- /dev/null +++ b/u64.h @@ -0,0 +1,159 @@ +/* uint64_t-like operations that work even on hosts lacking uint64_t + + Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert. */ + +#include +#include + +/* Return X rotated left by N bits, where 0 < N < 64. */ +#define u64rol(x, n) u64or (u64shl (x, n), u64shr (x, 64 - n)) + +#ifdef UINT64_MAX + +/* Native implementations are trivial. See below for comments on what + these operations do. */ +typedef uint64_t u64; +# define u64hilo(hi, lo) ((u64) (((u64) (hi) << 32) + (lo))) +# define u64init(hi, lo) u64hilo (hi, lo) +# define u64lo(x) ((u64) (x)) +# define u64lt(x, y) ((x) < (y)) +# define u64and(x, y) ((x) & (y)) +# define u64or(x, y) ((x) | (y)) +# define u64xor(x, y) ((x) ^ (y)) +# define u64plus(x, y) ((x) + (y)) +# define u64shl(x, n) ((x) << (n)) +# define u64shr(x, n) ((x) >> (n)) + +#else + +/* u64 is a 64-bit unsigned integer value. + u64init (HI, LO), is like u64hilo (HI, LO), but for use in + initializer contexts. */ +# ifdef WORDS_BIGENDIAN +typedef struct { uint32_t hi, lo; } u64; +# define u64init(hi, lo) { hi, lo } +# else +typedef struct { uint32_t lo, hi; } u64; +# define u64init(hi, lo) { lo, hi } +# endif + +/* Given the high and low-order 32-bit quantities HI and LO, return a u64 + value representing (HI << 32) + LO. */ +static inline u64 +u64hilo (uint32_t hi, uint32_t lo) +{ + u64 r; + r.hi = hi; + r.lo = lo; + return r; +} + +/* Return a u64 value representing LO. */ +static inline u64 +u64lo (uint32_t lo) +{ + u64 r; + r.hi = 0; + r.lo = lo; + return r; +} + +/* Return X < Y. */ +static inline int +u64lt (u64 x, u64 y) +{ + return x.hi < y.hi || (x.hi == y.hi && x.lo < y.lo); +} + +/* Return X & Y. */ +static inline u64 +u64and (u64 x, u64 y) +{ + u64 r; + r.hi = x.hi & y.hi; + r.lo = x.lo & y.lo; + return r; +} + +/* Return X | Y. */ +static inline u64 +u64or (u64 x, u64 y) +{ + u64 r; + r.hi = x.hi | y.hi; + r.lo = x.lo | y.lo; + return r; +} + +/* Return X ^ Y. */ +static inline u64 +u64xor (u64 x, u64 y) +{ + u64 r; + r.hi = x.hi ^ y.hi; + r.lo = x.lo ^ y.lo; + return r; +} + +/* Return X + Y. */ +static inline u64 +u64plus (u64 x, u64 y) +{ + u64 r; + r.lo = x.lo + y.lo; + r.hi = x.hi + y.hi + (r.lo < x.lo); + return r; +} + +/* Return X << N. */ +static inline u64 +u64shl (u64 x, int n) +{ + u64 r; + if (n < 32) + { + r.hi = (x.hi << n) | (x.lo >> (32 - n)); + r.lo = x.lo << n; + } + else + { + r.hi = x.lo << (n - 32); + r.lo = 0; + } + return r; +} + +/* Return X >> N. */ +static inline u64 +u64shr (u64 x, int n) +{ + u64 r; + if (n < 32) + { + r.hi = x.hi >> n; + r.lo = (x.hi << (32 - n)) | (x.lo >> n); + } + else + { + r.hi = 0; + r.lo = x.hi >> (n - 32); + } + return r; +} + +#endif -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:58 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:58 +0100 Subject: [PATCH 14/25] crypto: Copy an AES (Rijndael) implementation into tree In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-15-git-send-email-ijackson@chiark.greenend.org.uk> We are going to want an implementation of AES so that we can run publicly-provided test vectors of our EAX implementation. qemu seem to have a version with a fairly convenient shape, so lift it wholesale into our tree, from upstream qemu (their git commit 55616505876d6683130076b810a27c7889321560). The files in this patch are _exactly_ as copied from that qemu tree, so that we can separate out our own changes. Signed-off-by: Ian Jackson --- aes.c | 1314 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ aes.h | 26 ++ 2 files changed, 1340 insertions(+), 0 deletions(-) create mode 100644 aes.c create mode 100644 aes.h diff --git a/aes.c b/aes.c new file mode 100644 index 0000000..eb37adb --- /dev/null +++ b/aes.c @@ -0,0 +1,1314 @@ +/** + * + * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project. + */ +/* + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "qemu-common.h" +#include "aes.h" + +#ifndef NDEBUG +#define NDEBUG +#endif + +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +/* This controls loop-unrolling in aes_core.c */ +#undef FULL_UNROLL +# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) +# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +static const u32 Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +static const u32 Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +static const u32 Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +static const u32 Te3[256] = { + + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; +static const u32 Te4[256] = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; +static const u32 Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +static const u32 Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; +static const u32 Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; +static const u32 Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; +static const u32 Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; +static const u32 rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +/** + * Expand the cipher key into the encryption key schedule. + */ +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) { + + u32 *rk; + int i = 0; + u32 temp; + + if (!userKey || !key) + return -1; + if (bits != 128 && bits != 192 && bits != 256) + return -2; + + rk = key->rd_key; + + if (bits==128) + key->rounds = 10; + else if (bits==192) + key->rounds = 12; + else + key->rounds = 14; + + rk[0] = GETU32(userKey ); + rk[1] = GETU32(userKey + 4); + rk[2] = GETU32(userKey + 8); + rk[3] = GETU32(userKey + 12); + if (bits == 128) { + while (1) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 0; + } + rk += 4; + } + } + rk[4] = GETU32(userKey + 16); + rk[5] = GETU32(userKey + 20); + if (bits == 192) { + while (1) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + return 0; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(userKey + 24); + rk[7] = GETU32(userKey + 28); + if (bits == 256) { + while (1) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + return 0; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +/** + * Expand the cipher key into the decryption key schedule. + */ +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) { + + u32 *rk; + int i, j, status; + u32 temp; + + /* first, start with an encryption schedule */ + status = AES_set_encrypt_key(userKey, bits, key); + if (status < 0) + return status; + + rk = key->rd_key; + + /* invert the order of the round keys: */ + for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < (key->rounds); i++) { + rk += 4; + rk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + return 0; +} + +#ifndef AES_ASM +/* + * Encrypt a single block + * in and out can overlap + */ +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) { + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +/* + * Decrypt a single block + * in and out can overlap + */ +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) { + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out , s0); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +#endif /* AES_ASM */ + +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc) +{ + + unsigned long n; + unsigned long len = length; + unsigned char tmp[AES_BLOCK_SIZE]; + + assert(in && out && key && ivec); + + if (enc) { + while (len >= AES_BLOCK_SIZE) { + for(n=0; n < AES_BLOCK_SIZE; ++n) + tmp[n] = in[n] ^ ivec[n]; + AES_encrypt(tmp, out, key); + memcpy(ivec, out, AES_BLOCK_SIZE); + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (len) { + for(n=0; n < len; ++n) + tmp[n] = in[n] ^ ivec[n]; + for(n=len; n < AES_BLOCK_SIZE; ++n) + tmp[n] = ivec[n]; + AES_encrypt(tmp, tmp, key); + memcpy(out, tmp, AES_BLOCK_SIZE); + memcpy(ivec, tmp, AES_BLOCK_SIZE); + } + } else { + while (len >= AES_BLOCK_SIZE) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(in, out, key); + for(n=0; n < AES_BLOCK_SIZE; ++n) + out[n] ^= ivec[n]; + memcpy(ivec, tmp, AES_BLOCK_SIZE); + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (len) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(tmp, tmp, key); + for(n=0; n < len; ++n) + out[n] = tmp[n] ^ ivec[n]; + memcpy(ivec, tmp, AES_BLOCK_SIZE); + } + } +} diff --git a/aes.h b/aes.h new file mode 100644 index 0000000..a0167eb --- /dev/null +++ b/aes.h @@ -0,0 +1,26 @@ +#ifndef QEMU_AES_H +#define QEMU_AES_H + +#define AES_MAXNR 14 +#define AES_BLOCK_SIZE 16 + +struct aes_key_st { + uint32_t rd_key[4 *(AES_MAXNR + 1)]; + int rounds; +}; +typedef struct aes_key_st AES_KEY; + +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); + +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc); + +#endif -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:07 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:07 +0100 Subject: [PATCH 23/25] site: support multiple transforms In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-24-git-send-email-ijackson@chiark.greenend.org.uk> The "transform" key in site's dictionary argument can now be a list, as well as just a single transform. We use 16 bits of the capability mechanism to advertise the transforms we support; the config is supposed to nominate a transform capability number (from 0 to 15) for each transform closure - although the default numbers are sufficient if you don't need to do parameter rollover. The receiver of MSG2 intersects the two bitmaps and chooses the best transform, and states its choice in MSG3. A protocol downgrade attack is prevented by the fact that the capability bitmaps are advertised in the signed parts of MSG3 and MSG4. (If the one in MSG4 doesn't match what was in MSG2, the MSG4 is rejected and presumably the key exchange fails.) Signed-off-by: Ian Jackson --- NOTES | 2 +- example.conf | 4 +- magic.h | 28 +++++++- secnet.8 | 27 +++++++- secnet.h | 1 + site.c | 173 ++++++++++++++++++++++++++++++++++----------- test-example/common.conf | 4 +- transform-cbcmac.c | 2 + transform-common.h | 10 +++ transform-eax.c | 2 + 10 files changed, 199 insertions(+), 54 deletions(-) diff --git a/NOTES b/NOTES index 8619ee5..7ead923 100644 --- a/NOTES +++ b/NOTES @@ -232,7 +232,7 @@ zero as its "index" for another site.) (The order of B and A reverses in alternate messages so that the same code can be used to construct them...) -3) A->B: {iB,iA,msg3,A+,B+,nA,nB,g^x mod m}_PK_A^-1 +3) A->B: {iB,iA,msg3,A+,B+,[chosen-transform],nA,nB,g^x mod m}_PK_A^-1 If message 1 was a replay then A will not generate message 3, because it doesn't recognise nA. diff --git a/example.conf b/example.conf index d6908ff..ab40d05 100644 --- a/example.conf +++ b/example.conf @@ -148,9 +148,7 @@ local-name "your-site-name"; local-key rsa-private("/etc/secnet/key"); # On dodgy links you may want to specify a higher maximum sequence number skew -transform serpent256-cbc { - max-sequence-skew 10; -}; +transform eax-serpent, serpent256-cbc; include /etc/secnet/sites.conf diff --git a/magic.h b/magic.h index 3ae7af4..f2ba3a0 100644 --- a/magic.h +++ b/magic.h @@ -16,7 +16,31 @@ #define LABEL_MSG9 0x09090909 /* uses of the 32-bit capability bitmap */ -/* no flags currently defined */ -#define CAPAB_EARLY 0x00000000 /* no Early flags defined (see NOTES) */ +#define CAPAB_EARLY 0x00000000 /* no Early flags yet (see NOTES) */ +#define CAPAB_TRANSFORM_MASK 0x0000ffff +/* remaining 16 bits are unused */ + +/* + * The transform capability mask is a set of bits, one for each + * transform supported. The transform capability numbers are set in + * the configuration (and should correspond between the two sites), + * although there are sensible defaults. + * + * Iff both ends' transform capability masks are nonempty, MSG3 + * contains an additional byte specifying the transform capability + * number actually chosen by the MSG3 sender. + * + * Aside from that, an empty bitmask is treated the same as + * 1u< \fItransform closure\fR .PP +This transform +is deprecated as its security properties are poor; it should be +specified only alongside a better transform such as eax-serpent. +.PP Valid keys in the \fIDICT\fR argument are: .TP +.B capab-num +As above. The default for serpent256-cbc is 8. +.TP .B max-sequence-skew As above. @@ -518,8 +536,13 @@ An \fIrsapubkey closure\fR. The key used to verify the peer's identity. .TP .B transform -A \fItransform closure\fR. -Used to protect packets exchanged with the peer. +One or more \fItransform closures\fR. +Used to protect packets exchanged with the peer. These should +all have distinct \fBcapab-num\fR values, and the same \fBcapab-num\fR +value should refer to the same (or a compatible) transform at both +ends. The list should be in order of preference, most preferred +first. (The end which sends MSG1,MSG3 ends up choosing; the ordering +at the other end is irrelevant.) .TP .B dh A \fIdh closure\fR. diff --git a/secnet.h b/secnet.h index 3db0f6c..4dd5c03 100644 --- a/secnet.h +++ b/secnet.h @@ -418,6 +418,7 @@ struct transform_if { void *st; int32_t max_start_pad; /* these two are both <<< INT_MAX */ int32_t keylen; /* 0 means give the transform exactly as much as there is */ + int capab_transformnum; transform_createinstance_fn *create; }; diff --git a/site.c b/site.c index 35c2814..df45fd8 100644 --- a/site.c +++ b/site.c @@ -239,7 +239,8 @@ struct site { struct random_if *random; struct rsaprivkey_if *privkey; struct rsapubkey_if *pubkey; - struct transform_if *transform; + struct transform_if **transforms; + int ntransforms; struct dh_if *dh; struct hash_if *hash; @@ -277,6 +278,7 @@ struct site { timeout before we can listen for another setup packet); perhaps we should keep a list of 'bad' sources for setup packets. */ uint32_t remote_capabilities; + struct transform_if *chosen_transform; uint32_t setup_session_id; transport_peers setup_peers; uint8_t localN[NONCELEN]; /* Nonces for key exchange */ @@ -287,7 +289,7 @@ struct site { uint64_t timeout; /* Timeout for current state */ uint8_t *dhsecret; uint8_t *sharedsecret; - uint32_t sharedsecretlen; + uint32_t sharedsecretlen, sharedsecretallocd; struct transform_inst_if *new_transform; /* For key setup/verify */ }; @@ -360,6 +362,7 @@ struct msg { struct parsedname remote; struct parsedname local; uint32_t remote_capabilities; + int capab_transformnum; uint8_t *nR; uint8_t *nL; int32_t pklen; @@ -369,9 +372,23 @@ struct msg { char *sig; }; -static void set_new_transform(struct site *st) +static void set_new_transform(struct site *st, char *pk) { - struct transform_if *generator=st->transform; + /* Make room for the shared key */ + st->sharedsecretlen=st->chosen_transform->keylen?:st->dh->ceil_len; + assert(st->sharedsecretlen); + if (st->sharedsecretlen > st->sharedsecretallocd) { + st->sharedsecretallocd=st->sharedsecretlen; + st->sharedsecret=realloc(st->sharedsecret,st->sharedsecretallocd); + } + if (!st->sharedsecret) fatal_perror("site:sharedsecret"); + + /* Generate the shared key */ + st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,pk, + st->sharedsecret,st->sharedsecretlen); + + /* Set up the transform */ + struct transform_if *generator=st->chosen_transform; struct transform_inst_if *new_transform=generator->create(generator->st); new_transform->setkey(new_transform->st,st->sharedsecret, st->sharedsecretlen,st->setup_priority); @@ -380,6 +397,19 @@ static void set_new_transform(struct site *st) st->new_transform->destroy(st->new_transform->st); } st->new_transform=new_transform; + + slog(st,LOG_SETUP_INIT,"key exchange negotiated transform" + " capab-num=%d (capabilities ours=%#"PRIx32" theirs=%#"PRIx32")", + st->chosen_transform->capab_transformnum, + st->local_capabilities, st->remote_capabilities); +} + +static bool_t msg_specifies_transform(struct site *st, uint32_t msgtype) +{ + return + (msgtype==LABEL_MSG3) && + (st->local_capabilities & CAPAB_TRANSFORM_MASK) && + (st->remote_capabilities & CAPAB_TRANSFORM_MASK); } struct xinfoadd { @@ -441,6 +471,10 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) if (hacky_par_mid_failnow()) return False; + if (msg_specifies_transform(st,type)) + *(uint8_t*)buf_append(&st->buffer,1)= + st->chosen_transform->capab_transformnum; + dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->len); buf_append_string(&st->buffer,dhpub); free(dhpub); @@ -475,6 +509,7 @@ static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm) static bool_t unpick_msg(struct site *st, uint32_t type, struct buffer_if *msg, struct msg *m) { + m->capab_transformnum=-1; m->hashstart=msg->start; CHECK_AVAIL(msg,4); m->dest=buf_unprepend_uint32(msg); @@ -500,6 +535,12 @@ static bool_t unpick_msg(struct site *st, uint32_t type, CHECK_EMPTY(msg); return True; } + if (msg_specifies_transform(st,type)) { + CHECK_AVAIL(msg,1); + m->capab_transformnum = *(uint8_t*)buf_unprepend(msg,1); + } else { + m->capab_transformnum = CAPAB_TRANSFORMNUM_ANCIENT; + } CHECK_AVAIL(msg,2); m->pklen=buf_unprepend_uint16(msg); CHECK_AVAIL(msg,m->pklen); @@ -596,6 +637,29 @@ static bool_t process_msg2(struct site *st, struct buffer_if *msg2, } st->setup_session_id=m.source; st->remote_capabilities=m.remote_capabilities; + + /* Select the transform to use */ + + uint32_t remote_transforms = st->remote_capabilities & CAPAB_TRANSFORM_MASK; + if (!remote_transforms) + /* old secnets only had this one transform */ + remote_transforms = 1UL << CAPAB_TRANSFORMNUM_ANCIENT; + + struct transform_if *ti; + int i; + for (i=0; intransforms; i++) { + ti=st->transforms[i]; + if ((1UL << ti->capab_transformnum) & remote_transforms) + goto transform_found; + } + slog(st,LOG_ERROR,"no transforms in common" + " (us %#"PRIx32"; them: %#"PRIx32")", + st->local_capabilities & CAPAB_TRANSFORM_MASK, + remote_transforms); + return False; + transform_found: + st->chosen_transform=ti; + memcpy(st->remoteN,m.nR,NONCELEN); return True; } @@ -631,6 +695,19 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, } st->remote_capabilities|=m.remote_capabilities; + struct transform_if *ti; + int i; + for (i=0; intransforms; i++) { + ti=st->transforms[i]; + if (ti->capab_transformnum == m.capab_transformnum) + goto transform_found; + } + slog(st,LOG_SEC,"peer chose unknown-to-us transform %d!", + m.capab_transformnum); + return False; + transform_found: + st->chosen_transform=ti; + /* Check signature and store g^x mod m */ hash=safe_malloc(st->hash->len, "process_msg3"); hst=st->hash->init(); @@ -650,12 +727,8 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, /* Invent our DH secret key */ st->random->generate(st->random->st,st->dh->len,st->dhsecret); - /* Generate the shared key */ - st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->sharedsecretlen); - - /* Set up the transform */ - set_new_transform(st); + /* Generate the shared key and set up the transform */ + set_new_transform(st,m.pk); return True; } @@ -697,11 +770,9 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, /* Terminate their DH public key with a '0' */ m.pk[m.pklen]=0; - /* Generate the shared key */ - st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->sharedsecretlen); - /* Set up the transform */ - set_new_transform(st); + + /* Generate the shared key and set up the transform */ + set_new_transform(st,m.pk); return True; } @@ -1558,19 +1629,25 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->local_capabilities = 0; st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc); - list_t *comms_cfg=dict_lookup(dict,"comm"); - if (!comms_cfg) cfgfatal(loc,"site","closure list \"comm\" not found\n"); - st->ncomms=list_length(comms_cfg); - st->comms=safe_malloc_ary(sizeof(*st->comms),st->ncomms,"comms"); - assert(st->ncomms); - for (i=0; incomms; i++) { - item_t *item=list_elem(comms_cfg,i); - if (item->type!=t_closure) - cfgfatal(loc,"site","comm is not a closure\n"); - closure_t *cl=item->data.closure; - if (cl->type!=CL_COMM) cfgfatal(loc,"site","comm closure wrong type\n"); - st->comms[i]=cl->interface; - } +#define GET_CLOSURE_LIST(dictkey,things,nthings,CL_TYPE) do{ \ + list_t *closures_cfg=dict_lookup(dict,dictkey); \ + if (!closures_cfg) \ + cfgfatal(loc,"site","closure list \"%s\" not found\n",dictkey); \ + st->nthings=list_length(closures_cfg); \ + st->things=safe_malloc_ary(sizeof(*st->things),st->nthings,dictkey "s"); \ + assert(st->nthings); \ + for (i=0; inthings; i++) { \ + item_t *item=list_elem(closures_cfg,i); \ + if (item->type!=t_closure) \ + cfgfatal(loc,"site","%s is not a closure\n",dictkey); \ + closure_t *cl=item->data.closure; \ + if (cl->type!=CL_TYPE) \ + cfgfatal(loc,"site","%s closure wrong type\n",dictkey); \ + st->things[i]=cl->interface; \ + } \ +}while(0) + + GET_CLOSURE_LIST("comm",comms,ncomms,CL_COMM); st->resolver=find_cl_if(dict,"resolver",CL_RESOLVER,True,"site",loc); st->log=find_cl_if(dict,"log",CL_LOG,True,"site",loc); @@ -1583,8 +1660,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, else st->remoteport=0; st->pubkey=find_cl_if(dict,"key",CL_RSAPUBKEY,True,"site",loc); - st->transform= - find_cl_if(dict,"transform",CL_TRANSFORM,True,"site",loc); + GET_CLOSURE_LIST("transform",transforms,ntransforms,CL_TRANSFORM); st->dh=find_cl_if(dict,"dh",CL_DH,True,"site",loc); st->hash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc); @@ -1643,29 +1719,40 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->timeout=0; st->remote_capabilities=0; + st->chosen_transform=0; st->current.key_timeout=0; st->auxiliary_key.key_timeout=0; transport_peers_clear(st,&st->peers); transport_peers_clear(st,&st->setup_peers); /* XXX mlock these */ st->dhsecret=safe_malloc(st->dh->len,"site:dhsecret"); - st->sharedsecretlen=st->transform->keylen?:st->dh->ceil_len; - st->sharedsecret=safe_malloc(st->sharedsecretlen,"site:sharedsecret"); - - /* We need to compute some properties of our comms */ -#define COMPUTE_WORST(pad) \ - int worst_##pad=0; \ - for (i=0; incomms; i++) { \ - int thispad=st->comms[i]->pad; \ - if (thispad > worst_##pad) \ - worst_##pad=thispad; \ + st->sharedsecretlen=st->sharedsecretallocd=0; + st->sharedsecret=0; + + /* We need to compute some properties of our comms and transports */ +#define COMPUTE_WORST(things,pad) \ + int things##_worst_##pad=0; \ + for (i=0; in##things; i++) { \ + int thispad=st->things[i]->pad; \ + if (thispad > things##_worst_##pad) \ + things##_worst_##pad=thispad; \ + } + COMPUTE_WORST(comms,min_start_pad) + COMPUTE_WORST(transforms,max_start_pad) + + for (i=0; intransforms; i++) { + struct transform_if *ti=st->transforms[i]; + uint32_t capbit = 1UL << ti->capab_transformnum; + if (st->local_capabilities & capbit) + slog(st,LOG_ERROR,"transformnum capability bit" + " %d (%#"PRIx32") reused", ti->capab_transformnum, capbit); + st->local_capabilities |= capbit; } - COMPUTE_WORST(min_start_pad) /* We need to register the remote networks with the netlink device */ st->netlink->reg(st->netlink->st, site_outgoing, st, - st->transform->max_start_pad+(4*4)+ - worst_min_start_pad); + transforms_worst_max_start_pad+(4*4)+ + comms_worst_min_start_pad); for (i=0; incomms; i++) st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming); diff --git a/test-example/common.conf b/test-example/common.conf index 64bfc81..f41eab7 100644 --- a/test-example/common.conf +++ b/test-example/common.conf @@ -8,8 +8,6 @@ resolver adns { }; log-events "all"; random randomfile("/dev/urandom",no); -transform serpent256-cbc { - max-sequence-skew 10; -}; +transform eax-serpent, serpent256-cbc; include test-example/sites.conf sites map(site,vpn/test-example/all-sites); diff --git a/transform-cbcmac.c b/transform-cbcmac.c index 5640ad8..302160f 100644 --- a/transform-cbcmac.c +++ b/transform-cbcmac.c @@ -279,6 +279,8 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, st->max_seq_skew=dict_read_number(dict, "max-sequence-skew", False, "serpent-cbc256", loc, 10); + SET_CAPAB_TRANSFORMNUM(CAPAB_TRANSFORMNUM_SERPENT256CBC); + return new_closure(&st->cl); } diff --git a/transform-common.h b/transform-common.h index de19817..52f6067 100644 --- a/transform-common.h +++ b/transform-common.h @@ -2,6 +2,8 @@ #ifndef TRANSFORM_COMMON_H #define TRANSFORM_COMMON_H +#include "magic.h" + #define KEYED_CHECK do{ \ if (!ti->keyed) { \ *errmsg="transform unkeyed"; \ @@ -40,6 +42,14 @@ free(st); \ } +#define SET_CAPAB_TRANSFORMNUM(def) do{ \ + st->ops.capab_transformnum=dict_read_number(dict, "capab-num", \ + False, "transform", loc, def); \ + if (st->ops.capab_transformnum > CAPAB_TRANSFORMNUM_MAX) \ + cfgfatal(loc,"transform","capab-num out of range 0..%d\n", \ + CAPAB_TRANSFORMNUM_MAX); \ + }while(0) + #define TRANSFORM_CREATE_CORE \ struct transform_inst *ti; \ ti=safe_malloc(sizeof(*ti),"transform_create"); \ diff --git a/transform-eax.c b/transform-eax.c index f126408..0a47d5f 100644 --- a/transform-eax.c +++ b/transform-eax.c @@ -218,6 +218,8 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, cfgfatal(loc,"eax-serpent","parameter must be a dictionary\n"); dict=item->data.dict; + SET_CAPAB_TRANSFORMNUM(CAPAB_TRANSFORMNUM_EAXSERPENT); + st->p.max_seq_skew=dict_read_number(dict, "max-sequence-skew", False, "eax-serpent", loc, 10); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:08 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:08 +0100 Subject: [PATCH 24/25] Use FORMAT everywhere, and fix up the errors it finds In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-25-git-send-email-ijackson@chiark.greenend.org.uk> Many printf-like variadic functions weren't properly decorated with FORMAT annotations. Add them everywhere. It is not possible to annotate a function pointer type, so that doesn't work for the function pointers in struct log_if. However, we have convenience wrapper functions slilog and vslilog, which are appropriately decorated and therefore safer. Change all call sites to use those instead, and leave a comment. (Rename the function pointer variable names so that we don't miss any call sites.) Fix the bugs that this new compiler checking reveals. These are nearly all in fatal error reporting, and not very scary. Signed-off-by: Ian Jackson --- log.c | 31 ++++++++++++++++++++++--------- secnet.c | 3 ++- secnet.h | 22 +++++++++++++--------- site.c | 6 ++++-- slip.c | 3 ++- util.c | 6 +++--- 6 files changed, 46 insertions(+), 25 deletions(-) diff --git a/log.c b/log.c index d940df5..d330113 100644 --- a/log.c +++ b/log.c @@ -15,6 +15,8 @@ uint32_t message_level=M_WARNING|M_ERR|M_SECURITY|M_FATAL; struct log_if *system_log=NULL; static void vMessageFallback(uint32_t class, const char *message, va_list args) + FORMAT(printf,2,0); +static void vMessageFallback(uint32_t class, const char *message, va_list args) { FILE *dest=stdout; /* Messages go to stdout/stderr */ @@ -61,6 +63,8 @@ void Message(uint32_t class, const char *message, ...) } static void MessageFallback(uint32_t class, const char *message, ...) + FORMAT(printf,2,3); +static void MessageFallback(uint32_t class, const char *message, ...) { va_list ap; @@ -191,7 +195,7 @@ static void log_vmulti(void *sst, int class, const char *message, va_list args) if (secnet_is_daemon) { for (i=st; i; i=i->next) { - i->l->vlog(i->l->st,class,message,args); + vslilog(i->l,class,message,args); } } else { vMessage(class,message,args); @@ -200,6 +204,8 @@ static void log_vmulti(void *sst, int class, const char *message, va_list args) } static void log_multi(void *st, int priority, const char *message, ...) + FORMAT(printf,3,4); +static void log_multi(void *st, int priority, const char *message, ...) { va_list ap; @@ -242,8 +248,8 @@ struct log_if *init_log(list_t *ll) } r=safe_malloc(sizeof(*r), "init_log"); r->st=l; - r->log=log_multi; - r->vlog=log_vmulti; + r->logfn=log_multi; + r->vlogfn=log_vmulti; return r; } @@ -284,6 +290,8 @@ static void logfile_vlog(void *sst, int class, const char *message, } static void logfile_log(void *state, int class, const char *message, ...) + FORMAT(printf,3,4); +static void logfile_log(void *state, int class, const char *message, ...) { va_list ap; @@ -355,8 +363,8 @@ static list_t *logfile_apply(closure_t *self, struct cloc loc, dict_t *context, st->cl.apply=NULL; st->cl.interface=&st->ops; st->ops.st=st; - st->ops.log=logfile_log; - st->ops.vlog=logfile_vlog; + st->ops.logfn=logfile_log; + st->ops.vlogfn=logfile_vlog; st->loc=loc; st->f=NULL; @@ -401,6 +409,9 @@ static int msgclass_to_syslogpriority(uint32_t m) static void syslog_vlog(void *sst, int class, const char *message, va_list args) + FORMAT(printf,3,0); +static void syslog_vlog(void *sst, int class, const char *message, + va_list args) { struct syslog *st=sst; @@ -413,6 +424,8 @@ static void syslog_vlog(void *sst, int class, const char *message, } static void syslog_log(void *sst, int priority, const char *message, ...) + FORMAT(printf,3,4); +static void syslog_log(void *sst, int priority, const char *message, ...) { va_list ap; @@ -472,8 +485,8 @@ static list_t *syslog_apply(closure_t *self, struct cloc loc, dict_t *context, st->cl.apply=NULL; st->cl.interface=&st->ops; st->ops.st=st; - st->ops.log=syslog_log; - st->ops.vlog=syslog_vlog; + st->ops.logfn=syslog_log; + st->ops.vlogfn=syslog_vlog; item=list_elem(args,0); if (!item || item->type!=t_dict) @@ -528,7 +541,7 @@ static void log_from_fd_afterpoll(void *sst, struct pollfd *fds, int nfds) remain=FDLOG_BUFSIZE-st->i-1; if (remain<=0) { st->buffer[FDLOG_BUFSIZE-1]=0; - st->log->log(st->log,M_WARNING,"%s: overlong line: %s", + slilog(st->log,M_WARNING,"%s: overlong line: %s", st->prefix,st->buffer); st->i=0; remain=FDLOG_BUFSIZE-1; @@ -539,7 +552,7 @@ static void log_from_fd_afterpoll(void *sst, struct pollfd *fds, int nfds) for (i=0; ii; i++) { if (st->buffer[i]=='\n') { st->buffer[i]=0; - st->log->log(st->log->st,M_INFO,"%s: %s", + slilog(st->log,M_INFO,"%s: %s", st->prefix,st->buffer); i++; memmove(st->buffer,st->buffer+i,st->i-i); diff --git a/secnet.c b/secnet.c index 465a93f..c604d44 100644 --- a/secnet.c +++ b/secnet.c @@ -332,7 +332,8 @@ static void run(void) fatal("run: beforepoll_fn (%s) returns %d",i->desc,rv); } if (timeout<-1) { - fatal("run: beforepoll_fn (%s) set timeout to %d",timeout); + fatal("run: beforepoll_fn (%s) set timeout to %d", + i->desc,timeout); } idx+=nfds; remain-=nfds; diff --git a/secnet.h b/secnet.h index 4dd5c03..7504378 100644 --- a/secnet.h +++ b/secnet.h @@ -354,8 +354,8 @@ typedef void log_vmsg_fn(void *st, int class, const char *message, va_list args); struct log_if { void *st; - log_msg_fn *log; - log_vmsg_fn *vlog; + log_msg_fn *logfn; /* Do not call these directly - you don't get */ + log_vmsg_fn *vlogfn; /* printf format checking. Use [v]slilog instead */ }; /* (convenience functions, defined in util.c) */ extern void slilog(struct log_if *lf, int class, const char *message, ...) @@ -507,21 +507,25 @@ struct buffer_if { #define M_FATAL 0x100 /* The fatal() family of functions require messages that do not end in '\n' */ -extern NORETURN(fatal(const char *message, ...)); -extern NORETURN(fatal_perror(const char *message, ...)); -extern NORETURN(fatal_status(int status, const char *message, ...)); -extern NORETURN(fatal_perror_status(int status, const char *message, ...)); +extern NORETURN(fatal(const char *message, ...)) FORMAT(printf,1,2); +extern NORETURN(fatal_perror(const char *message, ...)) FORMAT(printf,1,2); +extern NORETURN(fatal_status(int status, const char *message, ...)) + FORMAT(printf,2,3); +extern NORETURN(fatal_perror_status(int status, const char *message, ...)) + FORMAT(printf,2,3); /* The cfgfatal() family of functions require messages that end in '\n' */ extern NORETURN(cfgfatal(struct cloc loc, cstring_t facility, - const char *message, ...)); + const char *message, ...)) FORMAT(printf,3,4); extern void cfgfile_postreadcheck(struct cloc loc, FILE *f); extern NORETURN(vcfgfatal_maybefile(FILE *maybe_f, struct cloc loc, cstring_t facility, const char *message, - va_list)); + va_list)) + FORMAT(printf,4,0); extern NORETURN(cfgfatal_maybefile(FILE *maybe_f, struct cloc loc, cstring_t facility, - const char *message, ...)); + const char *message, ...)) + FORMAT(printf,4,5); extern void Message(uint32_t class, const char *message, ...) FORMAT(printf,2,3); diff --git a/site.c b/site.c index df45fd8..7304ef8 100644 --- a/site.c +++ b/site.c @@ -294,6 +294,8 @@ struct site { }; static void slog(struct site *st, uint32_t event, cstring_t msg, ...) +FORMAT(printf,3,4); +static void slog(struct site *st, uint32_t event, cstring_t msg, ...) { va_list ap; char buf[240]; @@ -318,7 +320,7 @@ static void slog(struct site *st, uint32_t event, cstring_t msg, ...) } vsnprintf(buf,sizeof(buf),msg,ap); - st->log->log(st->log->st,class,"%s: %s",st->tunname,buf); + slilog(st->log,class,"%s: %s",st->tunname,buf); } va_end(ap); } @@ -1867,7 +1869,7 @@ static bool_t transport_compute_setupinit_peers(struct site *st, slog(st,LOG_SETUP_INIT, (!configured_addr ? "using only %d old peer address(es)" : "using configured address, and/or perhaps %d old peer address(es)"), - st->peers); + st->peers.npeers); /* Non-mobile peers havve st->peers.npeers==0 or ==1, since they * have transport_peers_max==1. The effect is that this code diff --git a/slip.c b/slip.c index db89a27..256e11d 100644 --- a/slip.c +++ b/slip.c @@ -197,7 +197,8 @@ static void userv_userv_callback(void *sst, pid_t pid, int status) fatal("%s: userv exited unexpectedly: uncaught signal %d", st->slip.nl.name,WTERMSIG(status)); } else { - fatal("%s: userv stopped unexpectedly"); + fatal("%s: userv stopped unexpectedly", + st->slip.nl.name); } } Message(M_WARNING,"%s: userv subprocess died with status %d\n", diff --git a/util.c b/util.c index 8228280..5740ef6 100644 --- a/util.c +++ b/util.c @@ -60,7 +60,7 @@ char *safe_strdup(const char *s, const char *message) char *d; d=strdup(s); if (!d) { - fatal_perror(message); + fatal_perror("%s",message); } return d; } @@ -70,7 +70,7 @@ void *safe_malloc(size_t size, const char *message) void *r; r=malloc(size); if (!r) { - fatal_perror(message); + fatal_perror("%s",message); } return r; } @@ -207,7 +207,7 @@ bool_t remove_hook(uint32_t phase, hook_fn *fn, void *state) void vslilog(struct log_if *lf, int priority, const char *message, va_list ap) { - lf->vlog(lf->st,priority,message,ap); + lf->vlogfn(lf->st,priority,message,ap); } void slilog(struct log_if *lf, int priority, const char *message, ...) -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:59 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:59 +0100 Subject: [PATCH 15/25] EAX: provide an implementation of EAX In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-16-git-send-email-ijackson@chiark.greenend.org.uk> EAX is a reasonably well-regarded Authenticated Encryption block cipher mode. We intend to replace the existing CBC and CBC-MAC transform with EAX. EAX can be used with any block cipher, but we will use it with Serpent. In this patch we provide an implementation of EAX itself. This primary consists of eax.c, the actual implementation of the EAX mode. To test that our implementation is correct, we use aes.[ch], which we copied from qemu in the previous commit, to run the EAX-AES test vectors. These are cut-and-pasted out of the EAX paper. (To do this we need to make aes.[ch] compile in our environment - but the changes are minimal. We also improve the copyright notices.) Then for completeness we also provide a set of EAX-Serpent test vectors and the corresponding test code. The EAX-Serpent test vectors were generated by this very code, so aren't independently verified. (The implementation of what is now consttime_curious_multiply, and the comment preeding it, were provided by Mark. I have lightly edited it to conform to the coding style etc. of the rest of the file.) Signed-off-by: Ian Jackson Signed-off-by: Mark Wooding --- .gitignore | 2 + Makefile.in | 21 +++- aes.c | 5 +- aes.h | 59 +++++++- eax-aes-test.c | 41 ++++++ eax-aes-test.vectors | 59 ++++++++ eax-serpent-test.c | 41 ++++++ eax-serpent-test.vectors | 59 ++++++++ eax-test.c | 154 ++++++++++++++++++++ eax-test.h | 52 +++++++ eax.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 842 insertions(+), 8 deletions(-) create mode 100644 eax-aes-test.c create mode 100644 eax-aes-test.vectors create mode 100644 eax-serpent-test.c create mode 100644 eax-serpent-test.vectors create mode 100644 eax-test.c create mode 100644 eax-test.h create mode 100644 eax.c diff --git a/.gitignore b/.gitignore index b7f6187..a445369 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ conffile.tab.[ch] conffile.yy.[ch] /version.c /secnet +/eax-*-test +/eax-*-test.confirm /config.log /config.h diff --git a/Makefile.in b/Makefile.in index 182204b..6f36e4f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -58,6 +58,8 @@ OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ process.o @LIBOBJS@ \ hackypar.o +TEST_OBJECTS=eax-aes-test.o eax-serpent-test.o eax-test.o aes.o + %.c: %.y %.yy.c: %.fl @@ -69,7 +71,7 @@ OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ %.o: %.c $(CC) $(CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@ -all: $(TARGETS) +all: $(TARGETS) check # Automatic remaking of configuration files, from autoconf documentation ${srcdir}/configure: configure.in @@ -93,8 +95,8 @@ config.status: configure # End of config file remaking rules # C and header file dependency rules -SOURCES:=$(OBJECTS:.o=.c) -DEPENDS:=$(OBJECTS:.o=.d) +SOURCES:=$(OBJECTS:.o=.c) $(TEST_OBJECTS:.o=.c) +DEPENDS:=$(OBJECTS:.o=.d) $(TEST_OBJECTS:.o=.d) $(DEPENDS): ${srcdir}/depend.sh @@ -112,11 +114,22 @@ conffile.tab.c: conffile.y secnet: $(OBJECTS) $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $(OBJECTS) $(LDLIBS) +check: eax-aes-test.confirm eax-serpent-test.confirm + version.c: Makefile echo "#include \"secnet.h\"" >$@.new echo "char version[]=\"secnet $(VERSION)\";" >>$@.new mv -f $@.new $@ +eax-%-test: eax-%-test.o eax-test.o %.o + $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $^ + +eax-%-test.confirm: eax-%-test eax-%-test.vectors + ./$< $@.new + mv -f $@.new $@ + +.PRECIOUS: eax-%-test + installdirs: $(INSTALL) -d $(prefix)/share/secnet $(sbindir) $(INSTALL) -d $(mandir)/man8 @@ -129,7 +142,7 @@ install: installdirs clean: $(RM) -f *.o *.yy.c *.tab.[ch] $(TARGETS) core version.c - $(RM) -f *.d *~ + $(RM) -f *.d *~ eax-*-test.confirm eax-*-test realclean: clean $(RM) -f *~ Makefile config.h *.d \ diff --git a/aes.c b/aes.c index eb37adb..4e155ab 100644 --- a/aes.c +++ b/aes.c @@ -1,6 +1,10 @@ /** * * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project. + * + * Copied to the secnet tree by Ian Jackson from the upstream qemu git + * tree revision 55616505876d6683130076b810a27c7889321560 + * and modified only to remove the include of qemu-common.h. */ /* * rijndael-alg-fst.c @@ -27,7 +31,6 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "qemu-common.h" #include "aes.h" #ifndef NDEBUG diff --git a/aes.h b/aes.h index a0167eb..fc69356 100644 --- a/aes.h +++ b/aes.h @@ -1,5 +1,58 @@ -#ifndef QEMU_AES_H -#define QEMU_AES_H +/* + * aes.h + * + * Header file declaring AES functions. + * + * Copied from the upstream qemu git tree revision + * 55616505876d6683130076b810a27c7889321560 + * but was introduced there by Fabrice Bellard in + * e4d4fe3c34cdd6e26f9b9975efec7d1e81ad00b6 + * AES crypto support + * git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk at 1036 \ + * c046a42c-6fe2-441c-8c8c-71466251a162 + * + * Modified by Ian Jackson to change the guard #define from + * QEMU_AES_H to AES_H and to add some needed system #include's. + * + * The header file doesn't appear to have a separate copyright notice + * but is clearly a lightly edited (by Bellard) version of code from + * Rijmen, Bosselaers and Barreto. + * + * The original is from rijndael-alg-fst.c, with this copyright + * notice: + * + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef AES_H +#define AES_H + +#include +#include +#include #define AES_MAXNR 14 #define AES_BLOCK_SIZE 16 @@ -23,4 +76,4 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, const unsigned long length, const AES_KEY *key, unsigned char *ivec, const int enc); -#endif +#endif /* AES_H */ diff --git a/eax-aes-test.c b/eax-aes-test.c new file mode 100644 index 0000000..d8ad027 --- /dev/null +++ b/eax-aes-test.c @@ -0,0 +1,41 @@ +/* + * eax-aes-test.c: test harness glue for EAX-AES (EAX-Rijndael) + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "eax-test.h" +#include "aes.h" + +#define BLOCK_SIZE AES_BLOCK_SIZE +static AES_KEY key; + +EAX_SOME_TEST; + +void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes) +{ + AES_set_encrypt_key(keydata, bytes*8, &key); +} + +static void BLOCK_ENCRYPT(uint8_t dst[BLOCK_SIZE], + const uint8_t src[BLOCK_SIZE]) +{ + AES_encrypt((const void*)src, (void*)dst, &key); +} + +#include "eax.c" diff --git a/eax-aes-test.vectors b/eax-aes-test.vectors new file mode 100644 index 0000000..f6bf3f4 --- /dev/null +++ b/eax-aes-test.vectors @@ -0,0 +1,59 @@ +MSG: +KEY: 233952DEE4D5ED5F9B9C6D6FF80FF478 +NONCE: 62EC67F9C3A4A407FCB2A8C49031A8B3 +HEADER: 6BFB914FD07EAE6B +CIPHER: E037830E8389F27B025A2D6527E79D01 + +MSG: F7FB +KEY: 91945D3F4DCBEE0BF45EF52255F095A4 +NONCE: BECAF043B0A23D843194BA972C66DEBD +HEADER: FA3BFD4806EB53FA +CIPHER: 19DD5C4C9331049D0BDAB0277408F67967E5 + +MSG: 1A47CB4933 +KEY: 01F74AD64077F2E704C0F60ADA3DD523 +NONCE: 70C3DB4F0D26368400A10ED05D2BFF5E +HEADER: 234A3463C1264AC6 +CIPHER: D851D5BAE03A59F238A23E39199DC9266626C40F80 + +MSG: 481C9E39B1 +KEY: D07CF6CBB7F313BDDE66B727AFD3C5E8 +NONCE: 8408DFFF3C1A2B1292DC199E46B7D617 +HEADER: 33CCE2EABFF5A79D +CIPHER: 632A9D131AD4C168A4225D8E1FF755939974A7BEDE + +MSG: 40D0C07DA5E4 +KEY: 35B6D0580005BBC12B0587124557D2C2 +NONCE: FDB6B06676EEDC5C61D74276E1F8E816 +HEADER: AEB96EAEBE2970E9 +CIPHER: 071DFE16C675CB0677E536F73AFE6A14B74EE49844DD + +MSG: 4DE3B35C3FC039245BD1FB7D +KEY: BD8E6E11475E60B268784C38C62FEB22 +NONCE: 6EAC5C93072D8E8513F750935E46DA1B +HEADER: D4482D1CA78DCE0F +CIPHER: 835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F + +MSG: 8B0A79306C9CE7ED99DAE4F87F8DD61636 +KEY: 7C77D6E813BED5AC98BAA417477A2E7D +NONCE: 1A8C98DCD73D38393B2BF1569DEEFC19 +HEADER: 65D2017990D62528 +CIPHER: 02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2 + +MSG: 1BDA122BCE8A8DBAF1877D962B8592DD2D56 +KEY: 5FFF20CAFAB119CA2FC73549E20F5B0D +NONCE: DDE59B97D722156D4D9AFF2BC7559826 +HEADER: 54B9F04E6A09189A +CIPHER: 2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A + +MSG: 6CF36720872B8513F6EAB1A8A44438D5EF11 +KEY: A4A4782BCFFD3EC5E7EF6D8C34A56123 +NONCE: B781FCF2F75FA5A8DE97A9CA48E522EC +HEADER: 899A175897561D7E +CIPHER: 0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700 + +MSG: CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7 +KEY: 8395FCF1E95BEBD697BD010BC766AAC3 +NONCE: 22E7ADD93CFC6393C57EC0B3C17D6B44 +HEADER: 126735FCC320D25A +CIPHER: CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E diff --git a/eax-serpent-test.c b/eax-serpent-test.c new file mode 100644 index 0000000..9e8d951 --- /dev/null +++ b/eax-serpent-test.c @@ -0,0 +1,41 @@ +/* + * eax-serpent-test.c: test harness glue for EAX-Serpent + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "eax-test.h" +#include "serpent.h" + +#define BLOCK_SIZE 16 +static struct keyInstance key; + +EAX_SOME_TEST; + +void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes) +{ + serpent_makekey(&key, bytes*8, keydata); +} + +static void BLOCK_ENCRYPT(uint8_t dst[BLOCK_SIZE], + const uint8_t src[BLOCK_SIZE]) +{ + serpent_encrypt(&key, src, dst); +} + +#include "eax.c" diff --git a/eax-serpent-test.vectors b/eax-serpent-test.vectors new file mode 100644 index 0000000..d7e4e6e --- /dev/null +++ b/eax-serpent-test.vectors @@ -0,0 +1,59 @@ +MSG: +KEY: 233952DEE4D5ED5F9B9C6D6FF80FF478 +NONCE: 62EC67F9C3A4A407FCB2A8C49031A8B3 +HEADER: 6BFB914FD07EAE6B +CIPHER: E667316E3FC40DF234575E203EA06EA0 + +MSG: F7FB +KEY: 91945D3F4DCBEE0BF45EF52255F095A4 +NONCE: BECAF043B0A23D843194BA972C66DEBD +HEADER: FA3BFD4806EB53FA +CIPHER: D6D0A45C2A76EEB6AD20C3DB5CE100A2AEC4 + +MSG: 1A47CB4933 +KEY: 01F74AD64077F2E704C0F60ADA3DD523 +NONCE: 70C3DB4F0D26368400A10ED05D2BFF5E +HEADER: 234A3463C1264AC6 +CIPHER: FD8218F8987B7CCEBE4D521F4374D40B2F85794B31 + +MSG: 481C9E39B1 +KEY: D07CF6CBB7F313BDDE66B727AFD3C5E8 +NONCE: 8408DFFF3C1A2B1292DC199E46B7D617 +HEADER: 33CCE2EABFF5A79D +CIPHER: 529951EDB28B9557667E88ED360EB51256DEC0F056 + +MSG: 40D0C07DA5E4 +KEY: 35B6D0580005BBC12B0587124557D2C2 +NONCE: FDB6B06676EEDC5C61D74276E1F8E816 +HEADER: AEB96EAEBE2970E9 +CIPHER: F46A8BFED3B22A6E4388659FF1C39B3D49AAD8ADEA74 + +MSG: 4DE3B35C3FC039245BD1FB7D +KEY: BD8E6E11475E60B268784C38C62FEB22 +NONCE: 6EAC5C93072D8E8513F750935E46DA1B +HEADER: D4482D1CA78DCE0F +CIPHER: C3C7281CE5790F14D4CD666E8494D4911D528548F200014C32B86719 + +MSG: 8B0A79306C9CE7ED99DAE4F87F8DD61636 +KEY: 7C77D6E813BED5AC98BAA417477A2E7D +NONCE: 1A8C98DCD73D38393B2BF1569DEEFC19 +HEADER: 65D2017990D62528 +CIPHER: 1DD9A93ACD19F0C3FB7A3B431DFCFB96D2B899FA2285AEC7DCA504AF75B97A58A3 + +MSG: 1BDA122BCE8A8DBAF1877D962B8592DD2D56 +KEY: 5FFF20CAFAB119CA2FC73549E20F5B0D +NONCE: DDE59B97D722156D4D9AFF2BC7559826 +HEADER: 54B9F04E6A09189A +CIPHER: 2BA4C477F2927210ADCA26DF72E2BEF81BF3D6B03160E7BFE7FD3EB57D255D66713F + +MSG: 6CF36720872B8513F6EAB1A8A44438D5EF11 +KEY: A4A4782BCFFD3EC5E7EF6D8C34A56123 +NONCE: B781FCF2F75FA5A8DE97A9CA48E522EC +HEADER: 899A175897561D7E +CIPHER: A17D854BA33FDBDF0BA86ADC9152D40B4EA01E1A8FAB1E0A80B19E73784219B29446 + +MSG: CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7 +KEY: 8395FCF1E95BEBD697BD010BC766AAC3 +NONCE: 22E7ADD93CFC6393C57EC0B3C17D6B44 +HEADER: 126735FCC320D25A +CIPHER: 9F30626B590A0A6E2F6CE0ED8835031654B3FCCF311BD7A6C6089AF1C7373D22CB80D4AFEE diff --git a/eax-test.c b/eax-test.c new file mode 100644 index 0000000..c29a51f --- /dev/null +++ b/eax-test.c @@ -0,0 +1,154 @@ +/* + * eax-test.c: test harness for EAX, implementation + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * usages: + * ./eax-foo-test len; i++) { + perturb->v[i] ^= delta; + trydecrypt(0); + perturb->v[i] ^= delta; + } +} + +static void something(void) +{ + if (!msg.got) return; + assert(key.got); + assert(nonce.got); + assert(header.got); + eaxtest_blockcipher_key_setup(V(key)); + eax_setup(-1); + if (cipher.got) { + assert(cipher.len > msg.len); + tau = cipher.len - msg.len; + assert(tau <= blocksize); + } else { + assert(msg.len + blocksize < sizeof(ourcipher.v)); + tau = blocksize; + } + ourcipher.len = msg.len + tau; + eax_encrypt(-1, V(nonce), V(header), V(msg), tau, ourcipher.v); + if (cipher.got) { + assert(ourcipher.len == cipher.len); + assert(!memcmp(ourcipher.v, cipher.v, cipher.len)); + trydecrypt(1); + negtest(&ourcipher); + negtest(&header); + } else { + size_t i; + printf("CIPHER: "); + for (i=0; igot = 1; + cv->len = 0; + for (;;) { + c = getputchar(); + if (c == ':') break; + assert(isalpha(c)); + } + for (;;) { + char hbuf[3], *ep; + c = getputchar(); + if (c == '\n') break; + if (isspace(c)) continue; + assert(isprint(c)); + hbuf[0] = c; + c = getputchar(); + assert(isprint(c)); + hbuf[1] = c; + hbuf[2] = 0; + assert(cv->len < sizeof(cv->v)); + cv->v[cv->len++] = strtoul(hbuf,&ep,16); + assert(!*ep); + } + } + assert(!ferror(stdin)); + assert(feof(stdin)); + assert(!ferror(stdout)); + assert(!fflush(stdout)); + return 0; +} diff --git a/eax-test.h b/eax-test.h new file mode 100644 index 0000000..14aa010 --- /dev/null +++ b/eax-test.h @@ -0,0 +1,52 @@ +/* + * eax-test.c: test harness for EAX, common declarations + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef EAX_TEST_H +#define EAX_TEST_H + +#include +#include +#include +#include +#include +#include +#include + +#define INFO int dummy_info +#define I dummy_info +#define EAX_ENTRYPOINT_DECL /* empty */ + +#define EAX_DECLARATIONS_ONLY +#include "eax.c" +#undef EAX_DECLARATIONS_ONLY + +void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes); + +#define consttime_memcmp memcmp /* fine for running test vectors */ + +extern const size_t blocksize; + +#define EAX_SOME_TEST \ + const size_t blocksize = BLOCK_SIZE; \ + static uint8_t INFO_B[BLOCK_SIZE], INFO_P[BLOCK_SIZE] + +#endif /* EAX_TEST_H */ diff --git a/eax.c b/eax.c new file mode 100644 index 0000000..8c07fac --- /dev/null +++ b/eax.c @@ -0,0 +1,357 @@ +/* + * eax.c: implementation of the EAX authenticated encryption block cipher mode + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * This file is designed to be #included into another .c file which + * sets up the environment. It will declare or define three + * functions, eax_setup, eax_encrypt and eax_decrypt. + * + * Manifest constants which are expected to be defined: + * + * INFO One or more formal parameter definitions. + * Used in all relevant function declarations. Typically + * the application will use this for its context pointer, + * key schedule structure, etc. + * + * I Corresponding actual parameters for chaining onto + * sub-functions declared to take INFO parameters + * + * EAX_ENTRYPOINT_DECL + * Declarator decoration for the three entry points. + * Typically either "static" or the empty string; + * + * EAX_DECLARATIONS_ONLY + * Tested with #ifdef, so should be #defined to 1, or left + * undefined. If defined, #including eax.c will produces + * only the function prototypes for the three entrypoints. + * Otherwise it will produce the implementation. + * + * BLOCK_SIZE + * Constant expresion of integer type. + * + * void BLOCK_ENCRYPT(uint8_t dst[n], const uint8_t src[n]); + * + * Function to encrypt with the selected key. The block + * cipher's key schedule (ie, the key) to be used is + * implicit; uses of BLOCK_ENCRYPT always occur in a + * context where the parameters defined by INFO are + * available. + * + * So in a real application which wants to use more than + * one key at a time, BLOCK_ENCRYPT must be a macro which + * accesses the block cipher's key schedule via one of the + * INFO parameters. + * + * BLOCK_ENCRYPT must tolerate dst==src. + * + * EAX does not need to use the block cipher's decryption + * function. + * + * uint8_t INFO_B[n], INFO_P[n]; + * + * Buffers used by the algorithm; they are written by + * eax_setup and used by eax_encrypt and eax_decrypt. + * + * That is, effectively they are the part of the key + * schedule specific to EAX. + * + * An application which wants to use more than one key at + * a time must define these as macros which refer to + * key-specific variables via one of the INFO parameters. + * + * int consttime_memcmp(const void *s1, const void *s2, size_t n); + * + * Like memcmp but takes the same amount of time no matter + * where the discrepancy is. + * + * The entrypoints which are then defined are: + * + * void eax_setup(INFO) + * + * Does the EAX-specific part of the key setup. The block + * cipher key schedule must already have been done, as + * eax_setup uses BLOCK_ENCRYPT. + * + * void eax_encrypt(INFO, const uint8_t nonce[nonce_len], size_t nonce_len, + * const uint8_t h[h_len], size_t h_len, + * const uint8_t m[m_len], size_t m_len, + * uint8_t tau, + * uint8_t ct[m_len+tau]) + * + * Does a single EAX authenticated encryption, providing + * confidentiality and integrity to the message m[0..m_len-1]. + * + * The output message is longer than m by tau bytes and is stored + * in the array ct which must be big enough. + * + * nonce must never be repeated with the same key or the security + * of the system is destroyed, but it does not need to be secret. + * It is OK to transmit the nonce with the message along with the + * ciphertext and have the receiver recover it. + * + * h is the "header" - it is some extra data which should be + * covered by the authentication, but not the encryption. The + * output message does not contain a representation of h: it is + * expected to be transmitted separately (perhaps even in a + * different format). (If h_len==0, h may be a NULL pointer.) + * + * tau is the tag length - that is, the length of the message + * authentication code. It should be chosen for the right + * tradeoff between message expansion and security (resistence to + * forgery). It must be no longer than the block cipher block + * size. + * + * For any particular key. the tag length should be fixed. (The + * tag length should NOT be encoded into the packet along with + * the ciphertext and extracted by the receiver! Rather, the + * receiver must know what tag length to expect.) + * + * It is permissible for ct==m, or for the arrays to be disjoint. + * They must not overlap more subtly. + * + * _Bool eax_decrypt(INFO, const uint8_t nonce[nonce_len], size_t nonce_len, + * const uint8_t h[h_len], size_t h_len, + * const uint8_t ct[ct_len], size_t ct_len, + * uint8_t tau, + * uint8_t m[ct_len-tau]) + * + * Does a single EAX authenticated decryption. + * + * On successful return, the plaintext message is written to m + * and eax_decrypt returns true. The length of the plaintext + * message is always ct_len-tau. + * + * If the message did not decrypt correctly, returns false. + * (There is no further indication of the nature of the error.) + * In this case the buffer m may contain arbitrary contents which + * should not be revealed to attackers. + * + * nonce, h, tau are as above. + * + * It is permissible to call eax_decrypt with an input message + * which is too short (i.e. shorter than tau) (notwithstanding + * the notation m[ct_len-tau] in the faux prototype above). + * In this case it will return false without touching m. + * + * As with eax_decrypt, ct==m is permissible. + */ + +/***** IMPLEMENTATION *****/ + +/* + * We use the notation from the EAX paper, mostly. + * (We write xscr for "x in fancy mathsy curly script".) + * + * See: + * Mihir Bellare, Phillip Rogaway, and David Wagner + * + * _The EAX Mode of Operation + * (A Two-Pass Authenticated Encryption Scheme + * Optimized for Simplicity and Efficiency)_ + * + * Preliminary version in: + * Fast Software Encryption (FSE) 2004. Lecture Notes in Computer Science, + * vol. ??, pp. ??--??. + * + * Full version at: + * http://www.cs.ucdavis.edu/~rogaway/papers/eax.html + */ +/* + * In general, all functions tolerate their destination arrays being + * the same pointer to their source arrays, or totally distinct. + * (Just like BLOCK_ENCRYPT and the public eax entrypoints.) + * They must not overlap in more subtle ways. + */ + +#define n ((size_t)BLOCK_SIZE) + +#ifndef EAX_DECLARATIONS_ONLY + +static void xor(uint8_t *dst, const uint8_t *a, const uint8_t *b, size_t l) + /* simple block xor */ +{ + while (l--) + *dst++ = *a++ ^ *b++; +} + +static void increment(uint8_t *value) + /* value is a single block; incremented (BE) mod 256^n */ +{ + uint8_t *p; + for (p=value+n; p>value; ) + if ((*--p)++) break; +} + +static void alg_ctr(INFO, uint8_t *c, const uint8_t *nscr, + const uint8_t *m, size_t m_len) +{ + uint8_t blocknonce[n], cipher[n]; + size_t in; + + memcpy(blocknonce, nscr, n); + for (in=0; in0 && remain> 7) - 1u) & POLY; + unsigned i, mm; + + for (i = n - 1; i < n; i--) { + mm = (v[i] >> 7) & 1u; + o[i] = (v[i] << 1) ^ m; + m = mm; + } + +#undef POLY +} + +#endif /* not EAX_DECLARATIONS_ONLY */ + +EAX_ENTRYPOINT_DECL +void eax_setup(INFO) +#ifndef EAX_DECLARATIONS_ONLY +{ + uint8_t work[n]; + memset(work,0,n); + BLOCK_ENCRYPT(work,work); + consttime_curious_multiply(I, INFO_B, work); + consttime_curious_multiply(I, INFO_P, INFO_B); +} +#endif /* not EAX_DECLARATIONS_ONLY */ +; + +EAX_ENTRYPOINT_DECL +void eax_encrypt(INFO, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *h, size_t h_len, + const uint8_t *m, size_t m_len, uint8_t tau, uint8_t *ct) +#ifndef EAX_DECLARATIONS_ONLY +{ + assert(tau <= n); + uint8_t nscr[n], hscr[n], cscr[n]; + alg_omac_t_k(I, nscr, 0, nonce,nonce_len); + alg_omac_t_k(I, hscr, 1, h,h_len); + alg_ctr(I, ct, nscr, m, m_len); + alg_omac_t_k(I, cscr, 2, ct, m_len); + uint8_t *t = ct + m_len; + xor(t, nscr, cscr, tau); + xor(t, t, hscr, tau); +} +#endif /* not EAX_DECLARATIONS_ONLY */ +; + +EAX_ENTRYPOINT_DECL +_Bool eax_decrypt(INFO, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *h, size_t h_len, + const uint8_t *ct, size_t ct_len, uint8_t tau, uint8_t *m) +#ifndef EAX_DECLARATIONS_ONLY +{ + assert(tau <= n); + const uint8_t *t; + uint8_t nscr[n], hscr[n], cscr[n], tprime[tau]; + if (ct_len < tau) return 0; + size_t m_len = ct_len - tau; + t = ct + m_len; + alg_omac_t_k(I, nscr, 0, nonce,nonce_len); + alg_omac_t_k(I, hscr, 1, h,h_len); + alg_omac_t_k(I, cscr, 2, ct,m_len); + xor(tprime, nscr, cscr, tau); + xor(tprime, tprime, hscr, tau); + if (consttime_memcmp(tprime, t, tau)) return 0; + alg_ctr(I, m, nscr, ct, m_len); + return 1; +} +#endif /* not EAX_DECLARATIONS_ONLY */ +; + +#undef n -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:54 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:54 +0100 Subject: [PATCH 10/25] site: use unaligned.h's functions, not pointer cast and ntohl In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-11-git-send-email-ijackson@chiark.greenend.org.uk> Switch site.c to using unaligned.h's functions for accessing multi-byte values inside messages. There were a few places where this construction was used: something = ntohl(*(uint32_t*)(buf->start + offset)); It is much clearer to use this equivalent construction: something = get_uint32(buf->start + offset); Also the packet's message type was extracted from the message using get_uint32 and then put through ntohl. This is, of course, wrong. Currently all the message type codes are palindromes, so it doesn't matter in practice. Fix it anyway. Signed-off-by: Ian Jackson --- site.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/site.c b/site.c index 7857956..8652c9e 100644 --- a/site.c +++ b/site.c @@ -850,9 +850,9 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0, static void dump_packet(struct site *st, struct buffer_if *buf, const struct comm_addr *addr, bool_t incoming) { - uint32_t dest=ntohl(*(uint32_t *)buf->start); - uint32_t source=ntohl(*(uint32_t *)(buf->start+4)); - uint32_t msgtype=ntohl(*(uint32_t *)(buf->start+8)); + uint32_t dest=get_uint32(buf->start); + uint32_t source=get_uint32(buf->start+4); + uint32_t msgtype=get_uint32(buf->start+8); if (st->log_events & LOG_DUMP) slilog(st->log,M_DEBUG,"%s: %s: %08x<-%08x: %08x:", @@ -1258,8 +1258,8 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, if (buf->size < 12) return False; - uint32_t msgtype=ntohl(get_uint32(buf->start+8)); - uint32_t dest=ntohl(*(uint32_t *)buf->start); + uint32_t dest=get_uint32(buf->start); + uint32_t msgtype=get_uint32(buf->start+8); struct msg named_msg; if (msgtype==LABEL_MSG1) { -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:55 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:55 +0100 Subject: [PATCH 11/25] site: interpret first 4 bytes of extrainfo as capabilities In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-12-git-send-email-ijackson@chiark.greenend.org.uk> Define the first four bytes of the additional data (after the nul in site names in MSG1..4) in the sender's name field to be a capability bitmask. Currently no capability flags are defined. To support this, replace extrainfo and its _len in struct parsedname with a struct buffer_if. We invent a new kind of buffer_if which is a readonly view of another buffer; such a view can be initialised with buffer_view_readonly. This makes it convenient to parse the extrainfo using our existing macros etc. We record the capabilities from MSG1 or MSG3, and check that they haven't changed when processing MSG2..4, as applicable. (Because older secnets don't cope with flags in MSG1, we have to define two kinds of capability flag: ones expected to be in MSG1, and ones which can appear later in the exchange.) The support for "Early" capabilities is intended to be used in the future to support algorithm agility in key exchange. We also advertise our own capabilities (currently, all-bits-zero) in our own messages. Signed-off-by: Ian Jackson --- NOTES | 28 ++++++++++++++++++++++- magic.h | 4 +++ site.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ util.c | 11 +++++++++ util.h | 5 ++++ 5 files changed, 113 insertions(+), 9 deletions(-) diff --git a/NOTES b/NOTES index 3e9d71d..8619ee5 100644 --- a/NOTES +++ b/NOTES @@ -176,7 +176,7 @@ Definitions: A is the originating gateway machine name B is the destination gateway machine name -A+ and B+ are the names with optional additional data, currently ignored +A+ and B+ are the names with optional additional data, see below PK_A is the public RSA key of A PK_B is the public RSA key of B PK_A^-1 is the private RSA key of A @@ -194,7 +194,31 @@ i? is appropriate index for receiver Note that 'i' may be re-used from one session to the next, whereas 'n' is always fresh. -The protocol version selection stuff is not yet implemented. +The optional additional data after the sender's name consists of some +initial subset of the following list of items: + * A 32-bit integer with a set of capability flags, representing the + abilities of the sender. + * More data which is yet to be defined and which must be ignored + by receivers. +The optional additional data after the receiver's name is not +currently used. If any is seen, it must be ignored. + +Capability flag bits must be in one the following two categories: + +1. Early capability flags must be advertised in MSG1 or MSG2, as + applicable. If MSG3 or MSG4 advertise any "early" capability bits, + MSG1 or MSG3 (as applicable) must have advertised them too. Sadly, + advertising an early capability flag will produce MSG1s which are + not understood by versions of secnet which predate the capability + mechanism. + +2. Late capability flags are advertised in MSG2 or MSG3, as + applicable. They may also appear in MSG1, but this is not + guaranteed. MSG4 must advertise the same set as MSG2. + +No capability flags are currently defined. Unknown capability flags +should be treated as late ones. + Messages: diff --git a/magic.h b/magic.h index c2503a0c..3ae7af4 100644 --- a/magic.h +++ b/magic.h @@ -15,4 +15,8 @@ #define LABEL_MSG8 0x08080808 #define LABEL_MSG9 0x09090909 +/* uses of the 32-bit capability bitmap */ +/* no flags currently defined */ +#define CAPAB_EARLY 0x00000000 /* no Early flags defined (see NOTES) */ + #endif /* magic_h */ diff --git a/site.c b/site.c index 8652c9e..23f5754 100644 --- a/site.c +++ b/site.c @@ -244,6 +244,7 @@ struct site { struct hash_if *hash; uint32_t index; /* Index of this site */ + uint32_t local_capabilities; int32_t setup_retries; /* How many times to send setup packets */ int32_t setup_retry_interval; /* Initial timeout for setup packets */ int32_t wait_timeout; /* How long to wait if setup unsuccessful */ @@ -275,6 +276,7 @@ struct site { packet; we keep trying to continue the exchange, and have to timeout before we can listen for another setup packet); perhaps we should keep a list of 'bad' sources for setup packets. */ + uint32_t remote_capabilities; uint32_t setup_session_id; transport_peers setup_peers; uint8_t localN[NONCELEN]; /* Nonces for key exchange */ @@ -346,8 +348,7 @@ static bool_t current_valid(struct site *st) struct parsedname { int32_t len; uint8_t *name; - int32_t extrainfo_len; - uint8_t *extrainfo; + struct buffer_if extrainfo; }; struct msg { @@ -356,6 +357,7 @@ struct msg { uint32_t source; struct parsedname remote; struct parsedname local; + uint32_t remote_capabilities; uint8_t *nR; uint8_t *nL; int32_t pklen; @@ -365,6 +367,34 @@ struct msg { char *sig; }; +struct xinfoadd { + int32_t lenpos, afternul; +}; +static void append_string_xinfo_start(struct buffer_if *buf, + struct xinfoadd *xia, + const char *str) + /* Helps construct one of the names with additional info as found + * in MSG1..4. Call this function first, then append all the + * desired extra info (not including the nul byte) to the buffer, + * then call append_string_xinfo_done. */ +{ + xia->lenpos = buf->size; + buf_append_string(buf,str); + *(uint8_t*)buf_append(buf,1) = 0; + xia->afternul = buf->size; +} +static void append_string_xinfo_done(struct buffer_if *buf, + struct xinfoadd *xia) +{ + /* we just need to adjust the string length */ + if (buf->size == xia->afternul) { + /* no extra info, strip the nul too */ + buf_unappend(buf,1); + } else { + put_uint16(buf->start+xia->lenpos, buf->size-(xia->lenpos+2)); + } +} + /* Build any of msg1 to msg4. msg5 and msg6 are built from the inside out using a transform of config data supplied by netlink */ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) @@ -380,7 +410,14 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) (type==LABEL_MSG1?0:st->setup_session_id)); buf_append_uint32(&st->buffer,st->index); buf_append_uint32(&st->buffer,type); - buf_append_string(&st->buffer,st->localname); + + struct xinfoadd xia; + append_string_xinfo_start(&st->buffer,&xia,st->localname); + if ((st->local_capabilities & CAPAB_EARLY) || (type != LABEL_MSG1)) { + buf_append_uint32(&st->buffer,st->local_capabilities); + } + append_string_xinfo_done(&st->buffer,&xia); + buf_append_string(&st->buffer,st->remotename); memcpy(buf_append(&st->buffer,NONCELEN),st->localN,NONCELEN); if (type==LABEL_MSG1) return True; @@ -405,17 +442,16 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm) { + struct buffer_if extrainfo; CHECK_AVAIL(msg,2); nm->len=buf_unprepend_uint16(msg); CHECK_AVAIL(msg,nm->len); nm->name=buf_unprepend(msg,nm->len); uint8_t *nul=memchr(nm->name,0,nm->len); if (!nul) { - nm->extrainfo_len=0; - nm->extrainfo=0; + buffer_readonly_view(&extrainfo,0,0); } else { - nm->extrainfo=nul+1; - nm->extrainfo_len=msg->start-nm->extrainfo; + buffer_readonly_view(&extrainfo, nul+1, msg->start-(nul+1)); nm->len=nul-nm->name; } return True; @@ -431,6 +467,11 @@ static bool_t unpick_msg(struct site *st, uint32_t type, m->source=buf_unprepend_uint32(msg); CHECK_TYPE(msg,type); if (!unpick_name(msg,&m->remote)) return False; + m->remote_capabilities=0; + if (m->remote.extrainfo.len) { + CHECK_AVAIL(&m->remote.extrainfo,4); + m->remote_capabilities=buf_unprepend_uint32(&m->remote.extrainfo); + } if (!unpick_name(msg,&m->local)) return False; CHECK_AVAIL(msg,NONCELEN); m->nR=buf_unprepend(msg,NONCELEN); @@ -489,7 +530,13 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, *error="wrong remotely-generated nonce"; return False; } + /* MSG3 has complicated rules about capabilities, which are + * handled in process_msg3. */ if (type==LABEL_MSG3) return True; + if (m->remote_capabilities!=st->remote_capabilities) { + *error="remote capabilities changed"; + return False; + } if (type==LABEL_MSG4) return True; *error="unknown message type"; return False; @@ -510,6 +557,7 @@ static bool_t process_msg1(struct site *st, struct buffer_if *msg1, transport_record_peer(st,&st->setup_peers,src,"msg1"); st->setup_session_id=m->source; + st->remote_capabilities=m->remote_capabilities; memcpy(st->remoteN,m->nR,NONCELEN); return True; } @@ -532,6 +580,7 @@ static bool_t process_msg2(struct site *st, struct buffer_if *msg2, return False; } st->setup_session_id=m.source; + st->remote_capabilities=m.remote_capabilities; memcpy(st->remoteN,m.nR,NONCELEN); return True; } @@ -557,6 +606,15 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, slog(st,LOG_SEC,"msg3: %s",err); return False; } + uint32_t capab_adv_late = m.remote_capabilities + & ~st->remote_capabilities & CAPAB_EARLY; + if (capab_adv_late) { + slog(st,LOG_SEC,"msg3 impermissibly adds early capability flag(s)" + " %#"PRIx32" (was %#"PRIx32", now %#"PRIx32")", + capab_adv_late, st->remote_capabilities, m.remote_capabilities); + return False; + } + st->remote_capabilities|=m.remote_capabilities; /* Check signature and store g^x mod m */ hash=safe_malloc(st->hash->len, "process_msg3"); @@ -1483,6 +1541,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, assert(index_sequence < 0xffffffffUL); st->index = ++index_sequence; + st->local_capabilities = 0; st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc); list_t *comms_cfg=dict_lookup(dict,"comm"); @@ -1569,6 +1628,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, register_for_poll(st, site_beforepoll, site_afterpoll, 0, "site"); st->timeout=0; + st->remote_capabilities=0; st->current.key_timeout=0; st->auxiliary_key.key_timeout=0; transport_peers_clear(st,&st->peers); diff --git a/util.c b/util.c index e50218c..d47b944 100644 --- a/util.c +++ b/util.c @@ -301,6 +301,17 @@ void buffer_new(struct buffer_if *buf, int32_t len) buf->base=safe_malloc(len,"buffer_new"); } +void buffer_readonly_view(struct buffer_if *buf, const void *data, int32_t len) +{ + buf->free=False; + buf->owner="READONLY"; + buf->flags=0; + buf->loc.file=NULL; + buf->loc.line=0; + buf->size=buf->len=len; + buf->base=buf->start=(uint8_t*)data; +} + void buffer_copy(struct buffer_if *dst, const struct buffer_if *src) { if (dst->len < src->len) { diff --git a/util.h b/util.h index 2491fd5..451d749 100644 --- a/util.h +++ b/util.h @@ -29,6 +29,11 @@ extern void *buf_prepend(struct buffer_if *buf, int32_t amount); extern void *buf_unappend(struct buffer_if *buf, int32_t amount); extern void *buf_unprepend(struct buffer_if *buf, int32_t amount); +extern void buffer_readonly_view(struct buffer_if*, const void*, int32_t len); + /* Caller must only use unappend, unprepend et al. + * buffer state before this can be undefined. After use, + * it must NOT be freed. */ + extern void buf_append_string(struct buffer_if *buf, cstring_t s); extern void read_mpbin(MP_INT *a, uint8_t *bin, int binsize); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:03 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:03 +0100 Subject: [PATCH 19/25] transform: Provide Serpment-EAX transform In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-20-git-send-email-ijackson@chiark.greenend.org.uk> This provides an alternative to the (rather badly broken) serpent256-cbc transform. In this patch, there is not yet any algorith negotiation for a smooth upgrade, nor any changes to the example configurations. Signed-off-by: Ian Jackson --- Makefile.in | 4 +- README | 5 + modules.c | 1 + secnet.8 | 21 ++++- secnet.h | 3 + transform-eax.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 282 insertions(+), 4 deletions(-) create mode 100644 transform-eax.c diff --git a/Makefile.in b/Makefile.in index 22f9de4..1e4f670 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,9 +53,9 @@ mandir:=@mandir@ TARGETS:=secnet OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ - resolver.o random.o udp.o site.o transform-cbcmac.o \ + resolver.o random.o udp.o site.o transform-cbcmac.o transform-eax.o \ netlink.o rsa.o dh.o \ - serpent.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ + serpent.o md5.o sha512.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ process.o @LIBOBJS@ \ hackypar.o diff --git a/README b/README index 93730e9..fc3bf55 100644 --- a/README +++ b/README @@ -336,6 +336,11 @@ setup but more relaxed about using old keys. These are noted with "mobile:", above, and apply whether the mobile peer is local or remote. +** transform-eax + +Defines: + serpent-eax (closure => transform closure) + ** transform-cbcmac Defines: diff --git a/modules.c b/modules.c index 0290cd4..724ccbb 100644 --- a/modules.c +++ b/modules.c @@ -7,6 +7,7 @@ void init_builtin_modules(dict_t *dict) udp_module(dict); util_module(dict); site_module(dict); + transform_eax_module(dict); transform_cbcmac_module(dict); netlink_module(dict); rsa_module(dict); diff --git a/secnet.8 b/secnet.8 index 869d297..e553321 100644 --- a/secnet.8 +++ b/secnet.8 @@ -415,8 +415,8 @@ A \fIrandomsource closure\fR is a source of random numbers. .PP Read the contents of the file \fIPATH\fR (a string) and return it as a string. -.SS serpent256-cbc -\fBserpent256-cbc(\fIDICT\fB)\fR => \fItransform closure\fR +.SS serpent-eax +\fBserpent-eax(\fIDICT\fB)\fR => \fItransform closure\fR .PP Valid keys in the \fIDICT\fR argument are: .TP @@ -425,11 +425,28 @@ The maximum acceptable difference between the sequence number in a received, decrypted message and the previous one. The default is 10. It may be necessary to increase this is if connectivity is poor. +.TP +.B tag-length-bytes +The length of the message authentication tag. The default is 16, +for a 128-bit tag length. It must be no longer than the Serpent +blocksize, 16. Must be have the same value at both ends. +.TP +.B padding-rounding +Messages are padded to a multiple of this many bytes. This +serves to obscure the exact length of messages. The default is 16, .PP A \fItransform closure\fR is a reversible means of transforming messages for transmission over a (presumably) insecure network. It is responsible for both confidentiality and integrity. +.SS serpent256-cbc +\fBserpent256-cbc(\fIDICT\fB)\fR => \fItransform closure\fR +.PP +Valid keys in the \fIDICT\fR argument are: +.TP +.B max-sequence-skew +As above. + .SS rsa-private \fBrsa-private(\fIPATH\fB\fR[, \fICHECK\fR]\fB)\fR => \fIrsaprivkey closure\fR .TP diff --git a/secnet.h b/secnet.h index 6ad8fc9..af0c1f7 100644 --- a/secnet.h +++ b/secnet.h @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -232,6 +234,7 @@ extern init_module random_module; extern init_module udp_module; extern init_module util_module; extern init_module site_module; +extern init_module transform_eax_module; extern init_module transform_cbcmac_module; extern init_module netlink_module; extern init_module rsa_module; diff --git a/transform-eax.c b/transform-eax.c new file mode 100644 index 0000000..506f05d --- /dev/null +++ b/transform-eax.c @@ -0,0 +1,252 @@ +/* + * eax-transform.c: EAX-Serpent bulk data transformation + * + * We use EAX with the following parameters: + * + * Plaintext: + * Concatenation of: + * Data packet as supplied to us + * Zero or more zero bytes ignored by receiver } padding + * One byte padding length } + * This is a bit like PKCS#5. It helps disguise message lengths. + * It also provides a further room for future expansion. When + * transmitting we pad the message to the next multiple of + * a configurable rounding factor, 16 bytes by default. + * + * Transmitted message: + * Concatenation of: + * EAX ciphertext + * 32-bit sequence number (initially zero) + * The sequence number allows us to discard far-too-old + * packets. + * + * Nonce: + * Concatenation of: + * 32-bit sequence number (big endian) starting at zero + * 1 byte: 0x01 if sender has setup priority, 0x00 if it doesn't + * (ie, the direction of data flow) + * + * Header: None + * + * Tag length: + * 16 bytes (128 bits) by default + * + * Key: + * The first 32 bytes of the SHA-512 hash of the shared secret + * from the DH key exchange (the latter being expressed as + * the shortest possible big-endian octet string). + */ + +#include "secnet.h" +#include "unaligned.h" +#include "util.h" +#include "serpent.h" +#include "sha512.h" +#include "transform-common.h" + +#define BLOCK_SIZE 16 +#define SEQLEN 4 + +struct transform_params { + uint32_t max_seq_skew, tag_length, padding_mask; +}; + +struct transform { + closure_t cl; + struct transform_if ops; + struct transform_params p; +}; + +struct transform_inst { + struct transform_inst_if ops; + struct transform_params p; + unsigned keyed:1; + /* remaining valid iff keyed */ + unsigned direction:1; + uint32_t sendseq; + uint32_t lastrecvseq; + struct keyInstance key; + uint8_t info_b[BLOCK_SIZE], info_p[BLOCK_SIZE]; +}; + +static void block_encrypt(struct transform_inst *transform_inst, + uint8_t dst[BLOCK_SIZE], + const uint8_t src[BLOCK_SIZE]) +{ + serpent_encrypt(&transform_inst->key, src, dst); +} + +#define INFO struct transform_inst *transform_inst +#define I transform_inst +#define EAX_ENTRYPOINT_DECL static +#define BLOCK_ENCRYPT(dst,src) block_encrypt(transform_inst,dst,src) +#define INFO_B (transform_inst->info_b) +#define INFO_P (transform_inst->info_p) + +#include "eax.c" + +static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen, + bool_t direction) +{ + struct transform_inst *ti=sst; + struct sha512_ctx hash_ctx; + uint8_t hash_out[64]; + + sha512_init_ctx(&hash_ctx); + sha512_process_bytes(key, keylen, &hash_ctx); + sha512_finish_ctx(&hash_ctx, hash_out); + + ti->direction=direction; + ti->sendseq=ti->lastrecvseq=0; + serpent_makekey(&ti->key, 32*8, hash_out); + eax_setup(ti); + ti->keyed=True; + + return True; +} + +TRANSFORM_VALID; + +TRANSFORM_DESTROY; + +static void transform_delkey(void *sst) +{ + struct transform_inst *ti=sst; + + FILLZERO(ti->key); + FILLZERO(ti->info_b); + FILLZERO(ti->info_p); + ti->keyed=False; +} + +static uint32_t transform_forward(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + + KEYED_CHECK; + + size_t padlen = ti->p.padding_mask - buf->size; + padlen &= ti->p.padding_mask; + padlen++; + + uint8_t *pad = buf_append(buf,padlen); + memset(pad, 0, padlen-1); + pad[padlen-1] = padlen; + + uint8_t nonce[SEQLEN+1]; + put_uint32(nonce,ti->sendseq); + nonce[SEQLEN] = ti->direction; + + assert(buf_append(buf,ti->p.tag_length)); + eax_encrypt(ti, nonce,sizeof(nonce), 0,0, buf->start,buf->size, + ti->p.tag_length, buf->start); + memcpy(buf_append(buf,SEQLEN), nonce, SEQLEN); + + ti->sendseq++; + + return 0; +} + +static uint32_t transform_reverse(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + + KEYED_CHECK; + + uint8_t nonce[SEQLEN+1]; + const uint8_t *seqp = buf_unappend(buf,SEQLEN); + if (!seqp) goto too_short; + + uint32_t seqnum = get_uint32(seqp); + SEQNUM_CHECK(seqnum, ti->p.max_seq_skew); + + memcpy(nonce,seqp,SEQLEN); + nonce[4] = !ti->direction; + + bool_t ok = eax_decrypt(ti, nonce,sizeof(nonce), 0,0, buf->start,buf->size, + ti->p.tag_length, buf->start); + if (!ok) { + *errmsg="EAX decryption failed"; + return 1; + } + assert(buf->size >= (int)ti->p.tag_length); + buf->size -= ti->p.tag_length; + + const uint8_t *padp = buf_unappend(buf,1); + if (!padp) goto too_short; + + size_t padlen = *padp; + if (!buf_unappend(buf,padlen-1)) goto too_short; + + return 0; + + too_short: + *errmsg="ciphertext or plaintext too short"; + return 1; +} + +static struct transform_inst_if *transform_create(void *sst) +{ + struct transform *st=sst; + + TRANSFORM_CREATE_CORE; + + ti->p=st->p; + + return &ti->ops; +} + +static list_t *transform_apply(closure_t *self, struct cloc loc, + dict_t *context, list_t *args) +{ + struct transform *st; + item_t *item; + dict_t *dict; + + st=safe_malloc(sizeof(*st),"eax-serpent"); + st->cl.description="eax-serpent"; + st->cl.type=CL_TRANSFORM; + st->cl.apply=NULL; + st->cl.interface=&st->ops; + st->ops.st=st; + + /* First parameter must be a dict */ + item=list_elem(args,0); + if (!item || item->type!=t_dict) + cfgfatal(loc,"eax-serpent","parameter must be a dictionary\n"); + dict=item->data.dict; + + st->p.max_seq_skew=dict_read_number(dict, "max-sequence-skew", + False, "eax-serpent", loc, 10); + + st->p.tag_length=dict_read_number(dict, "tag-length-bytes", + False, "eax-serpent", loc, 128/8); + if (st->p.tag_length<1 || st->p.tag_length>BLOCK_SIZE) + cfgfatal(loc,"eax-serpent","tag-length-bytes out of range 0..%d\n", + BLOCK_SIZE); + + uint32_t padding_round=dict_read_number(dict, "padding-rounding", + False, "eax-serpent", loc, 16); + if (padding_round & (padding_round-1)) + cfgfatal(loc,"eax-serpent","padding-round not a power of two\n"); + if (padding_round > 255) + cfgfatal(loc,"eax-serpent","padding-round must be 1..128\n"); + if (padding_round == 0) + padding_round = 1; + st->p.padding_mask = padding_round-1; + + st->ops.max_start_pad=0; + st->ops.max_end_pad= padding_round + st->p.tag_length + SEQLEN; + + st->ops.keylen=0; + st->ops.create=transform_create; + + return new_closure(&st->cl); +} + +void transform_eax_module(dict_t *dict) +{ + add_closure(dict,"serpent-eax",transform_apply); +} -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:00 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:00 +0100 Subject: [PATCH 16/25] transform: split out transform-common.h In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-17-git-send-email-ijackson@chiark.greenend.org.uk> To avoid too much duplication, some boilerplate and helpful code from transport.c is now brought out into macros in transport-common.h. It will be reused in the later commits introducing the EAX transform. Also, rename transform.c to transform-cbcmac.c, etc. Signed-off-by: Ian Jackson --- Makefile.in | 3 +- README | 2 +- modules.c | 2 +- secnet.h | 2 +- transform-cbcmac.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++ transform-common.h | 56 ++++++++ transform.c | 394 ---------------------------------------------------- 7 files changed, 420 insertions(+), 398 deletions(-) create mode 100644 transform-cbcmac.c create mode 100644 transform-common.h delete mode 100644 transform.c diff --git a/Makefile.in b/Makefile.in index 6f36e4f..22f9de4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,7 +53,8 @@ mandir:=@mandir@ TARGETS:=secnet OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ - resolver.o random.o udp.o site.o transform.o netlink.o rsa.o dh.o \ + resolver.o random.o udp.o site.o transform-cbcmac.o \ + netlink.o rsa.o dh.o \ serpent.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ process.o @LIBOBJS@ \ hackypar.o diff --git a/README b/README index 84bb392..93730e9 100644 --- a/README +++ b/README @@ -336,7 +336,7 @@ setup but more relaxed about using old keys. These are noted with "mobile:", above, and apply whether the mobile peer is local or remote. -** transform +** transform-cbcmac Defines: serpent256-cbc (closure => transform closure) diff --git a/modules.c b/modules.c index 9b94e25..0290cd4 100644 --- a/modules.c +++ b/modules.c @@ -7,7 +7,7 @@ void init_builtin_modules(dict_t *dict) udp_module(dict); util_module(dict); site_module(dict); - transform_module(dict); + transform_cbcmac_module(dict); netlink_module(dict); rsa_module(dict); dh_module(dict); diff --git a/secnet.h b/secnet.h index 6ac64e3..1a5aaad 100644 --- a/secnet.h +++ b/secnet.h @@ -232,7 +232,7 @@ extern init_module random_module; extern init_module udp_module; extern init_module util_module; extern init_module site_module; -extern init_module transform_module; +extern init_module transform_cbcmac_module; extern init_module netlink_module; extern init_module rsa_module; extern init_module dh_module; diff --git a/transform-cbcmac.c b/transform-cbcmac.c new file mode 100644 index 0000000..7b97ce9 --- /dev/null +++ b/transform-cbcmac.c @@ -0,0 +1,359 @@ +/* Transform module - bulk data transformation */ + +/* For now it's hard-coded to do sequence + number/pkcs5/serpent-cbcmac/serpent with a 256 bit key for each + instance of serpent. We also require key material for the IVs for + cbcmac and cbc. Hack: we're not using full 128-bit IVs, we're just + using 32 bits and encrypting to get the full IV to save space in + the packets sent over the wire. */ + +#include +#include +#include "secnet.h" +#include "util.h" +#include "serpent.h" +#include "unaligned.h" + +/* Required key length in bytes */ +#define REQUIRED_KEYLEN ((512+64+32)/8) + +struct transform { + closure_t cl; + struct transform_if ops; + uint32_t max_seq_skew; +}; + +struct transform_inst { + struct transform_inst_if ops; + struct keyInstance cryptkey; + struct keyInstance mackey; + uint32_t cryptiv; + uint32_t maciv; + uint32_t sendseq; + uint32_t lastrecvseq; + uint32_t max_skew; + bool_t keyed; +}; + +#include "transform-common.h" + +#define PKCS5_MASK 15 + +static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) +{ + struct transform_inst *ti=sst; + + if (keylencryptkey,256,key); + serpent_makekey(&ti->mackey,256,key+32); + ti->cryptiv=GET_32BIT_MSB_FIRST(key+64); + ti->maciv=GET_32BIT_MSB_FIRST(key+68); + ti->sendseq=GET_32BIT_MSB_FIRST(key+72); + ti->lastrecvseq=ti->sendseq; + ti->keyed=True; + + return True; +} + +TRANSFORM_VALID; + +static void transform_delkey(void *sst) +{ + struct transform_inst *ti=sst; + + FILLZERO(ti->cryptkey); + FILLZERO(ti->mackey); + ti->keyed=False; +} + +static uint32_t transform_forward(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + uint8_t *padp; + int padlen; + uint8_t iv[16]; + uint8_t macplain[16]; + uint8_t macacc[16]; + uint8_t *p, *n; + int i; + + KEYED_CHECK; + + /* Sequence number */ + buf_prepend_uint32(buf,ti->sendseq); + ti->sendseq++; + + /* PKCS5, stolen from IWJ */ + /* eg with blocksize=4 mask=3 mask+2=5 */ + /* msgsize 20 21 22 23 24 */ + padlen= PKCS5_MASK-buf->size; /* -17 -18 -19 -16 -17 */ + padlen &= PKCS5_MASK; /* 3 2 1 0 3 */ + padlen++; /* 4 3 2 1 4 */ + + padp=buf_append(buf,padlen); + memset(padp,padlen,padlen); + + /* Serpent-CBCMAC. We expand the IV from 32-bit to 128-bit using + one encryption. Then we do the MAC and append the result. We don't + bother sending the IV - it's the same each time. (If we wanted to send + it we've have to add 16 bytes to each message, not 4, so that the + message stays a multiple of 16 bytes long.) */ + memset(iv,0,16); + PUT_32BIT_MSB_FIRST(iv, ti->maciv); + serpent_encrypt(&ti->mackey,iv,macacc); + + /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted + block encrypted once again. */ + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + macplain[i] = macacc[i] ^ n[i]; + serpent_encrypt(&ti->mackey,macplain,macacc); + } + serpent_encrypt(&ti->mackey,macacc,macacc); + memcpy(buf_append(buf,16),macacc,16); + + /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption, + and prepend the IV before increasing it. */ + memset(iv,0,16); + PUT_32BIT_MSB_FIRST(iv, ti->cryptiv); + serpent_encrypt(&ti->cryptkey,iv,iv); + + /* CBC: each block is XORed with the previous encrypted block (or the IV) + before being encrypted. */ + p=iv; + + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + n[i] ^= p[i]; + serpent_encrypt(&ti->cryptkey,n,n); + p=n; + } + + buf_prepend_uint32(buf,ti->cryptiv); + ti->cryptiv++; + return 0; +} + +static uint32_t transform_reverse(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + uint8_t *padp; + int padlen; + int i; + uint32_t seqnum; + uint8_t iv[16]; + uint8_t pct[16]; + uint8_t macplain[16]; + uint8_t macacc[16]; + uint8_t *n; + uint8_t *macexpected; + + KEYED_CHECK; + + if (buf->size < 4 + 16 + 16) { + *errmsg="msg too short"; + return 1; + } + + /* CBC */ + memset(iv,0,16); + { + uint32_t ivword = buf_unprepend_uint32(buf); + PUT_32BIT_MSB_FIRST(iv, ivword); + } + /* Assert bufsize is multiple of blocksize */ + if (buf->size&0xf) { + *errmsg="msg not multiple of cipher blocksize"; + return 1; + } + serpent_encrypt(&ti->cryptkey,iv,iv); + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + pct[i] = n[i]; + serpent_decrypt(&ti->cryptkey,n,n); + for (i = 0; i < 16; i++) + n[i] ^= iv[i]; + memcpy(iv, pct, 16); + } + + /* CBCMAC */ + macexpected=buf_unappend(buf,16); + memset(iv,0,16); + PUT_32BIT_MSB_FIRST(iv, ti->maciv); + serpent_encrypt(&ti->mackey,iv,macacc); + + /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted + block encrypted once again. */ + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + macplain[i] = macacc[i] ^ n[i]; + serpent_encrypt(&ti->mackey,macplain,macacc); + } + serpent_encrypt(&ti->mackey,macacc,macacc); + if (consttime_memcmp(macexpected,macacc,16)!=0) { + *errmsg="invalid MAC"; + return 1; + } + + /* PKCS5, stolen from IWJ */ + + padp=buf_unappend(buf,1); + padlen=*padp; + if (!padlen || (padlen > PKCS5_MASK+1)) { + *errmsg="pkcs5: invalid length"; + return 1; + } + + buf_unappend(buf,padlen-1); + + /* Sequence number must be within max_skew of lastrecvseq; lastrecvseq + is only allowed to increase. */ + seqnum=buf_unprepend_uint32(buf); + SEQNUM_CHECK(seqnum, ti->max_skew); + + return 0; +} + +TRANSFORM_DESTROY; + +static struct transform_inst_if *transform_create(void *sst) +{ + struct transform *st=sst; + + TRANSFORM_CREATE_CORE; + + ti->max_skew=st->max_seq_skew; + + return &ti->ops; +} + +static list_t *transform_apply(closure_t *self, struct cloc loc, + dict_t *context, list_t *args) +{ + struct transform *st; + item_t *item; + dict_t *dict; + + st=safe_malloc(sizeof(*st),"serpent"); + st->cl.description="serpent-cbc256"; + st->cl.type=CL_TRANSFORM; + st->cl.apply=NULL; + st->cl.interface=&st->ops; + st->ops.st=st; + st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV, + 4byte IV */ + st->ops.max_end_pad=16; /* 16byte CBCMAC */ + + /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits + for CBCMAC-IV, and 32 bits for init sequence number */ + st->ops.keylen=REQUIRED_KEYLEN; + st->ops.create=transform_create; + + /* First parameter must be a dict */ + item=list_elem(args,0); + if (!item || item->type!=t_dict) + cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n"); + + dict=item->data.dict; + st->max_seq_skew=dict_read_number(dict, "max-sequence-skew", + False, "serpent-cbc256", loc, 10); + + return new_closure(&st->cl); +} + +void transform_cbcmac_module(dict_t *dict) +{ + struct keyInstance k; + uint8_t data[32]; + uint8_t plaintext[16]; + uint8_t ciphertext[16]; + + /* + * Serpent self-test. + * + * This test pattern is taken directly from the Serpent test + * vectors, to ensure we have all endianness issues correct. -sgt + */ + + /* Serpent self-test */ + memcpy(data, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" + "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00", + 32); + serpent_makekey(&k,256,data); + + memcpy(plaintext, + "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10", + 16); + serpent_encrypt(&k,plaintext,ciphertext); + + if (memcmp(ciphertext, "\xca\x7f\xa1\x93\xe3\xeb\x9e\x99" + "\xbd\x87\xe3\xaf\x3c\x9a\xdf\x93", 16)) { + fatal("transform_module: serpent failed self-test (encrypt)"); + } + serpent_decrypt(&k,ciphertext,plaintext); + if (memcmp(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\xfe\xdc\xba\x98\x76\x54\x32\x10", 16)) { + fatal("transform_module: serpent failed self-test (decrypt)"); + } + + add_closure(dict,"serpent256-cbc",transform_apply); + +#ifdef TEST_WHOLE_TRANSFORM + { + struct transform *tr; + void *ti; + struct buffer_if buf; + const char text[] = "This is a piece of test text."; + char keymaterial[76] = + "Seventy-six bytes i" + "n four rows of 19; " + "this looks almost l" + "ike a poem but not."; + const char *errmsg; + int i; + + tr = malloc(sizeof(struct transform)); + tr->max_seq_skew = 20; + ti = transform_create(tr); + + transform_setkey(ti, keymaterial, 76); + + buf.base = malloc(4096); + buffer_init(&buf, 2048); + memcpy(buf_append(&buf, sizeof(text)), text, sizeof(text)); + if (transform_forward(ti, &buf, &errmsg)) { + fatal("transform_forward test: %s", errmsg); + } + printf("transformed text is:\n"); + for (i = 0; i < buf.size; i++) + printf("%02x%c", buf.start[i], + (i%16==15 || i==buf.size-1 ? '\n' : ' ')); + if (transform_reverse(ti, &buf, &errmsg)) { + fatal("transform_reverse test: %s", errmsg); + } + printf("transform reversal worked OK\n"); + } +#endif +} diff --git a/transform-common.h b/transform-common.h new file mode 100644 index 0000000..b3c70a8 --- /dev/null +++ b/transform-common.h @@ -0,0 +1,56 @@ + +#ifndef TRANSFORM_COMMON_H +#define TRANSFORM_COMMON_H + +#define KEYED_CHECK do{ \ + if (!ti->keyed) { \ + *errmsg="transform unkeyed"; \ + return 1; \ + } \ + }while(0) + +#define SEQNUM_CHECK(seqnum, max_skew) do{ \ + uint32_t skew=seqnum-ti->lastrecvseq; \ + if (skew<0x8fffffff) { \ + /* Ok */ \ + ti->lastrecvseq=seqnum; \ + } else if ((0-skew)keyed; \ + } + +#define TRANSFORM_DESTROY \ + static void transform_destroy(void *sst) \ + { \ + struct transform_inst *st=sst; \ + \ + FILLZERO(*st); /* Destroy key material */ \ + free(st); \ + } + +#define TRANSFORM_CREATE_CORE \ + struct transform_inst *ti; \ + ti=safe_malloc(sizeof(*ti),"transform_create"); \ + /* mlock XXX */ \ + ti->ops.st=ti; \ + ti->ops.setkey=transform_setkey; \ + ti->ops.valid=transform_valid; \ + ti->ops.delkey=transform_delkey; \ + ti->ops.forwards=transform_forward; \ + ti->ops.reverse=transform_reverse; \ + ti->ops.destroy=transform_destroy; \ + ti->keyed=False; + +#endif /*TRANSFORM_COMMON_H*/ diff --git a/transform.c b/transform.c deleted file mode 100644 index 9ee0df0..0000000 --- a/transform.c +++ /dev/null @@ -1,394 +0,0 @@ -/* Transform module - bulk data transformation */ - -/* For now it's hard-coded to do sequence - number/pkcs5/serpent-cbcmac/serpent with a 256 bit key for each - instance of serpent. We also require key material for the IVs for - cbcmac and cbc. Hack: we're not using full 128-bit IVs, we're just - using 32 bits and encrypting to get the full IV to save space in - the packets sent over the wire. */ - -#include -#include -#include "secnet.h" -#include "util.h" -#include "serpent.h" -#include "unaligned.h" - -/* Required key length in bytes */ -#define REQUIRED_KEYLEN ((512+64+32)/8) - -struct transform { - closure_t cl; - struct transform_if ops; - uint32_t max_seq_skew; -}; - -struct transform_inst { - struct transform_inst_if ops; - struct keyInstance cryptkey; - struct keyInstance mackey; - uint32_t cryptiv; - uint32_t maciv; - uint32_t sendseq; - uint32_t lastrecvseq; - uint32_t max_skew; - bool_t keyed; -}; - -#define PKCS5_MASK 15 - -static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) -{ - struct transform_inst *ti=sst; - - if (keylencryptkey,256,key); - serpent_makekey(&ti->mackey,256,key+32); - ti->cryptiv=GET_32BIT_MSB_FIRST(key+64); - ti->maciv=GET_32BIT_MSB_FIRST(key+68); - ti->sendseq=GET_32BIT_MSB_FIRST(key+72); - ti->lastrecvseq=ti->sendseq; - ti->keyed=True; - - return True; -} - -static bool_t transform_valid(void *sst) -{ - struct transform_inst *ti=sst; - - return ti->keyed; -} - -static void transform_delkey(void *sst) -{ - struct transform_inst *ti=sst; - - FILLZERO(ti->cryptkey); - FILLZERO(ti->mackey); - ti->keyed=False; -} - -static uint32_t transform_forward(void *sst, struct buffer_if *buf, - const char **errmsg) -{ - struct transform_inst *ti=sst; - uint8_t *padp; - int padlen; - uint8_t iv[16]; - uint8_t macplain[16]; - uint8_t macacc[16]; - uint8_t *p, *n; - int i; - - if (!ti->keyed) { - *errmsg="transform unkeyed"; - return 1; - } - - /* Sequence number */ - buf_prepend_uint32(buf,ti->sendseq); - ti->sendseq++; - - /* PKCS5, stolen from IWJ */ - /* eg with blocksize=4 mask=3 mask+2=5 */ - /* msgsize 20 21 22 23 24 */ - padlen= PKCS5_MASK-buf->size; /* -17 -18 -19 -16 -17 */ - padlen &= PKCS5_MASK; /* 3 2 1 0 3 */ - padlen++; /* 4 3 2 1 4 */ - - padp=buf_append(buf,padlen); - memset(padp,padlen,padlen); - - /* Serpent-CBCMAC. We expand the IV from 32-bit to 128-bit using - one encryption. Then we do the MAC and append the result. We don't - bother sending the IV - it's the same each time. (If we wanted to send - it we've have to add 16 bytes to each message, not 4, so that the - message stays a multiple of 16 bytes long.) */ - memset(iv,0,16); - PUT_32BIT_MSB_FIRST(iv, ti->maciv); - serpent_encrypt(&ti->mackey,iv,macacc); - - /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted - block encrypted once again. */ - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - macplain[i] = macacc[i] ^ n[i]; - serpent_encrypt(&ti->mackey,macplain,macacc); - } - serpent_encrypt(&ti->mackey,macacc,macacc); - memcpy(buf_append(buf,16),macacc,16); - - /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption, - and prepend the IV before increasing it. */ - memset(iv,0,16); - PUT_32BIT_MSB_FIRST(iv, ti->cryptiv); - serpent_encrypt(&ti->cryptkey,iv,iv); - - /* CBC: each block is XORed with the previous encrypted block (or the IV) - before being encrypted. */ - p=iv; - - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - n[i] ^= p[i]; - serpent_encrypt(&ti->cryptkey,n,n); - p=n; - } - - buf_prepend_uint32(buf,ti->cryptiv); - ti->cryptiv++; - return 0; -} - -static uint32_t transform_reverse(void *sst, struct buffer_if *buf, - const char **errmsg) -{ - struct transform_inst *ti=sst; - uint8_t *padp; - int padlen; - int i; - uint32_t seqnum, skew; - uint8_t iv[16]; - uint8_t pct[16]; - uint8_t macplain[16]; - uint8_t macacc[16]; - uint8_t *n; - uint8_t *macexpected; - - if (!ti->keyed) { - *errmsg="transform unkeyed"; - return 1; - } - - if (buf->size < 4 + 16 + 16) { - *errmsg="msg too short"; - return 1; - } - - /* CBC */ - memset(iv,0,16); - { - uint32_t ivword = buf_unprepend_uint32(buf); - PUT_32BIT_MSB_FIRST(iv, ivword); - } - /* Assert bufsize is multiple of blocksize */ - if (buf->size&0xf) { - *errmsg="msg not multiple of cipher blocksize"; - return 1; - } - serpent_encrypt(&ti->cryptkey,iv,iv); - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - pct[i] = n[i]; - serpent_decrypt(&ti->cryptkey,n,n); - for (i = 0; i < 16; i++) - n[i] ^= iv[i]; - memcpy(iv, pct, 16); - } - - /* CBCMAC */ - macexpected=buf_unappend(buf,16); - memset(iv,0,16); - PUT_32BIT_MSB_FIRST(iv, ti->maciv); - serpent_encrypt(&ti->mackey,iv,macacc); - - /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted - block encrypted once again. */ - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - macplain[i] = macacc[i] ^ n[i]; - serpent_encrypt(&ti->mackey,macplain,macacc); - } - serpent_encrypt(&ti->mackey,macacc,macacc); - if (consttime_memcmp(macexpected,macacc,16)!=0) { - *errmsg="invalid MAC"; - return 1; - } - - /* PKCS5, stolen from IWJ */ - - padp=buf_unappend(buf,1); - padlen=*padp; - if (!padlen || (padlen > PKCS5_MASK+1)) { - *errmsg="pkcs5: invalid length"; - return 1; - } - - buf_unappend(buf,padlen-1); - - /* Sequence number must be within max_skew of lastrecvseq; lastrecvseq - is only allowed to increase. */ - seqnum=buf_unprepend_uint32(buf); - skew=seqnum-ti->lastrecvseq; - if (skew<0x8fffffff) { - /* Ok */ - ti->lastrecvseq=seqnum; - } else if ((0-skew)max_skew) { - /* Ok */ - } else { - /* Too much skew */ - *errmsg="seqnum: too much skew"; - return 2; - } - - return 0; -} - -static void transform_destroy(void *sst) -{ - struct transform_inst *st=sst; - - FILLZERO(*st); /* Destroy key material */ - free(st); -} - -static struct transform_inst_if *transform_create(void *sst) -{ - struct transform_inst *ti; - struct transform *st=sst; - - ti=safe_malloc(sizeof(*ti),"transform_create"); - /* mlock XXX */ - - ti->ops.st=ti; - ti->ops.setkey=transform_setkey; - ti->ops.valid=transform_valid; - ti->ops.delkey=transform_delkey; - ti->ops.forwards=transform_forward; - ti->ops.reverse=transform_reverse; - ti->ops.destroy=transform_destroy; - ti->max_skew=st->max_seq_skew; - ti->keyed=False; - - return &ti->ops; -} - -static list_t *transform_apply(closure_t *self, struct cloc loc, - dict_t *context, list_t *args) -{ - struct transform *st; - item_t *item; - dict_t *dict; - - st=safe_malloc(sizeof(*st),"serpent"); - st->cl.description="serpent-cbc256"; - st->cl.type=CL_TRANSFORM; - st->cl.apply=NULL; - st->cl.interface=&st->ops; - st->ops.st=st; - st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV, - 4byte IV */ - st->ops.max_end_pad=16; /* 16byte CBCMAC */ - - /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits - for CBCMAC-IV, and 32 bits for init sequence number */ - st->ops.keylen=REQUIRED_KEYLEN; - st->ops.create=transform_create; - - /* First parameter must be a dict */ - item=list_elem(args,0); - if (!item || item->type!=t_dict) - cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n"); - - dict=item->data.dict; - st->max_seq_skew=dict_read_number(dict, "max-sequence-skew", - False, "serpent-cbc256", loc, 10); - - return new_closure(&st->cl); -} - -void transform_module(dict_t *dict) -{ - struct keyInstance k; - uint8_t data[32]; - uint8_t plaintext[16]; - uint8_t ciphertext[16]; - - /* - * Serpent self-test. - * - * This test pattern is taken directly from the Serpent test - * vectors, to ensure we have all endianness issues correct. -sgt - */ - - /* Serpent self-test */ - memcpy(data, - "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" - "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00", - 32); - serpent_makekey(&k,256,data); - - memcpy(plaintext, - "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10", - 16); - serpent_encrypt(&k,plaintext,ciphertext); - - if (memcmp(ciphertext, "\xca\x7f\xa1\x93\xe3\xeb\x9e\x99" - "\xbd\x87\xe3\xaf\x3c\x9a\xdf\x93", 16)) { - fatal("transform_module: serpent failed self-test (encrypt)"); - } - serpent_decrypt(&k,ciphertext,plaintext); - if (memcmp(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", 16)) { - fatal("transform_module: serpent failed self-test (decrypt)"); - } - - add_closure(dict,"serpent256-cbc",transform_apply); - -#ifdef TEST_WHOLE_TRANSFORM - { - struct transform *tr; - void *ti; - struct buffer_if buf; - const char text[] = "This is a piece of test text."; - char keymaterial[76] = - "Seventy-six bytes i" - "n four rows of 19; " - "this looks almost l" - "ike a poem but not."; - const char *errmsg; - int i; - - tr = malloc(sizeof(struct transform)); - tr->max_seq_skew = 20; - ti = transform_create(tr); - - transform_setkey(ti, keymaterial, 76); - - buf.base = malloc(4096); - buffer_init(&buf, 2048); - memcpy(buf_append(&buf, sizeof(text)), text, sizeof(text)); - if (transform_forward(ti, &buf, &errmsg)) { - fatal("transform_forward test: %s", errmsg); - } - printf("transformed text is:\n"); - for (i = 0; i < buf.size; i++) - printf("%02x%c", buf.start[i], - (i%16==15 || i==buf.size-1 ? '\n' : ' ')); - if (transform_reverse(ti, &buf, &errmsg)) { - fatal("transform_reverse test: %s", errmsg); - } - printf("transform reversal worked OK\n"); - } -#endif -} -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:04 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:04 +0100 Subject: [PATCH 20/25] site: dynamically create and destroy transform instances In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-21-git-send-email-ijackson@chiark.greenend.org.uk> Rather than making three transform instances at setup time, and then using setkey on them, we create transform instances as needed and destroy them when we delete their keys. This is necessary because we are going to support multiple different kinds of transform, so each one of the three transforms might be of different kinds (supplied by different secnet modules) at different times. The variables current.transform, auxiliary_key.transform and new_transform can all be NULL now. Signed-off-by: Ian Jackson --- site.c | 31 ++++++++++++++++++++++--------- 1 files changed, 22 insertions(+), 9 deletions(-) diff --git a/site.c b/site.c index 5042af5..eb8460a 100644 --- a/site.c +++ b/site.c @@ -336,7 +336,8 @@ static void activate_new_key(struct site *st); static bool_t current_valid(struct site *st) { - return st->current.transform->valid(st->current.transform->st); + return st->current.transform && + st->current.transform->valid(st->current.transform->st); } #define CHECK_AVAIL(b,l) do { if ((b)->size<(l)) return False; } while(0) @@ -368,6 +369,19 @@ struct msg { char *sig; }; +static void set_new_transform(struct site *st) +{ + struct transform_if *generator=st->transform; + struct transform_inst_if *new_transform=generator->create(generator->st); + new_transform->setkey(new_transform->st,st->sharedsecret, + st->sharedsecretlen,st->setup_priority); + if (st->new_transform) { + st->new_transform->delkey(st->new_transform->st); + st->new_transform->destroy(st->new_transform->st); + } + st->new_transform=new_transform; +} + struct xinfoadd { int32_t lenpos, afternul; }; @@ -641,8 +655,7 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ - st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen,st->setup_priority); + set_new_transform(st); return True; } @@ -688,8 +701,7 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ - st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen,st->setup_priority); + set_new_transform(st); return True; } @@ -1027,9 +1039,10 @@ static void activate_new_key(struct site *st) static void delete_one_key(struct site *st, struct data_key *key, cstring_t reason, cstring_t which, uint32_t loglevel) { - if (!key->transform->valid(key->transform->st)) return; + if (!key->transform) return; if (reason) slog(st,loglevel,"%s deleted (%s)",which,reason); key->transform->delkey(key->transform->st); + key->transform->destroy(key->transform->st); key->key_timeout=0; } @@ -1659,9 +1672,9 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, for (i=0; incomms; i++) st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming); - st->current.transform=st->transform->create(st->transform->st); - st->auxiliary_key.transform=st->transform->create(st->transform->st); - st->new_transform=st->transform->create(st->transform->st); + st->current.transform=0; + st->auxiliary_key.transform=0; + st->new_transform=0; st->auxiliary_is_new=0; enter_state_stop(st); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:09 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:09 +0100 Subject: [PATCH 25/25] site: New PROD message In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-26-git-send-email-ijackson@chiark.greenend.org.uk> We introduce a new message PROD which requests that the peer initiate a key exchange with us, if it doesn't already have a key. This helps significantly reduce a possible "dead period" when one end of a connection is restarted during key exchange. The dead period is now limited to the time taken for the interrupted key exchange to time out. Signed-off-by: Ian Jackson --- NOTES | 34 +++++++++++++++++++++++ magic.h | 1 + site.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- udp.c | 1 + 4 files changed, 112 insertions(+), 15 deletions(-) diff --git a/NOTES b/NOTES index 7ead923..40cbf04 100644 --- a/NOTES +++ b/NOTES @@ -291,3 +291,37 @@ vaguely recent version of secnet. (In fact, there is no evidence in the git history of it ever being sent.) This message number is reserved. + +11) *,*,PROD,A,B + +Sent in response to a NAK from B to A. Requests that B initiates a +key exchange with A, if B is willing and lacks a transport key for A. +(If B doesn't have A's address configured, implicitly supplies A's +public address.) + +This is necessary because if one end of a link (B) is restarted while +a key exchange is in progress, the following bad state can persist: +the non-restarted end (A) thinks that the key is still valid and keeps +sending packets, but B either doesn't realise that a key exchange with +A is necessary or (if A is a mobile site) doesn't know A's public IP +address. + +Normally in these circumstances B would send NAKs to A, causing A to +initiate a key exchange. However if A and B were already in the +middle of a key exchange then A will not want to try another one until +the first one has timed out ("setup-time" x "setup-retries") and then +the key exchange retry timeout ("wait-time") has elapsed. + +However if B's setup has timed out, B would be willing to participate +in a key exchange initiated by A, if A could be induced to do so. +This is the purpose of the PROD packet. + +We send no more PRODs than we would want to send data packets, to +avoid a traffic amplification attack. We also send them only in state +WAIT, as in other states we wouldn't respond favourably. And we only +honour them if we don't already have a key. + +With PROD, the period of broken communication due to a key exchange +interrupted by a restart is limited to the key exchange total +retransmission timeout, rather than also including the key exchange +retry timeout. diff --git a/magic.h b/magic.h index f2ba3a0..b13ee1e 100644 --- a/magic.h +++ b/magic.h @@ -14,6 +14,7 @@ #define LABEL_MSG7 0x07070707 #define LABEL_MSG8 0x08080808 #define LABEL_MSG9 0x09090909 +#define LABEL_PROD 0x0a0a0a0a /* uses of the 32-bit capability bitmap */ #define CAPAB_EARLY 0x00000000 /* no Early flags yet (see NOTES) */ diff --git a/site.c b/site.c index 7304ef8..f640148 100644 --- a/site.c +++ b/site.c @@ -204,7 +204,8 @@ static void transport_peers_copy(struct site *st, transport_peers *dst, static void transport_setup_msgok(struct site *st, const struct comm_addr *a); static void transport_data_msgok(struct site *st, const struct comm_addr *a); static bool_t transport_compute_setupinit_peers(struct site *st, - const struct comm_addr *configured_addr /* 0 if none or not found */); + const struct comm_addr *configured_addr /* 0 if none or not found */, + const struct comm_addr *prod_hint_addr /* 0 if none */); static void transport_record_peer(struct site *st, transport_peers *peers, const struct comm_addr *addr, const char *m); @@ -262,6 +263,7 @@ struct site { /* runtime information */ uint32_t state; uint64_t now; /* Most recently seen time */ + bool_t allow_send_prod; /* The currently established session */ struct data_key current; @@ -331,7 +333,8 @@ static void delete_one_key(struct site *st, struct data_key *key, const char *reason /* may be 0 meaning don't log*/, const char *which /* ignored if !reasonn */, uint32_t loglevel /* ignored if !reasonn */); -static bool_t initiate_key_setup(struct site *st, cstring_t reason); +static bool_t initiate_key_setup(struct site *st, cstring_t reason, + const struct comm_addr *prod_hint); static void enter_state_run(struct site *st); static bool_t enter_state_resolve(struct site *st); static bool_t enter_new_state(struct site *st,uint32_t next); @@ -525,6 +528,10 @@ static bool_t unpick_msg(struct site *st, uint32_t type, m->remote_capabilities=buf_unprepend_uint32(&m->remote.extrainfo); } if (!unpick_name(msg,&m->local)) return False; + if (type==LABEL_PROD) { + CHECK_EMPTY(msg); + return True; + } CHECK_AVAIL(msg,NONCELEN); m->nR=buf_unprepend(msg,NONCELEN); if (type==LABEL_MSG1) { @@ -956,7 +963,7 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0) slog(st,LOG_SEC,"transform: %s (aux: %s, new: %s)", transform_err,auxkey_err,newkey_err); - initiate_key_setup(st,"incoming message would not decrypt"); + initiate_key_setup(st,"incoming message would not decrypt",0); return False; } @@ -981,7 +988,7 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0, transport_data_msgok(st,src); /* See whether we should start negotiating a new key */ if (st->now > st->renegotiate_key_time) - initiate_key_setup(st,"incoming packet in renegotiation window"); + initiate_key_setup(st,"incoming packet in renegotiation window",0); return True; default: slog(st,LOG_SEC,"incoming encrypted message of type %08x " @@ -1062,7 +1069,7 @@ static void site_resolve_callback(void *sst, struct in_addr *address) slog(st,LOG_ERROR,"resolution of %s failed",st->address); ca_use=0; } - if (transport_compute_setupinit_peers(st,ca_use)) { + if (transport_compute_setupinit_peers(st,ca_use,0)) { enter_new_state(st,SITE_SENTMSG1); } else { /* Can't figure out who to try to to talk to */ @@ -1071,14 +1078,15 @@ static void site_resolve_callback(void *sst, struct in_addr *address) } } -static bool_t initiate_key_setup(struct site *st, cstring_t reason) +static bool_t initiate_key_setup(struct site *st, cstring_t reason, + const struct comm_addr *prod_hint) { if (st->state!=SITE_RUN) return False; slog(st,LOG_SETUP_INIT,"initiating key exchange (%s)",reason); if (st->address) { slog(st,LOG_SETUP_INIT,"resolving peer address"); return enter_state_resolve(st); - } else if (transport_compute_setupinit_peers(st,0)) { + } else if (transport_compute_setupinit_peers(st,0,prod_hint)) { return enter_new_state(st,SITE_SENTMSG1); } slog(st,LOG_SETUP_INIT,"key exchange failed: no address for peer"); @@ -1289,6 +1297,30 @@ static void enter_state_wait(struct site *st) /* XXX Erase keys etc. */ } +static void generate_prod(struct site *st, struct buffer_if *buf) +{ + buffer_init(buf,0); + buf_append_uint32(buf,0); + buf_append_uint32(buf,0); + buf_append_uint32(buf,LABEL_PROD); + buf_append_string(buf,st->localname); + buf_append_string(buf,st->remotename); +} + +static void generate_send_prod(struct site *st, + const struct comm_addr *source) +{ + if (!st->allow_send_prod) return; /* too soon */ + if (!(st->state==SITE_RUN || st->state==SITE_RESOLVE || + st->state==SITE_WAIT)) return; /* we'd ignore peer's MSG1 */ + + slog(st,LOG_SETUP_INIT,"prodding peer for key exchange)"); + st->allow_send_prod=0; + generate_prod(st,&st->scratch); + dump_packet(st,&st->scratch,source,False); + source->comm->sendmsg(source->comm->st, &st->scratch, source); +} + static inline void site_settimeout(uint64_t timeout, int *timeout_io) { if (timeout) { @@ -1361,6 +1393,8 @@ static void site_outgoing(void *sst, struct buffer_if *buf) return; } + st->allow_send_prod=1; + /* In all other states we consider delivering the packet if we have a valid key and a valid address to send it to. */ if (current_valid(st) && transport_peers_valid(&st->peers)) { @@ -1380,7 +1414,7 @@ static void site_outgoing(void *sst, struct buffer_if *buf) slog(st,LOG_DROP,"discarding outgoing packet of size %d",buf->size); BUF_FREE(buf); - initiate_key_setup(st,"outgoing packet"); + initiate_key_setup(st,"outgoing packet",0); } static bool_t named_for_us(struct site *st, struct buffer_if *buf, @@ -1394,7 +1428,10 @@ static bool_t named_for_us(struct site *st, struct buffer_if *buf, } /* This function is called by the communication device to deliver - packets from our peers. */ + packets from our peers. + It should return True if the packet is recognised as being for + this current site instance (and should therefore not be processed + by other sites), even if the packet was otherwise ignored. */ static bool_t site_incoming(void *sst, struct buffer_if *buf, const struct comm_addr *source) { @@ -1452,6 +1489,19 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, BUF_FREE(buf); return True; } + if (msgtype==LABEL_PROD) { + if (!named_for_us(st,buf,msgtype,&named_msg)) + return False; + dump_packet(st,buf,source,True); + if (st->state!=SITE_RUN) { + slog(st,LOG_DROP,"ignoring PROD when not in state RUN"); + } else if (current_valid(st)) { + slog(st,LOG_DROP,"ignoring PROD when we think we have a key"); + } else { + initiate_key_setup(st,"peer sent PROD packet",source); + } + return True; + } if (dest==st->index) { /* Explicitly addressed to us */ if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); @@ -1460,7 +1510,9 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, /* If the source is our current peer then initiate a key setup, because our peer's forgotten the key */ if (get_uint32(buf->start+4)==st->current.remote_session_id) { - initiate_key_setup(st,"received a NAK"); + bool_t initiated; + initiated = initiate_key_setup(st,"received a NAK",0); + if (!initiated) generate_send_prod(st,source); } else { slog(st,LOG_SEC,"bad incoming NAK"); } @@ -1701,6 +1753,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->log_events=string_list_to_word(dict_lookup(dict,"log-events"), log_event_table,"site"); + st->allow_send_prod=0; + st->tunname=safe_malloc(strlen(st->localname)+strlen(st->remotename)+5, "site_apply"); sprintf(st->tunname,"%s<->%s",st->localname,st->remotename); @@ -1861,23 +1915,30 @@ static void transport_record_peer(struct site *st, transport_peers *peers, } static bool_t transport_compute_setupinit_peers(struct site *st, - const struct comm_addr *configured_addr /* 0 if none or not found */) { + const struct comm_addr *configured_addr /* 0 if none or not found */, + const struct comm_addr *prod_hint_addr /* 0 if none */) { - if (!configured_addr && !transport_peers_valid(&st->peers)) + if (!configured_addr && !prod_hint_addr && + !transport_peers_valid(&st->peers)) return False; slog(st,LOG_SETUP_INIT, - (!configured_addr ? "using only %d old peer address(es)" - : "using configured address, and/or perhaps %d old peer address(es)"), + "using:%s%s %d old peer address(es)", + configured_addr ? " configured address;" : "", + prod_hint_addr ? " PROD hint address;" : "", st->peers.npeers); /* Non-mobile peers havve st->peers.npeers==0 or ==1, since they * have transport_peers_max==1. The effect is that this code * always uses the configured address if supplied, or otherwise - * the existing data peer if one exists; this is as desired. */ + * the address of the incoming PROD, or the existing data peer if + * one exists; this is as desired. */ transport_peers_copy(st,&st->setup_peers,&st->peers); + if (prod_hint_addr) + transport_record_peer(st,&st->setup_peers,prod_hint_addr,"prod"); + if (configured_addr) transport_record_peer(st,&st->setup_peers,configured_addr,"setupinit"); diff --git a/udp.c b/udp.c index ba110fc..185d497 100644 --- a/udp.c +++ b/udp.c @@ -19,6 +19,7 @@ #include #include #include "util.h" +#include "magic.h" #include "unaligned.h" #include "ipaddr.h" #include "magic.h" -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:06 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:06 +0100 Subject: [PATCH 22/25] site, transform: per-transform-instance max_start_pad In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-23-git-send-email-ijackson@chiark.greenend.org.uk> Replicate the max_start_pad value from the transform interface into the instance interface. Use the instance's version in site.c. While we're at it, add an assertion to confirm that the value of max_start_pad passed to buffer_init doesn't overrun the buffer. Signed-off-by: Ian Jackson --- secnet.h | 1 + site.c | 6 +++--- transform-common.h | 1 + util.c | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/secnet.h b/secnet.h index 41578b4..3db0f6c 100644 --- a/secnet.h +++ b/secnet.h @@ -411,6 +411,7 @@ struct transform_inst_if { transform_apply_fn *forwards; transform_apply_fn *reverse; transform_destroyinstance_fn *destroy; + int32_t max_start_pad; /* same as from transform_if */ }; struct transform_if { diff --git a/site.c b/site.c index 817d5e4..35c2814 100644 --- a/site.c +++ b/site.c @@ -731,7 +731,7 @@ static bool_t generate_msg5(struct site *st) BUF_ALLOC(&st->buffer,"site:MSG5"); /* We are going to add four words to the message */ - buffer_init(&st->buffer,st->transform->max_start_pad+(4*4)); + buffer_init(&st->buffer,st->new_transform->max_start_pad+(4*4)); /* Give the netlink code an opportunity to put its own stuff in the message (configuration information, etc.) */ buf_prepend_uint32(&st->buffer,LABEL_MSG5); @@ -777,7 +777,7 @@ static void create_msg6(struct site *st, struct transform_inst_if *transform, BUF_ALLOC(&st->buffer,"site:MSG6"); /* We are going to add four words to the message */ - buffer_init(&st->buffer,st->transform->max_start_pad+(4*4)); + buffer_init(&st->buffer,transform->max_start_pad+(4*4)); /* Give the netlink code an opportunity to put its own stuff in the message (configuration information, etc.) */ buf_prepend_uint32(&st->buffer,LABEL_MSG6); @@ -1188,7 +1188,7 @@ static bool_t send_msg7(struct site *st, cstring_t reason) if (current_valid(st) && st->buffer.free && transport_peers_valid(&st->peers)) { BUF_ALLOC(&st->buffer,"site:MSG7"); - buffer_init(&st->buffer,st->transform->max_start_pad+(4*3)); + buffer_init(&st->buffer,st->current.transform->max_start_pad+(4*3)); buf_append_uint32(&st->buffer,LABEL_MSG7); buf_append_string(&st->buffer,reason); st->current.transform->forwards(st->current.transform->st, diff --git a/transform-common.h b/transform-common.h index b3c70a8..de19817 100644 --- a/transform-common.h +++ b/transform-common.h @@ -51,6 +51,7 @@ ti->ops.forwards=transform_forward; \ ti->ops.reverse=transform_reverse; \ ti->ops.destroy=transform_destroy; \ + ti->ops.max_start_pad=st->ops.max_start_pad; \ ti->keyed=False; #endif /*TRANSFORM_COMMON_H*/ diff --git a/util.c b/util.c index d47b944..8228280 100644 --- a/util.c +++ b/util.c @@ -244,6 +244,7 @@ void buffer_assert_used(struct buffer_if *buffer, cstring_t file, void buffer_init(struct buffer_if *buffer, int32_t max_start_pad) { + assert(max_start_pad<=buffer->len); buffer->start=buffer->base+max_start_pad; buffer->size=0; } -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:38:56 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:38:56 +0100 Subject: [PATCH 12/25] serpent: const-correct In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-13-git-send-email-ijackson@chiark.greenend.org.uk> Decorate serpent_encrypt, serpent_decrypt and serpent_makekey with appropriate consts in their arguments. Signed-off-by: Ian Jackson --- serpent.c | 6 +++--- serpent.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/serpent.c b/serpent.c index ce91854..34ef6aa 100644 --- a/serpent.c +++ b/serpent.c @@ -26,7 +26,7 @@ #include "serpentsboxes.h" void serpent_makekey(struct keyInstance *key, int keyLen, - uint8_t *keyMaterial) + const uint8_t *keyMaterial) { int i; uint32_t j; @@ -86,7 +86,7 @@ void serpent_makekey(struct keyInstance *key, int keyLen, } void serpent_encrypt(struct keyInstance *key, - uint8_t plaintext[16], + const uint8_t plaintext[16], uint8_t ciphertext[16]) { register uint32_t x0, x1, x2, x3; @@ -204,7 +204,7 @@ void serpent_encrypt(struct keyInstance *key, } void serpent_decrypt(struct keyInstance *key, - uint8_t ciphertext[16], + const uint8_t ciphertext[16], uint8_t plaintext[16]) { register uint32_t x0, x1, x2, x3; diff --git a/serpent.h b/serpent.h index 07176d7..19c01fe 100644 --- a/serpent.h +++ b/serpent.h @@ -8,12 +8,12 @@ struct keyInstance { /* Function protoypes */ void serpent_makekey(struct keyInstance *key, int keyLen, - uint8_t *keyMaterial); + const uint8_t *keyMaterial); -void serpent_encrypt(struct keyInstance *key, uint8_t plaintext[16], +void serpent_encrypt(struct keyInstance *key, const uint8_t plaintext[16], uint8_t ciphertext[16]); -void serpent_decrypt(struct keyInstance *key, uint8_t ciphertext[16], +void serpent_decrypt(struct keyInstance *key, const uint8_t ciphertext[16], uint8_t plaintext[16]); #endif /* serpent_h */ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:39:01 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:39:01 +0100 Subject: [PATCH 17/25] transform: Allow DH to set the key size In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374277149-4024-18-git-send-email-ijackson@chiark.greenend.org.uk> It turns out that the current Serpent CBC-MAC transform takes the raw DH shared secret, and parcels it up in byte ranges for the various uses (some of which are published). Well, obviously this is not a good idea. But also it means the interface isn't set up to allow the size of the key data provided to the transform to be determined by the size of the DH modulus. Fix this latter interface problem. Now a transform can set its keylen to 0, meaning it will be provided with the whole of the DH private value. We don't use this new feature yet. We can't make the existing transform use it without breaking compatibility, but it will be used by the new EAX-based transform. Signed-off-by: Ian Jackson --- dh.c | 4 ++++ secnet.h | 3 ++- site.c | 14 ++++++++------ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/dh.c b/dh.c index 2383192..c37b538 100644 --- a/dh.c +++ b/dh.c @@ -125,6 +125,10 @@ static list_t *dh_apply(closure_t *self, struct cloc loc, dict_t *context, st->ops.len=sz; + st->ops.ceil_len=(mpz_sizeinbase(&st->p,2)+7)/8; + /* According to the docs, mpz_sizeinbase(,256) is allowed to return + * an answer which is 1 too large. But mpz_sizeinbase(,2) isn't. */ + return new_closure(&st->cl); } diff --git a/secnet.h b/secnet.h index 1a5aaad..23d62ba 100644 --- a/secnet.h +++ b/secnet.h @@ -412,7 +412,7 @@ struct transform_if { void *st; int32_t max_start_pad; /* these three are all <<< INT_MAX */ int32_t max_end_pad; - int32_t keylen; + int32_t keylen; /* 0 means give the transform exactly as much as there is */ transform_createinstance_fn *create; }; @@ -459,6 +459,7 @@ typedef void dh_makeshared_fn(void *st, uint8_t *secret, struct dh_if { void *st; int32_t len; /* Approximate size of modulus in bytes */ + int32_t ceil_len; /* Number of bytes just sufficient to contain modulus */ dh_makepublic_fn *makepublic; dh_makeshared_fn *makeshared; }; diff --git a/site.c b/site.c index 23f5754..a0416d8 100644 --- a/site.c +++ b/site.c @@ -287,6 +287,7 @@ struct site { uint64_t timeout; /* Timeout for current state */ uint8_t *dhsecret; uint8_t *sharedsecret; + uint32_t sharedsecretlen; struct transform_inst_if *new_transform; /* For key setup/verify */ }; @@ -637,11 +638,11 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, /* Generate the shared key */ st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->transform->keylen); + st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->transform->keylen); + st->sharedsecretlen); return True; } @@ -685,10 +686,10 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, m.pk[m.pklen]=0; /* Generate the shared key */ st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->transform->keylen); + st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->transform->keylen); + st->sharedsecretlen); return True; } @@ -1085,7 +1086,7 @@ static void enter_state_run(struct site *st) memset(st->remoteN,0,NONCELEN); st->new_transform->delkey(st->new_transform->st); memset(st->dhsecret,0,st->dh->len); - memset(st->sharedsecret,0,st->transform->keylen); + memset(st->sharedsecret,0,st->sharedsecretlen); set_link_quality(st); } @@ -1635,7 +1636,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, transport_peers_clear(st,&st->setup_peers); /* XXX mlock these */ st->dhsecret=safe_malloc(st->dh->len,"site:dhsecret"); - st->sharedsecret=safe_malloc(st->transform->keylen,"site:sharedsecret"); + st->sharedsecretlen=st->transform->keylen?:st->dh->ceil_len; + st->sharedsecret=safe_malloc(st->sharedsecretlen,"site:sharedsecret"); /* We need to compute some properties of our comms */ #define COMPUTE_WORST(pad) \ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Sat Jul 20 00:45:08 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 00:45:08 +0100 Subject: [RFC PATCH v2 00/25] Algorithm agility, new transform, robustness In-Reply-To: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <20969.53124.629959.238245@chiark.greenend.org.uk> Ian Jackson writes ("[RFC PATCH v2 00/25] Algorithm agility, new transform, robustness"): > This is a portmanteau of my previous three patch series. They have > been extensively updated. I think these are mostly complete now, > although they have still NOT BEEN TESTED. git users can find it here: git://git.chiark.greenend.org.uk/~ian/secnet.git#master..wip-rebasing http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=shortlog;h=refs/heads/wip-rebasing Ian. From mdw at distorted.org.uk Sat Jul 20 14:12:58 2013 From: mdw at distorted.org.uk (Mark Wooding) Date: Sat, 20 Jul 2013 14:12:58 +0100 Subject: [PATCH 15/25] EAX: provide an implementation of EAX In-Reply-To: =?UTF-8?Q?=3C1374277149=2D4024=2D16=2Dgit=2Dsend=2Demail=2D?= =?UTF-8?Q?ijackson=40chiark=2Egreenend=2Eorg=2Euk=3E?= References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-16-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: Ian Jackson wrote: > Then for completeness we also provide a set of EAX-Serpent test > vectors and the corresponding test code. The EAX-Serpent test vectors > were generated by this very code, so aren't independently verified. I've understood how my Serpent implementation differs from Secnet's, and have reproduced your test vectors. NIST have managed to completely screw up their archive of the AES contest pages, but the WayBack Machine works fine -- even on the various PDF documents. The sorry tale begins with the initial Request for Candidate Algorithm Nominations, wherein the specification[1] for the test files unhelpfully muddles things by implying a big-endian representation in the test vector files, e.g., in 3.1, : Each of the possible key basis vectors is tested in this manner, by : shifting the "1" a single position at a time, starting at the most : significant (left-most) bit position of the key. It doesn't help that the original Serpent C implementations in the submission package[2] failed to implement the defined API correctly, and implicitly coerced BYTE pointer (from the defined entry point `blockEncrypt' to an `unsigned long' pointer as an argument to the internal `serpent_encrypt' function. The Java version carefully picks words out of its input byte array in a little-endian order. Secnet's implementation is derived from this original reference implementation. Originally, (v0.03) it had the same bug (only with `uint8_t' and `uint32_t'), but was patched (v0.1.16) to correct the obvious dependency on host endianness. Unfortunately, this patch is wrong: it creates a perfectly portable completely-byte-reversed Serpent compatible with nothing else. I've not found many other implementations, but where I have, they agree with me and the Java reference, and not with Secnet. [1] http://web.archive.org/web/20000420040415/http://csrc.nist.gov/encryption/aes/katmct/katmct.htm [2] http://www.cl.cam.ac.uk/~rja14/Papers/serpent.tar.gz > diff --git a/Makefile.in b/Makefile.in > index 182204b..6f36e4f 100644 > --- a/Makefile.in > +++ b/Makefile.in > +eax-%-test.confirm: eax-%-test eax-%-test.vectors > + ./$< $@.new > + mv -f $@.new $@ This should read ./$< <$(srcdir)/eax-$*-test.vectors >$@.new otherwise VPATH builds fail. > diff --git a/eax.c b/eax.c > new file mode 100644 > index 0000000..8c07fac > --- /dev/null > +++ b/eax.c > +static void xor(uint8_t *dst, const uint8_t *a, const uint8_t *b, size_t l) > + /* simple block xor */ > +{ > + while (l--) > + *dst++ = *a++ ^ *b++; > +} Annoyingly, `xor' is a reserved word in C++, and a macro defined in . I'd recommend a different name, like `block_xor' or something. > +static void alg_omac_t_k(INFO, uint8_t *mac_out, uint8_t t, > + const uint8_t *m, size_t m_len) > +{ > + cbc_init(I, mac_out); > + > + uint8_t tn[n]; > + memset(tn, 0, n-1); > + tn[n-1] = t; > + > + if (!m_len) { > + /* We're running pad() on just [t]_n, so we have to xor B into > + * [t]_n rather than some part of M */ > + xor(tn, tn, INFO_B, n); > + cbc_iter(I, mac_out, tn); > + return; > + } > + > + cbc_iter(I, mac_out, tn); > + > + size_t in=0; > + for (; in+n < m_len; in+=n) > + cbc_iter(I, mac_out, m+in); > + > + assert(in <= m_len); Following the logic, you should have strict inequality here. > + size_t remain = m_len - in; > + > + uint8_t lastblock[n]; > + if (remain==n) { > + xor(lastblock, m+in, INFO_B, n); > + } else { > + assert(remain>0 && remain + memcpy(lastblock, m+in, remain); > + size_t pos=remain; > + lastblock[pos++] = 0x80; > + assert(pos<=n); > + memset(lastblock+pos, 0, n-pos); > + xor(lastblock, lastblock, INFO_P, n); > + } > + cbc_iter(I, mac_out, lastblock); > +} This can be made less fiddly, I think, by splitting `cbc_iter' in two and delaying the `BLOCK_ENCRYPT' application. Something like this (tested). This subsumes the `cbc_init' and `cbc_iter' functions, so I removed them. static void alg_omac_t_k(INFO, uint8_t *mac_out, uint8_t t, const uint8_t *m, size_t m_len) { /* Initial tweak. */ memset(mac_out, 0, n-1); mac_out[n-1] = t; /* All of the whole blocks. */ size_t in=0; for (; in+n <= m_len; in+=n) { BLOCK_ENCRYPT(mac_out, mac_out); xor(mac_out, mac_out, m+in, n); } /* The last partial block, if there is one. */ assert(in <= m_len); size_t remain = m_len - in; if (!remain) xor(mac_out, mac_out, INFO_B, n); else { BLOCK_ENCRYPT(mac_out, mac_out); xor(mac_out, mac_out, m+in, remain); mac_out[remain] ^= 0x80; xor(mac_out, mac_out, INFO_P, n); } /* Final block-cipher application. */ BLOCK_ENCRYPT(mac_out, mac_out); } Also, this file has lines containing trailing whitespace and a mix of tabs and spaces for indentation, sometimes on the same line. (My Emacs goes into `angry-fruit-salad-mode'.) -- [mdw] From mdw at distorted.org.uk Sat Jul 20 12:36:01 2013 From: mdw at distorted.org.uk (Mark Wooding) Date: Sat, 20 Jul 2013 12:36:01 +0100 Subject: [PATCH 01/25] memcmp: Introduce and use consttime_memcmp In-Reply-To: =?UTF-8?Q?=3C1374277149=2D4024=2D2=2Dgit=2Dsend=2Demail=2Di?= =?UTF-8?Q?jackson=40chiark=2Egreenend=2Eorg=2Euk=3E?= References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-2-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: Ian Jackson wrote: > +int consttime_memcmp(const void *s1in, const void *s2in, size_t n) > +{ [...] > + return !!accumulator; > +} I think this function is named misleadingly. In particular, its return value merely tells you whether the two regions are unequal, and not their relative ordering. I'd call it something like `consttime_memneq'. Or change the sense of the output and call it `consttime_memeq', which is (more like) what I actually did. The `!!accumulator' is safe for the uses here, since the non-constant- time boolean canonification is done after the critical decision point, but it means that this function won't compose with other constant-time operations in a constant-time way (e.g., as is necessary when doing OAEP decoding). For example: int consttime_bool_canon(unsigned x) { assert(CHAR_BIT * sizeof(unsigned) <= 128); x |= x >> 8 >> 8 >> 8 >> 8 >> 8 >> 8 >> 8 >> 8; x |= x >> 8 >> 8 >> 8 >> 8; x |= x >> 8 >> 8; x |= x >> 8; x |= x >> 4; x |= x >> 2; x |= x >> 1; /* bottom bit now set if any */ x &= 1u; /* now either 0 or 1 */ return x; } -- [mdw] From ijackson at chiark.greenend.org.uk Sat Jul 20 13:45:11 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 13:45:11 +0100 Subject: [PATCH 01/25] memcmp: Introduce and use consttime_memcmp In-Reply-To: References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-2-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <20970.34391.907569.671435@chiark.greenend.org.uk> Mark Wooding writes ("Re: [PATCH 01/25] memcmp: Introduce and use consttime_memcmp"): > Ian Jackson wrote: > > +int consttime_memcmp(const void *s1in, const void *s2in, size_t n) > > +{ > [...] > > + return !!accumulator; > > +} > > I think this function is named misleadingly. In particular, its return > value merely tells you whether the two regions are unequal, and not > their relative ordering. I'd call it something like `consttime_memneq'. > Or change the sense of the output and call it `consttime_memeq', which > is (more like) what I actually did. Good point. > The `!!accumulator' is safe for the uses here, since the non-constant- > time boolean canonification is done after the critical decision point, > but it means that this function won't compose with other constant-time > operations in a constant-time way (e.g., as is necessary when doing OAEP > decoding). Hmm. > For example: > > int consttime_bool_canon(unsigned x) > { > assert(CHAR_BIT * sizeof(unsigned) <= 128); > x |= x >> 8 >> 8 >> 8 >> 8 >> 8 >> 8 >> 8 >> 8; > x |= x >> 8 >> 8 >> 8 >> 8; > x |= x >> 8 >> 8; > x |= x >> 8; > x |= x >> 4; > x |= x >> 2; > x |= x >> 1; /* bottom bit now set if any */ > x &= 1u; /* now either 0 or 1 */ > return x; > } I can see an clever compiler spotting this. I will think about this some more. Ian. From ijackson at chiark.greenend.org.uk Sat Jul 20 14:58:24 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 14:58:24 +0100 Subject: [PATCH 01/25] memcmp: Introduce and use consttime_memcmp In-Reply-To: <20970.34391.907569.671435@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-2-git-send-email-ijackson@chiark.greenend.org.uk> <20970.34391.907569.671435@chiark.greenend.org.uk> Message-ID: <20970.38784.491723.996145@chiark.greenend.org.uk> Ian Jackson writes ("Re: [PATCH 01/25] memcmp: Introduce and use consttime_memcmp"): > I can see an clever compiler spotting this. I will think about this > some more. I came up with this instead. Seems much better, although the main loop itself is slower. Ian. From: Ian Jackson Subject: memcmp: Introduce and use consttime_memeq We need to use a constant-time memcmp in MAC checking, to avoid leaking (to an adversary) how much of the MAC is right. (This would be especially dangerous if our MAC was outside the encryption, which thankfully it isn't.) The use of "volatile" on the accumulator prevents the compiler from optimising away any of the updates to the accumulator, each of which depends on all the bits of the two bytes being compared. So that stops the compiler shortcutting the computation. This also prevents the compiler spotting our boolean canonicalisation, and forces it to do it the way we say. This is true according to the spec by virtue of C99 6.7.3(6). In an attempt to get the compiler to eliminate the pointless repeated loading and storing of the single-byte accumulator value, I have specified it as "register volatile". There is no rule against "register volatile", but my compiler ignores the "register". To double check that all is well, here is an annotated disassembly, from this command line: gcc -save-temps -DHAVE_CONFIG_H -I. -I. -Wall -Wwrite-strings -g -O2 \ -Werror -W -Wno-unused -Wno-pointer-sign -Wstrict-prototypes \ -Wmissing-prototypes -Wmissing-declarations -Wnested-externs \ -Wredundant-decls -Wpointer-arith -Wformat=2 -Winit-self \ -Wswitch-enum -Wunused-variable -Wbad-function-cast \ -Wno-strict-aliasing -fno-strict-aliasing -c util.c -o util.o This is the relevant part of util.s, as generated by gcc 4.4.5-8 i486-linux-gnu, with my annotations: .globl consttime_memeq .type consttime_memeq, @function consttime_memeq: .LFB80: .loc 1 367 0 .cfi_startproc .LVL8: pushl %ebp .LCFI8: .cfi_def_cfa_offset 8 movl %esp, %ebp .cfi_offset 5, -8 .LCFI9: .cfi_def_cfa_register 5 pushl %edi pushl %esi pushl %ebx subl $16, %esp .loc 1 367 0 movl 16(%ebp), %ebx ebx : n .cfi_offset 3, -20 .cfi_offset 6, -16 .cfi_offset 7, -12 movl 8(%ebp), %esi esi : s1in movl 12(%ebp), %edi edi : s2in .loc 1 369 0 movb $0, -13(%ebp) -13(ebp) : accumulator .LVL9: .loc 1 371 0 testl %ebx, %ebx if (!n) je .L15 goto no_bytes; i.e. if (n) { ...loop... } .LVL10: The compiler has chosen to invent an offset variable for controlling the loop, rather than pointer arithmetic. We'll call that variable i. It ranges from 0..n-1 as expected. The compiler doesn't explictly compute the per-iteration pointers s1 and s2, instead using an addressing mode. xorl %edx, %edx edx : i .p2align 4,,7 .p2align 3 .L16: more_bytes: /* loop */ .loc 1 372 0 movzbl (%edi,%edx), %eax eax = *s2; .LVL11: movzbl -13(%ebp), %ecx ecx = accumulator; xorb (%esi,%edx), %al al = *s1 ^ *s2; addl $1, %edx i++; orl %ecx, %eax eax = accumulator | (*s1^*s2) .LVL12: .loc 1 371 0 cmpl %edx, %ebx [ if (i==n) ... ] .loc 1 372 0 movb %al, -13(%ebp) accumulator = eax; i.e., overall, accumulator |= *s1 ^ *s2 .loc 1 371 0 jne .L16 ... [if (i!=n)] goto more_bytes; .LVL13: .L15: no_bytes: .loc 1 374 0 /* end of loop and if */ /* now doing the shift-by-4: */ movzbl -13(%ebp), %eax eax = accumulator; movzbl -13(%ebp), %edx edx = accumulator; shrb $4, %al al >>= 4; .LVL14: orl %edx, %eax eax |= edx; .LVL15: movb %al, -13(%ebp) accumulator = eax; i.e., overall, accumulator |= accumulator >> 4; .loc 1 375 0 movzbl -13(%ebp), %eax /* same again but for shift-by-2 */ movzbl -13(%ebp), %edx shrb $2, %al orl %edx, %eax .LVL16: movb %al, -13(%ebp) .loc 1 376 0 movzbl -13(%ebp), %eax /* same again but for shift-by-1 */ movzbl -13(%ebp), %edx shrb %al orl %edx, %eax .LVL17: movb %al, -13(%ebp) /* now computed final accumulator */ .loc 1 377 0 movzbl -13(%ebp), %eax eax = accumulator; andl $1, %eax eax &= 1; .LVL18: movb %al, -13(%ebp) accumulator = eax; .loc 1 378 0 movzbl -13(%ebp), %eax eax = accumulator; xorl $1, %eax eax ^= 1; .LVL19: movb %al, -13(%ebp) accumulator = eax; .loc 1 379 0 movzbl -13(%ebp), %eax eax = accumulator; .LVL20: .loc 1 380 0 addl $16, %esp function epilogue popl %ebx ... .LVL21: popl %esi ... .LVL22: popl %edi ... .LVL23: .loc 1 379 0 movzbl %al, %eax sign extend? .loc 1 380 0 popl %ebp ... ret return eax; i.e. return accumulator; .cfi_endproc .LFE80: .size consttime_memeq, .-consttime_memeq Signed-off-by: Ian Jackson --- site.c | 2 +- transform.c | 2 +- util.c | 16 ++++++++++++++++ util.h | 2 ++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/site.c b/site.c index db65bd8..b9b4d0d 100644 --- a/site.c +++ b/site.c @@ -463,7 +463,7 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, return False; } if (type==LABEL_MSG2) return True; - if (memcmp(m->nR,st->remoteN,NONCELEN)!=0) { + if (!consttime_memeq(m->nR,st->remoteN,NONCELEN)!=0) { *error="wrong remotely-generated nonce"; return False; } diff --git a/transform.c b/transform.c index 289b02e..012f618 100644 --- a/transform.c +++ b/transform.c @@ -220,7 +220,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, serpent_encrypt(&ti->mackey,macplain,macacc); } serpent_encrypt(&ti->mackey,macacc,macacc); - if (memcmp(macexpected,macacc,16)!=0) { + if (!consttime_memeq(macexpected,macacc,16)!=0) { *errmsg="invalid MAC"; return 1; } diff --git a/util.c b/util.c index f5f3d75..10bff5a 100644 --- a/util.c +++ b/util.c @@ -363,6 +363,22 @@ static list_t *buffer_apply(closure_t *self, struct cloc loc, dict_t *context, return new_closure(&st->cl); } +int consttime_memeq(const void *s1in, const void *s2in, size_t n) +{ + const uint8_t *s1=s1in, *s2=s2in; + register volatile uint8_t accumulator=0; + + while (n-- > 0) { + accumulator |= (*s1++ ^ *s2++); + } + accumulator |= accumulator >> 4; /* constant-time */ + accumulator |= accumulator >> 2; /* boolean canonicalisation */ + accumulator |= accumulator >> 1; + accumulator &= 1; + accumulator ^= 1; + return accumulator; +} + void util_module(dict_t *dict) { add_closure(dict,"sysbuffer",buffer_apply); diff --git a/util.h b/util.h index af19363..4df27fd 100644 --- a/util.h +++ b/util.h @@ -39,4 +39,6 @@ extern int32_t write_mpbin(MP_INT *a, uint8_t *buffer, int32_t buflen); extern struct log_if *init_log(list_t *loglist); +extern int consttime_memeq(const void *s1, const void *s2, size_t n); + #endif /* util_h */ -- tg: (f237639..) nak/memcmp (depends on: master) From ijackson at chiark.greenend.org.uk Sat Jul 20 15:14:26 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sat, 20 Jul 2013 15:14:26 +0100 Subject: [PATCH 23/25] site: support multiple transforms In-Reply-To: <1374277149-4024-24-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-24-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <20970.39746.155378.517955@chiark.greenend.org.uk> Ian Jackson writes ("[PATCH 23/25] site: support multiple transforms"): ... > + * Iff both ends' transform capability masks are nonempty, MSG3 > + * contains an additional byte specifying the transform capability > + * number actually chosen by the MSG3 sender. This is quite ugly, really. After sleeping on it, I concluded that the right thing to do instead is to invent a new variant of MSG3 with a different LABEL, call it LABEL_MSG3BIS. > +static bool_t msg_specifies_transform(struct site *st, uint32_t msgtype) > +{ > + return > + (msgtype==LABEL_MSG3) && > + (st->local_capabilities & CAPAB_TRANSFORM_MASK) && > + (st->remote_capabilities & CAPAB_TRANSFORM_MASK); Which will simplify this, at the cost of having to turn several type==LABEL_MSG3 into type==LABEL_MSG3 || type==LABEL_MSG3BIS elsewhere. I haven't coded this up yet. Ian. From mdw at distorted.org.uk Sat Jul 20 16:16:34 2013 From: mdw at distorted.org.uk (Mark Wooding) Date: Sat, 20 Jul 2013 16:16:34 +0100 Subject: [PATCH 19/25] transform: Provide Serpment-EAX transform In-Reply-To: =?UTF-8?Q?=3C1374277149=2D4024=2D20=2Dgit=2Dsend=2Demail=2D?= =?UTF-8?Q?ijackson=40chiark=2Egreenend=2Eorg=2Euk=3E?= References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-20-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: Ian Jackson wrote: [...some plausible-looking code...] But, alas, `Serpment' in the subject line stood out as wanting fixing. -- [mdw] From ijackson at chiark.greenend.org.uk Sun Jul 21 01:50:28 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sun, 21 Jul 2013 01:50:28 +0100 Subject: [PATCH 19/25] transform: Provide Serpment-EAX transform In-Reply-To: References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-20-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <20971.12372.647898.163612@chiark.greenend.org.uk> Mark Wooding writes ("Re: [PATCH 19/25] transform: Provide Serpment-EAX transform"): > Ian Jackson wrote: > > [...some plausible-looking code...] Thanks for the review. > But, alas, `Serpment' in the subject line stood out as wanting fixing. Heh. Fixed, thanks. Ian. From ijackson at chiark.greenend.org.uk Sun Jul 21 11:47:09 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Sun, 21 Jul 2013 11:47:09 +0100 Subject: [PATCH 15/25] EAX: provide an implementation of EAX In-Reply-To: References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-16-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <20971.48173.795773.585966@chiark.greenend.org.uk> Mark Wooding writes ("Re: [PATCH 15/25] EAX: provide an implementation of EAX"): > Ian Jackson wrote: > > Then for completeness we also provide a set of EAX-Serpent test > > vectors and the corresponding test code. The EAX-Serpent test vectors > > were generated by this very code, so aren't independently verified. > > I've understood how my Serpent implementation differs from Secnet's, and > have reproduced your test vectors. > [stuff] Thanks for the research. This is now a bit of a mess, which I will deal with in a bit. > > +eax-%-test.confirm: eax-%-test eax-%-test.vectors > > + ./$< $@.new > > + mv -f $@.new $@ > > This should read > ./$< <$(srcdir)/eax-$*-test.vectors >$@.new > otherwise VPATH builds fail. Fixed. > Annoyingly, `xor' is a reserved word in C++, and a macro defined in > . I'd recommend a different name, like `block_xor' or > something. Fixed. > > +static void alg_omac_t_k(INFO, uint8_t *mac_out, uint8_t t, > > + const uint8_t *m, size_t m_len) ... > This can be made less fiddly, I think, by splitting `cbc_iter' in two > and delaying the `BLOCK_ENCRYPT' application. Something like this > (tested). This subsumes the `cbc_init' and `cbc_iter' functions, so I > removed them. Thanks, I like your version a lot better. I've incorporated it. (I've kept your S-o-b from your previous contribution to this patch.) > Also, this file has lines containing trailing whitespace and a mix of > tabs and spaces for indentation, sometimes on the same line. (My Emacs > goes into `angry-fruit-salad-mode'.) I don't think I would normally care abuut this in secnet. But this particular file is probably useful elsewhere, so to make that slightly less awkward I've untabified it and removed the trailing spaces. Thanks Ian. From ijackson at chiark.greenend.org.uk Mon Jul 22 00:06:30 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Mon, 22 Jul 2013 00:06:30 +0100 Subject: [PATCH 15/25] EAX: provide an implementation of EAX In-Reply-To: References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-16-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <20972.26998.71955.96117@chiark.greenend.org.uk> Mark Wooding writes ("Re: [PATCH 15/25] EAX: provide an implementation of EAX"): > I've understood how my Serpent implementation differs from Secnet's, and > have reproduced your test vectors. I've managed to produce a compile-time-bytesexual serpent.c which passes both your and my test vectors, and have plumbed it in in what seems to me the obvious way. The new transform will use Serpent[-LE]; the old one will continue to use Serpent-BE. Ian. From ijackson at chiark.greenend.org.uk Mon Jul 22 00:19:37 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Mon, 22 Jul 2013 00:19:37 +0100 Subject: [PATCH 0/4] rsa.c: Fixes for key length processing Message-ID: <1374448781-16806-1-git-send-email-ijackson@chiark.greenend.org.uk> Mark prepared this series and passed me the git URL. I'm posting it here for form's sake. I am integrating it into my enormous pending series. 1/4 rsa.c: Fix incorrect commentary. 2/4 rsa.c: Factor out constructing the EMSA-PKCS1 message representative. 3/4 rsa.c: Replace the magic length 1024 with a (larger) constant. 4/4 rsa.c: Check public key length. 4/4 is a fix for what is a security issue. An insider attacker can configure a stupidly large RSA public key (via the sites file, either manually updated or via a userv invocation). secnet will then overflow its buffer. In order to make it more than a denial of service attack, the attacker has to arrange for the MD5 hash of a message being verified contain their shellcode (or a jump to it). From ijackson at chiark.greenend.org.uk Mon Jul 22 00:19:38 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Mon, 22 Jul 2013 00:19:38 +0100 Subject: [PATCH 1/4] rsa.c: Fix incorrect commentary. In-Reply-To: <1374448781-16806-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374448781-16806-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374448781-16806-2-git-send-email-ijackson@chiark.greenend.org.uk> From: Mark Wooding The Euler function phi(n) is defined to be phi(n) = #{ 1 < i < n | gcd(i, n) = 1 } the number of natural numbers less than n and prime to it; equivalently, it's the size of the multiplicative group (Z/nZ)^*. If n = p q is the product of two primes then phi(n) = (p - 1)(q - 1). But phi(n) is not (if n is composite) the exponent of (Z/nZ)^*. It's certainly true that a^{phi(n)} = 1 for all a in (Z/nZ)^*; but the exponent of a group G is the /smallest/ positive integer e such that a^e == 1 for all a in G. This quantity is denoted lambda(n); in our simple case where n = p q is the product of two primes it's true that lambda(n) = lcm(p - 1, q - 1) Since p and q are large primes, both p - 1 and q - 1 are even, so lambda(n) is at least a factor of 2 smaller than phi(n). In fact, lambda(2) = 1, lambda(2^f) = 2^{f-2} for f >= 1, and lambda(p^f) = p^{f-1} (p - 1) for prime p > 2; and, in general, if n = p_1^{f_1} ... p_m^{f_m} is the prime factorization of n then lambda(n) = lcm(lambda(p_1^{f_1}), ... lambda(p_m^{f_m})) Signed-off-by: Mark Wooding --- rsa.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rsa.c b/rsa.c index 0bd106f..fed468d 100644 --- a/rsa.c +++ b/rsa.c @@ -430,8 +430,9 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, /* * Verify that d*e is congruent to 1 mod (p-1), and mod * (q-1). This is equivalent to it being congruent to 1 mod - * lcm(p-1,q-1), i.e. congruent to 1 mod phi(n). Note that - * phi(n) is _not_ simply (p-1)*(q-1). + * lambda(n) = lcm(p-1,q-1). The usual `textbook' condition, + * that d e == 1 (mod (p-1)(q-1)) is sufficient, but not + * actually necessary. */ mpz_mul(&tmp, &d, &e); mpz_sub_ui(&tmp2, &st->p, 1); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Mon Jul 22 00:19:39 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Mon, 22 Jul 2013 00:19:39 +0100 Subject: [PATCH 2/4] rsa.c: Factor out constructing the EMSA-PKCS1 message representative. In-Reply-To: <1374448781-16806-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374448781-16806-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374448781-16806-3-git-send-email-ijackson@chiark.greenend.org.uk> From: Mark Wooding This was done in two different places for no reason I could understand. Replace them both with a single implementation. Signed-off-by: Mark Wooding --- rsa.c | 47 ++++++++++++++++++----------------------------- 1 files changed, 18 insertions(+), 29 deletions(-) diff --git a/rsa.c b/rsa.c index fed468d..0ca5d19 100644 --- a/rsa.c +++ b/rsa.c @@ -36,16 +36,11 @@ struct rsapub { static const char *hexchars="0123456789abcdef"; -static string_t rsa_sign(void *sst, uint8_t *data, int32_t datalen) +static void emsa_pkcs1(MP_INT *n, MP_INT *m, + const uint8_t *data, int32_t datalen) { - struct rsapriv *st=sst; - MP_INT a, b, u, v, tmp, tmp2; char buff[2048]; int msize, i; - string_t signature; - - mpz_init(&a); - mpz_init(&b); /* RSA PKCS#1 v1.5 signature padding: * @@ -65,7 +60,7 @@ static string_t rsa_sign(void *sst, uint8_t *data, int32_t datalen) * -iwj 17.9.2002 */ - msize=mpz_sizeinbase(&st->n, 16); + msize=mpz_sizeinbase(n, 16); if (datalen*2+6>=msize) { fatal("rsa_sign: message too big"); @@ -86,7 +81,20 @@ static string_t rsa_sign(void *sst, uint8_t *data, int32_t datalen) buff[msize]=0; - mpz_set_str(&a, buff, 16); + mpz_set_str(m, buff, 16); +} + +static string_t rsa_sign(void *sst, uint8_t *data, int32_t datalen) +{ + struct rsapriv *st=sst; + MP_INT a, b, u, v, tmp, tmp2; + string_t signature; + + mpz_init(&a); + mpz_init(&b); + + /* Construct the message representative. */ + emsa_pkcs1(&st->n, &a, data, datalen); /* * Produce an RSA signature (a^d mod n) using the Chinese @@ -135,32 +143,13 @@ static bool_t rsa_sig_check(void *sst, uint8_t *data, int32_t datalen, { struct rsapub *st=sst; MP_INT a, b, c; - char buff[2048]; - int msize, i; bool_t ok; mpz_init(&a); mpz_init(&b); mpz_init(&c); - msize=mpz_sizeinbase(&st->n, 16); - - strcpy(buff,"0001"); - - for (i=0; i>4]; - buff[msize+(-datalen+i)*2+1]=hexchars[data[i]&0xf]; - } - - buff[msize-datalen*2-2]= '0'; - buff[msize-datalen*2-1]= '0'; - - for (i=4; in, &a, data, datalen); mpz_set_str(&b, signature, 16); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Mon Jul 22 00:19:40 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Mon, 22 Jul 2013 00:19:40 +0100 Subject: [PATCH 3/4] rsa.c: Replace the magic length 1024 with a (larger) constant. In-Reply-To: <1374448781-16806-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374448781-16806-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374448781-16806-4-git-send-email-ijackson@chiark.greenend.org.uk> From: Mark Wooding While 15360-bit RSA keys are rather large, they're not completely beyond the realms of possibility and it seems unreasonable to forbid them. (Specifically, 15360 is the length recommended by NIST for 256-bit security levels.) Signed-off-by: Mark Wooding --- rsa.c | 20 +++++++++++++------- 1 files changed, 13 insertions(+), 7 deletions(-) diff --git a/rsa.c b/rsa.c index 0ca5d19..2db03c9 100644 --- a/rsa.c +++ b/rsa.c @@ -34,12 +34,18 @@ struct rsapub { }; /* Sign data. NB data must be smaller than modulus */ +#define RSA_MAX_MODBYTES 2048 +/* The largest modulus I've seen is 15360 bits, which works out at 1920 + * bytes. Using keys this big is quite implausible, but it doesn't cost us + * much to support them. + */ + static const char *hexchars="0123456789abcdef"; static void emsa_pkcs1(MP_INT *n, MP_INT *m, const uint8_t *data, int32_t datalen) { - char buff[2048]; + char buff[2*RSA_MAX_MODBYTES + 1]; int msize, i; /* RSA PKCS#1 v1.5 signature padding: @@ -296,7 +302,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, /* Read the public key */ keyfile_get_int(loc,f); /* Not sure what this is */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausible length %ld for modulus\n", length); } @@ -308,7 +314,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, read_mpbin(&st->n,b,length); free(b); length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausible length %ld for e\n",length); } b=safe_malloc(length,"rsapriv_apply"); @@ -339,7 +345,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, /* Read d */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausibly long (%ld) decryption key\n", length); } @@ -353,7 +359,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, free(b); /* Read iqmp (inverse of q mod p) */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausibly long (%ld)" " iqmp auxiliary value\n", length); } @@ -367,7 +373,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, free(b); /* Read q (the smaller of the two primes) */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausibly long (%ld) q value\n", length); } @@ -381,7 +387,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, free(b); /* Read p (the larger of the two primes) */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausibly long (%ld) p value\n", length); } -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Mon Jul 22 00:19:41 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Mon, 22 Jul 2013 00:19:41 +0100 Subject: [PATCH 4/4] rsa.c: Check public key length. In-Reply-To: <1374448781-16806-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374448781-16806-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374448781-16806-5-git-send-email-ijackson@chiark.greenend.org.uk> From: Mark Wooding The private key is checked quite carefully -- even to a fault -- for being sensibly sized, but the corresponding function for public keys appears to have no checking at all. This is a shame since message- representative construction assumes that the message representative will fit in a fixed-size buffer. Fix this situation by checking public key sizes in `rsapub_apply'. Signed-off-by: Mark Wooding --- rsa.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/rsa.c b/rsa.c index 2db03c9..f4de7b4 100644 --- a/rsa.c +++ b/rsa.c @@ -199,6 +199,9 @@ static list_t *rsapub_apply(closure_t *self, struct cloc loc, dict_t *context, } else { cfgfatal(loc,"rsa-public","you must provide an encryption key\n"); } + if (mpz_sizeinbase(&st->e, 256) > RSA_MAX_MODBYTES) { + cfgfatal(loc, "rsa-public", "implausibly large public exponent"); + } i=list_elem(args,1); if (i) { @@ -213,6 +216,9 @@ static list_t *rsapub_apply(closure_t *self, struct cloc loc, dict_t *context, } else { cfgfatal(loc,"rsa-public","you must provide a modulus\n"); } + if (mpz_sizeinbase(&st->n, 256) > RSA_MAX_MODBYTES) { + cfgfatal(loc, "rsa-public", "implausibly large public exponent"); + } return new_closure(&st->cl); } -- 1.7.2.5 From mdw at distorted.org.uk Mon Jul 22 01:57:26 2013 From: mdw at distorted.org.uk (Mark Wooding) Date: Mon, 22 Jul 2013 01:57:26 +0100 Subject: [PATCH 15/25] EAX: provide an implementation of EAX In-Reply-To: <20972.26998.71955.96117@chiark.greenend.org.uk> References: <1374277149-4024-1-git-send-email-ijackson@chiark.greenend.org.uk> <1374277149-4024-16-git-send-email-ijackson@chiark.greenend.org.uk> <20972.26998.71955.96117@chiark.greenend.org.uk> Message-ID: Ian Jackson wrote: > I've managed to produce a compile-time-bytesexual serpent.c which > passes both your and my test vectors, and have plumbed it in in what > seems to me the obvious way. Good-oh. > The new transform will use Serpent[-LE]; the old one will continue to > use Serpent-BE. That sounds like a fine plan. -- [mdw] From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:26 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:26 +0100 Subject: [PATCH v3 00/41] Security and reliability fixes Message-ID: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> This series fixes several security problems, some serious, and a number of other bugs. git users can find it here: git://git.chiark.greenend.org.uk/~ian/secnet.git#master..wip-rebasing http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=shortlog;h=refs/heads/wip-rebasing I have repro'd all the significant bugs mentioned, and tested the fixes, the new transform, the new PROD message, and the backward compatibility machinery. I'm currently running this version on zealot, my netbook. If all goes well, and subject to comments, I plan to push this to master in the middle of next week and start beta-testing it on chiark. It would be good if people would at least read the descriptions of the patches to check that what I'm doing sounds sane. The most critical patches have been reviewed by Mark Wooding already, which is very helpful, and the other somewhat-dicey stuff has survived my testing. So unless anyone particularly wants to, I don't think there's a need for detailed code review. I have laid the groundwork for a future public key algorithm transition, but not actually gone any further in that direction. Our current arrangements are suboptimal, but they aren't in need of action. Mark: I have changed the eax-serpent transform to check the received sequence number _after_ decryption. This allows us to reliably distinguish "message was decryptable but stale due to network lag or attack" from "message is from previous session using same site index values". 01/41 rsa.c: Fix incorrect commentary. 02/41 rsa.c: Factor out constructing the EMSA-PKCS1 message representative. 03/41 rsa.c: Replace the magic length 1024 with a (larger) constant. 04/41 rsa.c: Check public key length. 05/41 unaligned.h: rationalise; provide buf_append_uint8 et al 06/41 util, buffers: Preparatory improvements 07/41 memcmp: Introduce and use consttime_memeq 08/41 transform: Do not look at any bytes of PKCS#5 padding other than the last 09/41 serpent: const-correct 10/41 serpent, transform: rework GET_32BIT_MSB_FIRST, PUT_... 11/41 serpent: Provide little-endian version too, but ours is big 12/41 serpent: Ad-hoc debugging facility 13/41 crypto: Copy a SHA512 implementation into tree 14/41 crypto: Copy an AES (Rijndael) implementation into tree 15/41 EAX: provide an implementation of EAX 16/41 transform: split out transform-common.h 17/41 transform: Allow DH to set the key size 18/41 transform: Pass a direction flag to the transform 19/41 transform: Provide Serpent-EAX transform 20/41 magic: Introduce LABEL_NAK 21/41 udp.c: Do not send NAKs in response to NAKs 22/41 udp, util: Break out send_nak function 23/41 site: Send NAKs for undecryptable data packets (msg0) 24/41 NOTES: Improve documentation of NAKs. 25/41 NOTES: Remove paragraph about slow-to-prepare messages 26/41 NOTES: Remove unimplemented protocol negotiation 27/41 site: fix site name checking leaving room for expansion 28/41 site: Extra info in name fields for MSG1, clearer processing 29/41 site: use unaligned.h's functions, not pointer cast and ntohl 30/41 site: interpret first 4 bytes of extrainfo as capabilities 31/41 site: Check transform errors; factor out transform handling 32/41 site: dynamically create and destroy transform instances 33/41 site, netlink: abolish max_end_pad and min_end_pad 34/41 site, transform: per-transform-instance max_start_pad 35/41 site: support multiple transforms 36/41 Use FORMAT everywhere, and fix up the errors it finds 37/41 max_start_pad: calculate globally, not via client graph 38/41 udp.c: call buffer_init 39/41 slip: Buffer management (max_start_pad) fixes 40/41 site: New PROD message 41/41 changelog: Describe 0.3.0~beta2 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:27 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:27 +0100 Subject: [PATCH 01/41] rsa.c: Fix incorrect commentary. In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-2-git-send-email-ijackson@chiark.greenend.org.uk> From: Mark Wooding The Euler function phi(n) is defined to be phi(n) = #{ 1 < i < n | gcd(i, n) = 1 } the number of natural numbers less than n and prime to it; equivalently, it's the size of the multiplicative group (Z/nZ)^*. If n = p q is the product of two primes then phi(n) = (p - 1)(q - 1). But phi(n) is not (if n is composite) the exponent of (Z/nZ)^*. It's certainly true that a^{phi(n)} = 1 for all a in (Z/nZ)^*; but the exponent of a group G is the /smallest/ positive integer e such that a^e == 1 for all a in G. This quantity is denoted lambda(n); in our simple case where n = p q is the product of two primes it's true that lambda(n) = lcm(p - 1, q - 1) Since p and q are large primes, both p - 1 and q - 1 are even, so lambda(n) is at least a factor of 2 smaller than phi(n). In fact, lambda(2) = 1, lambda(2^f) = 2^{f-2} for f >= 1, and lambda(p^f) = p^{f-1} (p - 1) for prime p > 2; and, in general, if n = p_1^{f_1} ... p_m^{f_m} is the prime factorization of n then lambda(n) = lcm(lambda(p_1^{f_1}), ... lambda(p_m^{f_m})) Signed-off-by: Mark Wooding --- rsa.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rsa.c b/rsa.c index 0bd106f..fed468d 100644 --- a/rsa.c +++ b/rsa.c @@ -430,8 +430,9 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, /* * Verify that d*e is congruent to 1 mod (p-1), and mod * (q-1). This is equivalent to it being congruent to 1 mod - * lcm(p-1,q-1), i.e. congruent to 1 mod phi(n). Note that - * phi(n) is _not_ simply (p-1)*(q-1). + * lambda(n) = lcm(p-1,q-1). The usual `textbook' condition, + * that d e == 1 (mod (p-1)(q-1)) is sufficient, but not + * actually necessary. */ mpz_mul(&tmp, &d, &e); mpz_sub_ui(&tmp2, &st->p, 1); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:28 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:28 +0100 Subject: [PATCH 02/41] rsa.c: Factor out constructing the EMSA-PKCS1 message representative. In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-3-git-send-email-ijackson@chiark.greenend.org.uk> From: Mark Wooding This was done in two different places for no reason I could understand. Replace them both with a single implementation. Signed-off-by: Mark Wooding --- rsa.c | 47 ++++++++++++++++++----------------------------- 1 files changed, 18 insertions(+), 29 deletions(-) diff --git a/rsa.c b/rsa.c index fed468d..0ca5d19 100644 --- a/rsa.c +++ b/rsa.c @@ -36,16 +36,11 @@ struct rsapub { static const char *hexchars="0123456789abcdef"; -static string_t rsa_sign(void *sst, uint8_t *data, int32_t datalen) +static void emsa_pkcs1(MP_INT *n, MP_INT *m, + const uint8_t *data, int32_t datalen) { - struct rsapriv *st=sst; - MP_INT a, b, u, v, tmp, tmp2; char buff[2048]; int msize, i; - string_t signature; - - mpz_init(&a); - mpz_init(&b); /* RSA PKCS#1 v1.5 signature padding: * @@ -65,7 +60,7 @@ static string_t rsa_sign(void *sst, uint8_t *data, int32_t datalen) * -iwj 17.9.2002 */ - msize=mpz_sizeinbase(&st->n, 16); + msize=mpz_sizeinbase(n, 16); if (datalen*2+6>=msize) { fatal("rsa_sign: message too big"); @@ -86,7 +81,20 @@ static string_t rsa_sign(void *sst, uint8_t *data, int32_t datalen) buff[msize]=0; - mpz_set_str(&a, buff, 16); + mpz_set_str(m, buff, 16); +} + +static string_t rsa_sign(void *sst, uint8_t *data, int32_t datalen) +{ + struct rsapriv *st=sst; + MP_INT a, b, u, v, tmp, tmp2; + string_t signature; + + mpz_init(&a); + mpz_init(&b); + + /* Construct the message representative. */ + emsa_pkcs1(&st->n, &a, data, datalen); /* * Produce an RSA signature (a^d mod n) using the Chinese @@ -135,32 +143,13 @@ static bool_t rsa_sig_check(void *sst, uint8_t *data, int32_t datalen, { struct rsapub *st=sst; MP_INT a, b, c; - char buff[2048]; - int msize, i; bool_t ok; mpz_init(&a); mpz_init(&b); mpz_init(&c); - msize=mpz_sizeinbase(&st->n, 16); - - strcpy(buff,"0001"); - - for (i=0; i>4]; - buff[msize+(-datalen+i)*2+1]=hexchars[data[i]&0xf]; - } - - buff[msize-datalen*2-2]= '0'; - buff[msize-datalen*2-1]= '0'; - - for (i=4; in, &a, data, datalen); mpz_set_str(&b, signature, 16); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:29 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:29 +0100 Subject: [PATCH 03/41] rsa.c: Replace the magic length 1024 with a (larger) constant. In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-4-git-send-email-ijackson@chiark.greenend.org.uk> From: Mark Wooding While 15360-bit RSA keys are rather large, they're not completely beyond the realms of possibility and it seems unreasonable to forbid them. (Specifically, 15360 is the length recommended by NIST for 256-bit security levels.) Signed-off-by: Mark Wooding --- rsa.c | 20 +++++++++++++------- 1 files changed, 13 insertions(+), 7 deletions(-) diff --git a/rsa.c b/rsa.c index 0ca5d19..2db03c9 100644 --- a/rsa.c +++ b/rsa.c @@ -34,12 +34,18 @@ struct rsapub { }; /* Sign data. NB data must be smaller than modulus */ +#define RSA_MAX_MODBYTES 2048 +/* The largest modulus I've seen is 15360 bits, which works out at 1920 + * bytes. Using keys this big is quite implausible, but it doesn't cost us + * much to support them. + */ + static const char *hexchars="0123456789abcdef"; static void emsa_pkcs1(MP_INT *n, MP_INT *m, const uint8_t *data, int32_t datalen) { - char buff[2048]; + char buff[2*RSA_MAX_MODBYTES + 1]; int msize, i; /* RSA PKCS#1 v1.5 signature padding: @@ -296,7 +302,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, /* Read the public key */ keyfile_get_int(loc,f); /* Not sure what this is */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausible length %ld for modulus\n", length); } @@ -308,7 +314,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, read_mpbin(&st->n,b,length); free(b); length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausible length %ld for e\n",length); } b=safe_malloc(length,"rsapriv_apply"); @@ -339,7 +345,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, /* Read d */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausibly long (%ld) decryption key\n", length); } @@ -353,7 +359,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, free(b); /* Read iqmp (inverse of q mod p) */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausibly long (%ld)" " iqmp auxiliary value\n", length); } @@ -367,7 +373,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, free(b); /* Read q (the smaller of the two primes) */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausibly long (%ld) q value\n", length); } @@ -381,7 +387,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context, free(b); /* Read p (the larger of the two primes) */ length=(keyfile_get_short(loc,f)+7)/8; - if (length>1024) { + if (length>RSA_MAX_MODBYTES) { cfgfatal(loc,"rsa-private","implausibly long (%ld) p value\n", length); } -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:30 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:30 +0100 Subject: [PATCH 04/41] rsa.c: Check public key length. In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-5-git-send-email-ijackson@chiark.greenend.org.uk> From: Mark Wooding The private key is checked quite carefully -- even to a fault -- for being sensibly sized, but the corresponding function for public keys appears to have no checking at all. This is a shame since message- representative construction assumes that the message representative will fit in a fixed-size buffer. Fix this situation by checking public key sizes in `rsapub_apply'. Signed-off-by: Mark Wooding Signed-off-by: Ian Jackson --- rsa.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/rsa.c b/rsa.c index 2db03c9..f7dd69d 100644 --- a/rsa.c +++ b/rsa.c @@ -199,6 +199,9 @@ static list_t *rsapub_apply(closure_t *self, struct cloc loc, dict_t *context, } else { cfgfatal(loc,"rsa-public","you must provide an encryption key\n"); } + if (mpz_sizeinbase(&st->e, 256) > RSA_MAX_MODBYTES) { + cfgfatal(loc, "rsa-public", "implausibly large public exponent\n"); + } i=list_elem(args,1); if (i) { @@ -213,6 +216,9 @@ static list_t *rsapub_apply(closure_t *self, struct cloc loc, dict_t *context, } else { cfgfatal(loc,"rsa-public","you must provide a modulus\n"); } + if (mpz_sizeinbase(&st->n, 256) > RSA_MAX_MODBYTES) { + cfgfatal(loc, "rsa-public", "implausibly large modulus\n"); + } return new_closure(&st->cl); } -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:31 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:31 +0100 Subject: [PATCH 05/41] unaligned.h: rationalise; provide buf_append_uint8 et al In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-6-git-send-email-ijackson@chiark.greenend.org.uk> Replace the formulaic macros buf_{,un}{append,prepend}_{uint32,uint16} with some macro-generated inline functions. These have better typechecking, and are also better because it's not possible to accidentally mess up one of the definitions by failing to permute it in the right way. Add the functions for uint8 too. This involves providing put_uint8 and get_uint8 macros, which we do along the lines of the existing put_ and get_ macros. Use the new uint8 function in the one place where it's currently useful. More call sites will appear shortly. Signed-off-by: Ian Jackson --- slip.c | 3 ++- unaligned.h | 46 +++++++++++++++++++++++----------------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/slip.c b/slip.c index a452926..d8f1a17 100644 --- a/slip.c +++ b/slip.c @@ -7,6 +7,7 @@ #include "util.h" #include "netlink.h" #include "process.h" +#include "unaligned.h" #include #include #include @@ -125,7 +126,7 @@ static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) buffer_init(st->buff,st->nl.max_start_pad); } else if (outputchr != OUTPUT_NOTHING) { if (st->buff->size < st->buff->len) { - *(uint8_t *)buf_append(st->buff,1)=outputchr; + buf_append_uint8(st->buff,outputchr); } else { Message(M_WARNING, "userv_afterpoll: dropping overlong" " SLIP packet\n"); diff --git a/unaligned.h b/unaligned.h index a15043e..00c6fc6 100644 --- a/unaligned.h +++ b/unaligned.h @@ -2,6 +2,7 @@ #define unaligned_h #include +#include "util.h" /* Parts of the secnet key-exchange protocol require access to unaligned big-endian quantities in buffers. These macros provide @@ -13,34 +14,33 @@ #define put_uint16(a,v) do {(a)[0]=((v)&0xff00)>>8; (a)[1]=(v)&0xff;} while(0) +#define put_uint8(a,v) do {(a)[0]=((v)&0xff);} while(0) + #define get_uint32(a) \ (((uint32_t)(a)[0]<<24) | ((uint32_t)(a)[1]<<16) | \ ((uint32_t)(a)[2]<<8) | (uint32_t)(a)[3]) #define get_uint16(a) (((uint16_t)(a)[0]<<8)|(uint16_t)(a)[1]) -#define buf_append_uint32(buf,v) do { uint8_t *c=buf_append((buf),4); \ - put_uint32(c,(v)); } while(0) - -#define buf_append_uint16(buf,v) do { uint8_t *c=buf_append((buf),2); \ - put_uint16(c,(v)); } while(0) - -#define buf_prepend_uint32(buf,v) do { uint8_t *c=buf_prepend((buf),4); \ - put_uint32(c,(v)); } while(0) - -#define buf_prepend_uint16(buf,v) do { uint8_t *c=buf_prepend((buf),2); \ - put_uint16(c,(v)); } while(0) - -#define buf_unappend_uint32(buf) ({uint8_t *c=buf_unappend((buf),4); \ - get_uint32(c);}) - -#define buf_unappend_uint16(buf) ({uint8_t *c=buf_unappend((buf),2); \ - get_uint16(c);}) - -#define buf_unprepend_uint32(buf) ({uint8_t *c=buf_unprepend((buf),4); \ - get_uint32(c);}) - -#define buf_unprepend_uint16(buf) ({uint8_t *c=buf_unprepend((buf),2); \ - get_uint16(c);}) +#define get_uint8(a) (((uint8_t)(a)[0])) + +#define UNALIGNED_DEF_FORTYPE(type,appre) \ +static inline void buf_##appre##_##type(struct buffer_if *buf, type##_t v) \ +{ \ + uint8_t *c=buf_##appre(buf,sizeof(type##_t)); \ + put_##type(c,v); \ +} \ +static inline type##_t buf_un##appre##_##type(struct buffer_if *buf) \ +{ \ + const uint8_t *c=buf_un##appre(buf,sizeof(type##_t)); \ + return get_##type(c); \ +} + +UNALIGNED_DEF_FORTYPE(uint32,append) +UNALIGNED_DEF_FORTYPE(uint16,append) +UNALIGNED_DEF_FORTYPE(uint8,append) +UNALIGNED_DEF_FORTYPE(uint32,prepend) +UNALIGNED_DEF_FORTYPE(uint16,prepend) +UNALIGNED_DEF_FORTYPE(uint8,prepend) #endif /* unaligned_h */ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:32 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:32 +0100 Subject: [PATCH 06/41] util, buffers: Preparatory improvements In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-7-git-send-email-ijackson@chiark.greenend.org.uk> We invent a new kind of buffer_if which is a readonly view of another block of memory; such a view can be initialised with buffer_view_readonly or buffer_view_clone. This makes a convenient function to allow reparsing a packet, or using the buffer machinery to parse a particular existing block of memory. Also, make buffer_assert_free and buffer_assert_used actually call assert (as well as logging the buffer ownership). So when these fail (a) we don't attempt the clean teardown, and (b) we get a core dump if those are enabled. Signed-off-by: Ian Jackson --- util.c | 26 ++++++++++++++++++++++---- util.h | 6 ++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/util.c b/util.c index f5f3d75..de91e1e 100644 --- a/util.c +++ b/util.c @@ -228,8 +228,9 @@ void buffer_assert_free(struct buffer_if *buffer, cstring_t file, int line) { if (!buffer->free) { - fatal("BUF_ASSERT_FREE, %s line %d, owned by %s", - file,line,buffer->owner); + fprintf(stderr,"secnet: BUF_ASSERT_FREE, %s line %d, owned by %s", + file,line,buffer->owner); + assert(!"buffer_assert_free failure"); } } @@ -237,8 +238,9 @@ void buffer_assert_used(struct buffer_if *buffer, cstring_t file, int line) { if (buffer->free) { - fatal("BUF_ASSERT_USED, %s line %d, last owned by %s", - file,line,buffer->owner); + fprintf(stderr,"secnet: BUF_ASSERT_USED, %s line %d, last owned by %s", + file,line,buffer->owner); + assert(!"buffer_assert_used failure"); } } @@ -301,6 +303,22 @@ void buffer_new(struct buffer_if *buf, int32_t len) buf->base=safe_malloc(len,"buffer_new"); } +void buffer_readonly_view(struct buffer_if *buf, const void *data, int32_t len) +{ + buf->free=False; + buf->owner="READONLY"; + buf->flags=0; + buf->loc.file=NULL; + buf->loc.line=0; + buf->size=buf->len=len; + buf->base=buf->start=(uint8_t*)data; +} + +void buffer_readonly_clone(struct buffer_if *out, const struct buffer_if *in) +{ + buffer_readonly_view(out,in->start,in->size); +} + void buffer_copy(struct buffer_if *dst, const struct buffer_if *src) { if (dst->len < src->len) { diff --git a/util.h b/util.h index af19363..7991743 100644 --- a/util.h +++ b/util.h @@ -29,6 +29,12 @@ extern void *buf_prepend(struct buffer_if *buf, int32_t amount); extern void *buf_unappend(struct buffer_if *buf, int32_t amount); extern void *buf_unprepend(struct buffer_if *buf, int32_t amount); +extern void buffer_readonly_view(struct buffer_if *n, const void*, int32_t len); +extern void buffer_readonly_clone(struct buffer_if *n, const struct buffer_if*); + /* Caller must only use unappend, unprepend et al. on n. + * New buffer state (in n) before this can be undefined. After use, + * it must NOT be freed. */ + extern void buf_append_string(struct buffer_if *buf, cstring_t s); extern void read_mpbin(MP_INT *a, uint8_t *bin, int binsize); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:33 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:33 +0100 Subject: [PATCH 07/41] memcmp: Introduce and use consttime_memeq In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-8-git-send-email-ijackson@chiark.greenend.org.uk> We need to use a constant-time memcmp in MAC checking, to avoid leaking (to an adversary) how much of the MAC is right. (This would be especially dangerous if our MAC was outside the encryption, which thankfully it isn't.) The use of "volatile" on the accumulator prevents the compiler from optimising away any of the updates to the accumulator, each of which depends on all the bits of the two bytes being compared. So that stops the compiler shortcutting the computation. This also prevents the compiler spotting our boolean canonicalisation, and forces it to do it the way we say. This is true according to the spec by virtue of C99 6.7.3(6). In an attempt to get the compiler to eliminate the pointless repeated loading and storing of the single-byte accumulator value, I have specified it as "register volatile". There is no rule against "register volatile", but my compiler ignores the "register". To double check that all is well, here is an annotated disassembly, from this command line: gcc -save-temps -DHAVE_CONFIG_H -I. -I. -Wall -Wwrite-strings -g -O2 \ -Werror -W -Wno-unused -Wno-pointer-sign -Wstrict-prototypes \ -Wmissing-prototypes -Wmissing-declarations -Wnested-externs \ -Wredundant-decls -Wpointer-arith -Wformat=2 -Winit-self \ -Wswitch-enum -Wunused-variable -Wbad-function-cast \ -Wno-strict-aliasing -fno-strict-aliasing -c util.c -o util.o This is the relevant part of util.s, as generated by gcc 4.4.5-8 i486-linux-gnu, with my annotations: .globl consttime_memeq .type consttime_memeq, @function consttime_memeq: .LFB80: .loc 1 367 0 .cfi_startproc .LVL8: pushl %ebp .LCFI8: .cfi_def_cfa_offset 8 movl %esp, %ebp .cfi_offset 5, -8 .LCFI9: .cfi_def_cfa_register 5 pushl %edi pushl %esi pushl %ebx subl $16, %esp .loc 1 367 0 movl 16(%ebp), %ebx ebx : n .cfi_offset 3, -20 .cfi_offset 6, -16 .cfi_offset 7, -12 movl 8(%ebp), %esi esi : s1in movl 12(%ebp), %edi edi : s2in .loc 1 369 0 movb $0, -13(%ebp) -13(ebp) : accumulator .LVL9: .loc 1 371 0 testl %ebx, %ebx if (!n) je .L15 goto no_bytes; i.e. if (n) { ...loop... } .LVL10: The compiler has chosen to invent an offset variable for controlling the loop, rather than pointer arithmetic. We'll call that variable i. It ranges from 0..n-1 as expected. The compiler doesn't explictly compute the per-iteration pointers s1 and s2, instead using an addressing mode. xorl %edx, %edx edx : i .p2align 4,,7 .p2align 3 .L16: more_bytes: /* loop */ .loc 1 372 0 movzbl (%edi,%edx), %eax eax = *s2; .LVL11: movzbl -13(%ebp), %ecx ecx = accumulator; xorb (%esi,%edx), %al al = *s1 ^ *s2; addl $1, %edx i++; orl %ecx, %eax eax = accumulator | (*s1^*s2) .LVL12: .loc 1 371 0 cmpl %edx, %ebx [ if (i==n) ... ] .loc 1 372 0 movb %al, -13(%ebp) accumulator = eax; i.e., overall, accumulator |= *s1 ^ *s2 .loc 1 371 0 jne .L16 ... [if (i!=n)] goto more_bytes; .LVL13: .L15: no_bytes: .loc 1 374 0 /* end of loop and if */ /* now doing the shift-by-4: */ movzbl -13(%ebp), %eax eax = accumulator; movzbl -13(%ebp), %edx edx = accumulator; shrb $4, %al al >>= 4; .LVL14: orl %edx, %eax eax |= edx; .LVL15: movb %al, -13(%ebp) accumulator = eax; i.e., overall, accumulator |= accumulator >> 4; .loc 1 375 0 movzbl -13(%ebp), %eax /* same again but for shift-by-2 */ movzbl -13(%ebp), %edx shrb $2, %al orl %edx, %eax .LVL16: movb %al, -13(%ebp) .loc 1 376 0 movzbl -13(%ebp), %eax /* same again but for shift-by-1 */ movzbl -13(%ebp), %edx shrb %al orl %edx, %eax .LVL17: movb %al, -13(%ebp) /* now computed final accumulator */ .loc 1 377 0 movzbl -13(%ebp), %eax eax = accumulator; andl $1, %eax eax &= 1; .LVL18: movb %al, -13(%ebp) accumulator = eax; .loc 1 378 0 movzbl -13(%ebp), %eax eax = accumulator; xorl $1, %eax eax ^= 1; .LVL19: movb %al, -13(%ebp) accumulator = eax; .loc 1 379 0 movzbl -13(%ebp), %eax eax = accumulator; .LVL20: .loc 1 380 0 addl $16, %esp function epilogue popl %ebx ... .LVL21: popl %esi ... .LVL22: popl %edi ... .LVL23: .loc 1 379 0 movzbl %al, %eax sign extend? .loc 1 380 0 popl %ebp ... ret return eax; i.e. return accumulator; .cfi_endproc .LFE80: .size consttime_memeq, .-consttime_memeq Signed-off-by: Ian Jackson --- site.c | 2 +- transform.c | 2 +- util.c | 16 ++++++++++++++++ util.h | 2 ++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/site.c b/site.c index db65bd8..b9b4d0d 100644 --- a/site.c +++ b/site.c @@ -463,7 +463,7 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, return False; } if (type==LABEL_MSG2) return True; - if (memcmp(m->nR,st->remoteN,NONCELEN)!=0) { + if (!consttime_memeq(m->nR,st->remoteN,NONCELEN)!=0) { *error="wrong remotely-generated nonce"; return False; } diff --git a/transform.c b/transform.c index 289b02e..012f618 100644 --- a/transform.c +++ b/transform.c @@ -220,7 +220,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, serpent_encrypt(&ti->mackey,macplain,macacc); } serpent_encrypt(&ti->mackey,macacc,macacc); - if (memcmp(macexpected,macacc,16)!=0) { + if (!consttime_memeq(macexpected,macacc,16)!=0) { *errmsg="invalid MAC"; return 1; } diff --git a/util.c b/util.c index de91e1e..3d11987 100644 --- a/util.c +++ b/util.c @@ -381,6 +381,22 @@ static list_t *buffer_apply(closure_t *self, struct cloc loc, dict_t *context, return new_closure(&st->cl); } +int consttime_memeq(const void *s1in, const void *s2in, size_t n) +{ + const uint8_t *s1=s1in, *s2=s2in; + register volatile uint8_t accumulator=0; + + while (n-- > 0) { + accumulator |= (*s1++ ^ *s2++); + } + accumulator |= accumulator >> 4; /* constant-time */ + accumulator |= accumulator >> 2; /* boolean canonicalisation */ + accumulator |= accumulator >> 1; + accumulator &= 1; + accumulator ^= 1; + return accumulator; +} + void util_module(dict_t *dict) { add_closure(dict,"sysbuffer",buffer_apply); diff --git a/util.h b/util.h index 7991743..cbe9f52 100644 --- a/util.h +++ b/util.h @@ -45,4 +45,6 @@ extern int32_t write_mpbin(MP_INT *a, uint8_t *buffer, int32_t buflen); extern struct log_if *init_log(list_t *loglist); +extern int consttime_memeq(const void *s1, const void *s2, size_t n); + #endif /* util_h */ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:34 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:34 +0100 Subject: [PATCH 08/41] transform: Do not look at any bytes of PKCS#5 padding other than the last In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-9-git-send-email-ijackson@chiark.greenend.org.uk> This might avoid some timing-related information leaks. In principle this is a protocol change: we now no longer use actual PKCS#5 padding; instead, we use a padding scheme where all but the last byte of the padding may be sent as anything and are ignored by the receiver. Signed-off-by: Ian Jackson --- transform.c | 8 +------- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/transform.c b/transform.c index 012f618..6618ec5 100644 --- a/transform.c +++ b/transform.c @@ -234,13 +234,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, return 1; } - padp=buf_unappend(buf,padlen-1); - for (i=0; i References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-10-git-send-email-ijackson@chiark.greenend.org.uk> Decorate serpent_encrypt, serpent_decrypt and serpent_makekey with appropriate consts in their arguments. Signed-off-by: Ian Jackson --- serpent.c | 6 +++--- serpent.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/serpent.c b/serpent.c index ce91854..34ef6aa 100644 --- a/serpent.c +++ b/serpent.c @@ -26,7 +26,7 @@ #include "serpentsboxes.h" void serpent_makekey(struct keyInstance *key, int keyLen, - uint8_t *keyMaterial) + const uint8_t *keyMaterial) { int i; uint32_t j; @@ -86,7 +86,7 @@ void serpent_makekey(struct keyInstance *key, int keyLen, } void serpent_encrypt(struct keyInstance *key, - uint8_t plaintext[16], + const uint8_t plaintext[16], uint8_t ciphertext[16]) { register uint32_t x0, x1, x2, x3; @@ -204,7 +204,7 @@ void serpent_encrypt(struct keyInstance *key, } void serpent_decrypt(struct keyInstance *key, - uint8_t ciphertext[16], + const uint8_t ciphertext[16], uint8_t plaintext[16]) { register uint32_t x0, x1, x2, x3; diff --git a/serpent.h b/serpent.h index 07176d7..19c01fe 100644 --- a/serpent.h +++ b/serpent.h @@ -8,12 +8,12 @@ struct keyInstance { /* Function protoypes */ void serpent_makekey(struct keyInstance *key, int keyLen, - uint8_t *keyMaterial); + const uint8_t *keyMaterial); -void serpent_encrypt(struct keyInstance *key, uint8_t plaintext[16], +void serpent_encrypt(struct keyInstance *key, const uint8_t plaintext[16], uint8_t ciphertext[16]); -void serpent_decrypt(struct keyInstance *key, uint8_t ciphertext[16], +void serpent_decrypt(struct keyInstance *key, const uint8_t ciphertext[16], uint8_t plaintext[16]); #endif /* serpent_h */ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:45:25 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:45:25 +0100 Subject: [PATCH] DO NOT APPLY: test generating MSG1 extrainfo In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774325-11751-1-git-send-email-ijackson@chiark.greenend.org.uk> This advertises some early capabilities and puts some further extra data in MSG1. Using the version with this patch it's possible to test the tolerance to new packets of the intended new version. Signed-off-by: Ian Jackson --- magic.h | 2 +- site.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/magic.h b/magic.h index 598a79e..e333dfa 100644 --- a/magic.h +++ b/magic.h @@ -18,7 +18,7 @@ #define LABEL_PROD 0x0a0a0a0a /* uses of the 32-bit capability bitmap */ -#define CAPAB_EARLY 0x00000000 /* no Early flags yet (see NOTES) */ +#define CAPAB_EARLY 0x00080000 /* no Early flags yet (see NOTES) */ #define CAPAB_TRANSFORM_MASK 0x0000ffff /* remaining 16 bits are unused */ diff --git a/site.c b/site.c index 0b39232..f346f4a 100644 --- a/site.c +++ b/site.c @@ -487,6 +487,7 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) if ((st->local_capabilities & CAPAB_EARLY) || (type != LABEL_MSG1)) { buf_append_uint32(&st->buffer,st->local_capabilities); } + buf_append_uint32(&st->buffer, 0x6767aaaa); append_string_xinfo_done(&st->buffer,&xia); buf_append_string(&st->buffer,st->remotename); @@ -1722,7 +1723,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, assert(index_sequence < 0xffffffffUL); st->index = ++index_sequence; - st->local_capabilities = 0; + st->local_capabilities = 0xe0000; st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc); #define GET_CLOSURE_LIST(dictkey,things,nthings,CL_TYPE) do{ \ -- tg: (9502034..) junk/future-test (depends on: empty/tip) From ijackson at chiark.greenend.org.uk Thu Jul 25 18:45:40 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:45:40 +0100 Subject: [PATCH] DO NOT APPLY: test anti-features for PROD In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774340-11835-1-git-send-email-ijackson@chiark.greenend.org.uk> These environment variable and config changes allow me to recreate the conditions for a PROD test. Runes are: I: # ./secnet -dvnc test-example/inside.conf O: # ISEQP=50 DIE3=1 ./secnet -dvnc test-example/outside.conf P: $ ping -I secnet-test-i 172.18.232.2 After O crashes, restart it with: O: # ./secnet -dvnc test-example/outside.conf Signed-off-by: Ian Jackson --- site.c | 3 ++ test-example/sites.conf | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 0 deletions(-) diff --git a/site.c b/site.c index 0b39232..3c2d734 100644 --- a/site.c +++ b/site.c @@ -1584,6 +1584,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, slog(st,LOG_UNEXPECTED,"unexpected MSG3"); } else if (process_msg3(st,buf,source,msgtype)) { transport_setup_msgok(st,source); +if (getenv("DIE3")) { static int counter; assert(++counter<2); } enter_new_state(st,SITE_SENTMSG4); } else { slog(st,LOG_SEC,"invalid MSG3"); @@ -1720,6 +1721,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, return NULL; } +index_sequence += atoi(getenv("ISEQP")?:"0"); + assert(index_sequence < 0xffffffffUL); st->index = ++index_sequence; st->local_capabilities = 0; diff --git a/test-example/sites.conf b/test-example/sites.conf new file mode 100644 index 0000000..d349ae8 --- /dev/null +++ b/test-example/sites.conf @@ -0,0 +1,50 @@ +# secnet sites file autogenerated by make-secnet-sites version 0.1.18 +# Thu Jul 25 04:05:12 2013 +# Command line: ../make-secnet-sites sites sites.conf + +vpn-data { + test-example { + setup-retries 5; + hash sha1; + dh diffie-hellman("8db5f2c15ac96d9f3382d1ef4688fba14dc7908ae7dfd71a9cfe7f479a75d506dc53f159aeaf488bde073fe544bc91c099f101fcf60074f30c06e36263c03ca9e07931ce3fc235fe1171dc6d9316fb097bd4362891e2c36e234e7c16b038fd97b1f165c710e90537de66ee4f54001f5712b050d4e07de3fba07607b19b64f6c3","2"); + key-lifetime 72000000; + wait-time 72000000; + renegotiate-time 10000; + # restrict-nets "172.18.232.0/28" + # Contact email address: + setup-timeout 2000; + + outside { + outside { + name "test-example/outside/outside"; + key rsa-public("65537","129251483458784900555621175262818292872587807329014927540074484804119474262261383244074013537736576331652560727149001626325243856012659665194546933097292703586821422085819615124517093786704646988649444946154384037948502112302285511195679291084694375811092516151263088200304199780052361048758446082354317801941"); + address "[127.0.0.1]"; port 16900; + link netlink { + routes "172.18.232.0/29"; + ptp-address "172.18.232.1"; + }; + }; + }; + inside { + inside { + name "test-example/inside/inside"; + mobile True; + key rsa-public("65537","130064631890186713927887504218626486455931306300999583387009075747001546036643522074275473238061323169592347601185592753550279410171535737146240085267000508853176463710554801101055212967131924064664249613912656320653505750073021702169423354903540699008756137338575553686987244488914481168225136440872431691669"); + address "[127.0.0.1]"; port 16910; + link netlink { + routes "172.18.232.8/29"; + ptp-address "172.18.232.9"; + }; + }; + }; + }; +}; +vpn { + test-example { + outside vpn-data/test-example/outside/outside; + inside vpn-data/test-example/inside/inside; + + all-sites outside,inside; + }; +}; +all-sites vpn/test-example/all-sites; -- tg: (9502034..) junk/prod-test (depends on: empty/tip) From ijackson at chiark.greenend.org.uk Thu Jul 25 18:41:02 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:41:02 +0100 Subject: [PATCH 36/41] Use FORMAT everywhere, and fix up the errors it finds In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-37-git-send-email-ijackson@chiark.greenend.org.uk> Many printf-like variadic functions weren't properly decorated with FORMAT annotations. Add them everywhere. It is not possible to annotate a function pointer type, so that doesn't work for the function pointers in struct log_if. However, we have convenience wrapper functions slilog and vslilog, which are appropriately decorated and therefore safer. Change all call sites to use those instead, and leave a comment. (Rename the function pointer variable names so that we don't miss any call sites.) Fix the bugs that this new compiler checking reveals. These are nearly all in fatal error reporting, and not very scary. Signed-off-by: Ian Jackson --- log.c | 31 ++++++++++++++++++++++--------- secnet.c | 3 ++- secnet.h | 22 +++++++++++++--------- site.c | 6 ++++-- slip.c | 3 ++- util.c | 6 +++--- 6 files changed, 46 insertions(+), 25 deletions(-) diff --git a/log.c b/log.c index d940df5..d330113 100644 --- a/log.c +++ b/log.c @@ -15,6 +15,8 @@ uint32_t message_level=M_WARNING|M_ERR|M_SECURITY|M_FATAL; struct log_if *system_log=NULL; static void vMessageFallback(uint32_t class, const char *message, va_list args) + FORMAT(printf,2,0); +static void vMessageFallback(uint32_t class, const char *message, va_list args) { FILE *dest=stdout; /* Messages go to stdout/stderr */ @@ -61,6 +63,8 @@ void Message(uint32_t class, const char *message, ...) } static void MessageFallback(uint32_t class, const char *message, ...) + FORMAT(printf,2,3); +static void MessageFallback(uint32_t class, const char *message, ...) { va_list ap; @@ -191,7 +195,7 @@ static void log_vmulti(void *sst, int class, const char *message, va_list args) if (secnet_is_daemon) { for (i=st; i; i=i->next) { - i->l->vlog(i->l->st,class,message,args); + vslilog(i->l,class,message,args); } } else { vMessage(class,message,args); @@ -200,6 +204,8 @@ static void log_vmulti(void *sst, int class, const char *message, va_list args) } static void log_multi(void *st, int priority, const char *message, ...) + FORMAT(printf,3,4); +static void log_multi(void *st, int priority, const char *message, ...) { va_list ap; @@ -242,8 +248,8 @@ struct log_if *init_log(list_t *ll) } r=safe_malloc(sizeof(*r), "init_log"); r->st=l; - r->log=log_multi; - r->vlog=log_vmulti; + r->logfn=log_multi; + r->vlogfn=log_vmulti; return r; } @@ -284,6 +290,8 @@ static void logfile_vlog(void *sst, int class, const char *message, } static void logfile_log(void *state, int class, const char *message, ...) + FORMAT(printf,3,4); +static void logfile_log(void *state, int class, const char *message, ...) { va_list ap; @@ -355,8 +363,8 @@ static list_t *logfile_apply(closure_t *self, struct cloc loc, dict_t *context, st->cl.apply=NULL; st->cl.interface=&st->ops; st->ops.st=st; - st->ops.log=logfile_log; - st->ops.vlog=logfile_vlog; + st->ops.logfn=logfile_log; + st->ops.vlogfn=logfile_vlog; st->loc=loc; st->f=NULL; @@ -401,6 +409,9 @@ static int msgclass_to_syslogpriority(uint32_t m) static void syslog_vlog(void *sst, int class, const char *message, va_list args) + FORMAT(printf,3,0); +static void syslog_vlog(void *sst, int class, const char *message, + va_list args) { struct syslog *st=sst; @@ -413,6 +424,8 @@ static void syslog_vlog(void *sst, int class, const char *message, } static void syslog_log(void *sst, int priority, const char *message, ...) + FORMAT(printf,3,4); +static void syslog_log(void *sst, int priority, const char *message, ...) { va_list ap; @@ -472,8 +485,8 @@ static list_t *syslog_apply(closure_t *self, struct cloc loc, dict_t *context, st->cl.apply=NULL; st->cl.interface=&st->ops; st->ops.st=st; - st->ops.log=syslog_log; - st->ops.vlog=syslog_vlog; + st->ops.logfn=syslog_log; + st->ops.vlogfn=syslog_vlog; item=list_elem(args,0); if (!item || item->type!=t_dict) @@ -528,7 +541,7 @@ static void log_from_fd_afterpoll(void *sst, struct pollfd *fds, int nfds) remain=FDLOG_BUFSIZE-st->i-1; if (remain<=0) { st->buffer[FDLOG_BUFSIZE-1]=0; - st->log->log(st->log,M_WARNING,"%s: overlong line: %s", + slilog(st->log,M_WARNING,"%s: overlong line: %s", st->prefix,st->buffer); st->i=0; remain=FDLOG_BUFSIZE-1; @@ -539,7 +552,7 @@ static void log_from_fd_afterpoll(void *sst, struct pollfd *fds, int nfds) for (i=0; ii; i++) { if (st->buffer[i]=='\n') { st->buffer[i]=0; - st->log->log(st->log->st,M_INFO,"%s: %s", + slilog(st->log,M_INFO,"%s: %s", st->prefix,st->buffer); i++; memmove(st->buffer,st->buffer+i,st->i-i); diff --git a/secnet.c b/secnet.c index 465a93f..c604d44 100644 --- a/secnet.c +++ b/secnet.c @@ -332,7 +332,8 @@ static void run(void) fatal("run: beforepoll_fn (%s) returns %d",i->desc,rv); } if (timeout<-1) { - fatal("run: beforepoll_fn (%s) set timeout to %d",timeout); + fatal("run: beforepoll_fn (%s) set timeout to %d", + i->desc,timeout); } idx+=nfds; remain-=nfds; diff --git a/secnet.h b/secnet.h index 252eeb6..98a3ae3 100644 --- a/secnet.h +++ b/secnet.h @@ -339,8 +339,8 @@ typedef void log_vmsg_fn(void *st, int class, const char *message, va_list args); struct log_if { void *st; - log_msg_fn *log; - log_vmsg_fn *vlog; + log_msg_fn *logfn; /* Do not call these directly - you don't get */ + log_vmsg_fn *vlogfn; /* printf format checking. Use [v]slilog instead */ }; /* (convenience functions, defined in util.c) */ extern void slilog(struct log_if *lf, int class, const char *message, ...) @@ -492,21 +492,25 @@ struct buffer_if { #define M_FATAL 0x100 /* The fatal() family of functions require messages that do not end in '\n' */ -extern NORETURN(fatal(const char *message, ...)); -extern NORETURN(fatal_perror(const char *message, ...)); -extern NORETURN(fatal_status(int status, const char *message, ...)); -extern NORETURN(fatal_perror_status(int status, const char *message, ...)); +extern NORETURN(fatal(const char *message, ...)) FORMAT(printf,1,2); +extern NORETURN(fatal_perror(const char *message, ...)) FORMAT(printf,1,2); +extern NORETURN(fatal_status(int status, const char *message, ...)) + FORMAT(printf,2,3); +extern NORETURN(fatal_perror_status(int status, const char *message, ...)) + FORMAT(printf,2,3); /* The cfgfatal() family of functions require messages that end in '\n' */ extern NORETURN(cfgfatal(struct cloc loc, cstring_t facility, - const char *message, ...)); + const char *message, ...)) FORMAT(printf,3,4); extern void cfgfile_postreadcheck(struct cloc loc, FILE *f); extern NORETURN(vcfgfatal_maybefile(FILE *maybe_f, struct cloc loc, cstring_t facility, const char *message, - va_list)); + va_list)) + FORMAT(printf,4,0); extern NORETURN(cfgfatal_maybefile(FILE *maybe_f, struct cloc loc, cstring_t facility, - const char *message, ...)); + const char *message, ...)) + FORMAT(printf,4,5); extern void Message(uint32_t class, const char *message, ...) FORMAT(printf,2,3); diff --git a/site.c b/site.c index 6c92193..20f9507 100644 --- a/site.c +++ b/site.c @@ -294,6 +294,8 @@ struct site { }; static void slog(struct site *st, uint32_t event, cstring_t msg, ...) +FORMAT(printf,3,4); +static void slog(struct site *st, uint32_t event, cstring_t msg, ...) { va_list ap; char buf[240]; @@ -318,7 +320,7 @@ static void slog(struct site *st, uint32_t event, cstring_t msg, ...) } vsnprintf(buf,sizeof(buf),msg,ap); - st->log->log(st->log->st,class,"%s: %s",st->tunname,buf); + slilog(st->log,class,"%s: %s",st->tunname,buf); } va_end(ap); } @@ -1906,7 +1908,7 @@ static bool_t transport_compute_setupinit_peers(struct site *st, slog(st,LOG_SETUP_INIT, (!configured_addr ? "using only %d old peer address(es)" : "using configured address, and/or perhaps %d old peer address(es)"), - st->peers); + st->peers.npeers); /* Non-mobile peers havve st->peers.npeers==0 or ==1, since they * have transport_peers_max==1. The effect is that this code diff --git a/slip.c b/slip.c index d8f1a17..0f62a69 100644 --- a/slip.c +++ b/slip.c @@ -230,7 +230,8 @@ static void userv_userv_callback(void *sst, pid_t pid, int status) fatal("%s: userv exited unexpectedly: uncaught signal %d", st->slip.nl.name,WTERMSIG(status)); } else { - fatal("%s: userv stopped unexpectedly"); + fatal("%s: userv stopped unexpectedly", + st->slip.nl.name); } } Message(M_WARNING,"%s: userv subprocess died with status %d\n", diff --git a/util.c b/util.c index cfaefd2..24dd9a3 100644 --- a/util.c +++ b/util.c @@ -61,7 +61,7 @@ char *safe_strdup(const char *s, const char *message) char *d; d=strdup(s); if (!d) { - fatal_perror(message); + fatal_perror("%s",message); } return d; } @@ -71,7 +71,7 @@ void *safe_malloc(size_t size, const char *message) void *r; r=malloc(size); if (!r) { - fatal_perror(message); + fatal_perror("%s",message); } return r; } @@ -208,7 +208,7 @@ bool_t remove_hook(uint32_t phase, hook_fn *fn, void *state) void vslilog(struct log_if *lf, int priority, const char *message, va_list ap) { - lf->vlog(lf->st,priority,message,ap); + lf->vlogfn(lf->st,priority,message,ap); } void slilog(struct log_if *lf, int priority, const char *message, ...) -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:41:01 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:41:01 +0100 Subject: [PATCH 35/41] site: support multiple transforms In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-36-git-send-email-ijackson@chiark.greenend.org.uk> The "transform" key in site's dictionary argument can now be a list, as well as just a single transform. We use 16 bits of the capability mechanism to advertise the transforms we support; the config is supposed to nominate a transform capability number (from 0 to 15) for each transform closure - although the default numbers are sufficient if you don't need to do parameter rollover. The receiver of MSG2 intersects the two bitmaps and chooses the best transform, and states its choice in MSG3. A protocol downgrade attack is prevented by the fact that the capability bitmaps are advertised in the signed parts of MSG3 and MSG4. (If the one in MSG4 doesn't match what was in MSG2, the MSG4 is rejected and presumably the key exchange fails.) Signed-off-by: Ian Jackson --- NOTES | 2 +- example.conf | 4 +- magic.h | 52 ++++++++++--- secnet.8 | 27 ++++++- secnet.h | 1 + site.c | 182 +++++++++++++++++++++++++++++++++------------ test-example/common.conf | 4 +- transform-cbcmac.c | 2 + transform-common.h | 10 +++ transform-eax.c | 2 + 10 files changed, 215 insertions(+), 71 deletions(-) diff --git a/NOTES b/NOTES index 8619ee5..7ead923 100644 --- a/NOTES +++ b/NOTES @@ -232,7 +232,7 @@ zero as its "index" for another site.) (The order of B and A reverses in alternate messages so that the same code can be used to construct them...) -3) A->B: {iB,iA,msg3,A+,B+,nA,nB,g^x mod m}_PK_A^-1 +3) A->B: {iB,iA,msg3,A+,B+,[chosen-transform],nA,nB,g^x mod m}_PK_A^-1 If message 1 was a replay then A will not generate message 3, because it doesn't recognise nA. diff --git a/example.conf b/example.conf index d6908ff..ab40d05 100644 --- a/example.conf +++ b/example.conf @@ -148,9 +148,7 @@ local-name "your-site-name"; local-key rsa-private("/etc/secnet/key"); # On dodgy links you may want to specify a higher maximum sequence number skew -transform serpent256-cbc { - max-sequence-skew 10; -}; +transform eax-serpent, serpent256-cbc; include /etc/secnet/sites.conf diff --git a/magic.h b/magic.h index 3ae7af4..e98f681 100644 --- a/magic.h +++ b/magic.h @@ -3,20 +3,46 @@ #ifndef magic_h #define magic_h -#define LABEL_NAK 0x00000000 -#define LABEL_MSG0 0x00020200 -#define LABEL_MSG1 0x01010101 -#define LABEL_MSG2 0x02020202 -#define LABEL_MSG3 0x03030303 -#define LABEL_MSG4 0x04040404 -#define LABEL_MSG5 0x05050505 -#define LABEL_MSG6 0x06060606 -#define LABEL_MSG7 0x07070707 -#define LABEL_MSG8 0x08080808 -#define LABEL_MSG9 0x09090909 +#define LABEL_NAK 0x00000000 +#define LABEL_MSG0 0x00020200 +#define LABEL_MSG1 0x01010101 +#define LABEL_MSG2 0x02020202 +#define LABEL_MSG3 0x03030303 +#define LABEL_MSG3BIS 0x13030313 +#define LABEL_MSG4 0x04040404 +#define LABEL_MSG5 0x05050505 +#define LABEL_MSG6 0x06060606 +#define LABEL_MSG7 0x07070707 +#define LABEL_MSG8 0x08080808 +#define LABEL_MSG9 0x09090909 /* uses of the 32-bit capability bitmap */ -/* no flags currently defined */ -#define CAPAB_EARLY 0x00000000 /* no Early flags defined (see NOTES) */ +#define CAPAB_EARLY 0x00000000 /* no Early flags yet (see NOTES) */ +#define CAPAB_TRANSFORM_MASK 0x0000ffff +/* remaining 16 bits are unused */ + +/* + * The transform capability mask is a set of bits, one for each + * transform supported. The transform capability numbers are set in + * the configuration (and should correspond between the two sites), + * although there are sensible defaults. + * + * Advertising a nonzero transform capability mask promises that + * the receiver understands LABEL_MSG3BIS messages, which + * contain an additional byte specifying the transform capability + * number actually chosen by the MSG3 sender. + * + * Aside from that, an empty bitmask is treated the same as + * 1u< \fItransform closure\fR .PP +This transform +is deprecated as its security properties are poor; it should be +specified only alongside a better transform such as eax-serpent. +.PP Valid keys in the \fIDICT\fR argument are: .TP +.B capab-num +As above. The default for serpent256-cbc is 8. +.TP .B max-sequence-skew As above. .PP @@ -520,8 +538,13 @@ An \fIrsapubkey closure\fR. The key used to verify the peer's identity. .TP .B transform -A \fItransform closure\fR. -Used to protect packets exchanged with the peer. +One or more \fItransform closures\fR. +Used to protect packets exchanged with the peer. These should +all have distinct \fBcapab-num\fR values, and the same \fBcapab-num\fR +value should refer to the same (or a compatible) transform at both +ends. The list should be in order of preference, most preferred +first. (The end which sends MSG1,MSG3 ends up choosing; the ordering +at the other end is irrelevant.) .TP .B dh A \fIdh closure\fR. diff --git a/secnet.h b/secnet.h index 2ccf161..252eeb6 100644 --- a/secnet.h +++ b/secnet.h @@ -403,6 +403,7 @@ struct transform_if { void *st; int32_t max_start_pad; /* these two are both <<< INT_MAX */ int32_t keylen; /* 0 means give the transform exactly as much as there is */ + int capab_transformnum; transform_createinstance_fn *create; }; diff --git a/site.c b/site.c index 2ada372..6c92193 100644 --- a/site.c +++ b/site.c @@ -239,7 +239,8 @@ struct site { struct random_if *random; struct rsaprivkey_if *privkey; struct rsapubkey_if *pubkey; - struct transform_if *transform; + struct transform_if **transforms; + int ntransforms; struct dh_if *dh; struct hash_if *hash; @@ -277,6 +278,7 @@ struct site { timeout before we can listen for another setup packet); perhaps we should keep a list of 'bad' sources for setup packets. */ uint32_t remote_capabilities; + struct transform_if *chosen_transform; uint32_t setup_session_id; transport_peers setup_peers; uint8_t localN[NONCELEN]; /* Nonces for key exchange */ @@ -287,7 +289,7 @@ struct site { uint64_t timeout; /* Timeout for current state */ uint8_t *dhsecret; uint8_t *sharedsecret; - uint32_t sharedsecretlen; + uint32_t sharedsecretlen, sharedsecretallocd; struct transform_inst_if *new_transform; /* For key setup/verify */ }; @@ -390,6 +392,7 @@ struct msg { struct parsedname remote; struct parsedname local; uint32_t remote_capabilities; + int capab_transformnum; uint8_t *nR; uint8_t *nL; int32_t pklen; @@ -399,14 +402,33 @@ struct msg { char *sig; }; -static void set_new_transform(struct site *st) +static void set_new_transform(struct site *st, char *pk) { - struct transform_if *generator=st->transform; + /* Make room for the shared key */ + st->sharedsecretlen=st->chosen_transform->keylen?:st->dh->ceil_len; + assert(st->sharedsecretlen); + if (st->sharedsecretlen > st->sharedsecretallocd) { + st->sharedsecretallocd=st->sharedsecretlen; + st->sharedsecret=realloc(st->sharedsecret,st->sharedsecretallocd); + } + if (!st->sharedsecret) fatal_perror("site:sharedsecret"); + + /* Generate the shared key */ + st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,pk, + st->sharedsecret,st->sharedsecretlen); + + /* Set up the transform */ + struct transform_if *generator=st->chosen_transform; struct transform_inst_if *generated=generator->create(generator->st); generated->setkey(generated->st,st->sharedsecret, st->sharedsecretlen,st->setup_priority); dispose_transform(&st->new_transform); st->new_transform=generated; + + slog(st,LOG_SETUP_INIT,"key exchange negotiated transform" + " %d (capabilities ours=%#"PRIx32" theirs=%#"PRIx32")", + st->chosen_transform->capab_transformnum, + st->local_capabilities, st->remote_capabilities); } struct xinfoadd { @@ -468,6 +490,9 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) if (hacky_par_mid_failnow()) return False; + if (type==LABEL_MSG3BIS) + buf_append_uint8(&st->buffer,st->chosen_transform->capab_transformnum); + dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->len); buf_append_string(&st->buffer,dhpub); free(dhpub); @@ -501,6 +526,7 @@ static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm) static bool_t unpick_msg(struct site *st, uint32_t type, struct buffer_if *msg, struct msg *m) { + m->capab_transformnum=-1; m->hashstart=msg->start; CHECK_AVAIL(msg,4); m->dest=buf_unprepend_uint32(msg); @@ -526,6 +552,12 @@ static bool_t unpick_msg(struct site *st, uint32_t type, CHECK_EMPTY(msg); return True; } + if (type==LABEL_MSG3BIS) { + CHECK_AVAIL(msg,1); + m->capab_transformnum = buf_unprepend_uint8(msg); + } else { + m->capab_transformnum = CAPAB_TRANSFORMNUM_ANCIENT; + } CHECK_AVAIL(msg,2); m->pklen=buf_unprepend_uint16(msg); CHECK_AVAIL(msg,m->pklen); @@ -573,7 +605,7 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, } /* MSG3 has complicated rules about capabilities, which are * handled in process_msg3. */ - if (type==LABEL_MSG3) return True; + if (type==LABEL_MSG3 || type==LABEL_MSG3BIS) return True; if (m->remote_capabilities!=st->remote_capabilities) { *error="remote capabilities changed"; return False; @@ -622,6 +654,29 @@ static bool_t process_msg2(struct site *st, struct buffer_if *msg2, } st->setup_session_id=m.source; st->remote_capabilities=m.remote_capabilities; + + /* Select the transform to use */ + + uint32_t remote_transforms = st->remote_capabilities & CAPAB_TRANSFORM_MASK; + if (!remote_transforms) + /* old secnets only had this one transform */ + remote_transforms = 1UL << CAPAB_TRANSFORMNUM_ANCIENT; + + struct transform_if *ti; + int i; + for (i=0; intransforms; i++) { + ti=st->transforms[i]; + if ((1UL << ti->capab_transformnum) & remote_transforms) + goto transform_found; + } + slog(st,LOG_ERROR,"no transforms in common" + " (us %#"PRIx32"; them: %#"PRIx32")", + st->local_capabilities & CAPAB_TRANSFORM_MASK, + remote_transforms); + return False; + transform_found: + st->chosen_transform=ti; + memcpy(st->remoteN,m.nR,NONCELEN); return True; } @@ -631,19 +686,24 @@ static bool_t generate_msg3(struct site *st) /* Now we have our nonce and their nonce. Think of a secret key, and create message number 3. */ st->random->generate(st->random->st,st->dh->len,st->dhsecret); - return generate_msg(st,LABEL_MSG3,"site:MSG3"); + return generate_msg(st, + (st->remote_capabilities & CAPAB_TRANSFORM_MASK + ? LABEL_MSG3BIS : LABEL_MSG3), + "site:MSG3"); } static bool_t process_msg3(struct site *st, struct buffer_if *msg3, - const struct comm_addr *src) + const struct comm_addr *src, uint32_t msgtype) { struct msg m; uint8_t *hash; void *hst; cstring_t err; - if (!unpick_msg(st,LABEL_MSG3,msg3,&m)) return False; - if (!check_msg(st,LABEL_MSG3,&m,&err)) { + assert(msgtype==LABEL_MSG3 || msgtype==LABEL_MSG3BIS); + + if (!unpick_msg(st,msgtype,msg3,&m)) return False; + if (!check_msg(st,msgtype,&m,&err)) { slog(st,LOG_SEC,"msg3: %s",err); return False; } @@ -657,6 +717,19 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, } st->remote_capabilities|=m.remote_capabilities; + struct transform_if *ti; + int i; + for (i=0; intransforms; i++) { + ti=st->transforms[i]; + if (ti->capab_transformnum == m.capab_transformnum) + goto transform_found; + } + slog(st,LOG_SEC,"peer chose unknown-to-us transform %d!", + m.capab_transformnum); + return False; + transform_found: + st->chosen_transform=ti; + /* Check signature and store g^x mod m */ hash=safe_malloc(st->hash->len, "process_msg3"); hst=st->hash->init(); @@ -676,12 +749,8 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, /* Invent our DH secret key */ st->random->generate(st->random->st,st->dh->len,st->dhsecret); - /* Generate the shared key */ - st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->sharedsecretlen); - - /* Set up the transform */ - set_new_transform(st); + /* Generate the shared key and set up the transform */ + set_new_transform(st,m.pk); return True; } @@ -723,11 +792,9 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, /* Terminate their DH public key with a '0' */ m.pk[m.pklen]=0; - /* Generate the shared key */ - st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->sharedsecretlen); - /* Set up the transform */ - set_new_transform(st); + + /* Generate the shared key and set up the transform */ + set_new_transform(st,m.pk); return True; } @@ -1454,10 +1521,11 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, } break; case LABEL_MSG3: + case LABEL_MSG3BIS: /* Setup packet: expected only in state SENTMSG2 */ if (st->state!=SITE_SENTMSG2) { slog(st,LOG_UNEXPECTED,"unexpected MSG3"); - } else if (process_msg3(st,buf,source)) { + } else if (process_msg3(st,buf,source,msgtype)) { transport_setup_msgok(st,source); enter_new_state(st,SITE_SENTMSG4); } else { @@ -1600,19 +1668,25 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->local_capabilities = 0; st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc); - list_t *comms_cfg=dict_lookup(dict,"comm"); - if (!comms_cfg) cfgfatal(loc,"site","closure list \"comm\" not found\n"); - st->ncomms=list_length(comms_cfg); - st->comms=safe_malloc_ary(sizeof(*st->comms),st->ncomms,"comms"); - assert(st->ncomms); - for (i=0; incomms; i++) { - item_t *item=list_elem(comms_cfg,i); - if (item->type!=t_closure) - cfgfatal(loc,"site","comm is not a closure\n"); - closure_t *cl=item->data.closure; - if (cl->type!=CL_COMM) cfgfatal(loc,"site","comm closure wrong type\n"); - st->comms[i]=cl->interface; - } +#define GET_CLOSURE_LIST(dictkey,things,nthings,CL_TYPE) do{ \ + list_t *things##_cfg=dict_lookup(dict,dictkey); \ + if (!things##_cfg) \ + cfgfatal(loc,"site","closure list \"%s\" not found\n",dictkey); \ + st->nthings=list_length(things##_cfg); \ + st->things=safe_malloc_ary(sizeof(*st->things),st->nthings,dictkey "s"); \ + assert(st->nthings); \ + for (i=0; inthings; i++) { \ + item_t *item=list_elem(things##_cfg,i); \ + if (item->type!=t_closure) \ + cfgfatal(loc,"site","%s is not a closure\n",dictkey); \ + closure_t *cl=item->data.closure; \ + if (cl->type!=CL_TYPE) \ + cfgfatal(loc,"site","%s closure wrong type\n",dictkey); \ + st->things[i]=cl->interface; \ + } \ +}while(0) + + GET_CLOSURE_LIST("comm",comms,ncomms,CL_COMM); st->resolver=find_cl_if(dict,"resolver",CL_RESOLVER,True,"site",loc); st->log=find_cl_if(dict,"log",CL_LOG,True,"site",loc); @@ -1625,8 +1699,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, else st->remoteport=0; st->pubkey=find_cl_if(dict,"key",CL_RSAPUBKEY,True,"site",loc); - st->transform= - find_cl_if(dict,"transform",CL_TRANSFORM,True,"site",loc); + GET_CLOSURE_LIST("transform",transforms,ntransforms,CL_TRANSFORM); st->dh=find_cl_if(dict,"dh",CL_DH,True,"site",loc); st->hash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc); @@ -1685,29 +1758,40 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->timeout=0; st->remote_capabilities=0; + st->chosen_transform=0; st->current.key_timeout=0; st->auxiliary_key.key_timeout=0; transport_peers_clear(st,&st->peers); transport_peers_clear(st,&st->setup_peers); /* XXX mlock these */ st->dhsecret=safe_malloc(st->dh->len,"site:dhsecret"); - st->sharedsecretlen=st->transform->keylen?:st->dh->ceil_len; - st->sharedsecret=safe_malloc(st->sharedsecretlen,"site:sharedsecret"); - - /* We need to compute some properties of our comms */ -#define COMPUTE_WORST(pad) \ - int worst_##pad=0; \ - for (i=0; incomms; i++) { \ - int thispad=st->comms[i]->pad; \ - if (thispad > worst_##pad) \ - worst_##pad=thispad; \ + st->sharedsecretlen=st->sharedsecretallocd=0; + st->sharedsecret=0; + + /* We need to compute some properties of our comms and transports */ +#define COMPUTE_WORST(things,pad) \ + int things##_worst_##pad=0; \ + for (i=0; in##things; i++) { \ + int thispad=st->things[i]->pad; \ + if (thispad > things##_worst_##pad) \ + things##_worst_##pad=thispad; \ + } + COMPUTE_WORST(comms,min_start_pad) + COMPUTE_WORST(transforms,max_start_pad) + + for (i=0; intransforms; i++) { + struct transform_if *ti=st->transforms[i]; + uint32_t capbit = 1UL << ti->capab_transformnum; + if (st->local_capabilities & capbit) + slog(st,LOG_ERROR,"transformnum capability bit" + " %d (%#"PRIx32") reused", ti->capab_transformnum, capbit); + st->local_capabilities |= capbit; } - COMPUTE_WORST(min_start_pad) /* We need to register the remote networks with the netlink device */ st->netlink->reg(st->netlink->st, site_outgoing, st, - st->transform->max_start_pad+(4*4)+ - worst_min_start_pad); + transforms_worst_max_start_pad+(4*4)+ + comms_worst_min_start_pad); for (i=0; incomms; i++) st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming); diff --git a/test-example/common.conf b/test-example/common.conf index 64bfc81..b849052 100644 --- a/test-example/common.conf +++ b/test-example/common.conf @@ -8,8 +8,6 @@ resolver adns { }; log-events "all"; random randomfile("/dev/urandom",no); -transform serpent256-cbc { - max-sequence-skew 10; -}; +transform eax-serpent { }, serpent256-cbc { }; include test-example/sites.conf sites map(site,vpn/test-example/all-sites); diff --git a/transform-cbcmac.c b/transform-cbcmac.c index 6920165..95c64e8 100644 --- a/transform-cbcmac.c +++ b/transform-cbcmac.c @@ -278,6 +278,8 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, st->max_seq_skew=dict_read_number(dict, "max-sequence-skew", False, "serpent-cbc256", loc, 10); + SET_CAPAB_TRANSFORMNUM(CAPAB_TRANSFORMNUM_SERPENT256CBC); + return new_closure(&st->cl); } diff --git a/transform-common.h b/transform-common.h index de19817..52f6067 100644 --- a/transform-common.h +++ b/transform-common.h @@ -2,6 +2,8 @@ #ifndef TRANSFORM_COMMON_H #define TRANSFORM_COMMON_H +#include "magic.h" + #define KEYED_CHECK do{ \ if (!ti->keyed) { \ *errmsg="transform unkeyed"; \ @@ -40,6 +42,14 @@ free(st); \ } +#define SET_CAPAB_TRANSFORMNUM(def) do{ \ + st->ops.capab_transformnum=dict_read_number(dict, "capab-num", \ + False, "transform", loc, def); \ + if (st->ops.capab_transformnum > CAPAB_TRANSFORMNUM_MAX) \ + cfgfatal(loc,"transform","capab-num out of range 0..%d\n", \ + CAPAB_TRANSFORMNUM_MAX); \ + }while(0) + #define TRANSFORM_CREATE_CORE \ struct transform_inst *ti; \ ti=safe_malloc(sizeof(*ti),"transform_create"); \ diff --git a/transform-eax.c b/transform-eax.c index 89c46c8..31d8171 100644 --- a/transform-eax.c +++ b/transform-eax.c @@ -273,6 +273,8 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, cfgfatal(loc,"eax-serpent","parameter must be a dictionary\n"); dict=item->data.dict; + SET_CAPAB_TRANSFORMNUM(CAPAB_TRANSFORMNUM_EAXSERPENT); + st->p.max_seq_skew=dict_read_number(dict, "max-sequence-skew", False, "eax-serpent", loc, 10); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:47 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:47 +0100 Subject: [PATCH 21/41] udp.c: Do not send NAKs in response to NAKs In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-22-git-send-email-ijackson@chiark.greenend.org.uk> If an incoming packet isn't name-addressed and has an invalid destination site id, udp.c would send a NAK. This is not a good idea - if somehow the source site id was wrong too, it will result in a NAK storm. This is a security vulnerability as it can be used by an attacker to trigger an unending NAK storm. Also, improve the message printed when a NAK is sent by udp.c because no site wanted to handle it. Signed-off-by: Ian Jackson --- udp.c | 31 ++++++++++++++++++++----------- 1 files changed, 20 insertions(+), 11 deletions(-) diff --git a/udp.c b/udp.c index 77be5b1..c83e618 100644 --- a/udp.c +++ b/udp.c @@ -133,17 +133,26 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds) } } if (!done) { - uint32_t source,dest; - /* Manufacture and send NAK packet */ - source=get_uint32(st->rbuf->start); /* Us */ - dest=get_uint32(st->rbuf->start+4); /* Them */ - Message(M_INFO,"udp (port %d): sending NAK\n",st->port); - buffer_init(st->rbuf,0); - buf_append_uint32(st->rbuf,dest); - buf_append_uint32(st->rbuf,source); - buf_append_uint32(st->rbuf,LABEL_NAK); - sendto(st->fd, st->rbuf->start, st->rbuf->size, 0, - (struct sockaddr *)&from, sizeof(from)); + uint32_t msgtype; + if (st->rbuf->size>12 /* prevents traffic amplification */ + && ((msgtype=get_uint32(st->rbuf->start+8)) + != LABEL_NAK)) { + uint32_t source,dest; + /* Manufacture and send NAK packet */ + source=get_uint32(st->rbuf->start); /* Us */ + dest=get_uint32(st->rbuf->start+4); /* Them */ + Message(M_INFO,"udp (port %d, peer %s):" + " %08"PRIx32"<-%08"PRIx32": %08"PRIx32":" + " unwanted/incorrect, sending NAK\n", + st->port, saddr_to_string(&from), + dest, source, msgtype); + buffer_init(st->rbuf,0); + buf_append_uint32(st->rbuf,dest); + buf_append_uint32(st->rbuf,source); + buf_append_uint32(st->rbuf,LABEL_NAK); + sendto(st->fd, st->rbuf->start, st->rbuf->size, 0, + (struct sockaddr *)&from, sizeof(from)); + } BUF_FREE(st->rbuf); } BUF_ASSERT_FREE(st->rbuf); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:41:00 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:41:00 +0100 Subject: [PATCH 34/41] site, transform: per-transform-instance max_start_pad In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-35-git-send-email-ijackson@chiark.greenend.org.uk> Replicate the max_start_pad value from the transform interface into the instance interface. Use the instance's version in site.c. While we're at it, add an assertion to confirm that the value of max_start_pad passed to buffer_init doesn't overrun the buffer. Signed-off-by: Ian Jackson --- secnet.h | 1 + site.c | 6 +++--- transform-common.h | 1 + util.c | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/secnet.h b/secnet.h index 46aac5b..2ccf161 100644 --- a/secnet.h +++ b/secnet.h @@ -396,6 +396,7 @@ struct transform_inst_if { transform_apply_fn *forwards; transform_apply_fn *reverse; transform_destroyinstance_fn *destroy; + int32_t max_start_pad; /* same as from transform_if */ }; struct transform_if { diff --git a/site.c b/site.c index 2cb53f6..2ada372 100644 --- a/site.c +++ b/site.c @@ -757,7 +757,7 @@ static bool_t generate_msg5(struct site *st) BUF_ALLOC(&st->buffer,"site:MSG5"); /* We are going to add four words to the message */ - buffer_init(&st->buffer,st->transform->max_start_pad+(4*4)); + buffer_init(&st->buffer,st->new_transform->max_start_pad+(4*4)); /* Give the netlink code an opportunity to put its own stuff in the message (configuration information, etc.) */ buf_prepend_uint32(&st->buffer,LABEL_MSG5); @@ -804,7 +804,7 @@ static void create_msg6(struct site *st, struct transform_inst_if *transform, BUF_ALLOC(&st->buffer,"site:MSG6"); /* We are going to add four words to the message */ - buffer_init(&st->buffer,st->transform->max_start_pad+(4*4)); + buffer_init(&st->buffer,transform->max_start_pad+(4*4)); /* Give the netlink code an opportunity to put its own stuff in the message (configuration information, etc.) */ buf_prepend_uint32(&st->buffer,LABEL_MSG6); @@ -1225,7 +1225,7 @@ static bool_t send_msg7(struct site *st, cstring_t reason) if (current_valid(st) && st->buffer.free && transport_peers_valid(&st->peers)) { BUF_ALLOC(&st->buffer,"site:MSG7"); - buffer_init(&st->buffer,st->transform->max_start_pad+(4*3)); + buffer_init(&st->buffer,st->current.transform->max_start_pad+(4*3)); buf_append_uint32(&st->buffer,LABEL_MSG7); buf_append_string(&st->buffer,reason); if (call_transform_forwards(st, st->current.transform, diff --git a/transform-common.h b/transform-common.h index b3c70a8..de19817 100644 --- a/transform-common.h +++ b/transform-common.h @@ -51,6 +51,7 @@ ti->ops.forwards=transform_forward; \ ti->ops.reverse=transform_reverse; \ ti->ops.destroy=transform_destroy; \ + ti->ops.max_start_pad=st->ops.max_start_pad; \ ti->keyed=False; #endif /*TRANSFORM_COMMON_H*/ diff --git a/util.c b/util.c index 1b46bc0..cfaefd2 100644 --- a/util.c +++ b/util.c @@ -247,6 +247,7 @@ void buffer_assert_used(struct buffer_if *buffer, cstring_t file, void buffer_init(struct buffer_if *buffer, int32_t max_start_pad) { + assert(max_start_pad<=buffer->len); buffer->start=buffer->base+max_start_pad; buffer->size=0; } -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:53 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:53 +0100 Subject: [PATCH 27/41] site: fix site name checking leaving room for expansion In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-28-git-send-email-ijackson@chiark.greenend.org.uk> Previously, secnet would only check that the site names sent by the peer had the expected site names as prefixes. This would be a security bug on a vpn where one site name is the prefix of another site name. In fact, if the peer sends a short name, secnet will suffer a buffer read overrun and maybe crash - although this is exploitable only for DoS at worst, and not as an information leak. (With reasonable peers, it won't cause packets to be mishandled, because the next field after each name string is a 16-byte integer giving a name or public key byte count, which would have to contain a value greater than 8000 to look like printable characters.) Fix this bug. However, we use this as an opportunity to provide some space (in the signed part of MSG2..4) for future extensions. (At present there is nothing in the parts of MSG3 and MSG4 covered by the signature which is not supposedly entirely fixed - apart from the amount of zero-padding at the MS end of our DH public exponent. This is bad because it provides no way to do transport protocol upgrade/downgrade negotiation without leaving open a protocol version downgrade attack.) After this change the name fields in MSG2..4 are, following the 16-bit length, either just the characters of the name, or the name, followed by a nul byte, followed by zero or more bytes of additional data. Additional data beyond what the receiver expects (which currently means any additional data), is to be ignored. Let us work through some examples. Suppose the expected site name is "expected". Here are the behaviours in relation to various names being transmitted in the packet. (This applies both to the local name, and to the remote name; "rejected" means other instances of the protocol engine get a go, and perhaps the instance with the correct names will accept the message.) MSG Sent name Old secnet New secnet 1 expected ok ok 1 expected\0extra rejected rejected 1 expected/suffix rejected rejected 1 expect rejected rejected 2-4 expected ok ok 2-4 expected\0extra ok, extra ignored ok, extra data 2-4 expected/suffix wrongly accepted rejected 2-4 expect read overrun rejected We will do the same for MSG1 in a later commit. Signed-off-by: Ian Jackson --- NOTES | 11 ++++++----- site.c | 53 +++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/NOTES b/NOTES index 33c010e..ddd14a5 100644 --- a/NOTES +++ b/NOTES @@ -174,8 +174,9 @@ quite stable so the feature doesn't gain us much. Definitions: -A is the originating gateway machine -B is the destination gateway machine +A is the originating gateway machine name +B is the destination gateway machine name +A+ and B+ are the names with optional additional data, currently ignored PK_A is the public RSA key of A PK_B is the public RSA key of B PK_A^-1 is the private RSA key of A @@ -199,12 +200,12 @@ Messages: 1) A->B: *,iA,msg1,A,B,nA -2) B->A: iA,iB,msg2,B,A,nB,nA +2) B->A: iA,iB,msg2,B+,A+,nB,nA (The order of B and A reverses in alternate messages so that the same code can be used to construct them...) -3) A->B: {iB,iA,msg3,A,B,nA,nB,g^x mod m}_PK_A^-1 +3) A->B: {iB,iA,msg3,A+,B+,nA,nB,g^x mod m}_PK_A^-1 If message 1 was a replay then A will not generate message 3, because it doesn't recognise nA. @@ -212,7 +213,7 @@ it doesn't recognise nA. If message 2 was from an attacker then B will not generate message 4, because it doesn't recognise nB. -4) B->A: {iA,iB,msg4,B,A,nB,nA,g^y mod m}_PK_B^-1 +4) B->A: {iA,iB,msg4,B+,A+,nB,nA,g^y mod m}_PK_B^-1 At this point, A and B share a key, k. B must keep retransmitting message 4 until it receives a packet encrypted using key k. diff --git a/site.c b/site.c index 8fa4c11..2e8335a 100644 --- a/site.c +++ b/site.c @@ -347,14 +347,19 @@ static bool_t current_valid(struct site *st) type=buf_unprepend_uint32((b)); \ if (type!=(t)) return False; } while(0) +struct parsedname { + int32_t len; + uint8_t *name; + int32_t extrainfo_len; + uint8_t *extrainfo; +}; + struct msg { uint8_t *hashstart; uint32_t dest; uint32_t source; - int32_t remlen; - uint8_t *remote; - int32_t loclen; - uint8_t *local; + struct parsedname remote; + struct parsedname local; uint8_t *nR; uint8_t *nL; int32_t pklen; @@ -402,6 +407,24 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) return True; } +static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm) +{ + CHECK_AVAIL(msg,2); + nm->len=buf_unprepend_uint16(msg); + CHECK_AVAIL(msg,nm->len); + nm->name=buf_unprepend(msg,nm->len); + uint8_t *nul=memchr(nm->name,0,nm->len); + if (!nul) { + nm->extrainfo_len=0; + nm->extrainfo=0; + } else { + nm->extrainfo=nul+1; + nm->extrainfo_len=msg->start-nm->extrainfo; + nm->len=nul-nm->name; + } + return True; +} + static bool_t unpick_msg(struct site *st, uint32_t type, struct buffer_if *msg, struct msg *m) { @@ -411,14 +434,8 @@ static bool_t unpick_msg(struct site *st, uint32_t type, CHECK_AVAIL(msg,4); m->source=buf_unprepend_uint32(msg); CHECK_TYPE(msg,type); - CHECK_AVAIL(msg,2); - m->remlen=buf_unprepend_uint16(msg); - CHECK_AVAIL(msg,m->remlen); - m->remote=buf_unprepend(msg,m->remlen); - CHECK_AVAIL(msg,2); - m->loclen=buf_unprepend_uint16(msg); - CHECK_AVAIL(msg,m->loclen); - m->local=buf_unprepend(msg,m->loclen); + if (!unpick_name(msg,&m->remote)) return False; + if (!unpick_name(msg,&m->local)) return False; CHECK_AVAIL(msg,NONCELEN); m->nR=buf_unprepend(msg,NONCELEN); if (type==LABEL_MSG1) { @@ -444,6 +461,14 @@ static bool_t unpick_msg(struct site *st, uint32_t type, return True; } +static bool_t name_matches(const struct parsedname *nm, const char *expected) +{ + int expected_len=strlen(expected); + return + nm->len == expected_len && + !memcmp(nm->name, expected, expected_len); +} + static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, cstring_t *error) { @@ -451,11 +476,11 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, /* Check that the site names and our nonce have been sent back correctly, and then store our peer's nonce. */ - if (memcmp(m->remote,st->remotename,strlen(st->remotename)!=0)) { + if (!name_matches(&m->remote,st->remotename)) { *error="wrong remote site name"; return False; } - if (memcmp(m->local,st->localname,strlen(st->localname)!=0)) { + if (!name_matches(&m->local,st->localname)) { *error="wrong local site name"; return False; } -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:37 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:37 +0100 Subject: [PATCH 11/41] serpent: Provide little-endian version too, but ours is big In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-12-git-send-email-ijackson@chiark.greenend.org.uk> Apparently, almost everyone else is using little-endian Serpent. Since we are going to introduce a new transform, we can make our new transform have conventional little-endian Serpent. But we need to retain the big-endian one for compatibility. In this patch: * Make serpent.h compile-time bytesexual by providing a new definition of GETPUT_CP. We default to (conventional) little-endian. * The big-endian and little-endian versions have different names: decorate the function names. serpent.h declares both sets. * Provide serpentbe.c which compiles to a .o implementing the big-endian version under the new names. Build only that one. * Change all the call sites to use the big-endian Serpent. * Mention this issue in the documentation. Ultimately, no functional change in this patch. Regarding the endianness of Serpent, Mark Wooding writes: I've understood how my Serpent implementation differs from Secnet's, and have reproduced [Ian's EAX] test vectors. NIST have managed to completely screw up their archive of the AES contest pages, but the WayBack Machine works fine -- even on the various PDF documents. The sorry tale begins with the initial Request for Candidate Algorithm Nominations, wherein the specification[1] for the test files unhelpfully muddles things by implying a big-endian representation in the test vector files, e.g., in 3.1, : Each of the possible key basis vectors is tested in this manner, by : shifting the "1" a single position at a time, starting at the most : significant (left-most) bit position of the key. It doesn't help that the original Serpent C implementations in the submission package[2] failed to implement the defined API correctly, and implicitly coerced BYTE pointer (from the defined entry point `blockEncrypt' to an `unsigned long' pointer as an argument to the internal `serpent_encrypt' function. The Java version carefully picks words out of its input byte array in a little-endian order. Secnet's implementation is derived from this original reference implementation. Originally, (v0.03) it had the same bug (only with `uint8_t' and `uint32_t'), but was patched (v0.1.16) to correct the obvious dependency on host endianness. Unfortunately, this patch is wrong: it creates a perfectly portable completely-byte-reversed Serpent compatible with nothing else. I've not found many other implementations, but where I have, they agree with me and the Java reference, and not with Secnet. [1] http://web.archive.org/web/20000420040415/http://csrc.nist.gov/encryption/aes/katmct/katmct.htm [2] http://www.cl.cam.ac.uk/~rja14/Papers/serpent.tar.gz Signed-off-by: Ian Jackson --- Makefile.in | 2 +- secnet.8 | 4 +++- serpent.c | 19 ++++++++++++++++--- serpent.h | 6 ++++++ serpentbe.c | 2 ++ transform.c | 35 ++++++++++++++++++----------------- 6 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 serpentbe.c diff --git a/Makefile.in b/Makefile.in index 182204b..d4d3815 100644 --- a/Makefile.in +++ b/Makefile.in @@ -54,7 +54,7 @@ TARGETS:=secnet OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ resolver.o random.o udp.o site.o transform.o netlink.o rsa.o dh.o \ - serpent.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ + serpentbe.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ process.o @LIBOBJS@ \ hackypar.o diff --git a/secnet.8 b/secnet.8 index 869d297..ef07a76 100644 --- a/secnet.8 +++ b/secnet.8 @@ -429,7 +429,9 @@ It may be necessary to increase this is if connectivity is poor. A \fItransform closure\fR is a reversible means of transforming messages for transmission over a (presumably) insecure network. It is responsible for both confidentiality and integrity. - +.PP +Note that this uses a big-endian variant of the Serpent block cipher +(which is not compatible with most other Serpent implementations). .SS rsa-private \fBrsa-private(\fIPATH\fB\fR[, \fICHECK\fR]\fB)\fR => \fIrsaprivkey closure\fR .TP diff --git a/serpent.c b/serpent.c index 3847437..6407c57 100644 --- a/serpent.c +++ b/serpent.c @@ -25,9 +25,22 @@ #include "serpent.h" #include "serpentsboxes.h" +#ifdef SERPENT_BIGENDIAN + #define GETPUT_CP(bytenum) \ (((basep) + (lenbytes) - (offset) - 4)[(bytenum)]) +#define SERPENT_DECORATE(func) serpentbe_##func + +#else /* !defined(SERPENT_BIGENDIAN) */ + +#define GETPUT_CP(bytenum) \ + (((basep) + (offset))[3-(bytenum)]) + +#define SERPENT_DECORATE(func) serpent_##func + +#endif /* !defined(SERPENT_BIGENDIAN) */ + static uint32_t serpent_get_32bit(const uint8_t *basep, int lenbytes, int offset) { @@ -45,7 +58,7 @@ static void serpent_put_32bit(uint8_t *basep, int lenbytes, int offset, uint32_t GETPUT_CP(3) = (char)(value); } -void serpent_makekey(struct keyInstance *key, int keyLen, +void SERPENT_DECORATE(makekey)(struct keyInstance *key, int keyLen, const uint8_t *keyMaterial) { int i; @@ -105,7 +118,7 @@ void serpent_makekey(struct keyInstance *key, int keyLen, key->subkeys[i][j] = k[4*i+j]; } -void serpent_encrypt(struct keyInstance *key, +void SERPENT_DECORATE(encrypt)(struct keyInstance *key, const uint8_t plaintext[16], uint8_t ciphertext[16]) { @@ -223,7 +236,7 @@ void serpent_encrypt(struct keyInstance *key, serpent_put_32bit(ciphertext,16,12, x3); } -void serpent_decrypt(struct keyInstance *key, +void SERPENT_DECORATE(decrypt)(struct keyInstance *key, const uint8_t ciphertext[16], uint8_t plaintext[16]) { diff --git a/serpent.h b/serpent.h index 19c01fe..857b1b9 100644 --- a/serpent.h +++ b/serpent.h @@ -9,11 +9,17 @@ struct keyInstance { /* Function protoypes */ void serpent_makekey(struct keyInstance *key, int keyLen, const uint8_t *keyMaterial); +void serpentbe_makekey(struct keyInstance *key, int keyLen, + const uint8_t *keyMaterial); void serpent_encrypt(struct keyInstance *key, const uint8_t plaintext[16], uint8_t ciphertext[16]); +void serpentbe_encrypt(struct keyInstance *key, const uint8_t plaintext[16], + uint8_t ciphertext[16]); void serpent_decrypt(struct keyInstance *key, const uint8_t ciphertext[16], uint8_t plaintext[16]); +void serpentbe_decrypt(struct keyInstance *key, const uint8_t ciphertext[16], + uint8_t plaintext[16]); #endif /* serpent_h */ diff --git a/serpentbe.c b/serpentbe.c new file mode 100644 index 0000000..758d5c9 --- /dev/null +++ b/serpentbe.c @@ -0,0 +1,2 @@ +#define SERPENT_BIGENDIAN +#include "serpent.c" diff --git a/transform.c b/transform.c index 08ddad6..a0665ad 100644 --- a/transform.c +++ b/transform.c @@ -57,8 +57,8 @@ static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) } #endif /* 0 */ - serpent_makekey(&ti->cryptkey,256,key); - serpent_makekey(&ti->mackey,256,key+32); + serpentbe_makekey(&ti->cryptkey,256,key); + serpentbe_makekey(&ti->mackey,256,key+32); ti->cryptiv=get_uint32(key+64); ti->maciv=get_uint32(key+68); ti->sendseq=get_uint32(key+72); @@ -122,7 +122,7 @@ static uint32_t transform_forward(void *sst, struct buffer_if *buf, message stays a multiple of 16 bytes long.) */ memset(iv,0,16); put_uint32(iv, ti->maciv); - serpent_encrypt(&ti->mackey,iv,macacc); + serpentbe_encrypt(&ti->mackey,iv,macacc); /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted block encrypted once again. */ @@ -130,16 +130,16 @@ static uint32_t transform_forward(void *sst, struct buffer_if *buf, { for (i = 0; i < 16; i++) macplain[i] = macacc[i] ^ n[i]; - serpent_encrypt(&ti->mackey,macplain,macacc); + serpentbe_encrypt(&ti->mackey,macplain,macacc); } - serpent_encrypt(&ti->mackey,macacc,macacc); + serpentbe_encrypt(&ti->mackey,macacc,macacc); memcpy(buf_append(buf,16),macacc,16); /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption, and prepend the IV before increasing it. */ memset(iv,0,16); put_uint32(iv, ti->cryptiv); - serpent_encrypt(&ti->cryptkey,iv,iv); + serpentbe_encrypt(&ti->cryptkey,iv,iv); /* CBC: each block is XORed with the previous encrypted block (or the IV) before being encrypted. */ @@ -149,7 +149,7 @@ static uint32_t transform_forward(void *sst, struct buffer_if *buf, { for (i = 0; i < 16; i++) n[i] ^= p[i]; - serpent_encrypt(&ti->cryptkey,n,n); + serpentbe_encrypt(&ti->cryptkey,n,n); p=n; } @@ -194,12 +194,12 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, *errmsg="msg not multiple of cipher blocksize"; return 1; } - serpent_encrypt(&ti->cryptkey,iv,iv); + serpentbe_encrypt(&ti->cryptkey,iv,iv); for (n=buf->start; nstart+buf->size; n+=16) { for (i = 0; i < 16; i++) pct[i] = n[i]; - serpent_decrypt(&ti->cryptkey,n,n); + serpentbe_decrypt(&ti->cryptkey,n,n); for (i = 0; i < 16; i++) n[i] ^= iv[i]; memcpy(iv, pct, 16); @@ -209,7 +209,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, macexpected=buf_unappend(buf,16); memset(iv,0,16); put_uint32(iv, ti->maciv); - serpent_encrypt(&ti->mackey,iv,macacc); + serpentbe_encrypt(&ti->mackey,iv,macacc); /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted block encrypted once again. */ @@ -217,9 +217,9 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, { for (i = 0; i < 16; i++) macplain[i] = macacc[i] ^ n[i]; - serpent_encrypt(&ti->mackey,macplain,macacc); + serpentbe_encrypt(&ti->mackey,macplain,macacc); } - serpent_encrypt(&ti->mackey,macacc,macacc); + serpentbe_encrypt(&ti->mackey,macacc,macacc); if (!consttime_memeq(macexpected,macacc,16)!=0) { *errmsg="invalid MAC"; return 1; @@ -327,8 +327,9 @@ void transform_module(dict_t *dict) /* * Serpent self-test. * - * This test pattern is taken directly from the Serpent test - * vectors, to ensure we have all endianness issues correct. -sgt + * This test pattern was taken directly from the Serpent test + * vectors, which results in a big-endian Serpent which is not + * compatible with other implementations. */ /* Serpent self-test */ @@ -336,18 +337,18 @@ void transform_module(dict_t *dict) "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00", 32); - serpent_makekey(&k,256,data); + serpentbe_makekey(&k,256,data); memcpy(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10", 16); - serpent_encrypt(&k,plaintext,ciphertext); + serpentbe_encrypt(&k,plaintext,ciphertext); if (memcmp(ciphertext, "\xca\x7f\xa1\x93\xe3\xeb\x9e\x99" "\xbd\x87\xe3\xaf\x3c\x9a\xdf\x93", 16)) { fatal("transform_module: serpent failed self-test (encrypt)"); } - serpent_decrypt(&k,ciphertext,plaintext); + serpentbe_decrypt(&k,ciphertext,plaintext); if (memcmp(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef" "\xfe\xdc\xba\x98\x76\x54\x32\x10", 16)) { fatal("transform_module: serpent failed self-test (decrypt)"); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:41:07 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:41:07 +0100 Subject: [PATCH 41/41] changelog: Describe 0.3.0~beta2 In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-42-git-send-email-ijackson@chiark.greenend.org.uk> Signed-off-by: Ian Jackson --- Makefile.in | 2 +- debian/changelog | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletions(-) diff --git a/Makefile.in b/Makefile.in index 5a140fb..04d59f4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,7 +18,7 @@ .PHONY: all clean realclean distclean dist install PACKAGE:=secnet -VERSION:=0.2.1 +VERSION:=0.3.0~beta2 @SET_MAKE@ diff --git a/debian/changelog b/debian/changelog index 9f164bb..cabe3f9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,20 @@ +secnet (0.3.0~beta2) unstable; urgency=low + + * New upstream version. + - SECURITY FIX: RSA public modulus and exponent buffer overflow. + - SECURITY FIX: Use constant-time memcmp for message authentication. + - SECURITY FIX: Provide a new transform, eax-serpent, to replace cbcmac. + - SECURITY FIX: No longer send NAKs for NAKs, avoiding NAK storm. + - SECURITY FIX: Fix site name checking when site name A is prefix of B. + - Better robustness for mobile sites (proper user of NAKs, new PROD msg). + - Better robustness against SLIP decoding errors. + - Fix bugs which caused routes to sometimes not be advertised. + - Protocol capability negotiation mechanism. + - Improvements and fixes to protocol and usage documentation. + - Other bugfixes and code tidying up. + + -- Ian Jackson Thu, 25 Jul 2013 18:26:01 +0100 + secnet (0.3.0~beta1) unstable; urgency=low * New upstream version. -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:49 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:49 +0100 Subject: [PATCH 23/41] site: Send NAKs for undecryptable data packets (msg0) In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-24-git-send-email-ijackson@chiark.greenend.org.uk> Packets which are not understood are supposed in general to produce NAKs, to let the peer know that we don't have the key they were using. However, previously this would only happen if the incoming packet had a local site index which was not in use. But it can happen that a particular index value is reused by a recently restarted secnet. Previously, in this case, data packets would simply be thrown away undecryptable. With this change, undecryptable data packets always generate a NAK. (But we don't generate a NAK if the packet was decryptable, but suffered from sequence number skew - if we did, then network glitches would trigger spurious key exchanges.) This is particularly relevant for mobile sites, as it can happen that the fixed site doesn't have an address for the mobile site - so the association will remain stuck in a broken state until the mobile site is also restarted. There is still a potential problem when a site is restarted mid key exchange. The peer will refuse to start a new key exchange (because of the retry timeout) and the restarted site may not know it's necessary. This will be dealt with in a later patch. Signed-off-by: Ian Jackson --- site.c | 26 +++++++++++++++++--------- 1 files changed, 17 insertions(+), 9 deletions(-) diff --git a/site.c b/site.c index a6fa9da..8fa4c11 100644 --- a/site.c +++ b/site.c @@ -731,7 +731,8 @@ static bool_t process_msg6(struct site *st, struct buffer_if *msg6, return True; } -static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0) +static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0, + const struct comm_addr *src) { cstring_t transform_err, auxkey_err, newkey_err="n/a"; struct msg0 m; @@ -750,11 +751,8 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0) "peer has used new key","auxiliary key",LOG_SEC); return True; } - - if (problem==2) { - slog(st,LOG_DROP,"transform: %s (merely skew)",transform_err); - return False; - } + if (problem==2) + goto skew; buffer_copy(msg0, &st->scratch); problem = st->auxiliary_key.transform->reverse @@ -778,11 +776,14 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0) } return True; } + if (problem==2) + goto skew; if (st->state==SITE_SENTMSG5) { buffer_copy(msg0, &st->scratch); - if (!st->new_transform->reverse(st->new_transform->st, - msg0,&newkey_err)) { + problem = st->new_transform->reverse(st->new_transform->st, + msg0,&newkey_err); + if (!problem) { /* It looks like we didn't get the peer's MSG6 */ /* This is like a cut-down enter_new_state(SITE_RUN) */ slog(st,LOG_STATE,"will enter state RUN (MSG0 with new key)"); @@ -791,11 +792,18 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0) activate_new_key(st); return True; /* do process the data in this packet */ } + if (problem==2) + goto skew; } slog(st,LOG_SEC,"transform: %s (aux: %s, new: %s)", transform_err,auxkey_err,newkey_err); initiate_key_setup(st,"incoming message would not decrypt"); + send_nak(src,m.dest,m.source,m.type,msg0,"message would not decrypt"); + return False; + + skew: + slog(st,LOG_DROP,"transform: %s (merely skew)",transform_err); return False; } @@ -804,7 +812,7 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0, { uint32_t type; - if (!decrypt_msg0(st,msg0)) + if (!decrypt_msg0(st,msg0,src)) return False; CHECK_AVAIL(msg0,4); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:55 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:55 +0100 Subject: [PATCH 29/41] site: use unaligned.h's functions, not pointer cast and ntohl In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-30-git-send-email-ijackson@chiark.greenend.org.uk> Switch site.c to using unaligned.h's functions for accessing multi-byte values inside messages. There were a few places where this construction was used: something = ntohl(*(uint32_t*)(buf->start + offset)); It is much clearer to use this equivalent construction: something = get_uint32(buf->start + offset); Also the packet's message type was extracted from the message using get_uint32 and then put through ntohl. This is, of course, wrong. Currently all the message type codes are palindromes, so it doesn't matter in practice. Fix it anyway. Signed-off-by: Ian Jackson --- site.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/site.c b/site.c index 98bd6b6..5b071b2 100644 --- a/site.c +++ b/site.c @@ -859,9 +859,9 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0, static void dump_packet(struct site *st, struct buffer_if *buf, const struct comm_addr *addr, bool_t incoming) { - uint32_t dest=ntohl(*(uint32_t *)buf->start); - uint32_t source=ntohl(*(uint32_t *)(buf->start+4)); - uint32_t msgtype=ntohl(*(uint32_t *)(buf->start+8)); + uint32_t dest=get_uint32(buf->start); + uint32_t source=get_uint32(buf->start+4); + uint32_t msgtype=get_uint32(buf->start+8); if (st->log_events & LOG_DUMP) slilog(st->log,M_DEBUG,"%s: %s: %08x<-%08x: %08x:", @@ -1268,8 +1268,8 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, if (buf->size < 12) return False; - uint32_t msgtype=ntohl(get_uint32(buf->start+8)); - uint32_t dest=ntohl(*(uint32_t *)buf->start); + uint32_t dest=get_uint32(buf->start); + uint32_t msgtype=get_uint32(buf->start+8); struct msg named_msg; if (msgtype==LABEL_MSG1) { -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:41:05 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:41:05 +0100 Subject: [PATCH 39/41] slip: Buffer management (max_start_pad) fixes In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-40-git-send-email-ijackson@chiark.greenend.org.uk> Nothing in slip.c calls buffer_init for the first packet. We don't normally notice this because userv-ipif _both_ prints a confirmation END byte right away, _and_ bookends packets with ENDs. But this should be fixed. Otherwise we fail an assertion when we try to prepend things to the first data packet. Signed-off-by: Ian Jackson --- netlink.c | 4 +++- slip.c | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/netlink.c b/netlink.c index 173d412..bc70757 100644 --- a/netlink.c +++ b/netlink.c @@ -603,11 +603,13 @@ static void netlink_incoming(struct netlink *st, struct netlink_client *client, uint32_t source,dest; struct iphdr *iph; char errmsgbuf[50]; + const char *sourcedesc=client?client->name:"host"; BUF_ASSERT_USED(buf); + if (!netlink_check(st,buf,errmsgbuf,sizeof(errmsgbuf))) { Message(M_WARNING,"%s: bad IP packet from %s: %s\n", - st->name,client?client->name:"host", + st->name,sourcedesc, errmsgbuf); BUF_FREE(buf); return; diff --git a/slip.c b/slip.c index 5eb8dbd..9e63cb3 100644 --- a/slip.c +++ b/slip.c @@ -79,6 +79,9 @@ static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) int outputchr; enum { OUTPUT_END = 256, OUTPUT_NOTHING = 257 }; + if (!st->buff->size) + buffer_init(st->buff,calculate_max_start_pad()); + if (st->pending_esc) { st->pending_esc=False; switch(buf[i]) { @@ -115,7 +118,7 @@ static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) if (st->ignoring_packet) { if (outputchr == OUTPUT_END) { st->ignoring_packet=False; - buffer_init(st->buff,calculate_max_start_pad()); + st->buff->size=0; } } else { if (outputchr == OUTPUT_END) { @@ -123,7 +126,7 @@ static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) st->netlink_to_tunnel(&st->nl,st->buff); BUF_ALLOC(st->buff,"userv_afterpoll"); } - buffer_init(st->buff,calculate_max_start_pad()); + st->buff->size=0; } else if (outputchr != OUTPUT_NOTHING) { if (st->buff->size < st->buff->len) { buf_append_uint8(st->buff,outputchr); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:46 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:46 +0100 Subject: [PATCH 20/41] magic: Introduce LABEL_NAK In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-21-git-send-email-ijackson@chiark.greenend.org.uk> Replace ad-hoc comments on the message number of NAK packets with an explicit #define. No functional change. Signed-off-by: Ian Jackson --- magic.h | 1 + site.c | 2 +- udp.c | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/magic.h b/magic.h index 5ac1e34..c2503a0 100644 --- a/magic.h +++ b/magic.h @@ -3,6 +3,7 @@ #ifndef magic_h #define magic_h +#define LABEL_NAK 0x00000000 #define LABEL_MSG0 0x00020200 #define LABEL_MSG1 0x01010101 #define LABEL_MSG2 0x02020202 diff --git a/site.c b/site.c index f1a0317..a6fa9da 100644 --- a/site.c +++ b/site.c @@ -1286,7 +1286,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, uint32_t msgtype=ntohl(get_uint32(buf->start+8)); if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); switch (msgtype) { - case 0: /* NAK */ + case LABEL_NAK: /* If the source is our current peer then initiate a key setup, because our peer's forgotten the key */ if (get_uint32(buf->start+4)==st->current.remote_session_id) { diff --git a/udp.c b/udp.c index bbf8c64..77be5b1 100644 --- a/udp.c +++ b/udp.c @@ -21,6 +21,7 @@ #include "util.h" #include "unaligned.h" #include "ipaddr.h" +#include "magic.h" static beforepoll_fn udp_beforepoll; static afterpoll_fn udp_afterpoll; @@ -140,7 +141,7 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds) buffer_init(st->rbuf,0); buf_append_uint32(st->rbuf,dest); buf_append_uint32(st->rbuf,source); - buf_append_uint32(st->rbuf,0); /* NAK is msg type 0 */ + buf_append_uint32(st->rbuf,LABEL_NAK); sendto(st->fd, st->rbuf->start, st->rbuf->size, 0, (struct sockaddr *)&from, sizeof(from)); BUF_FREE(st->rbuf); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:39 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:39 +0100 Subject: [PATCH 13/41] crypto: Copy a SHA512 implementation into tree In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-14-git-send-email-ijackson@chiark.greenend.org.uk> We are going to want an implementation of SHA512 (initially for hashing DH secrets into EAX keys). Copy the version from coreutils 8.5, along with u64.h. In this patch, we commit exactly the files from coreutils. They will be made to compile later. Doing it this way means we can more easily isolate changes we have to make. Copying these files from coreutils makes secnet GPL-3+. Signed-off-by: Ian Jackson --- COPYING | 914 ++++++++++++++++++++++++++++++++++++++++++-------------------- sha512.c | 619 ++++++++++++++++++++++++++++++++++++++++++ sha512.h | 95 +++++++ u64.h | 159 +++++++++++ 4 files changed, 1497 insertions(+), 290 deletions(-) create mode 100644 sha512.c create mode 100644 sha512.h create mode 100644 u64.h diff --git a/COPYING b/COPYING index 60549be..94a9ed0 100644 --- a/COPYING +++ b/COPYING @@ -1,285 +1,626 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of this License. - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least +state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -304,37 +645,30 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/sha512.c b/sha512.c new file mode 100644 index 0000000..5c0b2ed --- /dev/null +++ b/sha512.c @@ -0,0 +1,619 @@ +/* sha512.c - Functions to compute SHA512 and SHA384 message digest of files or + memory blocks according to the NIST specification FIPS-180-2. + + Copyright (C) 2005, 2006, 2008, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by David Madore, considerably copypasting from + Scott G. Miller's sha1.c +*/ + +#include + +#include "sha512.h" + +#include +#include +#include + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + u64or (u64or (u64or (u64shl (n, 56), \ + u64shl (u64and (n, u64lo (0x0000ff00)), 40)), \ + u64or (u64shl (u64and (n, u64lo (0x00ff0000)), 24), \ + u64shl (u64and (n, u64lo (0xff000000)), 8))), \ + u64or (u64or (u64and (u64shr (n, 8), u64lo (0xff000000)), \ + u64and (u64shr (n, 24), u64lo (0x00ff0000))), \ + u64or (u64and (u64shr (n, 40), u64lo (0x0000ff00)), \ + u64shr (n, 56)))) +#endif + +#define BLOCKSIZE 32768 +#if BLOCKSIZE % 128 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 128-byte boundary. */ +static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 512 bit block of data (eight 64 bit ints) and + intializes it to the start constants of the SHA512 algorithm. This + must be called before using hash in the call to sha512_hash +*/ +void +sha512_init_ctx (struct sha512_ctx *ctx) +{ + ctx->state[0] = u64hilo (0x6a09e667, 0xf3bcc908); + ctx->state[1] = u64hilo (0xbb67ae85, 0x84caa73b); + ctx->state[2] = u64hilo (0x3c6ef372, 0xfe94f82b); + ctx->state[3] = u64hilo (0xa54ff53a, 0x5f1d36f1); + ctx->state[4] = u64hilo (0x510e527f, 0xade682d1); + ctx->state[5] = u64hilo (0x9b05688c, 0x2b3e6c1f); + ctx->state[6] = u64hilo (0x1f83d9ab, 0xfb41bd6b); + ctx->state[7] = u64hilo (0x5be0cd19, 0x137e2179); + + ctx->total[0] = ctx->total[1] = u64lo (0); + ctx->buflen = 0; +} + +void +sha384_init_ctx (struct sha512_ctx *ctx) +{ + ctx->state[0] = u64hilo (0xcbbb9d5d, 0xc1059ed8); + ctx->state[1] = u64hilo (0x629a292a, 0x367cd507); + ctx->state[2] = u64hilo (0x9159015a, 0x3070dd17); + ctx->state[3] = u64hilo (0x152fecd8, 0xf70e5939); + ctx->state[4] = u64hilo (0x67332667, 0xffc00b31); + ctx->state[5] = u64hilo (0x8eb44a87, 0x68581511); + ctx->state[6] = u64hilo (0xdb0c2e0d, 0x64f98fa7); + ctx->state[7] = u64hilo (0x47b5481d, 0xbefa4fa4); + + ctx->total[0] = ctx->total[1] = u64lo (0); + ctx->buflen = 0; +} + +/* Copy the value from V into the memory location pointed to by *CP, + If your architecture allows unaligned access, this is equivalent to + * (__typeof__ (v) *) cp = v */ +static inline void +set_uint64 (char *cp, u64 v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 64 bytes following RESBUF. + The result must be in little endian byte order. */ +void * +sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 8; i++) + set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +void * +sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 6; i++) + set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +static void +sha512_conclude_ctx (struct sha512_ctx *ctx) +{ + /* Take yet unprocessed bytes into account. */ + size_t bytes = ctx->buflen; + size_t size = (bytes < 112) ? 128 / 8 : 128 * 2 / 8; + + /* Now count remaining bytes. */ + ctx->total[0] = u64plus (ctx->total[0], u64lo (bytes)); + if (u64lt (ctx->total[0], u64lo (bytes))) + ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); + + /* Put the 128-bit file length in *bits* at the end of the buffer. + Use set_uint64 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint64 ((char *) &ctx->buffer[size - 2], + SWAP (u64or (u64shl (ctx->total[1], 3), + u64shr (ctx->total[0], 61)))); + set_uint64 ((char *) &ctx->buffer[size - 1], + SWAP (u64shl (ctx->total[0], 3))); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes); + + /* Process last bytes. */ + sha512_process_block (ctx->buffer, size * 8, ctx); +} + +void * +sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf) +{ + sha512_conclude_ctx (ctx); + return sha512_read_ctx (ctx, resbuf); +} + +void * +sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf) +{ + sha512_conclude_ctx (ctx); + return sha384_read_ctx (ctx, resbuf); +} + +/* Compute SHA512 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 64 bytes + beginning at RESBLOCK. */ +int +sha512_stream (FILE *stream, void *resblock) +{ + struct sha512_ctx ctx; + size_t sum; + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + /* Initialize the computation context. */ + sha512_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + { + free (buffer); + return 1; + } + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 128 == 0 + */ + sha512_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha512_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha512_finish_ctx (&ctx, resblock); + free (buffer); + return 0; +} + +/* FIXME: Avoid code duplication */ +int +sha384_stream (FILE *stream, void *resblock) +{ + struct sha512_ctx ctx; + size_t sum; + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + /* Initialize the computation context. */ + sha384_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + { + free (buffer); + return 1; + } + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 128 == 0 + */ + sha512_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha512_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha384_finish_ctx (&ctx, resblock); + free (buffer); + return 0; +} + +/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +sha512_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha512_ctx ctx; + + /* Initialize the computation context. */ + sha512_init_ctx (&ctx); + + /* Process whole buffer but last len % 128 bytes. */ + sha512_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha512_finish_ctx (&ctx, resblock); +} + +void * +sha384_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha512_ctx ctx; + + /* Initialize the computation context. */ + sha384_init_ctx (&ctx); + + /* Process whole buffer but last len % 128 bytes. */ + sha512_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha384_finish_ctx (&ctx, resblock); +} + +void +sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 256 - left_over > len ? len : 256 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 128) + { + sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx); + + ctx->buflen &= 127; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~127], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 128) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (u64) != 0) + if (UNALIGNED_P (buffer)) + while (len > 128) + { + sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128, ctx); + buffer = (const char *) buffer + 128; + len -= 128; + } + else +#endif + { + sha512_process_block (buffer, len & ~127, ctx); + buffer = (const char *) buffer + (len & ~127); + len &= 127; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 128) + { + sha512_process_block (ctx->buffer, 128, ctx); + left_over -= 128; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha512.c --- */ + +/* SHA512 round constants */ +#define K(I) sha512_round_constants[I] +static u64 const sha512_round_constants[80] = { + u64init (0x428a2f98, 0xd728ae22), u64init (0x71374491, 0x23ef65cd), + u64init (0xb5c0fbcf, 0xec4d3b2f), u64init (0xe9b5dba5, 0x8189dbbc), + u64init (0x3956c25b, 0xf348b538), u64init (0x59f111f1, 0xb605d019), + u64init (0x923f82a4, 0xaf194f9b), u64init (0xab1c5ed5, 0xda6d8118), + u64init (0xd807aa98, 0xa3030242), u64init (0x12835b01, 0x45706fbe), + u64init (0x243185be, 0x4ee4b28c), u64init (0x550c7dc3, 0xd5ffb4e2), + u64init (0x72be5d74, 0xf27b896f), u64init (0x80deb1fe, 0x3b1696b1), + u64init (0x9bdc06a7, 0x25c71235), u64init (0xc19bf174, 0xcf692694), + u64init (0xe49b69c1, 0x9ef14ad2), u64init (0xefbe4786, 0x384f25e3), + u64init (0x0fc19dc6, 0x8b8cd5b5), u64init (0x240ca1cc, 0x77ac9c65), + u64init (0x2de92c6f, 0x592b0275), u64init (0x4a7484aa, 0x6ea6e483), + u64init (0x5cb0a9dc, 0xbd41fbd4), u64init (0x76f988da, 0x831153b5), + u64init (0x983e5152, 0xee66dfab), u64init (0xa831c66d, 0x2db43210), + u64init (0xb00327c8, 0x98fb213f), u64init (0xbf597fc7, 0xbeef0ee4), + u64init (0xc6e00bf3, 0x3da88fc2), u64init (0xd5a79147, 0x930aa725), + u64init (0x06ca6351, 0xe003826f), u64init (0x14292967, 0x0a0e6e70), + u64init (0x27b70a85, 0x46d22ffc), u64init (0x2e1b2138, 0x5c26c926), + u64init (0x4d2c6dfc, 0x5ac42aed), u64init (0x53380d13, 0x9d95b3df), + u64init (0x650a7354, 0x8baf63de), u64init (0x766a0abb, 0x3c77b2a8), + u64init (0x81c2c92e, 0x47edaee6), u64init (0x92722c85, 0x1482353b), + u64init (0xa2bfe8a1, 0x4cf10364), u64init (0xa81a664b, 0xbc423001), + u64init (0xc24b8b70, 0xd0f89791), u64init (0xc76c51a3, 0x0654be30), + u64init (0xd192e819, 0xd6ef5218), u64init (0xd6990624, 0x5565a910), + u64init (0xf40e3585, 0x5771202a), u64init (0x106aa070, 0x32bbd1b8), + u64init (0x19a4c116, 0xb8d2d0c8), u64init (0x1e376c08, 0x5141ab53), + u64init (0x2748774c, 0xdf8eeb99), u64init (0x34b0bcb5, 0xe19b48a8), + u64init (0x391c0cb3, 0xc5c95a63), u64init (0x4ed8aa4a, 0xe3418acb), + u64init (0x5b9cca4f, 0x7763e373), u64init (0x682e6ff3, 0xd6b2b8a3), + u64init (0x748f82ee, 0x5defb2fc), u64init (0x78a5636f, 0x43172f60), + u64init (0x84c87814, 0xa1f0ab72), u64init (0x8cc70208, 0x1a6439ec), + u64init (0x90befffa, 0x23631e28), u64init (0xa4506ceb, 0xde82bde9), + u64init (0xbef9a3f7, 0xb2c67915), u64init (0xc67178f2, 0xe372532b), + u64init (0xca273ece, 0xea26619c), u64init (0xd186b8c7, 0x21c0c207), + u64init (0xeada7dd6, 0xcde0eb1e), u64init (0xf57d4f7f, 0xee6ed178), + u64init (0x06f067aa, 0x72176fba), u64init (0x0a637dc5, 0xa2c898a6), + u64init (0x113f9804, 0xbef90dae), u64init (0x1b710b35, 0x131c471b), + u64init (0x28db77f5, 0x23047d84), u64init (0x32caab7b, 0x40c72493), + u64init (0x3c9ebe0a, 0x15c9bebc), u64init (0x431d67c4, 0x9c100d4c), + u64init (0x4cc5d4be, 0xcb3e42b6), u64init (0x597f299c, 0xfc657e2a), + u64init (0x5fcb6fab, 0x3ad6faec), u64init (0x6c44198c, 0x4a475817), +}; + +/* Round functions. */ +#define F2(A, B, C) u64or (u64and (A, B), u64and (C, u64or (A, B))) +#define F1(E, F, G) u64xor (G, u64and (E, u64xor (F, G))) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 128 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void +sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx) +{ + u64 const *words = buffer; + u64 const *endp = words + len / sizeof (u64); + u64 x[16]; + u64 a = ctx->state[0]; + u64 b = ctx->state[1]; + u64 c = ctx->state[2]; + u64 d = ctx->state[3]; + u64 e = ctx->state[4]; + u64 f = ctx->state[5]; + u64 g = ctx->state[6]; + u64 h = ctx->state[7]; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^128 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] = u64plus (ctx->total[0], u64lo (len)); + if (u64lt (ctx->total[0], u64lo (len))) + ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); + +#define S0(x) u64xor (u64rol(x, 63), u64xor (u64rol (x, 56), u64shr (x, 7))) +#define S1(x) u64xor (u64rol (x, 45), u64xor (u64rol (x, 3), u64shr (x, 6))) +#define SS0(x) u64xor (u64rol (x, 36), u64xor (u64rol (x, 30), u64rol (x, 25))) +#define SS1(x) u64xor (u64rol(x, 50), u64xor (u64rol (x, 46), u64rol (x, 23))) + +#define M(I) (x[(I) & 15] \ + = u64plus (x[(I) & 15], \ + u64plus (S1 (x[((I) - 2) & 15]), \ + u64plus (x[((I) - 7) & 15], \ + S0 (x[((I) - 15) & 15]))))) + +#define R(A, B, C, D, E, F, G, H, K, M) \ + do \ + { \ + u64 t0 = u64plus (SS0 (A), F2 (A, B, C)); \ + u64 t1 = \ + u64plus (H, u64plus (SS1 (E), \ + u64plus (F1 (E, F, G), u64plus (K, M)))); \ + D = u64plus (D, t1); \ + H = u64plus (t0, t1); \ + } \ + while (0) + + while (words < endp) + { + int t; + /* FIXME: see sha1.c for a better implementation. */ + for (t = 0; t < 16; t++) + { + x[t] = SWAP (*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + R( a, b, c, d, e, f, g, h, K(64), M(64) ); + R( h, a, b, c, d, e, f, g, K(65), M(65) ); + R( g, h, a, b, c, d, e, f, K(66), M(66) ); + R( f, g, h, a, b, c, d, e, K(67), M(67) ); + R( e, f, g, h, a, b, c, d, K(68), M(68) ); + R( d, e, f, g, h, a, b, c, K(69), M(69) ); + R( c, d, e, f, g, h, a, b, K(70), M(70) ); + R( b, c, d, e, f, g, h, a, K(71), M(71) ); + R( a, b, c, d, e, f, g, h, K(72), M(72) ); + R( h, a, b, c, d, e, f, g, K(73), M(73) ); + R( g, h, a, b, c, d, e, f, K(74), M(74) ); + R( f, g, h, a, b, c, d, e, K(75), M(75) ); + R( e, f, g, h, a, b, c, d, K(76), M(76) ); + R( d, e, f, g, h, a, b, c, K(77), M(77) ); + R( c, d, e, f, g, h, a, b, K(78), M(78) ); + R( b, c, d, e, f, g, h, a, K(79), M(79) ); + + a = ctx->state[0] = u64plus (ctx->state[0], a); + b = ctx->state[1] = u64plus (ctx->state[1], b); + c = ctx->state[2] = u64plus (ctx->state[2], c); + d = ctx->state[3] = u64plus (ctx->state[3], d); + e = ctx->state[4] = u64plus (ctx->state[4], e); + f = ctx->state[5] = u64plus (ctx->state[5], f); + g = ctx->state[6] = u64plus (ctx->state[6], g); + h = ctx->state[7] = u64plus (ctx->state[7], h); + } +} diff --git a/sha512.h b/sha512.h new file mode 100644 index 0000000..ea85194 --- /dev/null +++ b/sha512.h @@ -0,0 +1,95 @@ +/* Declarations of functions and data types used for SHA512 and SHA384 sum + library functions. + Copyright (C) 2005, 2006, 2008, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef SHA512_H +# define SHA512_H 1 + +# include + +# include "u64.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/* Structure to save state of computation between the single steps. */ +struct sha512_ctx +{ + u64 state[8]; + + u64 total[2]; + size_t buflen; + u64 buffer[32]; +}; + +enum { SHA384_DIGEST_SIZE = 384 / 8 }; +enum { SHA512_DIGEST_SIZE = 512 / 8 }; + +/* Initialize structure containing state of computation. */ +extern void sha512_init_ctx (struct sha512_ctx *ctx); +extern void sha384_init_ctx (struct sha512_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 128!!! */ +extern void sha512_process_block (const void *buffer, size_t len, + struct sha512_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 128. */ +extern void sha512_process_bytes (const void *buffer, size_t len, + struct sha512_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 64 (48) bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf); +extern void *sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 64 (48) bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf); +extern void *sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf); + + +/* Compute SHA512 (SHA384) message digest for bytes read from STREAM. The + resulting message digest number will be written into the 64 (48) bytes + beginning at RESBLOCK. */ +extern int sha512_stream (FILE *stream, void *resblock); +extern int sha384_stream (FILE *stream, void *resblock); + +/* Compute SHA512 (SHA384) message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha512_buffer (const char *buffer, size_t len, void *resblock); +extern void *sha384_buffer (const char *buffer, size_t len, void *resblock); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/u64.h b/u64.h new file mode 100644 index 0000000..0d35c55 --- /dev/null +++ b/u64.h @@ -0,0 +1,159 @@ +/* uint64_t-like operations that work even on hosts lacking uint64_t + + Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert. */ + +#include +#include + +/* Return X rotated left by N bits, where 0 < N < 64. */ +#define u64rol(x, n) u64or (u64shl (x, n), u64shr (x, 64 - n)) + +#ifdef UINT64_MAX + +/* Native implementations are trivial. See below for comments on what + these operations do. */ +typedef uint64_t u64; +# define u64hilo(hi, lo) ((u64) (((u64) (hi) << 32) + (lo))) +# define u64init(hi, lo) u64hilo (hi, lo) +# define u64lo(x) ((u64) (x)) +# define u64lt(x, y) ((x) < (y)) +# define u64and(x, y) ((x) & (y)) +# define u64or(x, y) ((x) | (y)) +# define u64xor(x, y) ((x) ^ (y)) +# define u64plus(x, y) ((x) + (y)) +# define u64shl(x, n) ((x) << (n)) +# define u64shr(x, n) ((x) >> (n)) + +#else + +/* u64 is a 64-bit unsigned integer value. + u64init (HI, LO), is like u64hilo (HI, LO), but for use in + initializer contexts. */ +# ifdef WORDS_BIGENDIAN +typedef struct { uint32_t hi, lo; } u64; +# define u64init(hi, lo) { hi, lo } +# else +typedef struct { uint32_t lo, hi; } u64; +# define u64init(hi, lo) { lo, hi } +# endif + +/* Given the high and low-order 32-bit quantities HI and LO, return a u64 + value representing (HI << 32) + LO. */ +static inline u64 +u64hilo (uint32_t hi, uint32_t lo) +{ + u64 r; + r.hi = hi; + r.lo = lo; + return r; +} + +/* Return a u64 value representing LO. */ +static inline u64 +u64lo (uint32_t lo) +{ + u64 r; + r.hi = 0; + r.lo = lo; + return r; +} + +/* Return X < Y. */ +static inline int +u64lt (u64 x, u64 y) +{ + return x.hi < y.hi || (x.hi == y.hi && x.lo < y.lo); +} + +/* Return X & Y. */ +static inline u64 +u64and (u64 x, u64 y) +{ + u64 r; + r.hi = x.hi & y.hi; + r.lo = x.lo & y.lo; + return r; +} + +/* Return X | Y. */ +static inline u64 +u64or (u64 x, u64 y) +{ + u64 r; + r.hi = x.hi | y.hi; + r.lo = x.lo | y.lo; + return r; +} + +/* Return X ^ Y. */ +static inline u64 +u64xor (u64 x, u64 y) +{ + u64 r; + r.hi = x.hi ^ y.hi; + r.lo = x.lo ^ y.lo; + return r; +} + +/* Return X + Y. */ +static inline u64 +u64plus (u64 x, u64 y) +{ + u64 r; + r.lo = x.lo + y.lo; + r.hi = x.hi + y.hi + (r.lo < x.lo); + return r; +} + +/* Return X << N. */ +static inline u64 +u64shl (u64 x, int n) +{ + u64 r; + if (n < 32) + { + r.hi = (x.hi << n) | (x.lo >> (32 - n)); + r.lo = x.lo << n; + } + else + { + r.hi = x.lo << (n - 32); + r.lo = 0; + } + return r; +} + +/* Return X >> N. */ +static inline u64 +u64shr (u64 x, int n) +{ + u64 r; + if (n < 32) + { + r.hi = x.hi >> n; + r.lo = (x.hi << (32 - n)) | (x.lo >> n); + } + else + { + r.hi = 0; + r.lo = x.hi >> (n - 32); + } + return r; +} + +#endif -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:48 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:48 +0100 Subject: [PATCH 22/41] udp, util: Break out send_nak function In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-23-git-send-email-ijackson@chiark.greenend.org.uk> Move the code in udp.c which constructs NAKs into its own function in util.c. This will make it easier to reuse. Signed-off-by: Ian Jackson --- udp.c | 20 +++++--------------- util.c | 17 +++++++++++++++++ util.h | 4 ++++ 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/udp.c b/udp.c index c83e618..483ed37 100644 --- a/udp.c +++ b/udp.c @@ -121,12 +121,12 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds) buf_unprepend(st->rbuf,2); memcpy(&from.sin_port,buf_unprepend(st->rbuf,2),2); } + struct comm_addr ca; + FILLZERO(ca); + ca.comm=&st->ops; + ca.sin=from; done=False; for (n=st->notify; n; n=n->next) { - struct comm_addr ca; - FILLZERO(ca); - ca.comm=&st->ops; - ca.sin=from; if (n->fn(n->state, st->rbuf, &ca)) { done=True; break; @@ -141,17 +141,7 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds) /* Manufacture and send NAK packet */ source=get_uint32(st->rbuf->start); /* Us */ dest=get_uint32(st->rbuf->start+4); /* Them */ - Message(M_INFO,"udp (port %d, peer %s):" - " %08"PRIx32"<-%08"PRIx32": %08"PRIx32":" - " unwanted/incorrect, sending NAK\n", - st->port, saddr_to_string(&from), - dest, source, msgtype); - buffer_init(st->rbuf,0); - buf_append_uint32(st->rbuf,dest); - buf_append_uint32(st->rbuf,source); - buf_append_uint32(st->rbuf,LABEL_NAK); - sendto(st->fd, st->rbuf->start, st->rbuf->size, 0, - (struct sockaddr *)&from, sizeof(from)); + send_nak(&ca,source,dest,msgtype,st->rbuf,"unwanted"); } BUF_FREE(st->rbuf); } diff --git a/util.c b/util.c index 3d11987..1b46bc0 100644 --- a/util.c +++ b/util.c @@ -38,6 +38,7 @@ #include #include "util.h" #include "unaligned.h" +#include "magic.h" #define MIN_BUFFER_SIZE 64 #define DEFAULT_BUFFER_SIZE 4096 @@ -381,6 +382,22 @@ static list_t *buffer_apply(closure_t *self, struct cloc loc, dict_t *context, return new_closure(&st->cl); } +void send_nak(const struct comm_addr *dest, uint32_t our_index, + uint32_t their_index, uint32_t msgtype, + struct buffer_if *buf, const char *logwhy) +{ + buffer_init(buf,dest->comm->min_start_pad); + buf_append_uint32(buf,their_index); + buf_append_uint32(buf,our_index); + buf_append_uint32(buf,LABEL_NAK); + if (logwhy) + Message(M_INFO,"%s: %08"PRIx32"<-%08"PRIx32": %08"PRIx32":" + " %s; sending NAK\n", + dest->comm->addr_to_string(dest->comm->st,dest), + our_index, their_index, msgtype, logwhy); + dest->comm->sendmsg(dest->comm->st, buf, dest); +} + int consttime_memeq(const void *s1in, const void *s2in, size_t n) { const uint8_t *s1=s1in, *s2=s2in; diff --git a/util.h b/util.h index cbe9f52..816c056 100644 --- a/util.h +++ b/util.h @@ -45,6 +45,10 @@ extern int32_t write_mpbin(MP_INT *a, uint8_t *buffer, int32_t buflen); extern struct log_if *init_log(list_t *loglist); +extern void send_nak(const struct comm_addr *dest, uint32_t our_index, + uint32_t their_index, uint32_t msgtype, + struct buffer_if *buf, const char *logwhy); + extern int consttime_memeq(const void *s1, const void *s2, size_t n); #endif /* util_h */ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:41 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:41 +0100 Subject: [PATCH 15/41] EAX: provide an implementation of EAX In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-16-git-send-email-ijackson@chiark.greenend.org.uk> EAX is a reasonably well-regarded Authenticated Encryption block cipher mode. We intend to replace the existing CBC and CBC-MAC transform with EAX. EAX can be used with any block cipher, but we will use it with Serpent. In this patch we provide an implementation of EAX itself. This primary consists of eax.c, the actual implementation of the EAX mode. To test that our implementation is correct, we use aes.[ch], which we copied from qemu in the previous commit, to run the EAX-AES test vectors. These are cut-and-pasted out of the EAX paper. (To do this we need to make aes.[ch] compile in our environment - but the changes are minimal. We also improve the copyright notices.) Then for completeness we also provide EAX-Serpent and EAX-Serpent-BE test vectors and the corresponding test code. The EAX-Serpent test vectors are from Mark Wooding. The EAX-SerpentBE test vectors were generated by this very code, so aren't independently verified. (The implementation of what is now consttime_curious_multiply, and the comment preeding it, was provided by Mark. I have lightly edited it to conform to the coding style etc. of the rest of the file. Mark also contributed improvements to alg_omac_t_k.) Signed-off-by: Ian Jackson Signed-off-by: Mark Wooding --- .gitignore | 2 + Makefile.in | 23 +++- aes.c | 5 +- aes.h | 59 +++++++- eax-aes-test.c | 41 ++++++ eax-aes-test.vectors | 59 ++++++++ eax-serpent-test.c | 41 ++++++ eax-serpent-test.vectors | 59 ++++++++ eax-serpentbe-test.c | 9 ++ eax-serpentbe-test.vectors | 59 ++++++++ eax-test.c | 154 ++++++++++++++++++++ eax-test.h | 53 +++++++ eax.c | 341 ++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 897 insertions(+), 8 deletions(-) create mode 100644 eax-aes-test.c create mode 100644 eax-aes-test.vectors create mode 100644 eax-serpent-test.c create mode 100644 eax-serpent-test.vectors create mode 100644 eax-serpentbe-test.c create mode 100644 eax-serpentbe-test.vectors create mode 100644 eax-test.c create mode 100644 eax-test.h create mode 100644 eax.c diff --git a/.gitignore b/.gitignore index b7f6187..a445369 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ conffile.tab.[ch] conffile.yy.[ch] /version.c /secnet +/eax-*-test +/eax-*-test.confirm /config.log /config.h diff --git a/Makefile.in b/Makefile.in index d4d3815..3f15f01 100644 --- a/Makefile.in +++ b/Makefile.in @@ -58,6 +58,9 @@ OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ process.o @LIBOBJS@ \ hackypar.o +TEST_OBJECTS:=eax-aes-test.o eax-serpent-test.o eax-serpentbe-test.o \ + eax-test.o aes.o + %.c: %.y %.yy.c: %.fl @@ -69,7 +72,7 @@ OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ %.o: %.c $(CC) $(CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@ -all: $(TARGETS) +all: $(TARGETS) check # Automatic remaking of configuration files, from autoconf documentation ${srcdir}/configure: configure.in @@ -93,8 +96,8 @@ config.status: configure # End of config file remaking rules # C and header file dependency rules -SOURCES:=$(OBJECTS:.o=.c) -DEPENDS:=$(OBJECTS:.o=.d) +SOURCES:=$(OBJECTS:.o=.c) $(TEST_OBJECTS:.o=.c) +DEPENDS:=$(OBJECTS:.o=.d) $(TEST_OBJECTS:.o=.d) $(DEPENDS): ${srcdir}/depend.sh @@ -112,11 +115,23 @@ conffile.tab.c: conffile.y secnet: $(OBJECTS) $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $(OBJECTS) $(LDLIBS) +check: eax-aes-test.confirm eax-serpent-test.confirm \ + eax-serpentbe-test.confirm + version.c: Makefile echo "#include \"secnet.h\"" >$@.new echo "char version[]=\"secnet $(VERSION)\";" >>$@.new mv -f $@.new $@ +eax-%-test: eax-%-test.o eax-test.o %.o + $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $^ + +eax-%-test.confirm: eax-%-test eax-%-test.vectors + ./$< <$(srcdir)/eax-$*-test.vectors >$@.new + mv -f $@.new $@ + +.PRECIOUS: eax-%-test + installdirs: $(INSTALL) -d $(prefix)/share/secnet $(sbindir) $(INSTALL) -d $(mandir)/man8 @@ -129,7 +144,7 @@ install: installdirs clean: $(RM) -f *.o *.yy.c *.tab.[ch] $(TARGETS) core version.c - $(RM) -f *.d *~ + $(RM) -f *.d *~ eax-*-test.confirm eax-*-test realclean: clean $(RM) -f *~ Makefile config.h *.d \ diff --git a/aes.c b/aes.c index eb37adb..4e155ab 100644 --- a/aes.c +++ b/aes.c @@ -1,6 +1,10 @@ /** * * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project. + * + * Copied to the secnet tree by Ian Jackson from the upstream qemu git + * tree revision 55616505876d6683130076b810a27c7889321560 + * and modified only to remove the include of qemu-common.h. */ /* * rijndael-alg-fst.c @@ -27,7 +31,6 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "qemu-common.h" #include "aes.h" #ifndef NDEBUG diff --git a/aes.h b/aes.h index a0167eb..fc69356 100644 --- a/aes.h +++ b/aes.h @@ -1,5 +1,58 @@ -#ifndef QEMU_AES_H -#define QEMU_AES_H +/* + * aes.h + * + * Header file declaring AES functions. + * + * Copied from the upstream qemu git tree revision + * 55616505876d6683130076b810a27c7889321560 + * but was introduced there by Fabrice Bellard in + * e4d4fe3c34cdd6e26f9b9975efec7d1e81ad00b6 + * AES crypto support + * git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk at 1036 \ + * c046a42c-6fe2-441c-8c8c-71466251a162 + * + * Modified by Ian Jackson to change the guard #define from + * QEMU_AES_H to AES_H and to add some needed system #include's. + * + * The header file doesn't appear to have a separate copyright notice + * but is clearly a lightly edited (by Bellard) version of code from + * Rijmen, Bosselaers and Barreto. + * + * The original is from rijndael-alg-fst.c, with this copyright + * notice: + * + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef AES_H +#define AES_H + +#include +#include +#include #define AES_MAXNR 14 #define AES_BLOCK_SIZE 16 @@ -23,4 +76,4 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, const unsigned long length, const AES_KEY *key, unsigned char *ivec, const int enc); -#endif +#endif /* AES_H */ diff --git a/eax-aes-test.c b/eax-aes-test.c new file mode 100644 index 0000000..d8ad027 --- /dev/null +++ b/eax-aes-test.c @@ -0,0 +1,41 @@ +/* + * eax-aes-test.c: test harness glue for EAX-AES (EAX-Rijndael) + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "eax-test.h" +#include "aes.h" + +#define BLOCK_SIZE AES_BLOCK_SIZE +static AES_KEY key; + +EAX_SOME_TEST; + +void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes) +{ + AES_set_encrypt_key(keydata, bytes*8, &key); +} + +static void BLOCK_ENCRYPT(uint8_t dst[BLOCK_SIZE], + const uint8_t src[BLOCK_SIZE]) +{ + AES_encrypt((const void*)src, (void*)dst, &key); +} + +#include "eax.c" diff --git a/eax-aes-test.vectors b/eax-aes-test.vectors new file mode 100644 index 0000000..f6bf3f4 --- /dev/null +++ b/eax-aes-test.vectors @@ -0,0 +1,59 @@ +MSG: +KEY: 233952DEE4D5ED5F9B9C6D6FF80FF478 +NONCE: 62EC67F9C3A4A407FCB2A8C49031A8B3 +HEADER: 6BFB914FD07EAE6B +CIPHER: E037830E8389F27B025A2D6527E79D01 + +MSG: F7FB +KEY: 91945D3F4DCBEE0BF45EF52255F095A4 +NONCE: BECAF043B0A23D843194BA972C66DEBD +HEADER: FA3BFD4806EB53FA +CIPHER: 19DD5C4C9331049D0BDAB0277408F67967E5 + +MSG: 1A47CB4933 +KEY: 01F74AD64077F2E704C0F60ADA3DD523 +NONCE: 70C3DB4F0D26368400A10ED05D2BFF5E +HEADER: 234A3463C1264AC6 +CIPHER: D851D5BAE03A59F238A23E39199DC9266626C40F80 + +MSG: 481C9E39B1 +KEY: D07CF6CBB7F313BDDE66B727AFD3C5E8 +NONCE: 8408DFFF3C1A2B1292DC199E46B7D617 +HEADER: 33CCE2EABFF5A79D +CIPHER: 632A9D131AD4C168A4225D8E1FF755939974A7BEDE + +MSG: 40D0C07DA5E4 +KEY: 35B6D0580005BBC12B0587124557D2C2 +NONCE: FDB6B06676EEDC5C61D74276E1F8E816 +HEADER: AEB96EAEBE2970E9 +CIPHER: 071DFE16C675CB0677E536F73AFE6A14B74EE49844DD + +MSG: 4DE3B35C3FC039245BD1FB7D +KEY: BD8E6E11475E60B268784C38C62FEB22 +NONCE: 6EAC5C93072D8E8513F750935E46DA1B +HEADER: D4482D1CA78DCE0F +CIPHER: 835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F + +MSG: 8B0A79306C9CE7ED99DAE4F87F8DD61636 +KEY: 7C77D6E813BED5AC98BAA417477A2E7D +NONCE: 1A8C98DCD73D38393B2BF1569DEEFC19 +HEADER: 65D2017990D62528 +CIPHER: 02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2 + +MSG: 1BDA122BCE8A8DBAF1877D962B8592DD2D56 +KEY: 5FFF20CAFAB119CA2FC73549E20F5B0D +NONCE: DDE59B97D722156D4D9AFF2BC7559826 +HEADER: 54B9F04E6A09189A +CIPHER: 2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A + +MSG: 6CF36720872B8513F6EAB1A8A44438D5EF11 +KEY: A4A4782BCFFD3EC5E7EF6D8C34A56123 +NONCE: B781FCF2F75FA5A8DE97A9CA48E522EC +HEADER: 899A175897561D7E +CIPHER: 0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700 + +MSG: CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7 +KEY: 8395FCF1E95BEBD697BD010BC766AAC3 +NONCE: 22E7ADD93CFC6393C57EC0B3C17D6B44 +HEADER: 126735FCC320D25A +CIPHER: CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E diff --git a/eax-serpent-test.c b/eax-serpent-test.c new file mode 100644 index 0000000..9e8d951 --- /dev/null +++ b/eax-serpent-test.c @@ -0,0 +1,41 @@ +/* + * eax-serpent-test.c: test harness glue for EAX-Serpent + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "eax-test.h" +#include "serpent.h" + +#define BLOCK_SIZE 16 +static struct keyInstance key; + +EAX_SOME_TEST; + +void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes) +{ + serpent_makekey(&key, bytes*8, keydata); +} + +static void BLOCK_ENCRYPT(uint8_t dst[BLOCK_SIZE], + const uint8_t src[BLOCK_SIZE]) +{ + serpent_encrypt(&key, src, dst); +} + +#include "eax.c" diff --git a/eax-serpent-test.vectors b/eax-serpent-test.vectors new file mode 100644 index 0000000..e016783 --- /dev/null +++ b/eax-serpent-test.vectors @@ -0,0 +1,59 @@ +MSG: +KEY: 233952DEE4D5ED5F9B9C6D6FF80FF478 +NONCE: 62EC67F9C3A4A407FCB2A8C49031A8B3 +HEADER: 6BFB914FD07EAE6B +CIPHER: 1271EC1E68330EB461A96D3A3A7A2707 + +MSG: F7FB +KEY: 91945D3F4DCBEE0BF45EF52255F095A4 +NONCE: BECAF043B0A23D843194BA972C66DEBD +HEADER: FA3BFD4806EB53FA +CIPHER: 1C7367D3DB493A1F7B054ECECA2A2CF37EE6 + +MSG: 1A47CB4933 +KEY: 01F74AD64077F2E704C0F60ADA3DD523 +NONCE: 70C3DB4F0D26368400A10ED05D2BFF5E +HEADER: 234A3463C1264AC6 +CIPHER: 2439712B59B13982351BA05B25BB2BD3B95DF62D73 + +MSG: 481C9E39B1 +KEY: D07CF6CBB7F313BDDE66B727AFD3C5E8 +NONCE: 8408DFFF3C1A2B1292DC199E46B7D617 +HEADER: 33CCE2EABFF5A79D +CIPHER: F1D718884BE94B29E143A264B54E283CA9E439C90D + +MSG: 40D0C07DA5E4 +KEY: 35B6D0580005BBC12B0587124557D2C2 +NONCE: FDB6B06676EEDC5C61D74276E1F8E816 +HEADER: AEB96EAEBE2970E9 +CIPHER: 5936DB85DF31199BA3556A5D5EFF1964A6BEFEA0D950 + +MSG: 4DE3B35C3FC039245BD1FB7D +KEY: BD8E6E11475E60B268784C38C62FEB22 +NONCE: 6EAC5C93072D8E8513F750935E46DA1B +HEADER: D4482D1CA78DCE0F +CIPHER: 7A3A7997EE349B57152CC43F723903A85B09D86456315AC0D9180724 + +MSG: 8B0A79306C9CE7ED99DAE4F87F8DD61636 +KEY: 7C77D6E813BED5AC98BAA417477A2E7D +NONCE: 1A8C98DCD73D38393B2BF1569DEEFC19 +HEADER: 65D2017990D62528 +CIPHER: 73548FFAF45D2617EB25AD1DFFA18420836D48394D5EF2CD2E0E30CDD2F4C52D96 + +MSG: 1BDA122BCE8A8DBAF1877D962B8592DD2D56 +KEY: 5FFF20CAFAB119CA2FC73549E20F5B0D +NONCE: DDE59B97D722156D4D9AFF2BC7559826 +HEADER: 54B9F04E6A09189A +CIPHER: E8BD1C6FE47DF149A141CE813B0C1239542EC4CBF7B3968388D631E6F4FFE86E14E7 + +MSG: 6CF36720872B8513F6EAB1A8A44438D5EF11 +KEY: A4A4782BCFFD3EC5E7EF6D8C34A56123 +NONCE: B781FCF2F75FA5A8DE97A9CA48E522EC +HEADER: 899A175897561D7E +CIPHER: E4A9D72847D437B85F10B7DAA46F1E00E3509AF0B97961C39DFBB70170B6C4CADBC1 + +MSG: CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7 +KEY: 8395FCF1E95BEBD697BD010BC766AAC3 +NONCE: 22E7ADD93CFC6393C57EC0B3C17D6B44 +HEADER: 126735FCC320D25A +CIPHER: 83D69403EAE9386B679DAEAAD2951465F8DDF9BE1AFFAD1C5FEF072F8B48BD58C07FEE3D83 diff --git a/eax-serpentbe-test.c b/eax-serpentbe-test.c new file mode 100644 index 0000000..ce5b3dc --- /dev/null +++ b/eax-serpentbe-test.c @@ -0,0 +1,9 @@ +#include "eax-test.h" +#include "serpent.h" +/* multiple-inclusion protection means that serpent.h's inclusion + * by eax-serpent-test.c is suppressed, so we don't get useless + * duplicate declarations of serpentbe_makekey and serpentbe_encrypt + */ +#define serpent_makekey serpentbe_makekey +#define serpent_encrypt serpentbe_encrypt +#include "eax-serpent-test.c" diff --git a/eax-serpentbe-test.vectors b/eax-serpentbe-test.vectors new file mode 100644 index 0000000..d7e4e6e --- /dev/null +++ b/eax-serpentbe-test.vectors @@ -0,0 +1,59 @@ +MSG: +KEY: 233952DEE4D5ED5F9B9C6D6FF80FF478 +NONCE: 62EC67F9C3A4A407FCB2A8C49031A8B3 +HEADER: 6BFB914FD07EAE6B +CIPHER: E667316E3FC40DF234575E203EA06EA0 + +MSG: F7FB +KEY: 91945D3F4DCBEE0BF45EF52255F095A4 +NONCE: BECAF043B0A23D843194BA972C66DEBD +HEADER: FA3BFD4806EB53FA +CIPHER: D6D0A45C2A76EEB6AD20C3DB5CE100A2AEC4 + +MSG: 1A47CB4933 +KEY: 01F74AD64077F2E704C0F60ADA3DD523 +NONCE: 70C3DB4F0D26368400A10ED05D2BFF5E +HEADER: 234A3463C1264AC6 +CIPHER: FD8218F8987B7CCEBE4D521F4374D40B2F85794B31 + +MSG: 481C9E39B1 +KEY: D07CF6CBB7F313BDDE66B727AFD3C5E8 +NONCE: 8408DFFF3C1A2B1292DC199E46B7D617 +HEADER: 33CCE2EABFF5A79D +CIPHER: 529951EDB28B9557667E88ED360EB51256DEC0F056 + +MSG: 40D0C07DA5E4 +KEY: 35B6D0580005BBC12B0587124557D2C2 +NONCE: FDB6B06676EEDC5C61D74276E1F8E816 +HEADER: AEB96EAEBE2970E9 +CIPHER: F46A8BFED3B22A6E4388659FF1C39B3D49AAD8ADEA74 + +MSG: 4DE3B35C3FC039245BD1FB7D +KEY: BD8E6E11475E60B268784C38C62FEB22 +NONCE: 6EAC5C93072D8E8513F750935E46DA1B +HEADER: D4482D1CA78DCE0F +CIPHER: C3C7281CE5790F14D4CD666E8494D4911D528548F200014C32B86719 + +MSG: 8B0A79306C9CE7ED99DAE4F87F8DD61636 +KEY: 7C77D6E813BED5AC98BAA417477A2E7D +NONCE: 1A8C98DCD73D38393B2BF1569DEEFC19 +HEADER: 65D2017990D62528 +CIPHER: 1DD9A93ACD19F0C3FB7A3B431DFCFB96D2B899FA2285AEC7DCA504AF75B97A58A3 + +MSG: 1BDA122BCE8A8DBAF1877D962B8592DD2D56 +KEY: 5FFF20CAFAB119CA2FC73549E20F5B0D +NONCE: DDE59B97D722156D4D9AFF2BC7559826 +HEADER: 54B9F04E6A09189A +CIPHER: 2BA4C477F2927210ADCA26DF72E2BEF81BF3D6B03160E7BFE7FD3EB57D255D66713F + +MSG: 6CF36720872B8513F6EAB1A8A44438D5EF11 +KEY: A4A4782BCFFD3EC5E7EF6D8C34A56123 +NONCE: B781FCF2F75FA5A8DE97A9CA48E522EC +HEADER: 899A175897561D7E +CIPHER: A17D854BA33FDBDF0BA86ADC9152D40B4EA01E1A8FAB1E0A80B19E73784219B29446 + +MSG: CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7 +KEY: 8395FCF1E95BEBD697BD010BC766AAC3 +NONCE: 22E7ADD93CFC6393C57EC0B3C17D6B44 +HEADER: 126735FCC320D25A +CIPHER: 9F30626B590A0A6E2F6CE0ED8835031654B3FCCF311BD7A6C6089AF1C7373D22CB80D4AFEE diff --git a/eax-test.c b/eax-test.c new file mode 100644 index 0000000..c29a51f --- /dev/null +++ b/eax-test.c @@ -0,0 +1,154 @@ +/* + * eax-test.c: test harness for EAX, implementation + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * usages: + * ./eax-foo-test len; i++) { + perturb->v[i] ^= delta; + trydecrypt(0); + perturb->v[i] ^= delta; + } +} + +static void something(void) +{ + if (!msg.got) return; + assert(key.got); + assert(nonce.got); + assert(header.got); + eaxtest_blockcipher_key_setup(V(key)); + eax_setup(-1); + if (cipher.got) { + assert(cipher.len > msg.len); + tau = cipher.len - msg.len; + assert(tau <= blocksize); + } else { + assert(msg.len + blocksize < sizeof(ourcipher.v)); + tau = blocksize; + } + ourcipher.len = msg.len + tau; + eax_encrypt(-1, V(nonce), V(header), V(msg), tau, ourcipher.v); + if (cipher.got) { + assert(ourcipher.len == cipher.len); + assert(!memcmp(ourcipher.v, cipher.v, cipher.len)); + trydecrypt(1); + negtest(&ourcipher); + negtest(&header); + } else { + size_t i; + printf("CIPHER: "); + for (i=0; igot = 1; + cv->len = 0; + for (;;) { + c = getputchar(); + if (c == ':') break; + assert(isalpha(c)); + } + for (;;) { + char hbuf[3], *ep; + c = getputchar(); + if (c == '\n') break; + if (isspace(c)) continue; + assert(isprint(c)); + hbuf[0] = c; + c = getputchar(); + assert(isprint(c)); + hbuf[1] = c; + hbuf[2] = 0; + assert(cv->len < sizeof(cv->v)); + cv->v[cv->len++] = strtoul(hbuf,&ep,16); + assert(!*ep); + } + } + assert(!ferror(stdin)); + assert(feof(stdin)); + assert(!ferror(stdout)); + assert(!fflush(stdout)); + return 0; +} diff --git a/eax-test.h b/eax-test.h new file mode 100644 index 0000000..2fe5d96 --- /dev/null +++ b/eax-test.h @@ -0,0 +1,53 @@ +/* + * eax-test.c: test harness for EAX, common declarations + */ +/* + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef EAX_TEST_H +#define EAX_TEST_H + +#include +#include +#include +#include +#include +#include +#include + +#define INFO int dummy_info +#define I dummy_info +#define EAX_ENTRYPOINT_DECL /* empty */ + +#define EAX_DECLARATIONS_ONLY +#include "eax.c" +#undef EAX_DECLARATIONS_ONLY + +void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes); + +#define consttime_memeq(s1,s2,sz) (!memcmp((s1),(s2),(sz))) + /* fine for running test vectors */ + +extern const size_t blocksize; + +#define EAX_SOME_TEST \ + const size_t blocksize = BLOCK_SIZE; \ + static uint8_t INFO_B[BLOCK_SIZE], INFO_P[BLOCK_SIZE] + +#endif /* EAX_TEST_H */ diff --git a/eax.c b/eax.c new file mode 100644 index 0000000..af5ccae --- /dev/null +++ b/eax.c @@ -0,0 +1,341 @@ +/* + * eax.c: implementation of the EAX authenticated encryption block cipher mode + */ +/* + * Copyright 2013 Ian Jackson + * Copyright 2013 Mark Wooding + * + * This file is Free Software. It was originally written for secnet. + * + * You may redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * This file is designed to be #included into another .c file which + * sets up the environment. It will declare or define three + * functions, eax_setup, eax_encrypt and eax_decrypt. + * + * Manifest constants which are expected to be defined: + * + * INFO One or more formal parameter definitions. + * Used in all relevant function declarations. Typically + * the application will use this for its context pointer, + * key schedule structure, etc. + * + * I Corresponding actual parameters for chaining onto + * sub-functions declared to take INFO parameters + * + * EAX_ENTRYPOINT_DECL + * Declarator decoration for the three entry points. + * Typically either "static" or the empty string; + * + * EAX_DECLARATIONS_ONLY + * Tested with #ifdef, so should be #defined to 1, or left + * undefined. If defined, #including eax.c will produces + * only the function prototypes for the three entrypoints. + * Otherwise it will produce the implementation. + * + * BLOCK_SIZE + * Constant expresion of integer type. + * + * void BLOCK_ENCRYPT(uint8_t dst[n], const uint8_t src[n]); + * + * Function to encrypt with the selected key. The block + * cipher's key schedule (ie, the key) to be used is + * implicit; uses of BLOCK_ENCRYPT always occur in a + * context where the parameters defined by INFO are + * available. + * + * So in a real application which wants to use more than + * one key at a time, BLOCK_ENCRYPT must be a macro which + * accesses the block cipher's key schedule via one of the + * INFO parameters. + * + * BLOCK_ENCRYPT must tolerate dst==src. + * + * EAX does not need to use the block cipher's decryption + * function. + * + * uint8_t INFO_B[n], INFO_P[n]; + * + * Buffers used by the algorithm; they are written by + * eax_setup and used by eax_encrypt and eax_decrypt. + * + * That is, effectively they are the part of the key + * schedule specific to EAX. + * + * An application which wants to use more than one key at + * a time must define these as macros which refer to + * key-specific variables via one of the INFO parameters. + * + * int consttime_memeq(const void *s1, const void *s2, size_t n); + * + * Like !memcmp(s1,s2,n) but takes the same amount of time + * no matter where the discrepancy is. Result must be + * a canonicalised boolean. + * + * The entrypoints which are then defined are: + * + * void eax_setup(INFO) + * + * Does the EAX-specific part of the key setup. The block + * cipher key schedule must already have been done, as + * eax_setup uses BLOCK_ENCRYPT. + * + * void eax_encrypt(INFO, const uint8_t nonce[nonce_len], size_t nonce_len, + * const uint8_t h[h_len], size_t h_len, + * const uint8_t m[m_len], size_t m_len, + * uint8_t tau, + * uint8_t ct[m_len+tau]) + * + * Does a single EAX authenticated encryption, providing + * confidentiality and integrity to the message m[0..m_len-1]. + * + * The output message is longer than m by tau bytes and is stored + * in the array ct which must be big enough. + * + * nonce must never be repeated with the same key or the security + * of the system is destroyed, but it does not need to be secret. + * It is OK to transmit the nonce with the message along with the + * ciphertext and have the receiver recover it. + * + * h is the "header" - it is some extra data which should be + * covered by the authentication, but not the encryption. The + * output message does not contain a representation of h: it is + * expected to be transmitted separately (perhaps even in a + * different format). (If h_len==0, h may be a NULL pointer.) + * + * tau is the tag length - that is, the length of the message + * authentication code. It should be chosen for the right + * tradeoff between message expansion and security (resistence to + * forgery). It must be no longer than the block cipher block + * size. + * + * For any particular key. the tag length should be fixed. (The + * tag length should NOT be encoded into the packet along with + * the ciphertext and extracted by the receiver! Rather, the + * receiver must know what tag length to expect.) + * + * It is permissible for ct==m, or for the arrays to be disjoint. + * They must not overlap more subtly. + * + * _Bool eax_decrypt(INFO, const uint8_t nonce[nonce_len], size_t nonce_len, + * const uint8_t h[h_len], size_t h_len, + * const uint8_t ct[ct_len], size_t ct_len, + * uint8_t tau, + * uint8_t m[ct_len-tau]) + * + * Does a single EAX authenticated decryption. + * + * On successful return, the plaintext message is written to m + * and eax_decrypt returns true. The length of the plaintext + * message is always ct_len-tau. + * + * If the message did not decrypt correctly, returns false. + * (There is no further indication of the nature of the error.) + * In this case the buffer m may contain arbitrary contents which + * should not be revealed to attackers. + * + * nonce, h, tau are as above. + * + * It is permissible to call eax_decrypt with an input message + * which is too short (i.e. shorter than tau) (notwithstanding + * the notation m[ct_len-tau] in the faux prototype above). + * In this case it will return false without touching m. + * + * As with eax_decrypt, ct==m is permissible. + */ + +/***** IMPLEMENTATION *****/ + +/* + * We use the notation from the EAX paper, mostly. + * (We write xscr for "x in fancy mathsy curly script".) + * + * See: + * Mihir Bellare, Phillip Rogaway, and David Wagner + * + * _The EAX Mode of Operation + * (A Two-Pass Authenticated Encryption Scheme + * Optimized for Simplicity and Efficiency)_ + * + * Preliminary version in: + * Fast Software Encryption (FSE) 2004. Lecture Notes in Computer Science, + * vol. ??, pp. ??--??. + * + * Full version at: + * http://www.cs.ucdavis.edu/~rogaway/papers/eax.html + */ +/* + * In general, all functions tolerate their destination arrays being + * the same pointer to their source arrays, or totally distinct. + * (Just like BLOCK_ENCRYPT and the public eax entrypoints.) + * They must not overlap in more subtle ways. + */ + +#define n ((size_t)BLOCK_SIZE) + +#ifndef EAX_DECLARATIONS_ONLY + +static void xor_block(uint8_t *dst, const uint8_t *a, const uint8_t *b, + size_t l) + /* simple block xor */ +{ + while (l--) + *dst++ = *a++ ^ *b++; +} + +static void increment(uint8_t *value) + /* value is a single block; incremented (BE) mod 256^n */ +{ + uint8_t *p; + for (p=value+n; p>value; ) + if ((*--p)++) break; +} + +static void alg_ctr(INFO, uint8_t *c, const uint8_t *nscr, + const uint8_t *m, size_t m_len) +{ + uint8_t blocknonce[n], cipher[n]; + size_t in; + + memcpy(blocknonce, nscr, n); + for (in=0; in> 7) - 1u) & POLY; + unsigned i, mm; + + for (i = n - 1; i < n; i--) { + mm = (v[i] >> 7) & 1u; + o[i] = (v[i] << 1) ^ m; + m = mm; + } + +#undef POLY +} + +#endif /* not EAX_DECLARATIONS_ONLY */ + +EAX_ENTRYPOINT_DECL +void eax_setup(INFO) +#ifndef EAX_DECLARATIONS_ONLY +{ + uint8_t work[n]; + memset(work,0,n); + BLOCK_ENCRYPT(work,work); + consttime_curious_multiply(I, INFO_B, work); + consttime_curious_multiply(I, INFO_P, INFO_B); +} +#endif /* not EAX_DECLARATIONS_ONLY */ +; + +EAX_ENTRYPOINT_DECL +void eax_encrypt(INFO, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *h, size_t h_len, + const uint8_t *m, size_t m_len, uint8_t tau, uint8_t *ct) +#ifndef EAX_DECLARATIONS_ONLY +{ + assert(tau <= n); + uint8_t nscr[n], hscr[n], cscr[n]; + alg_omac_t_k(I, nscr, 0, nonce,nonce_len); + alg_omac_t_k(I, hscr, 1, h,h_len); + alg_ctr(I, ct, nscr, m, m_len); + alg_omac_t_k(I, cscr, 2, ct, m_len); + uint8_t *t = ct + m_len; + xor_block(t, nscr, cscr, tau); + xor_block(t, t, hscr, tau); +} +#endif /* not EAX_DECLARATIONS_ONLY */ +; + +EAX_ENTRYPOINT_DECL +_Bool eax_decrypt(INFO, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *h, size_t h_len, + const uint8_t *ct, size_t ct_len, uint8_t tau, uint8_t *m) +#ifndef EAX_DECLARATIONS_ONLY +{ + assert(tau <= n); + const uint8_t *t; + uint8_t nscr[n], hscr[n], cscr[n], tprime[tau]; + if (ct_len < tau) return 0; + size_t m_len = ct_len - tau; + t = ct + m_len; + alg_omac_t_k(I, nscr, 0, nonce,nonce_len); + alg_omac_t_k(I, hscr, 1, h,h_len); + alg_omac_t_k(I, cscr, 2, ct,m_len); + xor_block(tprime, nscr, cscr, tau); + xor_block(tprime, tprime, hscr, tau); + if (!consttime_memeq(tprime, t, tau)) return 0; + alg_ctr(I, m, nscr, ct, m_len); + return 1; +} +#endif /* not EAX_DECLARATIONS_ONLY */ +; + +#undef n -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:52 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:52 +0100 Subject: [PATCH 26/41] NOTES: Remove unimplemented protocol negotiation In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-27-git-send-email-ijackson@chiark.greenend.org.uk> The protocol negotiation mechanism documented in NOTES is not implemented. Remove it from the document. Signed-off-by: Ian Jackson --- NOTES | 20 +++++--------------- 1 files changed, 5 insertions(+), 15 deletions(-) diff --git a/NOTES b/NOTES index 09c083e..33c010e 100644 --- a/NOTES +++ b/NOTES @@ -193,21 +193,18 @@ i? is appropriate index for receiver Note that 'i' may be re-used from one session to the next, whereas 'n' is always fresh. -The protocol version selection stuff is not yet implemented: I'm not -yet convinced it's a good idea. Instead, the initiator could try -using its preferred protocol (which starts with a different magic -number) and fall back if there's no reply. +The protocol version selection stuff is not yet implemented. Messages: -1) A->B: *,iA,msg1,A,B,protorange-A,nA +1) A->B: *,iA,msg1,A,B,nA -2) B->A: iA,iB,msg2,B,A,chosen-protocol,nB,nA +2) B->A: iA,iB,msg2,B,A,nB,nA (The order of B and A reverses in alternate messages so that the same code can be used to construct them...) -3) A->B: {iB,iA,msg3,A,B,protorange-A,chosen-protocol,nA,nB,g^x mod m}_PK_A^-1 +3) A->B: {iB,iA,msg3,A,B,nA,nB,g^x mod m}_PK_A^-1 If message 1 was a replay then A will not generate message 3, because it doesn't recognise nA. @@ -215,18 +212,11 @@ it doesn't recognise nA. If message 2 was from an attacker then B will not generate message 4, because it doesn't recognise nB. -If an attacker is trying to manipulate the chosen protocol, B can spot -this when it sees A's message 3. - -4) B->A: {iA,iB,msg4,B,A,protorange-B,chosen-protocol,nB,nA,g^y mod m}_PK_B^-1 +4) B->A: {iA,iB,msg4,B,A,nB,nA,g^y mod m}_PK_B^-1 At this point, A and B share a key, k. B must keep retransmitting message 4 until it receives a packet encrypted using key k. -A can abandon the exchange if the chosen protocol is not the one that -it would have chosen knowing the acceptable protocol ranges of A and -B. - 5) A: iB,iA,msg5,(ping/msg5)_k 6) B: iA,iB,msg6,(pong/msg6)_k -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:58 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:58 +0100 Subject: [PATCH 32/41] site: dynamically create and destroy transform instances In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-33-git-send-email-ijackson@chiark.greenend.org.uk> Rather than making three transform instances at setup time, and then using setkey on them, we create transform instances as needed and destroy them when we delete their keys. This is necessary because we are going to support multiple different kinds of transform, so each one of the three transforms might be of different kinds (supplied by different secnet modules) at different times. The variables current.transform, auxiliary_key.transform and new_transform can all be NULL now. Signed-off-by: Ian Jackson --- site.c | 31 +++++++++++++++++++++---------- 1 files changed, 21 insertions(+), 10 deletions(-) diff --git a/site.c b/site.c index 9813de0..f9a005a 100644 --- a/site.c +++ b/site.c @@ -336,7 +336,7 @@ static void activate_new_key(struct site *st); static bool_t is_transform_valid(struct transform_inst_if *transform) { - return transform->valid(transform->st); + return transform && transform->valid(transform->st); } static bool_t current_valid(struct site *st) @@ -350,6 +350,10 @@ static int call_transform_##fwdrev(struct site *st, \ struct buffer_if *buf, \ const char **errmsg) \ { \ + if (!is_transform_valid(transform)) { \ + *errmsg="transform not set up"; \ + return 1; \ + } \ return transform->fwdrev(transform->st,buf,errmsg); \ } @@ -358,9 +362,12 @@ DEFINE_CALL_TRANSFORM(reverse) static void dispose_transform(struct transform_inst_if **transform_var) { - /* will become more sophisticated very shortly */ struct transform_inst_if *transform=*transform_var; - transform->delkey(transform->st); + if (transform) { + transform->delkey(transform->st); + transform->destroy(transform->st); + } + *transform_var = 0; } #define CHECK_AVAIL(b,l) do { if ((b)->size<(l)) return False; } while(0) @@ -394,8 +401,12 @@ struct msg { static void set_new_transform(struct site *st) { - st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen,st->setup_priority); + struct transform_if *generator=st->transform; + struct transform_inst_if *generated=generator->create(generator->st); + generated->setkey(generated->st,st->sharedsecret, + st->sharedsecretlen,st->setup_priority); + dispose_transform(&st->new_transform); + st->new_transform=generated; } struct xinfoadd { @@ -862,8 +873,8 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0, goto skew; buffer_copy(msg0, &st->scratch); - problem = call_transform_reverse - (st,st->auxiliary_key.transform->st,msg0,&auxkey_err); + problem = call_transform_reverse(st,st->auxiliary_key.transform, + msg0,&auxkey_err); if (problem==0) { slog(st,LOG_DROP,"processing packet which uses auxiliary key"); if (st->auxiliary_is_new) { @@ -1703,9 +1714,9 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, for (i=0; incomms; i++) st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming); - st->current.transform=st->transform->create(st->transform->st); - st->auxiliary_key.transform=st->transform->create(st->transform->st); - st->new_transform=st->transform->create(st->transform->st); + st->current.transform=0; + st->auxiliary_key.transform=0; + st->new_transform=0; st->auxiliary_is_new=0; enter_state_stop(st); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:41:03 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:41:03 +0100 Subject: [PATCH 37/41] max_start_pad: calculate globally, not via client graph In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-38-git-send-email-ijackson@chiark.greenend.org.uk> There is quite a lot of plumbing of max_start_pad values from one place to another. Sadly this plumbing is not complete, which can lead to crashes as the start padding is exhausted. And completing it is a lot of work which would be difficult to get correct, even if that's possible in principle. Instead, we take a different approach. We calculate a single global max_pad_start value that can be used everywhere. It is the sum of: * Headers that "site" instances might need add to the start of packets (source and destination site indices, message type both inside and outside the encryption; * Anything that "transform" instances might need to add to the start of packets. This depends on the transforms, but since it isn't a priori predictable which path any particular incoming packet might take, we have to take the worst case. These transform instances are applied only by "site" and each packet goes through at most on "forward" transform instance. * Anything that "comm" instances might need to add. This is currently only needed for the proxy feature. This is based on the assumption that a packet may follow one of these paths: comm -->- site_incoming --. ,-- site_outgoing -->- comm \ / netlink / \ tun/slip ----->-----------' `------>---------- tun/slip On the inbound side, tun and slip have to set up the buffer with the necessary start padding. site_incoming only removes stuff from the beginning (since it uses transform->reverse). netlink doesn't add or remove anything. It is site_outgoing and comm which may need to prepend things. site additionally calls transform->forwards. If in the future a module appears which can take packets out of the RHS of this diagram and feed them back into the left, it may have to do something about the buffer. Signed-off-by: Ian Jackson --- netlink.c | 7 ++----- netlink.h | 1 - secnet.h | 20 +++++++++++++------- site.c | 23 ++++++----------------- slip.c | 4 ++-- transform-cbcmac.c | 4 ++-- transform-common.h | 1 - transform-eax.c | 2 +- tun.c | 4 ++-- udp.c | 7 ++++--- util.c | 18 +++++++++++++++++- 11 files changed, 49 insertions(+), 42 deletions(-) diff --git a/netlink.c b/netlink.c index 5d586d0..173d412 100644 --- a/netlink.c +++ b/netlink.c @@ -238,7 +238,7 @@ static struct icmphdr *netlink_icmp_tmpl(struct netlink *st, struct icmphdr *h; BUF_ALLOC(&st->icmp,"netlink_icmp_tmpl"); - buffer_init(&st->icmp,st->max_start_pad); + buffer_init(&st->icmp,calculate_max_start_pad()); h=buf_append(&st->icmp,sizeof(*h)); h->iph.version=4; @@ -808,12 +808,10 @@ static void netlink_inst_set_mtu(void *sst, int32_t new_mtu) } static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver, - void *dst, int32_t max_start_pad) + void *dst) { struct netlink_client *c=sst; - struct netlink *st=c->nst; - if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad; c->deliver=deliver; c->dst=dst; } @@ -941,7 +939,6 @@ netlink_deliver_fn *netlink_init(struct netlink *st, st->cl.type=CL_PURE; st->cl.apply=netlink_inst_apply; st->cl.interface=st; - st->max_start_pad=0; st->clients=NULL; st->routes=NULL; st->n_clients=0; diff --git a/netlink.h b/netlink.h index 5e6ad49..7c42716 100644 --- a/netlink.h +++ b/netlink.h @@ -45,7 +45,6 @@ struct netlink { closure_t cl; void *dst; /* Pointer to host interface state */ cstring_t name; - int32_t max_start_pad; struct ipset *networks; /* Local networks */ struct subnet_list *subnets; /* Same as networks, for display */ struct ipset *remote_networks; /* Allowable remote networks */ diff --git a/secnet.h b/secnet.h index 98a3ae3..9bec310 100644 --- a/secnet.h +++ b/secnet.h @@ -146,6 +146,16 @@ static const struct timeval *const tv_now = &tv_now_global; /***** END of utility functions *****/ +/***** START of max_start_pad handling *****/ + +extern int32_t site_max_start_pad, transform_max_start_pad, + comm_max_start_pad; + +void update_max_start_pad(int32_t *our_module_global, int32_t our_instance); +int32_t calculate_max_start_pad(void); + +/***** END of max_start_pad handling *****/ + /***** SCHEDULING support */ /* If nfds_io is insufficient for your needs, set it to the required @@ -325,7 +335,6 @@ typedef const char *comm_addr_to_string_fn(void *commst, /* Returned string is in a static buffer. */ struct comm_if { void *st; - int32_t min_start_pad; comm_request_notify_fn *request_notify; comm_release_notify_fn *release_notify; comm_sendmsg_fn *sendmsg; @@ -363,8 +372,7 @@ struct site_if { /* TRANSFORM interface */ /* A reversable transformation. Transforms buffer in-place; may add - data to start or end. Maximum amount of data to be added before - the packet specified in max_start_pad. (Reverse transformations decrease + data to start or end. (Reverse transformations decrease length, of course.) Transformations may be key-dependent, in which case key material is passed in at initialisation time. They may also depend on internal factors (eg. time) and keep internal @@ -396,14 +404,12 @@ struct transform_inst_if { transform_apply_fn *forwards; transform_apply_fn *reverse; transform_destroyinstance_fn *destroy; - int32_t max_start_pad; /* same as from transform_if */ }; struct transform_if { void *st; - int32_t max_start_pad; /* these two are both <<< INT_MAX */ - int32_t keylen; /* 0 means give the transform exactly as much as there is */ int capab_transformnum; + int32_t keylen; /* <<< INT_MAX */ transform_createinstance_fn *create; }; @@ -425,7 +431,7 @@ typedef void netlink_deliver_fn(void *st, struct buffer_if *buf); #define MAXIMUM_LINK_QUALITY 3 typedef void netlink_link_quality_fn(void *st, uint32_t quality); typedef void netlink_register_fn(void *st, netlink_deliver_fn *deliver, - void *dst, int32_t max_start_pad); + void *dst); typedef void netlink_output_config_fn(void *st, struct buffer_if *buf); typedef bool_t netlink_check_config_fn(void *st, struct buffer_if *buf); typedef void netlink_set_mtu_fn(void *st, int32_t new_mtu); diff --git a/site.c b/site.c index 20f9507..909e8e9 100644 --- a/site.c +++ b/site.c @@ -89,6 +89,8 @@ #define SITE_SENTMSG5 7 #define SITE_WAIT 8 +int32_t site_max_start_pad = 4*4; + static cstring_t state_name(uint32_t state) { switch (state) { @@ -826,7 +828,7 @@ static bool_t generate_msg5(struct site *st) BUF_ALLOC(&st->buffer,"site:MSG5"); /* We are going to add four words to the message */ - buffer_init(&st->buffer,st->new_transform->max_start_pad+(4*4)); + buffer_init(&st->buffer,calculate_max_start_pad()); /* Give the netlink code an opportunity to put its own stuff in the message (configuration information, etc.) */ buf_prepend_uint32(&st->buffer,LABEL_MSG5); @@ -873,7 +875,7 @@ static void create_msg6(struct site *st, struct transform_inst_if *transform, BUF_ALLOC(&st->buffer,"site:MSG6"); /* We are going to add four words to the message */ - buffer_init(&st->buffer,transform->max_start_pad+(4*4)); + buffer_init(&st->buffer,calculate_max_start_pad()); /* Give the netlink code an opportunity to put its own stuff in the message (configuration information, etc.) */ buf_prepend_uint32(&st->buffer,LABEL_MSG6); @@ -1294,7 +1296,7 @@ static bool_t send_msg7(struct site *st, cstring_t reason) if (current_valid(st) && st->buffer.free && transport_peers_valid(&st->peers)) { BUF_ALLOC(&st->buffer,"site:MSG7"); - buffer_init(&st->buffer,st->current.transform->max_start_pad+(4*3)); + buffer_init(&st->buffer,calculate_max_start_pad()); buf_append_uint32(&st->buffer,LABEL_MSG7); buf_append_string(&st->buffer,reason); if (call_transform_forwards(st, st->current.transform, @@ -1770,17 +1772,6 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->sharedsecretlen=st->sharedsecretallocd=0; st->sharedsecret=0; - /* We need to compute some properties of our comms and transports */ -#define COMPUTE_WORST(things,pad) \ - int things##_worst_##pad=0; \ - for (i=0; in##things; i++) { \ - int thispad=st->things[i]->pad; \ - if (thispad > things##_worst_##pad) \ - things##_worst_##pad=thispad; \ - } - COMPUTE_WORST(comms,min_start_pad) - COMPUTE_WORST(transforms,max_start_pad) - for (i=0; intransforms; i++) { struct transform_if *ti=st->transforms[i]; uint32_t capbit = 1UL << ti->capab_transformnum; @@ -1791,9 +1782,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, } /* We need to register the remote networks with the netlink device */ - st->netlink->reg(st->netlink->st, site_outgoing, st, - transforms_worst_max_start_pad+(4*4)+ - comms_worst_min_start_pad); + st->netlink->reg(st->netlink->st, site_outgoing, st); for (i=0; incomms; i++) st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming); diff --git a/slip.c b/slip.c index 0f62a69..5eb8dbd 100644 --- a/slip.c +++ b/slip.c @@ -115,7 +115,7 @@ static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) if (st->ignoring_packet) { if (outputchr == OUTPUT_END) { st->ignoring_packet=False; - buffer_init(st->buff,st->nl.max_start_pad); + buffer_init(st->buff,calculate_max_start_pad()); } } else { if (outputchr == OUTPUT_END) { @@ -123,7 +123,7 @@ static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) st->netlink_to_tunnel(&st->nl,st->buff); BUF_ALLOC(st->buff,"userv_afterpoll"); } - buffer_init(st->buff,st->nl.max_start_pad); + buffer_init(st->buff,calculate_max_start_pad()); } else if (outputchr != OUTPUT_NOTHING) { if (st->buff->size < st->buff->len) { buf_append_uint8(st->buff,outputchr); diff --git a/transform-cbcmac.c b/transform-cbcmac.c index 95c64e8..26e0a12 100644 --- a/transform-cbcmac.c +++ b/transform-cbcmac.c @@ -261,8 +261,8 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, st->cl.apply=NULL; st->cl.interface=&st->ops; st->ops.st=st; - st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV, - 4byte IV */ + update_max_start_pad(&transform_max_start_pad, 28); + /* 4byte seqnum, 16byte pad, 4byte MACIV, 4byte IV */ /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits for CBCMAC-IV, and 32 bits for init sequence number */ diff --git a/transform-common.h b/transform-common.h index 52f6067..24ab8dc 100644 --- a/transform-common.h +++ b/transform-common.h @@ -61,7 +61,6 @@ ti->ops.forwards=transform_forward; \ ti->ops.reverse=transform_reverse; \ ti->ops.destroy=transform_destroy; \ - ti->ops.max_start_pad=st->ops.max_start_pad; \ ti->keyed=False; #endif /*TRANSFORM_COMMON_H*/ diff --git a/transform-eax.c b/transform-eax.c index 31d8171..f881abb 100644 --- a/transform-eax.c +++ b/transform-eax.c @@ -294,7 +294,7 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, padding_round = 1; st->p.padding_mask = padding_round-1; - st->ops.max_start_pad=0; + update_max_start_pad(&transform_max_start_pad, 0); st->ops.keylen=0; st->ops.create=transform_create; diff --git a/tun.c b/tun.c index b0bde38..40bf6dd 100644 --- a/tun.c +++ b/tun.c @@ -116,8 +116,8 @@ static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds) } if (fds[0].revents&POLLIN) { BUF_ALLOC(st->buff,"tun_afterpoll"); - buffer_init(st->buff,st->nl.max_start_pad); - l=read(st->fd,st->buff->start,st->buff->len-st->nl.max_start_pad); + buffer_init(st->buff,calculate_max_start_pad()); + l=read(st->fd,st->buff->start,st->buff->len-calculate_max_start_pad()); if (l<0) { fatal_perror("tun_afterpoll: read()"); } diff --git a/udp.c b/udp.c index 12fcfe8..42fbb1f 100644 --- a/udp.c +++ b/udp.c @@ -193,12 +193,13 @@ static bool_t udp_sendmsg(void *commst, struct buffer_if *buf, uint8_t *sa; if (st->use_proxy) { - sa=buf->start-8; + sa=buf_prepend(buf,8); memcpy(sa,&dest->sin.sin_addr,4); memset(sa+4,0,4); memcpy(sa+6,&dest->sin.sin_port,2); sendto(st->fd,sa,buf->size+8,0,(struct sockaddr *)&st->proxy, sizeof(st->proxy)); + buf_unprepend(buf,8); } else { sendto(st->fd, buf->start, buf->size, 0, (struct sockaddr *)&dest->sin, sizeof(dest->sin)); @@ -288,7 +289,6 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context, st->cl.apply=NULL; st->cl.interface=&st->ops; st->ops.st=st; - st->ops.min_start_pad=0; st->ops.request_notify=request_notify; st->ops.release_notify=release_notify; st->ops.sendmsg=udp_sendmsg; @@ -323,9 +323,10 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context, cfgfatal(st->loc,"udp","proxy must supply ""addr"",port\n"); } st->proxy.sin_port=htons(i->data.number); - st->ops.min_start_pad=8; } + update_max_start_pad(&comm_max_start_pad, st->use_proxy ? 8 : 0); + add_hook(PHASE_GETRESOURCES,udp_phase_hook,st); return new_closure(&st->cl); diff --git a/util.c b/util.c index 24dd9a3..8c23485 100644 --- a/util.c +++ b/util.c @@ -387,7 +387,7 @@ void send_nak(const struct comm_addr *dest, uint32_t our_index, uint32_t their_index, uint32_t msgtype, struct buffer_if *buf, const char *logwhy) { - buffer_init(buf,dest->comm->min_start_pad); + buffer_init(buf,calculate_max_start_pad()); buf_append_uint32(buf,their_index); buf_append_uint32(buf,our_index); buf_append_uint32(buf,LABEL_NAK); @@ -419,3 +419,19 @@ void util_module(dict_t *dict) { add_closure(dict,"sysbuffer",buffer_apply); } + +void update_max_start_pad(int32_t *our_module_global, int32_t our_instance) +{ + if (*our_module_global < our_instance) + *our_module_global=our_instance; +} + +int32_t transform_max_start_pad, comm_max_start_pad; + +int32_t calculate_max_start_pad(void) +{ + return + site_max_start_pad + + transform_max_start_pad + + comm_max_start_pad; +} -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:51 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:51 +0100 Subject: [PATCH 25/41] NOTES: Remove paragraph about slow-to-prepare messages In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-26-git-send-email-ijackson@chiark.greenend.org.uk> NOTES contained this paragraph: Some messages may take a long time to prepare (software modexp on slow machines); this is a "please wait" message to indicate that a message is in preparation. This paragraph was immediately after the description of the msg0(msg9) packet - ie, the ordinary data packet. It is therefore at the very least misplaced. In the git history this paragraph was introduced in "Import release 0.1.14" (4f5e39ec). However, the diff for that commit (ie the diff between 0.1.13 and 0.1.4) does not show any code which might correspond to this comment. There is not currently any code in site.c which responds to a message of this kind. I have had a quick look for code which sends such a message and failed to find any. So I think this paragraph represents a never-implemented intent, and should be removed. It certainly predates the "hacky parallelism" by a long way. Signed-off-by: Ian Jackson --- NOTES | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/NOTES b/NOTES index 6a245ec..09c083e 100644 --- a/NOTES +++ b/NOTES @@ -251,10 +251,6 @@ some reason. 8) i?,i?,msg0,(send-packet/msg9,packet)_k -Some messages may take a long time to prepare (software modexp on slow -machines); this is a "please wait" message to indicate that a message -is in preparation. - **** Other messages 9) i?,i?,NAK (NAK is encoded as zero) -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:42 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:42 +0100 Subject: [PATCH 16/41] transform: split out transform-common.h In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-17-git-send-email-ijackson@chiark.greenend.org.uk> To avoid too much duplication, some boilerplate and helpful code from transport.c is now brought out into macros in transport-common.h. It will be reused in the later commits introducing the EAX transform. Also, rename transform.c to transform-cbcmac.c, etc. Signed-off-by: Ian Jackson --- Makefile.in | 3 +- README | 2 +- modules.c | 2 +- secnet.h | 2 +- transform-cbcmac.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++ transform-common.h | 56 ++++++++ transform.c | 394 ---------------------------------------------------- 7 files changed, 420 insertions(+), 398 deletions(-) create mode 100644 transform-cbcmac.c create mode 100644 transform-common.h delete mode 100644 transform.c diff --git a/Makefile.in b/Makefile.in index 3f15f01..401fbb8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,7 +53,8 @@ mandir:=@mandir@ TARGETS:=secnet OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ - resolver.o random.o udp.o site.o transform.o netlink.o rsa.o dh.o \ + resolver.o random.o udp.o site.o transform-cbcmac.o \ + netlink.o rsa.o dh.o \ serpentbe.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ process.o @LIBOBJS@ \ hackypar.o diff --git a/README b/README index 84bb392..93730e9 100644 --- a/README +++ b/README @@ -336,7 +336,7 @@ setup but more relaxed about using old keys. These are noted with "mobile:", above, and apply whether the mobile peer is local or remote. -** transform +** transform-cbcmac Defines: serpent256-cbc (closure => transform closure) diff --git a/modules.c b/modules.c index 9b94e25..0290cd4 100644 --- a/modules.c +++ b/modules.c @@ -7,7 +7,7 @@ void init_builtin_modules(dict_t *dict) udp_module(dict); util_module(dict); site_module(dict); - transform_module(dict); + transform_cbcmac_module(dict); netlink_module(dict); rsa_module(dict); dh_module(dict); diff --git a/secnet.h b/secnet.h index 037ef80..dbca664 100644 --- a/secnet.h +++ b/secnet.h @@ -217,7 +217,7 @@ extern init_module random_module; extern init_module udp_module; extern init_module util_module; extern init_module site_module; -extern init_module transform_module; +extern init_module transform_cbcmac_module; extern init_module netlink_module; extern init_module rsa_module; extern init_module dh_module; diff --git a/transform-cbcmac.c b/transform-cbcmac.c new file mode 100644 index 0000000..1e8a5e9 --- /dev/null +++ b/transform-cbcmac.c @@ -0,0 +1,359 @@ +/* Transform module - bulk data transformation */ + +/* For now it's hard-coded to do sequence + number/pkcs5/serpent-cbcmac/serpent with a 256 bit key for each + instance of serpent. We also require key material for the IVs for + cbcmac and cbc. Hack: we're not using full 128-bit IVs, we're just + using 32 bits and encrypting to get the full IV to save space in + the packets sent over the wire. */ + +#include +#include +#include "secnet.h" +#include "util.h" +#include "serpent.h" +#include "unaligned.h" +#include "hexdebug.h" + +/* Required key length in bytes */ +#define REQUIRED_KEYLEN ((512+64+32)/8) + +struct transform { + closure_t cl; + struct transform_if ops; + uint32_t max_seq_skew; +}; + +struct transform_inst { + struct transform_inst_if ops; + struct keyInstance cryptkey; + struct keyInstance mackey; + uint32_t cryptiv; + uint32_t maciv; + uint32_t sendseq; + uint32_t lastrecvseq; + uint32_t max_skew; + bool_t keyed; +}; + +#include "transform-common.h" + +#define PKCS5_MASK 15 + +static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) +{ + struct transform_inst *ti=sst; + + if (keylencryptkey,256,key); + serpentbe_makekey(&ti->mackey,256,key+32); + ti->cryptiv=get_uint32(key+64); + ti->maciv=get_uint32(key+68); + ti->sendseq=get_uint32(key+72); + ti->lastrecvseq=ti->sendseq; + ti->keyed=True; + + return True; +} + +TRANSFORM_VALID; + +static void transform_delkey(void *sst) +{ + struct transform_inst *ti=sst; + + FILLZERO(ti->cryptkey); + FILLZERO(ti->mackey); + ti->keyed=False; +} + +static uint32_t transform_forward(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + uint8_t *padp; + int padlen; + uint8_t iv[16]; + uint8_t macplain[16]; + uint8_t macacc[16]; + uint8_t *p, *n; + int i; + + KEYED_CHECK; + + /* Sequence number */ + buf_prepend_uint32(buf,ti->sendseq); + ti->sendseq++; + + /* PKCS5, stolen from IWJ */ + /* eg with blocksize=4 mask=3 mask+2=5 */ + /* msgsize 20 21 22 23 24 */ + padlen= PKCS5_MASK-buf->size; /* -17 -18 -19 -16 -17 */ + padlen &= PKCS5_MASK; /* 3 2 1 0 3 */ + padlen++; /* 4 3 2 1 4 */ + + padp=buf_append(buf,padlen); + memset(padp,padlen,padlen); + + /* Serpent-CBCMAC. We expand the IV from 32-bit to 128-bit using + one encryption. Then we do the MAC and append the result. We don't + bother sending the IV - it's the same each time. (If we wanted to send + it we've have to add 16 bytes to each message, not 4, so that the + message stays a multiple of 16 bytes long.) */ + memset(iv,0,16); + put_uint32(iv, ti->maciv); + serpentbe_encrypt(&ti->mackey,iv,macacc); + + /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted + block encrypted once again. */ + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + macplain[i] = macacc[i] ^ n[i]; + serpentbe_encrypt(&ti->mackey,macplain,macacc); + } + serpentbe_encrypt(&ti->mackey,macacc,macacc); + memcpy(buf_append(buf,16),macacc,16); + + /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption, + and prepend the IV before increasing it. */ + memset(iv,0,16); + put_uint32(iv, ti->cryptiv); + serpentbe_encrypt(&ti->cryptkey,iv,iv); + + /* CBC: each block is XORed with the previous encrypted block (or the IV) + before being encrypted. */ + p=iv; + + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + n[i] ^= p[i]; + serpentbe_encrypt(&ti->cryptkey,n,n); + p=n; + } + + buf_prepend_uint32(buf,ti->cryptiv); + ti->cryptiv++; + return 0; +} + +static uint32_t transform_reverse(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + uint8_t *padp; + int padlen; + int i; + uint32_t seqnum; + uint8_t iv[16]; + uint8_t pct[16]; + uint8_t macplain[16]; + uint8_t macacc[16]; + uint8_t *n; + uint8_t *macexpected; + + KEYED_CHECK; + + if (buf->size < 4 + 16 + 16) { + *errmsg="msg too short"; + return 1; + } + + /* CBC */ + memset(iv,0,16); + { + uint32_t ivword = buf_unprepend_uint32(buf); + put_uint32(iv, ivword); + } + /* Assert bufsize is multiple of blocksize */ + if (buf->size&0xf) { + *errmsg="msg not multiple of cipher blocksize"; + return 1; + } + serpentbe_encrypt(&ti->cryptkey,iv,iv); + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + pct[i] = n[i]; + serpentbe_decrypt(&ti->cryptkey,n,n); + for (i = 0; i < 16; i++) + n[i] ^= iv[i]; + memcpy(iv, pct, 16); + } + + /* CBCMAC */ + macexpected=buf_unappend(buf,16); + memset(iv,0,16); + put_uint32(iv, ti->maciv); + serpentbe_encrypt(&ti->mackey,iv,macacc); + + /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted + block encrypted once again. */ + for (n=buf->start; nstart+buf->size; n+=16) + { + for (i = 0; i < 16; i++) + macplain[i] = macacc[i] ^ n[i]; + serpentbe_encrypt(&ti->mackey,macplain,macacc); + } + serpentbe_encrypt(&ti->mackey,macacc,macacc); + if (!consttime_memeq(macexpected,macacc,16)!=0) { + *errmsg="invalid MAC"; + return 1; + } + + /* PKCS5, stolen from IWJ */ + + padp=buf_unappend(buf,1); + padlen=*padp; + if (!padlen || (padlen > PKCS5_MASK+1)) { + *errmsg="pkcs5: invalid length"; + return 1; + } + + buf_unappend(buf,padlen-1); + + /* Sequence number must be within max_skew of lastrecvseq; lastrecvseq + is only allowed to increase. */ + seqnum=buf_unprepend_uint32(buf); + SEQNUM_CHECK(seqnum, ti->max_skew); + + return 0; +} + +TRANSFORM_DESTROY; + +static struct transform_inst_if *transform_create(void *sst) +{ + struct transform *st=sst; + + TRANSFORM_CREATE_CORE; + + ti->max_skew=st->max_seq_skew; + + return &ti->ops; +} + +static list_t *transform_apply(closure_t *self, struct cloc loc, + dict_t *context, list_t *args) +{ + struct transform *st; + item_t *item; + dict_t *dict; + + st=safe_malloc(sizeof(*st),"serpent"); + st->cl.description="serpent-cbc256"; + st->cl.type=CL_TRANSFORM; + st->cl.apply=NULL; + st->cl.interface=&st->ops; + st->ops.st=st; + st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV, + 4byte IV */ + st->ops.max_end_pad=16; /* 16byte CBCMAC */ + + /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits + for CBCMAC-IV, and 32 bits for init sequence number */ + st->ops.keylen=REQUIRED_KEYLEN; + st->ops.create=transform_create; + + /* First parameter must be a dict */ + item=list_elem(args,0); + if (!item || item->type!=t_dict) + cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n"); + + dict=item->data.dict; + st->max_seq_skew=dict_read_number(dict, "max-sequence-skew", + False, "serpent-cbc256", loc, 10); + + return new_closure(&st->cl); +} + +void transform_cbcmac_module(dict_t *dict) +{ + struct keyInstance k; + uint8_t data[32]; + uint8_t plaintext[16]; + uint8_t ciphertext[16]; + + /* + * Serpent self-test. + * + * This test pattern was taken directly from the Serpent test + * vectors, which results in a big-endian Serpent which is not + * compatible with other implementations. + */ + + /* Serpent self-test */ + memcpy(data, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" + "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00", + 32); + serpentbe_makekey(&k,256,data); + + memcpy(plaintext, + "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10", + 16); + serpentbe_encrypt(&k,plaintext,ciphertext); + + if (memcmp(ciphertext, "\xca\x7f\xa1\x93\xe3\xeb\x9e\x99" + "\xbd\x87\xe3\xaf\x3c\x9a\xdf\x93", 16)) { + fatal("transform_module: serpent failed self-test (encrypt)"); + } + serpentbe_decrypt(&k,ciphertext,plaintext); + if (memcmp(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\xfe\xdc\xba\x98\x76\x54\x32\x10", 16)) { + fatal("transform_module: serpent failed self-test (decrypt)"); + } + + add_closure(dict,"serpent256-cbc",transform_apply); + +#ifdef TEST_WHOLE_TRANSFORM + { + struct transform *tr; + void *ti; + struct buffer_if buf; + const char text[] = "This is a piece of test text."; + char keymaterial[76] = + "Seventy-six bytes i" + "n four rows of 19; " + "this looks almost l" + "ike a poem but not."; + const char *errmsg; + int i; + + tr = malloc(sizeof(struct transform)); + tr->max_seq_skew = 20; + ti = transform_create(tr); + + transform_setkey(ti, keymaterial, 76); + + buf.base = malloc(4096); + buffer_init(&buf, 2048); + memcpy(buf_append(&buf, sizeof(text)), text, sizeof(text)); + if (transform_forward(ti, &buf, &errmsg)) { + fatal("transform_forward test: %s", errmsg); + } + printf("transformed text is:\n"); + for (i = 0; i < buf.size; i++) + printf("%02x%c", buf.start[i], + (i%16==15 || i==buf.size-1 ? '\n' : ' ')); + if (transform_reverse(ti, &buf, &errmsg)) { + fatal("transform_reverse test: %s", errmsg); + } + printf("transform reversal worked OK\n"); + } +#endif +} diff --git a/transform-common.h b/transform-common.h new file mode 100644 index 0000000..b3c70a8 --- /dev/null +++ b/transform-common.h @@ -0,0 +1,56 @@ + +#ifndef TRANSFORM_COMMON_H +#define TRANSFORM_COMMON_H + +#define KEYED_CHECK do{ \ + if (!ti->keyed) { \ + *errmsg="transform unkeyed"; \ + return 1; \ + } \ + }while(0) + +#define SEQNUM_CHECK(seqnum, max_skew) do{ \ + uint32_t skew=seqnum-ti->lastrecvseq; \ + if (skew<0x8fffffff) { \ + /* Ok */ \ + ti->lastrecvseq=seqnum; \ + } else if ((0-skew)keyed; \ + } + +#define TRANSFORM_DESTROY \ + static void transform_destroy(void *sst) \ + { \ + struct transform_inst *st=sst; \ + \ + FILLZERO(*st); /* Destroy key material */ \ + free(st); \ + } + +#define TRANSFORM_CREATE_CORE \ + struct transform_inst *ti; \ + ti=safe_malloc(sizeof(*ti),"transform_create"); \ + /* mlock XXX */ \ + ti->ops.st=ti; \ + ti->ops.setkey=transform_setkey; \ + ti->ops.valid=transform_valid; \ + ti->ops.delkey=transform_delkey; \ + ti->ops.forwards=transform_forward; \ + ti->ops.reverse=transform_reverse; \ + ti->ops.destroy=transform_destroy; \ + ti->keyed=False; + +#endif /*TRANSFORM_COMMON_H*/ diff --git a/transform.c b/transform.c deleted file mode 100644 index 281e667..0000000 --- a/transform.c +++ /dev/null @@ -1,394 +0,0 @@ -/* Transform module - bulk data transformation */ - -/* For now it's hard-coded to do sequence - number/pkcs5/serpent-cbcmac/serpent with a 256 bit key for each - instance of serpent. We also require key material for the IVs for - cbcmac and cbc. Hack: we're not using full 128-bit IVs, we're just - using 32 bits and encrypting to get the full IV to save space in - the packets sent over the wire. */ - -#include -#include -#include "secnet.h" -#include "util.h" -#include "serpent.h" -#include "unaligned.h" -#include "hexdebug.h" - -/* Required key length in bytes */ -#define REQUIRED_KEYLEN ((512+64+32)/8) - -struct transform { - closure_t cl; - struct transform_if ops; - uint32_t max_seq_skew; -}; - -struct transform_inst { - struct transform_inst_if ops; - struct keyInstance cryptkey; - struct keyInstance mackey; - uint32_t cryptiv; - uint32_t maciv; - uint32_t sendseq; - uint32_t lastrecvseq; - uint32_t max_skew; - bool_t keyed; -}; - -#define PKCS5_MASK 15 - -static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) -{ - struct transform_inst *ti=sst; - - if (keylencryptkey,256,key); - serpentbe_makekey(&ti->mackey,256,key+32); - ti->cryptiv=get_uint32(key+64); - ti->maciv=get_uint32(key+68); - ti->sendseq=get_uint32(key+72); - ti->lastrecvseq=ti->sendseq; - ti->keyed=True; - - return True; -} - -static bool_t transform_valid(void *sst) -{ - struct transform_inst *ti=sst; - - return ti->keyed; -} - -static void transform_delkey(void *sst) -{ - struct transform_inst *ti=sst; - - FILLZERO(ti->cryptkey); - FILLZERO(ti->mackey); - ti->keyed=False; -} - -static uint32_t transform_forward(void *sst, struct buffer_if *buf, - const char **errmsg) -{ - struct transform_inst *ti=sst; - uint8_t *padp; - int padlen; - uint8_t iv[16]; - uint8_t macplain[16]; - uint8_t macacc[16]; - uint8_t *p, *n; - int i; - - if (!ti->keyed) { - *errmsg="transform unkeyed"; - return 1; - } - - /* Sequence number */ - buf_prepend_uint32(buf,ti->sendseq); - ti->sendseq++; - - /* PKCS5, stolen from IWJ */ - /* eg with blocksize=4 mask=3 mask+2=5 */ - /* msgsize 20 21 22 23 24 */ - padlen= PKCS5_MASK-buf->size; /* -17 -18 -19 -16 -17 */ - padlen &= PKCS5_MASK; /* 3 2 1 0 3 */ - padlen++; /* 4 3 2 1 4 */ - - padp=buf_append(buf,padlen); - memset(padp,padlen,padlen); - - /* Serpent-CBCMAC. We expand the IV from 32-bit to 128-bit using - one encryption. Then we do the MAC and append the result. We don't - bother sending the IV - it's the same each time. (If we wanted to send - it we've have to add 16 bytes to each message, not 4, so that the - message stays a multiple of 16 bytes long.) */ - memset(iv,0,16); - put_uint32(iv, ti->maciv); - serpentbe_encrypt(&ti->mackey,iv,macacc); - - /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted - block encrypted once again. */ - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - macplain[i] = macacc[i] ^ n[i]; - serpentbe_encrypt(&ti->mackey,macplain,macacc); - } - serpentbe_encrypt(&ti->mackey,macacc,macacc); - memcpy(buf_append(buf,16),macacc,16); - - /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption, - and prepend the IV before increasing it. */ - memset(iv,0,16); - put_uint32(iv, ti->cryptiv); - serpentbe_encrypt(&ti->cryptkey,iv,iv); - - /* CBC: each block is XORed with the previous encrypted block (or the IV) - before being encrypted. */ - p=iv; - - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - n[i] ^= p[i]; - serpentbe_encrypt(&ti->cryptkey,n,n); - p=n; - } - - buf_prepend_uint32(buf,ti->cryptiv); - ti->cryptiv++; - return 0; -} - -static uint32_t transform_reverse(void *sst, struct buffer_if *buf, - const char **errmsg) -{ - struct transform_inst *ti=sst; - uint8_t *padp; - int padlen; - int i; - uint32_t seqnum, skew; - uint8_t iv[16]; - uint8_t pct[16]; - uint8_t macplain[16]; - uint8_t macacc[16]; - uint8_t *n; - uint8_t *macexpected; - - if (!ti->keyed) { - *errmsg="transform unkeyed"; - return 1; - } - - if (buf->size < 4 + 16 + 16) { - *errmsg="msg too short"; - return 1; - } - - /* CBC */ - memset(iv,0,16); - { - uint32_t ivword = buf_unprepend_uint32(buf); - put_uint32(iv, ivword); - } - /* Assert bufsize is multiple of blocksize */ - if (buf->size&0xf) { - *errmsg="msg not multiple of cipher blocksize"; - return 1; - } - serpentbe_encrypt(&ti->cryptkey,iv,iv); - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - pct[i] = n[i]; - serpentbe_decrypt(&ti->cryptkey,n,n); - for (i = 0; i < 16; i++) - n[i] ^= iv[i]; - memcpy(iv, pct, 16); - } - - /* CBCMAC */ - macexpected=buf_unappend(buf,16); - memset(iv,0,16); - put_uint32(iv, ti->maciv); - serpentbe_encrypt(&ti->mackey,iv,macacc); - - /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted - block encrypted once again. */ - for (n=buf->start; nstart+buf->size; n+=16) - { - for (i = 0; i < 16; i++) - macplain[i] = macacc[i] ^ n[i]; - serpentbe_encrypt(&ti->mackey,macplain,macacc); - } - serpentbe_encrypt(&ti->mackey,macacc,macacc); - if (!consttime_memeq(macexpected,macacc,16)!=0) { - *errmsg="invalid MAC"; - return 1; - } - - /* PKCS5, stolen from IWJ */ - - padp=buf_unappend(buf,1); - padlen=*padp; - if (!padlen || (padlen > PKCS5_MASK+1)) { - *errmsg="pkcs5: invalid length"; - return 1; - } - - buf_unappend(buf,padlen-1); - - /* Sequence number must be within max_skew of lastrecvseq; lastrecvseq - is only allowed to increase. */ - seqnum=buf_unprepend_uint32(buf); - skew=seqnum-ti->lastrecvseq; - if (skew<0x8fffffff) { - /* Ok */ - ti->lastrecvseq=seqnum; - } else if ((0-skew)max_skew) { - /* Ok */ - } else { - /* Too much skew */ - *errmsg="seqnum: too much skew"; - return 2; - } - - return 0; -} - -static void transform_destroy(void *sst) -{ - struct transform_inst *st=sst; - - FILLZERO(*st); /* Destroy key material */ - free(st); -} - -static struct transform_inst_if *transform_create(void *sst) -{ - struct transform_inst *ti; - struct transform *st=sst; - - ti=safe_malloc(sizeof(*ti),"transform_create"); - /* mlock XXX */ - - ti->ops.st=ti; - ti->ops.setkey=transform_setkey; - ti->ops.valid=transform_valid; - ti->ops.delkey=transform_delkey; - ti->ops.forwards=transform_forward; - ti->ops.reverse=transform_reverse; - ti->ops.destroy=transform_destroy; - ti->max_skew=st->max_seq_skew; - ti->keyed=False; - - return &ti->ops; -} - -static list_t *transform_apply(closure_t *self, struct cloc loc, - dict_t *context, list_t *args) -{ - struct transform *st; - item_t *item; - dict_t *dict; - - st=safe_malloc(sizeof(*st),"serpent"); - st->cl.description="serpent-cbc256"; - st->cl.type=CL_TRANSFORM; - st->cl.apply=NULL; - st->cl.interface=&st->ops; - st->ops.st=st; - st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV, - 4byte IV */ - st->ops.max_end_pad=16; /* 16byte CBCMAC */ - - /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits - for CBCMAC-IV, and 32 bits for init sequence number */ - st->ops.keylen=REQUIRED_KEYLEN; - st->ops.create=transform_create; - - /* First parameter must be a dict */ - item=list_elem(args,0); - if (!item || item->type!=t_dict) - cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n"); - - dict=item->data.dict; - st->max_seq_skew=dict_read_number(dict, "max-sequence-skew", - False, "serpent-cbc256", loc, 10); - - return new_closure(&st->cl); -} - -void transform_module(dict_t *dict) -{ - struct keyInstance k; - uint8_t data[32]; - uint8_t plaintext[16]; - uint8_t ciphertext[16]; - - /* - * Serpent self-test. - * - * This test pattern was taken directly from the Serpent test - * vectors, which results in a big-endian Serpent which is not - * compatible with other implementations. - */ - - /* Serpent self-test */ - memcpy(data, - "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" - "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00", - 32); - serpentbe_makekey(&k,256,data); - - memcpy(plaintext, - "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10", - 16); - serpentbe_encrypt(&k,plaintext,ciphertext); - - if (memcmp(ciphertext, "\xca\x7f\xa1\x93\xe3\xeb\x9e\x99" - "\xbd\x87\xe3\xaf\x3c\x9a\xdf\x93", 16)) { - fatal("transform_module: serpent failed self-test (encrypt)"); - } - serpentbe_decrypt(&k,ciphertext,plaintext); - if (memcmp(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", 16)) { - fatal("transform_module: serpent failed self-test (decrypt)"); - } - - add_closure(dict,"serpent256-cbc",transform_apply); - -#ifdef TEST_WHOLE_TRANSFORM - { - struct transform *tr; - void *ti; - struct buffer_if buf; - const char text[] = "This is a piece of test text."; - char keymaterial[76] = - "Seventy-six bytes i" - "n four rows of 19; " - "this looks almost l" - "ike a poem but not."; - const char *errmsg; - int i; - - tr = malloc(sizeof(struct transform)); - tr->max_seq_skew = 20; - ti = transform_create(tr); - - transform_setkey(ti, keymaterial, 76); - - buf.base = malloc(4096); - buffer_init(&buf, 2048); - memcpy(buf_append(&buf, sizeof(text)), text, sizeof(text)); - if (transform_forward(ti, &buf, &errmsg)) { - fatal("transform_forward test: %s", errmsg); - } - printf("transformed text is:\n"); - for (i = 0; i < buf.size; i++) - printf("%02x%c", buf.start[i], - (i%16==15 || i==buf.size-1 ? '\n' : ' ')); - if (transform_reverse(ti, &buf, &errmsg)) { - fatal("transform_reverse test: %s", errmsg); - } - printf("transform reversal worked OK\n"); - } -#endif -} -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:56 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:56 +0100 Subject: [PATCH 30/41] site: interpret first 4 bytes of extrainfo as capabilities In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-31-git-send-email-ijackson@chiark.greenend.org.uk> Define the first four bytes of the additional data (after the nul in site names in MSG1..4) in the sender's name field to be a capability bitmask. Currently no capability flags are defined. To support this, replace extrainfo and its _len in struct parsedname with a struct buffer_if. We record the capabilities from MSG1 or MSG3, and check that they haven't changed when processing MSG2..4, as applicable. (Because older secnets don't cope with flags in MSG1, we have to define two kinds of capability flag: ones expected to be in MSG1, and ones which can appear later in the exchange.) The support for "Early" capabilities is intended to be used in the future to support algorithm agility in key exchange. We also advertise our own capabilities (currently, all-bits-zero) in our own messages. Signed-off-by: Ian Jackson --- NOTES | 28 ++++++++++++++++++++++- magic.h | 4 +++ site.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/NOTES b/NOTES index 3e9d71d..8619ee5 100644 --- a/NOTES +++ b/NOTES @@ -176,7 +176,7 @@ Definitions: A is the originating gateway machine name B is the destination gateway machine name -A+ and B+ are the names with optional additional data, currently ignored +A+ and B+ are the names with optional additional data, see below PK_A is the public RSA key of A PK_B is the public RSA key of B PK_A^-1 is the private RSA key of A @@ -194,7 +194,31 @@ i? is appropriate index for receiver Note that 'i' may be re-used from one session to the next, whereas 'n' is always fresh. -The protocol version selection stuff is not yet implemented. +The optional additional data after the sender's name consists of some +initial subset of the following list of items: + * A 32-bit integer with a set of capability flags, representing the + abilities of the sender. + * More data which is yet to be defined and which must be ignored + by receivers. +The optional additional data after the receiver's name is not +currently used. If any is seen, it must be ignored. + +Capability flag bits must be in one the following two categories: + +1. Early capability flags must be advertised in MSG1 or MSG2, as + applicable. If MSG3 or MSG4 advertise any "early" capability bits, + MSG1 or MSG3 (as applicable) must have advertised them too. Sadly, + advertising an early capability flag will produce MSG1s which are + not understood by versions of secnet which predate the capability + mechanism. + +2. Late capability flags are advertised in MSG2 or MSG3, as + applicable. They may also appear in MSG1, but this is not + guaranteed. MSG4 must advertise the same set as MSG2. + +No capability flags are currently defined. Unknown capability flags +should be treated as late ones. + Messages: diff --git a/magic.h b/magic.h index c2503a0..3ae7af4 100644 --- a/magic.h +++ b/magic.h @@ -15,4 +15,8 @@ #define LABEL_MSG8 0x08080808 #define LABEL_MSG9 0x09090909 +/* uses of the 32-bit capability bitmap */ +/* no flags currently defined */ +#define CAPAB_EARLY 0x00000000 /* no Early flags defined (see NOTES) */ + #endif /* magic_h */ diff --git a/site.c b/site.c index 5b071b2..0a02785 100644 --- a/site.c +++ b/site.c @@ -244,6 +244,7 @@ struct site { struct hash_if *hash; uint32_t index; /* Index of this site */ + uint32_t local_capabilities; int32_t setup_retries; /* How many times to send setup packets */ int32_t setup_retry_interval; /* Initial timeout for setup packets */ int32_t wait_timeout; /* How long to wait if setup unsuccessful */ @@ -275,6 +276,7 @@ struct site { packet; we keep trying to continue the exchange, and have to timeout before we can listen for another setup packet); perhaps we should keep a list of 'bad' sources for setup packets. */ + uint32_t remote_capabilities; uint32_t setup_session_id; transport_peers setup_peers; uint8_t localN[NONCELEN]; /* Nonces for key exchange */ @@ -347,8 +349,7 @@ static bool_t current_valid(struct site *st) struct parsedname { int32_t len; uint8_t *name; - int32_t extrainfo_len; - uint8_t *extrainfo; + struct buffer_if extrainfo; }; struct msg { @@ -357,6 +358,7 @@ struct msg { uint32_t source; struct parsedname remote; struct parsedname local; + uint32_t remote_capabilities; uint8_t *nR; uint8_t *nL; int32_t pklen; @@ -366,6 +368,34 @@ struct msg { char *sig; }; +struct xinfoadd { + int32_t lenpos, afternul; +}; +static void append_string_xinfo_start(struct buffer_if *buf, + struct xinfoadd *xia, + const char *str) + /* Helps construct one of the names with additional info as found + * in MSG1..4. Call this function first, then append all the + * desired extra info (not including the nul byte) to the buffer, + * then call append_string_xinfo_done. */ +{ + xia->lenpos = buf->size; + buf_append_string(buf,str); + buf_append_uint8(buf,0); + xia->afternul = buf->size; +} +static void append_string_xinfo_done(struct buffer_if *buf, + struct xinfoadd *xia) +{ + /* we just need to adjust the string length */ + if (buf->size == xia->afternul) { + /* no extra info, strip the nul too */ + buf_unappend_uint8(buf); + } else { + put_uint16(buf->start+xia->lenpos, buf->size-(xia->lenpos+2)); + } +} + /* Build any of msg1 to msg4. msg5 and msg6 are built from the inside out using a transform of config data supplied by netlink */ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) @@ -381,7 +411,14 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) (type==LABEL_MSG1?0:st->setup_session_id)); buf_append_uint32(&st->buffer,st->index); buf_append_uint32(&st->buffer,type); - buf_append_string(&st->buffer,st->localname); + + struct xinfoadd xia; + append_string_xinfo_start(&st->buffer,&xia,st->localname); + if ((st->local_capabilities & CAPAB_EARLY) || (type != LABEL_MSG1)) { + buf_append_uint32(&st->buffer,st->local_capabilities); + } + append_string_xinfo_done(&st->buffer,&xia); + buf_append_string(&st->buffer,st->remotename); memcpy(buf_append(&st->buffer,NONCELEN),st->localN,NONCELEN); if (type==LABEL_MSG1) return True; @@ -412,11 +449,9 @@ static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm) nm->name=buf_unprepend(msg,nm->len); uint8_t *nul=memchr(nm->name,0,nm->len); if (!nul) { - nm->extrainfo_len=0; - nm->extrainfo=0; + buffer_readonly_view(&nm->extrainfo,0,0); } else { - nm->extrainfo=nul+1; - nm->extrainfo_len=msg->start-nm->extrainfo; + buffer_readonly_view(&nm->extrainfo, nul+1, msg->start-(nul+1)); nm->len=nul-nm->name; } return True; @@ -432,6 +467,11 @@ static bool_t unpick_msg(struct site *st, uint32_t type, m->source=buf_unprepend_uint32(msg); CHECK_TYPE(msg,type); if (!unpick_name(msg,&m->remote)) return False; + m->remote_capabilities=0; + if (m->remote.extrainfo.size) { + CHECK_AVAIL(&m->remote.extrainfo,4); + m->remote_capabilities=buf_unprepend_uint32(&m->remote.extrainfo); + } if (!unpick_name(msg,&m->local)) return False; CHECK_AVAIL(msg,NONCELEN); m->nR=buf_unprepend(msg,NONCELEN); @@ -490,7 +530,13 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, *error="wrong remotely-generated nonce"; return False; } + /* MSG3 has complicated rules about capabilities, which are + * handled in process_msg3. */ if (type==LABEL_MSG3) return True; + if (m->remote_capabilities!=st->remote_capabilities) { + *error="remote capabilities changed"; + return False; + } if (type==LABEL_MSG4) return True; *error="unknown message type"; return False; @@ -511,6 +557,7 @@ static bool_t process_msg1(struct site *st, struct buffer_if *msg1, transport_record_peer(st,&st->setup_peers,src,"msg1"); st->setup_session_id=m->source; + st->remote_capabilities=m->remote_capabilities; memcpy(st->remoteN,m->nR,NONCELEN); return True; } @@ -533,6 +580,7 @@ static bool_t process_msg2(struct site *st, struct buffer_if *msg2, return False; } st->setup_session_id=m.source; + st->remote_capabilities=m.remote_capabilities; memcpy(st->remoteN,m.nR,NONCELEN); return True; } @@ -558,6 +606,15 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, slog(st,LOG_SEC,"msg3: %s",err); return False; } + uint32_t capab_adv_late = m.remote_capabilities + & ~st->remote_capabilities & CAPAB_EARLY; + if (capab_adv_late) { + slog(st,LOG_SEC,"msg3 impermissibly adds early capability flag(s)" + " %#"PRIx32" (was %#"PRIx32", now %#"PRIx32")", + capab_adv_late, st->remote_capabilities, m.remote_capabilities); + return False; + } + st->remote_capabilities|=m.remote_capabilities; /* Check signature and store g^x mod m */ hash=safe_malloc(st->hash->len, "process_msg3"); @@ -1493,6 +1550,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, assert(index_sequence < 0xffffffffUL); st->index = ++index_sequence; + st->local_capabilities = 0; st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc); list_t *comms_cfg=dict_lookup(dict,"comm"); @@ -1579,6 +1637,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, register_for_poll(st, site_beforepoll, site_afterpoll, 0, "site"); st->timeout=0; + st->remote_capabilities=0; st->current.key_timeout=0; st->auxiliary_key.key_timeout=0; transport_peers_clear(st,&st->peers); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:57 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:57 +0100 Subject: [PATCH 31/41] site: Check transform errors; factor out transform handling In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-32-git-send-email-ijackson@chiark.greenend.org.uk> Make sure we always check the error return from transform->forwards and ->backwards. Otherwise logic errors in the site state machine might result in us sending out packets with unencrypted insider plaintext, or the like, due to the transform being unkeyed when we try to use it. Factor some repeated idioms for transform handling into a set of new functions. This will make the next patch much easier. We arrange to pass dispose_transform a pointer to the actual state variable where the transform is kept; this means that it can be changed to update that pointer. Signed-off-by: Ian Jackson --- site.c | 90 ++++++++++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 63 insertions(+), 27 deletions(-) diff --git a/site.c b/site.c index 0a02785..9813de0 100644 --- a/site.c +++ b/site.c @@ -334,11 +334,35 @@ static bool_t enter_new_state(struct site *st,uint32_t next); static void enter_state_wait(struct site *st); static void activate_new_key(struct site *st); +static bool_t is_transform_valid(struct transform_inst_if *transform) +{ + return transform->valid(transform->st); +} + static bool_t current_valid(struct site *st) { - return st->current.transform->valid(st->current.transform->st); + return is_transform_valid(st->current.transform); +} + +#define DEFINE_CALL_TRANSFORM(fwdrev) \ +static int call_transform_##fwdrev(struct site *st, \ + struct transform_inst_if *transform, \ + struct buffer_if *buf, \ + const char **errmsg) \ +{ \ + return transform->fwdrev(transform->st,buf,errmsg); \ } +DEFINE_CALL_TRANSFORM(forwards) +DEFINE_CALL_TRANSFORM(reverse) + +static void dispose_transform(struct transform_inst_if **transform_var) +{ + /* will become more sophisticated very shortly */ + struct transform_inst_if *transform=*transform_var; + transform->delkey(transform->st); +} + #define CHECK_AVAIL(b,l) do { if ((b)->size<(l)) return False; } while(0) #define CHECK_EMPTY(b) do { if ((b)->size!=0) return False; } while(0) #define CHECK_TYPE(b,t) do { uint32_t type; \ @@ -368,6 +392,12 @@ struct msg { char *sig; }; +static void set_new_transform(struct site *st) +{ + st->new_transform->setkey(st->new_transform->st,st->sharedsecret, + st->sharedsecretlen,st->setup_priority); +} + struct xinfoadd { int32_t lenpos, afternul; }; @@ -640,8 +670,7 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ - st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen,st->setup_priority); + set_new_transform(st); return True; } @@ -687,8 +716,7 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ - st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen,st->setup_priority); + set_new_transform(st); return True; } @@ -722,8 +750,9 @@ static bool_t generate_msg5(struct site *st) /* Give the netlink code an opportunity to put its own stuff in the message (configuration information, etc.) */ buf_prepend_uint32(&st->buffer,LABEL_MSG5); - st->new_transform->forwards(st->new_transform->st,&st->buffer, - &transform_err); + if (call_transform_forwards(st,st->new_transform, + &st->buffer,&transform_err)) + return False; buf_prepend_uint32(&st->buffer,LABEL_MSG5); buf_prepend_uint32(&st->buffer,st->index); buf_prepend_uint32(&st->buffer,st->setup_session_id); @@ -741,7 +770,7 @@ static bool_t process_msg5(struct site *st, struct buffer_if *msg5, if (!unpick_msg0(st,msg5,&m)) return False; - if (transform->reverse(transform->st,msg5,&transform_err)) { + if (call_transform_reverse(st,transform,msg5,&transform_err)) { /* There's a problem */ slog(st,LOG_SEC,"process_msg5: transform: %s",transform_err); return False; @@ -768,7 +797,9 @@ static void create_msg6(struct site *st, struct transform_inst_if *transform, /* Give the netlink code an opportunity to put its own stuff in the message (configuration information, etc.) */ buf_prepend_uint32(&st->buffer,LABEL_MSG6); - transform->forwards(transform->st,&st->buffer,&transform_err); + int problem = call_transform_forwards(st,transform, + &st->buffer,&transform_err); + assert(!problem); buf_prepend_uint32(&st->buffer,LABEL_MSG6); buf_prepend_uint32(&st->buffer,st->index); buf_prepend_uint32(&st->buffer,session_id); @@ -776,6 +807,8 @@ static void create_msg6(struct site *st, struct transform_inst_if *transform, static bool_t generate_msg6(struct site *st) { + if (!is_transform_valid(st->new_transform)) + return False; create_msg6(st,st->new_transform,st->setup_session_id); st->retries=1; /* Peer will retransmit MSG5 if this packet gets lost */ return True; @@ -789,8 +822,7 @@ static bool_t process_msg6(struct site *st, struct buffer_if *msg6, if (!unpick_msg0(st,msg6,&m)) return False; - if (st->new_transform->reverse(st->new_transform->st, - msg6,&transform_err)) { + if (call_transform_reverse(st,st->new_transform,msg6,&transform_err)) { /* There's a problem */ slog(st,LOG_SEC,"process_msg6: transform: %s",transform_err); return False; @@ -818,8 +850,8 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0, /* Keep a copy so we can try decrypting it with multiple keys */ buffer_copy(&st->scratch, msg0); - problem = st->current.transform->reverse(st->current.transform->st, - msg0,&transform_err); + problem = call_transform_reverse(st,st->current.transform, + msg0,&transform_err); if (!problem) { if (!st->auxiliary_is_new) delete_one_key(st,&st->auxiliary_key, @@ -830,8 +862,8 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0, goto skew; buffer_copy(msg0, &st->scratch); - problem = st->auxiliary_key.transform->reverse - (st->auxiliary_key.transform->st,msg0,&auxkey_err); + problem = call_transform_reverse + (st,st->auxiliary_key.transform->st,msg0,&auxkey_err); if (problem==0) { slog(st,LOG_DROP,"processing packet which uses auxiliary key"); if (st->auxiliary_is_new) { @@ -856,8 +888,8 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0, if (st->state==SITE_SENTMSG5) { buffer_copy(msg0, &st->scratch); - problem = st->new_transform->reverse(st->new_transform->st, - msg0,&newkey_err); + problem = call_transform_reverse(st,st->new_transform, + msg0,&newkey_err); if (!problem) { /* It looks like we didn't get the peer's MSG6 */ /* This is like a cut-down enter_new_state(SITE_RUN) */ @@ -947,8 +979,8 @@ static bool_t send_msg(struct site *st) t=st->auxiliary_key.transform; st->auxiliary_key.transform=st->new_transform; st->new_transform=t; + dispose_transform(&st->new_transform); - t->delkey(t->st); st->auxiliary_is_new=1; st->auxiliary_key.key_timeout=st->now+st->key_lifetime; st->auxiliary_renegotiate_key_time=st->now+st->key_renegotiate_time; @@ -1017,8 +1049,8 @@ static void activate_new_key(struct site *st) st->auxiliary_key.transform=st->current.transform; st->current.transform=st->new_transform; st->new_transform=t; + dispose_transform(&st->new_transform); - t->delkey(t->st); st->timeout=0; st->auxiliary_is_new=0; st->auxiliary_key.key_timeout=st->current.key_timeout; @@ -1034,9 +1066,9 @@ static void activate_new_key(struct site *st) static void delete_one_key(struct site *st, struct data_key *key, cstring_t reason, cstring_t which, uint32_t loglevel) { - if (!key->transform->valid(key->transform->st)) return; + if (!is_transform_valid(key->transform)) return; if (reason) slog(st,loglevel,"%s deleted (%s)",which,reason); - key->transform->delkey(key->transform->st); + dispose_transform(&key->transform); key->key_timeout=0; } @@ -1061,7 +1093,7 @@ static void enter_state_stop(struct site *st) st->state=SITE_STOP; st->timeout=0; delete_keys(st,"entering state STOP",LOG_TIMEOUT_KEY); - st->new_transform->delkey(st->new_transform->st); + dispose_transform(&st->new_transform); } static void set_link_quality(struct site *st) @@ -1091,7 +1123,7 @@ static void enter_state_run(struct site *st) transport_peers_clear(st,&st->setup_peers); memset(st->localN,0,NONCELEN); memset(st->remoteN,0,NONCELEN); - st->new_transform->delkey(st->new_transform->st); + dispose_transform(&st->new_transform); memset(st->dhsecret,0,st->dh->len); memset(st->sharedsecret,0,st->sharedsecretlen); set_link_quality(st); @@ -1185,13 +1217,15 @@ static bool_t send_msg7(struct site *st, cstring_t reason) buffer_init(&st->buffer,st->transform->max_start_pad+(4*3)); buf_append_uint32(&st->buffer,LABEL_MSG7); buf_append_string(&st->buffer,reason); - st->current.transform->forwards(st->current.transform->st, - &st->buffer, &transform_err); + if (call_transform_forwards(st, st->current.transform, + &st->buffer, &transform_err)) + goto free_out; buf_prepend_uint32(&st->buffer,LABEL_MSG0); buf_prepend_uint32(&st->buffer,st->index); buf_prepend_uint32(&st->buffer,st->current.remote_session_id); transport_xmit(st,&st->peers,&st->buffer,True); BUF_FREE(&st->buffer); + free_out: return True; } return False; @@ -1288,13 +1322,15 @@ static void site_outgoing(void *sst, struct buffer_if *buf) /* Transform it and send it */ if (buf->size>0) { buf_prepend_uint32(buf,LABEL_MSG9); - st->current.transform->forwards(st->current.transform->st, - buf, &transform_err); + if (call_transform_forwards(st, st->current.transform, + buf, &transform_err)) + goto free_out; buf_prepend_uint32(buf,LABEL_MSG0); buf_prepend_uint32(buf,st->index); buf_prepend_uint32(buf,st->current.remote_session_id); transport_xmit(st,&st->peers,buf,False); } + free_out: BUF_FREE(buf); return; } -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:54 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:54 +0100 Subject: [PATCH 28/41] site: Extra info in name fields for MSG1, clearer processing In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-29-git-send-email-ijackson@chiark.greenend.org.uk> We change the parsing of the names in MSG1 packets to align it with that used for MSG2..4, abolishing the simple memcmp-based "setupsig" arrangement. This means that MSG1 packets, like MSG2..4, can contain extra information in the name fields. This results in the following table of behaviours (where "old secnet" is the version before we introduced additional data at all): MSG Sent name Old secnet New secnet 1 expected ok ok 1 expected\0extra rejected ok, extra data 1 expected/suffix rejected rejected 1 expect rejected rejected 2-4 expected ok ok 2-4 expected\0extra ok, extra ignored ok, extra data 2-4 expected/suffix wrongly accepted rejected 2-4 expect read overrun rejected After the new secnet is widely deployed, we will be able to use the extra data field in MSG1 for public key algorithm agility and public key rollover. Also, intend to introduce a new packet which (like MSG1) is addressed by name rather than the site id; this change makes that easier too. In detail, we: * Make site_incoming extract the message type earlier, and use the message type to choose how to check the address. * Abolish st->setupsig and st->setupsiglen; * Break out a function named_for_us, which uses unpick_msg and then checks the names; * Arrange to keep the unpicked message from named_for_us and reuse it in process_msg1. * Eliminate checking dest==0 for name-addressed packets. This last point constitutes a change to the implemented protocol. The old code would treat a packet as name-addressed iff the destination "index" was zero. However, the requirement to send a zero in this field is not documented. After this patch, peers which send MSG1 with a non-zero destination index will have their messages honoured rather than discarded. But we do document the restriction. There is no other significant functional implication of this last point. Peers which send non-MSG1s with zero destination index will have their packets rejected both before and afterwards (although there may be a change in whether a NAK is sent and in logging) but anyway those peers are broken because all of our generated indexes are nonzero. A downside of this change is that we will now unpick an incoming MSG1 repeatedly until we find which site instance wants it. But this unpicking is not particularly arduous. Signed-off-by: Ian Jackson --- NOTES | 5 ++- site.c | 116 ++++++++++++++++++++++++++++++--------------------------------- 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/NOTES b/NOTES index ddd14a5..3e9d71d 100644 --- a/NOTES +++ b/NOTES @@ -198,7 +198,10 @@ The protocol version selection stuff is not yet implemented. Messages: -1) A->B: *,iA,msg1,A,B,nA +1) A->B: *,iA,msg1,A+,B+,nA + +i* must be encoded as 0. (However, it is permitted for a site to use +zero as its "index" for another site.) 2) B->A: iA,iB,msg2,B+,A+,nB,nA diff --git a/site.c b/site.c index 2e8335a..98bd6b6 100644 --- a/site.c +++ b/site.c @@ -253,9 +253,6 @@ struct site { after this time, initiate a new key exchange */ - uint8_t *setupsig; /* Expected signature of incoming MSG1 packets */ - int32_t setupsiglen; /* Allows us to discard packets quickly if - they are not for us */ bool_t setup_priority; /* Do we have precedence if both sites emit message 1 simultaneously? */ uint32_t log_events; @@ -506,19 +503,15 @@ static bool_t generate_msg1(struct site *st) } static bool_t process_msg1(struct site *st, struct buffer_if *msg1, - const struct comm_addr *src) + const struct comm_addr *src, struct msg *m) { - struct msg m; - /* We've already determined we're in an appropriate state to process an incoming MSG1, and that the MSG1 has correct values of A and B. */ - if (!unpick_msg(st,LABEL_MSG1,msg1,&m)) return False; - transport_record_peer(st,&st->setup_peers,src,"msg1"); - st->setup_session_id=m.source; - memcpy(st->remoteN,m.nR,NONCELEN); + st->setup_session_id=m->source; + memcpy(st->remoteN,m->nR,NONCELEN); return True; } @@ -1254,6 +1247,18 @@ static void site_outgoing(void *sst, struct buffer_if *buf) initiate_key_setup(st,"outgoing packet"); } +static bool_t named_for_us(struct site *st, const struct buffer_if *buf_in, + uint32_t type, struct msg *m) + /* For packets which are identified by the local and remote names. + * If it has our name and our peer's name in it it's for us. */ +{ + struct buffer_if buf[1]; + buffer_readonly_clone(buf,buf_in); + return unpick_msg(st,type,buf,m) + && name_matches(&m->remote,st->remotename) + && name_matches(&m->local,st->localname); +} + /* This function is called by the communication device to deliver packets from our peers. */ static bool_t site_incoming(void *sst, struct buffer_if *buf, @@ -1263,60 +1268,57 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, if (buf->size < 12) return False; + uint32_t msgtype=ntohl(get_uint32(buf->start+8)); uint32_t dest=ntohl(*(uint32_t *)buf->start); - - if (dest==0) { - /* It could be for any site - it should have LABEL_MSG1 and - might have our name and our peer's name in it */ - if (buf->size<(st->setupsiglen+8+NONCELEN)) return False; - if (memcmp(buf->start+8,st->setupsig,st->setupsiglen)==0) { - /* It's addressed to us. Decide what to do about it. */ - dump_packet(st,buf,source,True); - if (st->state==SITE_RUN || st->state==SITE_RESOLVE || - st->state==SITE_WAIT) { - /* We should definitely process it */ - if (process_msg1(st,buf,source)) { - slog(st,LOG_SETUP_INIT,"key setup initiated by peer"); + struct msg named_msg; + + if (msgtype==LABEL_MSG1) { + if (!named_for_us(st,buf,msgtype,&named_msg)) + return False; + /* It's a MSG1 addressed to us. Decide what to do about it. */ + dump_packet(st,buf,source,True); + if (st->state==SITE_RUN || st->state==SITE_RESOLVE || + st->state==SITE_WAIT) { + /* We should definitely process it */ + if (process_msg1(st,buf,source,&named_msg)) { + slog(st,LOG_SETUP_INIT,"key setup initiated by peer"); + enter_new_state(st,SITE_SENTMSG2); + } else { + slog(st,LOG_ERROR,"failed to process incoming msg1"); + } + BUF_FREE(buf); + return True; + } else if (st->state==SITE_SENTMSG1) { + /* We've just sent a message 1! They may have crossed on + the wire. If we have priority then we ignore the + incoming one, otherwise we process it as usual. */ + if (st->setup_priority) { + BUF_FREE(buf); + slog(st,LOG_DUMP,"crossed msg1s; we are higher " + "priority => ignore incoming msg1"); + return True; + } else { + slog(st,LOG_DUMP,"crossed msg1s; we are lower " + "priority => use incoming msg1"); + if (process_msg1(st,buf,source,&named_msg)) { + BUF_FREE(&st->buffer); /* Free our old message 1 */ enter_new_state(st,SITE_SENTMSG2); } else { - slog(st,LOG_ERROR,"failed to process incoming msg1"); + slog(st,LOG_ERROR,"failed to process an incoming " + "crossed msg1 (we have low priority)"); } BUF_FREE(buf); return True; - } else if (st->state==SITE_SENTMSG1) { - /* We've just sent a message 1! They may have crossed on - the wire. If we have priority then we ignore the - incoming one, otherwise we process it as usual. */ - if (st->setup_priority) { - BUF_FREE(buf); - slog(st,LOG_DUMP,"crossed msg1s; we are higher " - "priority => ignore incoming msg1"); - return True; - } else { - slog(st,LOG_DUMP,"crossed msg1s; we are lower " - "priority => use incoming msg1"); - if (process_msg1(st,buf,source)) { - BUF_FREE(&st->buffer); /* Free our old message 1 */ - enter_new_state(st,SITE_SENTMSG2); - } else { - slog(st,LOG_ERROR,"failed to process an incoming " - "crossed msg1 (we have low priority)"); - } - BUF_FREE(buf); - return True; - } } - /* The message 1 was received at an unexpected stage of the - key setup. XXX POLICY - what do we do? */ - slog(st,LOG_UNEXPECTED,"unexpected incoming message 1"); - BUF_FREE(buf); - return True; } - return False; /* Not for us. */ + /* The message 1 was received at an unexpected stage of the + key setup. XXX POLICY - what do we do? */ + slog(st,LOG_UNEXPECTED,"unexpected incoming message 1"); + BUF_FREE(buf); + return True; } if (dest==st->index) { /* Explicitly addressed to us */ - uint32_t msgtype=ntohl(get_uint32(buf->start+8)); if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); switch (msgtype) { case LABEL_NAK: @@ -1565,14 +1567,6 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, /* The information we expect to see in incoming messages of type 1 */ /* fixme: lots of unchecked overflows here, but the results are only corrupted packets rather than undefined behaviour */ - st->setupsiglen=strlen(st->remotename)+strlen(st->localname)+8; - st->setupsig=safe_malloc(st->setupsiglen,"site_apply"); - put_uint32(st->setupsig+0,LABEL_MSG1); - put_uint16(st->setupsig+4,strlen(st->remotename)); - memcpy(&st->setupsig[6],st->remotename,strlen(st->remotename)); - put_uint16(st->setupsig+(6+strlen(st->remotename)),strlen(st->localname)); - memcpy(&st->setupsig[8+strlen(st->remotename)],st->localname, - strlen(st->localname)); st->setup_priority=(strcmp(st->localname,st->remotename)>0); buffer_new(&st->buffer,SETUP_BUFFER_LEN); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:38 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:38 +0100 Subject: [PATCH 12/41] serpent: Ad-hoc debugging facility In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-13-git-send-email-ijackson@chiark.greenend.org.uk> Provide an ad-hoc debugging facility in serpent.c. If the "#if 0" is changed to "#if 1", the key material, plaintext and ciphertext of all Serpent operations is printed in hex to stderr. We provide a new header file hexdebug.h to facilitate this. And we use this new header file in the "#if 0" debugging in transform_setkey. No functional change. Signed-off-by: Ian Jackson --- hexdebug.h | 15 +++++++++++++++ serpent.c | 31 +++++++++++++++++++++++++++++++ transform.c | 5 ++--- 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 hexdebug.h diff --git a/hexdebug.h b/hexdebug.h new file mode 100644 index 0000000..4139f72 --- /dev/null +++ b/hexdebug.h @@ -0,0 +1,15 @@ +#ifndef HEXDEBUG_H +#define HEXDEBUG_H + +#include +#include + +static inline void hexdebug(FILE *file, const void *buffer, size_t len) +{ + const uint8_t *array=buffer; + size_t i; + for (i=0; i +#include "hexdebug.h" #include "serpent.h" #include "serpentsboxes.h" @@ -41,6 +42,26 @@ #endif /* !defined(SERPENT_BIGENDIAN) */ +#if 0 + +#include + +static void SERP_DEBUG(const char *str1, + const void *ary, int sz, + const char *str2) +{ + fprintf(stderr,"%s",str1); + hexdebug(stderr,ary,sz); + fprintf(stderr,"%s",str2); +} + +#else + +#define SERP_DEBUG(str1,aryv,sz,str2) /*empty*/ + +#endif + + static uint32_t serpent_get_32bit(const uint8_t *basep, int lenbytes, int offset) { @@ -65,6 +86,8 @@ void SERPENT_DECORATE(makekey)(struct keyInstance *key, int keyLen, uint32_t j; uint32_t w[132],k[132]; + SERP_DEBUG("SERPENT makekey ",keyMaterial,keyLen/8,"\n"); + for(i=0; i"); + x0=serpent_get_32bit(plaintext,16,+0); x1=serpent_get_32bit(plaintext,16,+4); x2=serpent_get_32bit(plaintext,16,+8); @@ -234,6 +259,8 @@ void SERPENT_DECORATE(encrypt)(struct keyInstance *key, serpent_put_32bit(ciphertext,16,+4, x1); serpent_put_32bit(ciphertext,16,+8, x2); serpent_put_32bit(ciphertext,16,12, x3); + + SERP_DEBUG(" ",ciphertext,16,"\n"); } void SERPENT_DECORATE(decrypt)(struct keyInstance *key, @@ -243,6 +270,8 @@ void SERPENT_DECORATE(decrypt)(struct keyInstance *key, register uint32_t x0, x1, x2, x3; register uint32_t y0, y1, y2, y3; + SERP_DEBUG("SERPENT decrypt ",ciphertext,16," ->"); + x0=serpent_get_32bit(ciphertext,16,+0); x1=serpent_get_32bit(ciphertext,16,+4); x2=serpent_get_32bit(ciphertext,16,+8); @@ -352,4 +381,6 @@ void SERPENT_DECORATE(decrypt)(struct keyInstance *key, serpent_put_32bit(plaintext,16,+4, x1); serpent_put_32bit(plaintext,16,+8, x2); serpent_put_32bit(plaintext,16,12, x3); + + SERP_DEBUG(" ",plaintext,16,"\n"); } diff --git a/transform.c b/transform.c index a0665ad..281e667 100644 --- a/transform.c +++ b/transform.c @@ -13,6 +13,7 @@ #include "util.h" #include "serpent.h" #include "unaligned.h" +#include "hexdebug.h" /* Required key length in bytes */ #define REQUIRED_KEYLEN ((512+64+32)/8) @@ -49,10 +50,8 @@ static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) #if 0 { - int i; printf("Setting key to: "); - for (i=0; i References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-41-git-send-email-ijackson@chiark.greenend.org.uk> We introduce a new message PROD which requests that the peer initiate a key exchange with us, if it doesn't already have a key. This helps significantly reduce a possible "dead period" when one end of a connection is restarted during key exchange. The dead period is now limited to the time taken for the interrupted key exchange to time out. Signed-off-by: Ian Jackson --- NOTES | 34 +++++++++++++++++++++++ magic.h | 1 + site.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- udp.c | 1 + 4 files changed, 113 insertions(+), 15 deletions(-) diff --git a/NOTES b/NOTES index 7ead923..40cbf04 100644 --- a/NOTES +++ b/NOTES @@ -291,3 +291,37 @@ vaguely recent version of secnet. (In fact, there is no evidence in the git history of it ever being sent.) This message number is reserved. + +11) *,*,PROD,A,B + +Sent in response to a NAK from B to A. Requests that B initiates a +key exchange with A, if B is willing and lacks a transport key for A. +(If B doesn't have A's address configured, implicitly supplies A's +public address.) + +This is necessary because if one end of a link (B) is restarted while +a key exchange is in progress, the following bad state can persist: +the non-restarted end (A) thinks that the key is still valid and keeps +sending packets, but B either doesn't realise that a key exchange with +A is necessary or (if A is a mobile site) doesn't know A's public IP +address. + +Normally in these circumstances B would send NAKs to A, causing A to +initiate a key exchange. However if A and B were already in the +middle of a key exchange then A will not want to try another one until +the first one has timed out ("setup-time" x "setup-retries") and then +the key exchange retry timeout ("wait-time") has elapsed. + +However if B's setup has timed out, B would be willing to participate +in a key exchange initiated by A, if A could be induced to do so. +This is the purpose of the PROD packet. + +We send no more PRODs than we would want to send data packets, to +avoid a traffic amplification attack. We also send them only in state +WAIT, as in other states we wouldn't respond favourably. And we only +honour them if we don't already have a key. + +With PROD, the period of broken communication due to a key exchange +interrupted by a restart is limited to the key exchange total +retransmission timeout, rather than also including the key exchange +retry timeout. diff --git a/magic.h b/magic.h index e98f681..598a79e 100644 --- a/magic.h +++ b/magic.h @@ -15,6 +15,7 @@ #define LABEL_MSG7 0x07070707 #define LABEL_MSG8 0x08080808 #define LABEL_MSG9 0x09090909 +#define LABEL_PROD 0x0a0a0a0a /* uses of the 32-bit capability bitmap */ #define CAPAB_EARLY 0x00000000 /* no Early flags yet (see NOTES) */ diff --git a/site.c b/site.c index 909e8e9..0b39232 100644 --- a/site.c +++ b/site.c @@ -206,7 +206,8 @@ static void transport_peers_copy(struct site *st, transport_peers *dst, static void transport_setup_msgok(struct site *st, const struct comm_addr *a); static void transport_data_msgok(struct site *st, const struct comm_addr *a); static bool_t transport_compute_setupinit_peers(struct site *st, - const struct comm_addr *configured_addr /* 0 if none or not found */); + const struct comm_addr *configured_addr /* 0 if none or not found */, + const struct comm_addr *prod_hint_addr /* 0 if none */); static void transport_record_peer(struct site *st, transport_peers *peers, const struct comm_addr *addr, const char *m); @@ -264,6 +265,7 @@ struct site { /* runtime information */ uint32_t state; uint64_t now; /* Most recently seen time */ + bool_t allow_send_prod; /* The currently established session */ struct data_key current; @@ -333,7 +335,8 @@ static void delete_one_key(struct site *st, struct data_key *key, const char *reason /* may be 0 meaning don't log*/, const char *which /* ignored if !reasonn */, uint32_t loglevel /* ignored if !reasonn */); -static bool_t initiate_key_setup(struct site *st, cstring_t reason); +static bool_t initiate_key_setup(struct site *st, cstring_t reason, + const struct comm_addr *prod_hint); static void enter_state_run(struct site *st); static bool_t enter_state_resolve(struct site *st); static bool_t enter_new_state(struct site *st,uint32_t next); @@ -544,6 +547,10 @@ static bool_t unpick_msg(struct site *st, uint32_t type, m->remote_capabilities=buf_unprepend_uint32(&m->remote.extrainfo); } if (!unpick_name(msg,&m->local)) return False; + if (type==LABEL_PROD) { + CHECK_EMPTY(msg); + return True; + } CHECK_AVAIL(msg,NONCELEN); m->nR=buf_unprepend(msg,NONCELEN); if (type==LABEL_MSG1) { @@ -987,7 +994,7 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0, slog(st,LOG_SEC,"transform: %s (aux: %s, new: %s)", transform_err,auxkey_err,newkey_err); - initiate_key_setup(st,"incoming message would not decrypt"); + initiate_key_setup(st,"incoming message would not decrypt",0); send_nak(src,m.dest,m.source,m.type,msg0,"message would not decrypt"); return False; @@ -1017,7 +1024,7 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0, transport_data_msgok(st,src); /* See whether we should start negotiating a new key */ if (st->now > st->renegotiate_key_time) - initiate_key_setup(st,"incoming packet in renegotiation window"); + initiate_key_setup(st,"incoming packet in renegotiation window",0); return True; default: slog(st,LOG_SEC,"incoming encrypted message of type %08x " @@ -1098,7 +1105,7 @@ static void site_resolve_callback(void *sst, struct in_addr *address) slog(st,LOG_ERROR,"resolution of %s failed",st->address); ca_use=0; } - if (transport_compute_setupinit_peers(st,ca_use)) { + if (transport_compute_setupinit_peers(st,ca_use,0)) { enter_new_state(st,SITE_SENTMSG1); } else { /* Can't figure out who to try to to talk to */ @@ -1107,14 +1114,15 @@ static void site_resolve_callback(void *sst, struct in_addr *address) } } -static bool_t initiate_key_setup(struct site *st, cstring_t reason) +static bool_t initiate_key_setup(struct site *st, cstring_t reason, + const struct comm_addr *prod_hint) { if (st->state!=SITE_RUN) return False; slog(st,LOG_SETUP_INIT,"initiating key exchange (%s)",reason); if (st->address) { slog(st,LOG_SETUP_INIT,"resolving peer address"); return enter_state_resolve(st); - } else if (transport_compute_setupinit_peers(st,0)) { + } else if (transport_compute_setupinit_peers(st,0,prod_hint)) { return enter_new_state(st,SITE_SENTMSG1); } slog(st,LOG_SETUP_INIT,"key exchange failed: no address for peer"); @@ -1326,6 +1334,30 @@ static void enter_state_wait(struct site *st) /* XXX Erase keys etc. */ } +static void generate_prod(struct site *st, struct buffer_if *buf) +{ + buffer_init(buf,0); + buf_append_uint32(buf,0); + buf_append_uint32(buf,0); + buf_append_uint32(buf,LABEL_PROD); + buf_append_string(buf,st->localname); + buf_append_string(buf,st->remotename); +} + +static void generate_send_prod(struct site *st, + const struct comm_addr *source) +{ + if (!st->allow_send_prod) return; /* too soon */ + if (!(st->state==SITE_RUN || st->state==SITE_RESOLVE || + st->state==SITE_WAIT)) return; /* we'd ignore peer's MSG1 */ + + slog(st,LOG_SETUP_INIT,"prodding peer for key exchange"); + st->allow_send_prod=0; + generate_prod(st,&st->scratch); + dump_packet(st,&st->scratch,source,False); + source->comm->sendmsg(source->comm->st, &st->scratch, source); +} + static inline void site_settimeout(uint64_t timeout, int *timeout_io) { if (timeout) { @@ -1398,6 +1430,8 @@ static void site_outgoing(void *sst, struct buffer_if *buf) return; } + st->allow_send_prod=1; + /* In all other states we consider delivering the packet if we have a valid key and a valid address to send it to. */ if (current_valid(st) && transport_peers_valid(&st->peers)) { @@ -1419,7 +1453,7 @@ static void site_outgoing(void *sst, struct buffer_if *buf) slog(st,LOG_DROP,"discarding outgoing packet of size %d",buf->size); BUF_FREE(buf); - initiate_key_setup(st,"outgoing packet"); + initiate_key_setup(st,"outgoing packet",0); } static bool_t named_for_us(struct site *st, const struct buffer_if *buf_in, @@ -1435,7 +1469,10 @@ static bool_t named_for_us(struct site *st, const struct buffer_if *buf_in, } /* This function is called by the communication device to deliver - packets from our peers. */ + packets from our peers. + It should return True if the packet is recognised as being for + this current site instance (and should therefore not be processed + by other sites), even if the packet was otherwise ignored. */ static bool_t site_incoming(void *sst, struct buffer_if *buf, const struct comm_addr *source) { @@ -1492,6 +1529,20 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, BUF_FREE(buf); return True; } + if (msgtype==LABEL_PROD) { + if (!named_for_us(st,buf,msgtype,&named_msg)) + return False; + dump_packet(st,buf,source,True); + if (st->state!=SITE_RUN) { + slog(st,LOG_DROP,"ignoring PROD when not in state RUN"); + } else if (current_valid(st)) { + slog(st,LOG_DROP,"ignoring PROD when we think we have a key"); + } else { + initiate_key_setup(st,"peer sent PROD packet",source); + } + BUF_FREE(buf); + return True; + } if (dest==st->index) { /* Explicitly addressed to us */ if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True); @@ -1500,7 +1551,9 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, /* If the source is our current peer then initiate a key setup, because our peer's forgotten the key */ if (get_uint32(buf->start+4)==st->current.remote_session_id) { - initiate_key_setup(st,"received a NAK"); + bool_t initiated; + initiated = initiate_key_setup(st,"received a NAK",0); + if (!initiated) generate_send_prod(st,source); } else { slog(st,LOG_SEC,"bad incoming NAK"); } @@ -1742,6 +1795,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->log_events=string_list_to_word(dict_lookup(dict,"log-events"), log_event_table,"site"); + st->allow_send_prod=0; + st->tunname=safe_malloc(strlen(st->localname)+strlen(st->remotename)+5, "site_apply"); sprintf(st->tunname,"%s<->%s",st->localname,st->remotename); @@ -1889,23 +1944,30 @@ static void transport_record_peer(struct site *st, transport_peers *peers, } static bool_t transport_compute_setupinit_peers(struct site *st, - const struct comm_addr *configured_addr /* 0 if none or not found */) { + const struct comm_addr *configured_addr /* 0 if none or not found */, + const struct comm_addr *prod_hint_addr /* 0 if none */) { - if (!configured_addr && !transport_peers_valid(&st->peers)) + if (!configured_addr && !prod_hint_addr && + !transport_peers_valid(&st->peers)) return False; slog(st,LOG_SETUP_INIT, - (!configured_addr ? "using only %d old peer address(es)" - : "using configured address, and/or perhaps %d old peer address(es)"), + "using:%s%s %d old peer address(es)", + configured_addr ? " configured address;" : "", + prod_hint_addr ? " PROD hint address;" : "", st->peers.npeers); /* Non-mobile peers havve st->peers.npeers==0 or ==1, since they * have transport_peers_max==1. The effect is that this code * always uses the configured address if supplied, or otherwise - * the existing data peer if one exists; this is as desired. */ + * the address of the incoming PROD, or the existing data peer if + * one exists; this is as desired. */ transport_peers_copy(st,&st->setup_peers,&st->peers); + if (prod_hint_addr) + transport_record_peer(st,&st->setup_peers,prod_hint_addr,"prod"); + if (configured_addr) transport_record_peer(st,&st->setup_peers,configured_addr,"setupinit"); diff --git a/udp.c b/udp.c index 1e637b6..97b92a6 100644 --- a/udp.c +++ b/udp.c @@ -19,6 +19,7 @@ #include #include #include "util.h" +#include "magic.h" #include "unaligned.h" #include "ipaddr.h" #include "magic.h" -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:45 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:45 +0100 Subject: [PATCH 19/41] transform: Provide Serpent-EAX transform In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-20-git-send-email-ijackson@chiark.greenend.org.uk> This provides an alternative to the (rather badly broken) serpent256-cbc transform. In this patch, there is not yet any algorith negotiation for a smooth upgrade, nor any changes to the example configurations. Signed-off-by: Ian Jackson --- Makefile.in | 6 +- README | 5 + modules.c | 1 + secnet.8 | 21 ++++- secnet.h | 3 + transform-eax.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 338 insertions(+), 5 deletions(-) create mode 100644 transform-eax.c diff --git a/Makefile.in b/Makefile.in index 401fbb8..5a140fb 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,9 +53,9 @@ mandir:=@mandir@ TARGETS:=secnet OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \ - resolver.o random.o udp.o site.o transform-cbcmac.o \ - netlink.o rsa.o dh.o \ - serpentbe.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ + resolver.o random.o udp.o site.o transform-cbcmac.o transform-eax.o \ + netlink.o rsa.o dh.o serpent.o serpentbe.o \ + md5.o sha512.o version.o tun.o slip.o sha1.o ipaddr.o log.o \ process.o @LIBOBJS@ \ hackypar.o diff --git a/README b/README index 93730e9..71a5a44 100644 --- a/README +++ b/README @@ -336,6 +336,11 @@ setup but more relaxed about using old keys. These are noted with "mobile:", above, and apply whether the mobile peer is local or remote. +** transform-eax + +Defines: + eax-serpent (closure => transform closure) + ** transform-cbcmac Defines: diff --git a/modules.c b/modules.c index 0290cd4..724ccbb 100644 --- a/modules.c +++ b/modules.c @@ -7,6 +7,7 @@ void init_builtin_modules(dict_t *dict) udp_module(dict); util_module(dict); site_module(dict); + transform_eax_module(dict); transform_cbcmac_module(dict); netlink_module(dict); rsa_module(dict); diff --git a/secnet.8 b/secnet.8 index ef07a76..2bf2250 100644 --- a/secnet.8 +++ b/secnet.8 @@ -415,8 +415,8 @@ A \fIrandomsource closure\fR is a source of random numbers. .PP Read the contents of the file \fIPATH\fR (a string) and return it as a string. -.SS serpent256-cbc -\fBserpent256-cbc(\fIDICT\fB)\fR => \fItransform closure\fR +.SS eax-serpent +\eax-fBserpent(\fIDICT\fB)\fR => \fItransform closure\fR .PP Valid keys in the \fIDICT\fR argument are: .TP @@ -425,10 +425,27 @@ The maximum acceptable difference between the sequence number in a received, decrypted message and the previous one. The default is 10. It may be necessary to increase this is if connectivity is poor. +.TP +.B tag-length-bytes +The length of the message authentication tag. The default is 16, +for a 128-bit tag length. It must be no longer than the Serpent +blocksize, 16. Must be have the same value at both ends. +.TP +.B padding-rounding +Messages are padded to a multiple of this many bytes. This +serves to obscure the exact length of messages. The default is 16, .PP A \fItransform closure\fR is a reversible means of transforming messages for transmission over a (presumably) insecure network. It is responsible for both confidentiality and integrity. + +.SS serpent256-cbc +\fBserpent256-cbc(\fIDICT\fB)\fR => \fItransform closure\fR +.PP +Valid keys in the \fIDICT\fR argument are: +.TP +.B max-sequence-skew +As above. .PP Note that this uses a big-endian variant of the Serpent block cipher (which is not compatible with most other Serpent implementations). diff --git a/secnet.h b/secnet.h index 5e66a17..0433c1e 100644 --- a/secnet.h +++ b/secnet.h @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -217,6 +219,7 @@ extern init_module random_module; extern init_module udp_module; extern init_module util_module; extern init_module site_module; +extern init_module transform_eax_module; extern init_module transform_cbcmac_module; extern init_module netlink_module; extern init_module rsa_module; diff --git a/transform-eax.c b/transform-eax.c new file mode 100644 index 0000000..5c7a120 --- /dev/null +++ b/transform-eax.c @@ -0,0 +1,307 @@ +/* + * eax-transform.c: EAX-Serpent bulk data transformation + * + * We use EAX with the following parameters: + * + * Plaintext: + * Concatenation of: + * Data packet as supplied to us + * Zero or more zero bytes ignored by receiver } padding + * One byte padding length } + * This is a bit like PKCS#5. It helps disguise message lengths. + * It also provides a further room for future expansion. When + * transmitting we pad the message to the next multiple of + * a configurable rounding factor, 16 bytes by default. + * + * Transmitted message: + * Concatenation of: + * EAX ciphertext + * 32-bit sequence number (initially zero) + * The sequence number allows us to discard far-too-old + * packets. + * + * Nonce: + * Concatenation of: + * 32-bit sequence number (big endian) + * initial value comes from SHA-512 hash (see below) + * 1 byte: 0x01 if sender has setup priority, 0x00 if it doesn't + * (ie, the direction of data flow) + * + * Header: None + * + * Tag length: + * 16 bytes (128 bits) by default + * + * Key: + * The first 32 bytes of the SHA-512 hash of the shared secret + * from the DH key exchange (the latter being expressed as + * the shortest possible big-endian octet string). + * + * The bytes [32,40> of the hash of the shared secret are used for + * initial sequence numbers: [32,36> for those sent by the end without + * setup priority, [36,40> for those for the other end. + * + */ + +#include "secnet.h" +#include "unaligned.h" +#include "util.h" +#include "serpent.h" +#include "sha512.h" +#include "transform-common.h" +#include "hexdebug.h" + +#define BLOCK_SIZE 16 +#define SEQLEN 4 + +struct transform_params { + uint32_t max_seq_skew, tag_length, padding_mask; +}; + +struct transform { + closure_t cl; + struct transform_if ops; + struct transform_params p; +}; + +struct transform_inst { + struct transform_inst_if ops; + struct transform_params p; + unsigned keyed:1; + /* remaining valid iff keyed */ + unsigned direction:1; + uint32_t sendseq; + uint32_t lastrecvseq; + struct keyInstance key; + uint8_t info_b[BLOCK_SIZE], info_p[BLOCK_SIZE]; +}; + +static void block_encrypt(struct transform_inst *transform_inst, + uint8_t dst[BLOCK_SIZE], + const uint8_t src[BLOCK_SIZE]) +{ + serpent_encrypt(&transform_inst->key, src, dst); +} + +#define INFO struct transform_inst *transform_inst +#define I transform_inst +#define EAX_ENTRYPOINT_DECL static +#define BLOCK_ENCRYPT(dst,src) block_encrypt(transform_inst,dst,src) +#define INFO_B (transform_inst->info_b) +#define INFO_P (transform_inst->info_p) + +#include "eax.c" + +#if 0 + +#define TEAX_DEBUG(ary,sz) teax_debug(__func__,__LINE__,#ary,#sz,ary,sz) +static void teax_debug(const char *func, int line, + const char *aryp, const char *szp, + const void *ary, size_t sz) +{ + fprintf(stderr,"TEAX %s:%-3d %10s %15s : ", func,line,aryp,szp); + hexdebug(stderr,ary,sz); + fprintf(stderr,"\n"); +} + +#else + +#define TEAX_DEBUG(ary,sz) /* empty */ + +#endif + +static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen, + bool_t direction) +{ + struct transform_inst *ti=sst; + struct sha512_ctx hash_ctx; + uint8_t hash_out[64]; + + TEAX_DEBUG(key,keylen); + + sha512_init_ctx(&hash_ctx); + sha512_process_bytes(key, keylen, &hash_ctx); + sha512_finish_ctx(&hash_ctx, hash_out); + + TEAX_DEBUG(hash_out,32); + TEAX_DEBUG(hash_out+32,8); + + ti->direction=direction; + ti->sendseq=get_uint32(hash_out+32+direction*4); + ti->lastrecvseq=get_uint32(hash_out+32+!direction*4); + serpent_makekey(&ti->key, 32*8, hash_out); + eax_setup(ti); + ti->keyed=True; + + return True; +} + +TRANSFORM_VALID; + +TRANSFORM_DESTROY; + +static void transform_delkey(void *sst) +{ + struct transform_inst *ti=sst; + + FILLZERO(ti->key); + FILLZERO(ti->info_b); + FILLZERO(ti->info_p); + ti->keyed=False; +} + +static uint32_t transform_forward(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + + KEYED_CHECK; + + size_t padlen = ti->p.padding_mask - buf->size; + padlen &= ti->p.padding_mask; + padlen++; + + uint8_t *pad = buf_append(buf,padlen); + memset(pad, 0, padlen-1); + pad[padlen-1] = padlen; + + uint8_t nonce[SEQLEN+1]; + put_uint32(nonce,ti->sendseq); + nonce[SEQLEN] = ti->direction; + + TEAX_DEBUG(nonce,sizeof(nonce)); + TEAX_DEBUG(buf->start,buf->size); + + assert(buf_append(buf,ti->p.tag_length)); + eax_encrypt(ti, nonce,sizeof(nonce), 0,0, + buf->start,buf->size-ti->p.tag_length, + ti->p.tag_length, buf->start); + + TEAX_DEBUG(buf->start,buf->size); + + memcpy(buf_append(buf,SEQLEN), nonce, SEQLEN); + + TEAX_DEBUG(nonce,SEQLEN); + + ti->sendseq++; + + return 0; +} + +static uint32_t transform_reverse(void *sst, struct buffer_if *buf, + const char **errmsg) +{ + struct transform_inst *ti=sst; + + KEYED_CHECK; + + TEAX_DEBUG(buf->start,buf->size); + + uint8_t nonce[SEQLEN+1]; + const uint8_t *seqp = buf_unappend(buf,SEQLEN); + if (!seqp) goto too_short; + + TEAX_DEBUG(seqp,SEQLEN); + + uint32_t seqnum = get_uint32(seqp); + + memcpy(nonce,seqp,SEQLEN); + nonce[4] = !ti->direction; + + TEAX_DEBUG(nonce,sizeof(nonce)); + TEAX_DEBUG(buf->start,buf->size); + + bool_t ok = eax_decrypt(ti, nonce,sizeof(nonce), 0,0, buf->start,buf->size, + ti->p.tag_length, buf->start); + if (!ok) { + TEAX_DEBUG(0,0); + *errmsg="EAX decryption failed"; + return 1; + } + assert(buf->size >= (int)ti->p.tag_length); + buf->size -= ti->p.tag_length; + + TEAX_DEBUG(buf->start,buf->size); + + const uint8_t *padp = buf_unappend(buf,1); + if (!padp) goto too_short; + + TEAX_DEBUG(padp,1); + + size_t padlen = *padp; + if (!buf_unappend(buf,padlen-1)) goto too_short; + + SEQNUM_CHECK(seqnum, ti->p.max_seq_skew); + + TEAX_DEBUG(buf->start,buf->size); + + return 0; + + too_short: + *errmsg="ciphertext or plaintext too short"; + return 1; +} + +static struct transform_inst_if *transform_create(void *sst) +{ + struct transform *st=sst; + + TRANSFORM_CREATE_CORE; + + ti->p=st->p; + + return &ti->ops; +} + +static list_t *transform_apply(closure_t *self, struct cloc loc, + dict_t *context, list_t *args) +{ + struct transform *st; + item_t *item; + dict_t *dict; + + st=safe_malloc(sizeof(*st),"eax-serpent"); + st->cl.description="eax-serpent"; + st->cl.type=CL_TRANSFORM; + st->cl.apply=NULL; + st->cl.interface=&st->ops; + st->ops.st=st; + + /* First parameter must be a dict */ + item=list_elem(args,0); + if (!item || item->type!=t_dict) + cfgfatal(loc,"eax-serpent","parameter must be a dictionary\n"); + dict=item->data.dict; + + st->p.max_seq_skew=dict_read_number(dict, "max-sequence-skew", + False, "eax-serpent", loc, 10); + + st->p.tag_length=dict_read_number(dict, "tag-length-bytes", + False, "eax-serpent", loc, 128/8); + if (st->p.tag_length<1 || st->p.tag_length>BLOCK_SIZE) + cfgfatal(loc,"eax-serpent","tag-length-bytes out of range 0..%d\n", + BLOCK_SIZE); + + uint32_t padding_round=dict_read_number(dict, "padding-rounding", + False, "eax-serpent", loc, 16); + if (padding_round & (padding_round-1)) + cfgfatal(loc,"eax-serpent","padding-round not a power of two\n"); + if (padding_round > 255) + cfgfatal(loc,"eax-serpent","padding-round must be 1..128\n"); + if (padding_round == 0) + padding_round = 1; + st->p.padding_mask = padding_round-1; + + st->ops.max_start_pad=0; + st->ops.max_end_pad= padding_round + st->p.tag_length + SEQLEN; + + st->ops.keylen=0; + st->ops.create=transform_create; + + return new_closure(&st->cl); +} + +void transform_eax_module(dict_t *dict) +{ + add_closure(dict,"eax-serpent",transform_apply); +} -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:43 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:43 +0100 Subject: [PATCH 17/41] transform: Allow DH to set the key size In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-18-git-send-email-ijackson@chiark.greenend.org.uk> It turns out that the current Serpent CBC-MAC transform takes the raw DH shared secret, and parcels it up in byte ranges for the various uses (some of which are published). Well, obviously this is not a good idea. But also it means the interface isn't set up to allow the size of the key data provided to the transform to be determined by the size of the DH modulus. Fix this latter interface problem. Now a transform can set its keylen to 0, meaning it will be provided with the whole of the DH private value. We don't use this new feature yet. We can't make the existing transform use it without breaking compatibility, but it will be used by the new EAX-based transform. Signed-off-by: Ian Jackson --- dh.c | 4 ++++ secnet.h | 3 ++- site.c | 14 ++++++++------ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/dh.c b/dh.c index 2383192..c37b538 100644 --- a/dh.c +++ b/dh.c @@ -125,6 +125,10 @@ static list_t *dh_apply(closure_t *self, struct cloc loc, dict_t *context, st->ops.len=sz; + st->ops.ceil_len=(mpz_sizeinbase(&st->p,2)+7)/8; + /* According to the docs, mpz_sizeinbase(,256) is allowed to return + * an answer which is 1 too large. But mpz_sizeinbase(,2) isn't. */ + return new_closure(&st->cl); } diff --git a/secnet.h b/secnet.h index dbca664..7d7eb4f 100644 --- a/secnet.h +++ b/secnet.h @@ -397,7 +397,7 @@ struct transform_if { void *st; int32_t max_start_pad; /* these three are all <<< INT_MAX */ int32_t max_end_pad; - int32_t keylen; + int32_t keylen; /* 0 means give the transform exactly as much as there is */ transform_createinstance_fn *create; }; @@ -444,6 +444,7 @@ typedef void dh_makeshared_fn(void *st, uint8_t *secret, struct dh_if { void *st; int32_t len; /* Approximate size of modulus in bytes */ + int32_t ceil_len; /* Number of bytes just sufficient to contain modulus */ dh_makepublic_fn *makepublic; dh_makeshared_fn *makeshared; }; diff --git a/site.c b/site.c index b9b4d0d..566b215 100644 --- a/site.c +++ b/site.c @@ -288,6 +288,7 @@ struct site { uint64_t timeout; /* Timeout for current state */ uint8_t *dhsecret; uint8_t *sharedsecret; + uint32_t sharedsecretlen; struct transform_inst_if *new_transform; /* For key setup/verify */ }; @@ -561,11 +562,11 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, /* Generate the shared key */ st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->transform->keylen); + st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->transform->keylen); + st->sharedsecretlen); return True; } @@ -609,10 +610,10 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, m.pk[m.pklen]=0; /* Generate the shared key */ st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk, - st->sharedsecret,st->transform->keylen); + st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->transform->keylen); + st->sharedsecretlen); return True; } @@ -1009,7 +1010,7 @@ static void enter_state_run(struct site *st) memset(st->remoteN,0,NONCELEN); st->new_transform->delkey(st->new_transform->st); memset(st->dhsecret,0,st->dh->len); - memset(st->sharedsecret,0,st->transform->keylen); + memset(st->sharedsecret,0,st->sharedsecretlen); set_link_quality(st); } @@ -1557,7 +1558,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, transport_peers_clear(st,&st->setup_peers); /* XXX mlock these */ st->dhsecret=safe_malloc(st->dh->len,"site:dhsecret"); - st->sharedsecret=safe_malloc(st->transform->keylen,"site:sharedsecret"); + st->sharedsecretlen=st->transform->keylen?:st->dh->ceil_len; + st->sharedsecret=safe_malloc(st->sharedsecretlen,"site:sharedsecret"); /* We need to compute some properties of our comms */ #define COMPUTE_WORST(pad) \ -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:41:04 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:41:04 +0100 Subject: [PATCH 38/41] udp.c: call buffer_init In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-39-git-send-email-ijackson@chiark.greenend.org.uk> Nothing in udp.c call buffer_init. This might result in start padding underflows (assertion failures) if packets come in via routes that don't strip (much) off the front and then go out via routes that do add lots at the front. Signed-off-by: Ian Jackson --- udp.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/udp.c b/udp.c index 42fbb1f..1e637b6 100644 --- a/udp.c +++ b/udp.c @@ -102,6 +102,7 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds) fromlen=sizeof(from); BUF_ASSERT_FREE(st->rbuf); BUF_ALLOC(st->rbuf,"udp_afterpoll"); + buffer_init(st->rbuf,calculate_max_start_pad()); rv=recvfrom(st->fd, st->rbuf->start, st->rbuf->len, 0, (struct sockaddr *)&from, &fromlen); if (rv>0) { -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:50 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:50 +0100 Subject: [PATCH 24/41] NOTES: Improve documentation of NAKs. In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-25-git-send-email-ijackson@chiark.greenend.org.uk> Improve the description of the function of NAK packets. Document an ancient form of NAK, MSG8. Add a missing heading "Other messages" and put the description of the NAK message and of the obsolete NAK in it. Signed-off-by: Ian Jackson --- NOTES | 41 +++++++++++++++++++++-------------------- 1 files changed, 21 insertions(+), 20 deletions(-) diff --git a/NOTES b/NOTES index 84453df..6a245ec 100644 --- a/NOTES +++ b/NOTES @@ -247,32 +247,33 @@ retransmit or confirm reception. It is suggested that this message be sent when a key times out, or the tunnel is forcibly terminated for some reason. -8) i?,i?,NAK (encoded as zero) +**** Protocol sub-goal 3: send a packet -If the link-layer can't work out what to do with a packet (session has -gone away, etc.) it can transmit a NAK back to the sender. The sender -can then try to verify whether the session is alive by sending ping -packets, and forget the key if it isn't. Potential denial-of-service -if the attacker can stop the ping/pong packets getting through (the -key will be forgotten and another key setup must take place), but if -they can delete packets then we've lost anyway... +8) i?,i?,msg0,(send-packet/msg9,packet)_k -The attacker can of course forge NAKs since they aren't protected. But -if they can only forge packets then they won't be able to stop the -ping/pong working. Trust in NAKs can be rate-limited... +Some messages may take a long time to prepare (software modexp on slow +machines); this is a "please wait" message to indicate that a message +is in preparation. -Alternative idea (which is actually implemented): if you receive a -packet you can't decode, because there's no key established, then -initiate key setup... +**** Other messages -Keepalives are probably a good idea. +9) i?,i?,NAK (NAK is encoded as zero) -**** Protocol sub-goal 3: send a packet +If the link-layer can't work out what to do with a packet (session has +gone away, etc.) it can transmit a NAK back to the sender. -9) i?,i?,msg0,(send-packet/msg9,packet)_k +This can alert the sender to the situation where the sender has a key +but the receiver doesn't (eg because it has been restarted). The +sender, on receiving the NAK, will try to initiate a key exchange. -Some messages may take a long time to prepare (software modexp on slow -machines); this is a "please wait" message to indicate that a message -is in preparation. +Forged (or overly delayed) NAKs can cause wasted resources due to +spurious key exchange initiation, but there is a limit on this because +of the key exchange retry timeout. 10) i?,i?,msg8,A,B,nA,nB,msg? + +This is an obsolete form of NAK packet which is not sent by any even +vaguely recent version of secnet. (In fact, there is no evidence in +the git history of it ever being sent.) + +This message number is reserved. -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:40 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:40 +0100 Subject: [PATCH 14/41] crypto: Copy an AES (Rijndael) implementation into tree In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-15-git-send-email-ijackson@chiark.greenend.org.uk> We are going to want an implementation of AES so that we can run publicly-provided test vectors of our EAX implementation. qemu seem to have a version with a fairly convenient shape, so lift it wholesale into our tree, from upstream qemu (their git commit 55616505876d6683130076b810a27c7889321560). The files in this patch are _exactly_ as copied from that qemu tree, so that we can separate out our own changes. Signed-off-by: Ian Jackson --- aes.c | 1314 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ aes.h | 26 ++ 2 files changed, 1340 insertions(+), 0 deletions(-) create mode 100644 aes.c create mode 100644 aes.h diff --git a/aes.c b/aes.c new file mode 100644 index 0000000..eb37adb --- /dev/null +++ b/aes.c @@ -0,0 +1,1314 @@ +/** + * + * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project. + */ +/* + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "qemu-common.h" +#include "aes.h" + +#ifndef NDEBUG +#define NDEBUG +#endif + +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +/* This controls loop-unrolling in aes_core.c */ +#undef FULL_UNROLL +# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) +# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +static const u32 Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +static const u32 Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +static const u32 Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +static const u32 Te3[256] = { + + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; +static const u32 Te4[256] = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; +static const u32 Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +static const u32 Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; +static const u32 Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; +static const u32 Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; +static const u32 Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; +static const u32 rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +/** + * Expand the cipher key into the encryption key schedule. + */ +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) { + + u32 *rk; + int i = 0; + u32 temp; + + if (!userKey || !key) + return -1; + if (bits != 128 && bits != 192 && bits != 256) + return -2; + + rk = key->rd_key; + + if (bits==128) + key->rounds = 10; + else if (bits==192) + key->rounds = 12; + else + key->rounds = 14; + + rk[0] = GETU32(userKey ); + rk[1] = GETU32(userKey + 4); + rk[2] = GETU32(userKey + 8); + rk[3] = GETU32(userKey + 12); + if (bits == 128) { + while (1) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 0; + } + rk += 4; + } + } + rk[4] = GETU32(userKey + 16); + rk[5] = GETU32(userKey + 20); + if (bits == 192) { + while (1) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + return 0; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(userKey + 24); + rk[7] = GETU32(userKey + 28); + if (bits == 256) { + while (1) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + return 0; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +/** + * Expand the cipher key into the decryption key schedule. + */ +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) { + + u32 *rk; + int i, j, status; + u32 temp; + + /* first, start with an encryption schedule */ + status = AES_set_encrypt_key(userKey, bits, key); + if (status < 0) + return status; + + rk = key->rd_key; + + /* invert the order of the round keys: */ + for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < (key->rounds); i++) { + rk += 4; + rk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + return 0; +} + +#ifndef AES_ASM +/* + * Encrypt a single block + * in and out can overlap + */ +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) { + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +/* + * Decrypt a single block + * in and out can overlap + */ +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) { + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out , s0); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +#endif /* AES_ASM */ + +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc) +{ + + unsigned long n; + unsigned long len = length; + unsigned char tmp[AES_BLOCK_SIZE]; + + assert(in && out && key && ivec); + + if (enc) { + while (len >= AES_BLOCK_SIZE) { + for(n=0; n < AES_BLOCK_SIZE; ++n) + tmp[n] = in[n] ^ ivec[n]; + AES_encrypt(tmp, out, key); + memcpy(ivec, out, AES_BLOCK_SIZE); + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (len) { + for(n=0; n < len; ++n) + tmp[n] = in[n] ^ ivec[n]; + for(n=len; n < AES_BLOCK_SIZE; ++n) + tmp[n] = ivec[n]; + AES_encrypt(tmp, tmp, key); + memcpy(out, tmp, AES_BLOCK_SIZE); + memcpy(ivec, tmp, AES_BLOCK_SIZE); + } + } else { + while (len >= AES_BLOCK_SIZE) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(in, out, key); + for(n=0; n < AES_BLOCK_SIZE; ++n) + out[n] ^= ivec[n]; + memcpy(ivec, tmp, AES_BLOCK_SIZE); + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (len) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(tmp, tmp, key); + for(n=0; n < len; ++n) + out[n] = tmp[n] ^ ivec[n]; + memcpy(ivec, tmp, AES_BLOCK_SIZE); + } + } +} diff --git a/aes.h b/aes.h new file mode 100644 index 0000000..a0167eb --- /dev/null +++ b/aes.h @@ -0,0 +1,26 @@ +#ifndef QEMU_AES_H +#define QEMU_AES_H + +#define AES_MAXNR 14 +#define AES_BLOCK_SIZE 16 + +struct aes_key_st { + uint32_t rd_key[4 *(AES_MAXNR + 1)]; + int rounds; +}; +typedef struct aes_key_st AES_KEY; + +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); + +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc); + +#endif -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:36 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:36 +0100 Subject: [PATCH 10/41] serpent, transform: rework GET_32BIT_MSB_FIRST, PUT_... In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-11-git-send-email-ijackson@chiark.greenend.org.uk> The macros GET_32BIT_MSB_FIRST and PUT_32BIT_MSB_FIRST duplicate functionality available in unaligned.h, namely get_uint32 and put_uint32. Replace all uses outside serpent.c with calls to get_uint32 and put_uint32. We are going to make our serpent implementation compile-time bytesexual, so we do retain a separate implementation of this functionality in a form which will make that easier. In particular, they take arguments for the base and length of the array in which 32-bit we are making the 32-bit access. Also, this disentangles serpent.c from secnet.h. To make serpent.c easier to reuse, remove the #include of secnet.h (and replace it with stdint.h, which we do need and were getting via secnet.h). No functional change. Signed-off-by: Ian Jackson --- secnet.h | 15 --------------- serpent.c | 58 +++++++++++++++++++++++++++++++++++++++------------------- transform.c | 14 +++++++------- 3 files changed, 46 insertions(+), 41 deletions(-) diff --git a/secnet.h b/secnet.h index 6ac64e3..037ef80 100644 --- a/secnet.h +++ b/secnet.h @@ -12,21 +12,6 @@ #include #include -/* - * Macros added by SGT for endianness-independence - */ -#define GET_32BIT_MSB_FIRST(cp) \ - (((unsigned long)(unsigned char)(cp)[0] << 24) | \ - ((unsigned long)(unsigned char)(cp)[1] << 16) | \ - ((unsigned long)(unsigned char)(cp)[2] << 8) | \ - ((unsigned long)(unsigned char)(cp)[3])) - -#define PUT_32BIT_MSB_FIRST(cp, value) ( \ - (cp)[0] = (char)((value) >> 24), \ - (cp)[1] = (char)((value) >> 16), \ - (cp)[2] = (char)((value) >> 8), \ - (cp)[3] = (char)(value) ) - typedef char *string_t; typedef const char *cstring_t; typedef enum {False,True} bool_t; diff --git a/serpent.c b/serpent.c index 34ef6aa..3847437 100644 --- a/serpent.c +++ b/serpent.c @@ -20,11 +20,31 @@ * */ -#include "secnet.h" +#include #include "serpent.h" #include "serpentsboxes.h" +#define GETPUT_CP(bytenum) \ + (((basep) + (lenbytes) - (offset) - 4)[(bytenum)]) + +static uint32_t serpent_get_32bit(const uint8_t *basep, + int lenbytes, int offset) +{ + return (((uint32_t)GETPUT_CP(0) << 24) | + ((uint32_t)GETPUT_CP(1) << 16) | + ((uint32_t)GETPUT_CP(2) << +8) | + ((uint32_t)GETPUT_CP(3))); +} + +static void serpent_put_32bit(uint8_t *basep, int lenbytes, int offset, uint32_t value) +{ + GETPUT_CP(0) = (char)((value) >> 24); + GETPUT_CP(1) = (char)((value) >> 16); + GETPUT_CP(2) = (char)((value) >> 8); + GETPUT_CP(3) = (char)(value); +} + void serpent_makekey(struct keyInstance *key, int keyLen, const uint8_t *keyMaterial) { @@ -33,9 +53,9 @@ void serpent_makekey(struct keyInstance *key, int keyLen, uint32_t w[132],k[132]; for(i=0; isubkeys[ 0]); @@ -197,10 +217,10 @@ void serpent_encrypt(struct keyInstance *key, keying(x0, x1, x2, x3, key->subkeys[32]); /* The ciphertext is now in x */ - PUT_32BIT_MSB_FIRST(ciphertext+12, x0); - PUT_32BIT_MSB_FIRST(ciphertext+8, x1); - PUT_32BIT_MSB_FIRST(ciphertext+4, x2); - PUT_32BIT_MSB_FIRST(ciphertext, x3); + serpent_put_32bit(ciphertext,16,+0, x0); + serpent_put_32bit(ciphertext,16,+4, x1); + serpent_put_32bit(ciphertext,16,+8, x2); + serpent_put_32bit(ciphertext,16,12, x3); } void serpent_decrypt(struct keyInstance *key, @@ -210,10 +230,10 @@ void serpent_decrypt(struct keyInstance *key, register uint32_t x0, x1, x2, x3; register uint32_t y0, y1, y2, y3; - x0=GET_32BIT_MSB_FIRST(ciphertext+12); - x1=GET_32BIT_MSB_FIRST(ciphertext+8); - x2=GET_32BIT_MSB_FIRST(ciphertext+4); - x3=GET_32BIT_MSB_FIRST(ciphertext); + x0=serpent_get_32bit(ciphertext,16,+0); + x1=serpent_get_32bit(ciphertext,16,+4); + x2=serpent_get_32bit(ciphertext,16,+8); + x3=serpent_get_32bit(ciphertext,16,12); /* Start to decrypt the ciphertext x */ keying(x0, x1, x2, x3, key->subkeys[32]); @@ -315,8 +335,8 @@ void serpent_decrypt(struct keyInstance *key, keying(x0, x1, x2, x3, key->subkeys[ 0]); /* The plaintext is now in x */ - PUT_32BIT_MSB_FIRST(plaintext+12, x0); - PUT_32BIT_MSB_FIRST(plaintext+8, x1); - PUT_32BIT_MSB_FIRST(plaintext+4, x2); - PUT_32BIT_MSB_FIRST(plaintext, x3); + serpent_put_32bit(plaintext,16,+0, x0); + serpent_put_32bit(plaintext,16,+4, x1); + serpent_put_32bit(plaintext,16,+8, x2); + serpent_put_32bit(plaintext,16,12, x3); } diff --git a/transform.c b/transform.c index 6618ec5..08ddad6 100644 --- a/transform.c +++ b/transform.c @@ -59,9 +59,9 @@ static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) serpent_makekey(&ti->cryptkey,256,key); serpent_makekey(&ti->mackey,256,key+32); - ti->cryptiv=GET_32BIT_MSB_FIRST(key+64); - ti->maciv=GET_32BIT_MSB_FIRST(key+68); - ti->sendseq=GET_32BIT_MSB_FIRST(key+72); + ti->cryptiv=get_uint32(key+64); + ti->maciv=get_uint32(key+68); + ti->sendseq=get_uint32(key+72); ti->lastrecvseq=ti->sendseq; ti->keyed=True; @@ -121,7 +121,7 @@ static uint32_t transform_forward(void *sst, struct buffer_if *buf, it we've have to add 16 bytes to each message, not 4, so that the message stays a multiple of 16 bytes long.) */ memset(iv,0,16); - PUT_32BIT_MSB_FIRST(iv, ti->maciv); + put_uint32(iv, ti->maciv); serpent_encrypt(&ti->mackey,iv,macacc); /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted @@ -138,7 +138,7 @@ static uint32_t transform_forward(void *sst, struct buffer_if *buf, /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption, and prepend the IV before increasing it. */ memset(iv,0,16); - PUT_32BIT_MSB_FIRST(iv, ti->cryptiv); + put_uint32(iv, ti->cryptiv); serpent_encrypt(&ti->cryptkey,iv,iv); /* CBC: each block is XORed with the previous encrypted block (or the IV) @@ -187,7 +187,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, memset(iv,0,16); { uint32_t ivword = buf_unprepend_uint32(buf); - PUT_32BIT_MSB_FIRST(iv, ivword); + put_uint32(iv, ivword); } /* Assert bufsize is multiple of blocksize */ if (buf->size&0xf) { @@ -208,7 +208,7 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf, /* CBCMAC */ macexpected=buf_unappend(buf,16); memset(iv,0,16); - PUT_32BIT_MSB_FIRST(iv, ti->maciv); + put_uint32(iv, ti->maciv); serpent_encrypt(&ti->mackey,iv,macacc); /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:44 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:44 +0100 Subject: [PATCH 18/41] transform: Pass a direction flag to the transform In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-19-git-send-email-ijackson@chiark.greenend.org.uk> The same transform is used for inbound and outbound packets. The transform should know which direction these packets are flowing in; that (a) allows a transform to reject packets which are "looping back" so to speak, and (b) makes it easier for a transform to generate unique nonces. This will be used by the forthcoming EAX transform. It is combined with the sequence number (the same values of which are used by both ends) to make the nonce, which must be unique across the single shared key, ie unique across both flows. Signed-off-by: Ian Jackson --- secnet.h | 7 +++++-- site.c | 4 ++-- transform-cbcmac.c | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/secnet.h b/secnet.h index 7d7eb4f..5e66a17 100644 --- a/secnet.h +++ b/secnet.h @@ -368,10 +368,13 @@ struct site_if { also depend on internal factors (eg. time) and keep internal state. A struct transform_if only represents a particular type of transformation; instances of the transformation (eg. with - particular key material) have a different C type. */ + particular key material) have a different C type. The same + secret key will be used in opposite directions between a pair of + secnets; one of these pairs will get direction==False, the other True. */ typedef struct transform_inst_if *transform_createinstance_fn(void *st); -typedef bool_t transform_setkey_fn(void *st, uint8_t *key, int32_t keylen); +typedef bool_t transform_setkey_fn(void *st, uint8_t *key, int32_t keylen, + bool_t direction); typedef bool_t transform_valid_fn(void *st); /* 0: no key; 1: ok */ typedef void transform_delkey_fn(void *st); typedef void transform_destroyinstance_fn(void *st); diff --git a/site.c b/site.c index 566b215..f1a0317 100644 --- a/site.c +++ b/site.c @@ -566,7 +566,7 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen); + st->sharedsecretlen,st->setup_priority); return True; } @@ -613,7 +613,7 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, st->sharedsecret,st->sharedsecretlen); /* Set up the transform */ st->new_transform->setkey(st->new_transform->st,st->sharedsecret, - st->sharedsecretlen); + st->sharedsecretlen,st->setup_priority); return True; } diff --git a/transform-cbcmac.c b/transform-cbcmac.c index 1e8a5e9..5fb66ba 100644 --- a/transform-cbcmac.c +++ b/transform-cbcmac.c @@ -40,7 +40,8 @@ struct transform_inst { #define PKCS5_MASK 15 -static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen) +static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen, + bool_t direction) { struct transform_inst *ti=sst; -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Thu Jul 25 18:40:59 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 25 Jul 2013 18:40:59 +0100 Subject: [PATCH 33/41] site, netlink: abolish max_end_pad and min_end_pad In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <1374774067-11296-34-git-send-email-ijackson@chiark.greenend.org.uk> There is much code to compute these values, but they are never used anywhere. Signed-off-by: Ian Jackson --- netlink.c | 5 +---- netlink.h | 1 - secnet.h | 11 ++++------- site.c | 4 +--- transform-cbcmac.c | 1 - transform-eax.c | 1 - udp.c | 1 - 7 files changed, 6 insertions(+), 18 deletions(-) diff --git a/netlink.c b/netlink.c index b2bd224..5d586d0 100644 --- a/netlink.c +++ b/netlink.c @@ -808,14 +808,12 @@ static void netlink_inst_set_mtu(void *sst, int32_t new_mtu) } static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver, - void *dst, int32_t max_start_pad, - int32_t max_end_pad) + void *dst, int32_t max_start_pad) { struct netlink_client *c=sst; struct netlink *st=c->nst; if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad; - if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad; c->deliver=deliver; c->dst=dst; } @@ -944,7 +942,6 @@ netlink_deliver_fn *netlink_init(struct netlink *st, st->cl.apply=netlink_inst_apply; st->cl.interface=st; st->max_start_pad=0; - st->max_end_pad=0; st->clients=NULL; st->routes=NULL; st->n_clients=0; diff --git a/netlink.h b/netlink.h index a7bc9af..5e6ad49 100644 --- a/netlink.h +++ b/netlink.h @@ -46,7 +46,6 @@ struct netlink { void *dst; /* Pointer to host interface state */ cstring_t name; int32_t max_start_pad; - int32_t max_end_pad; struct ipset *networks; /* Local networks */ struct subnet_list *subnets; /* Same as networks, for display */ struct ipset *remote_networks; /* Allowable remote networks */ diff --git a/secnet.h b/secnet.h index 0433c1e..46aac5b 100644 --- a/secnet.h +++ b/secnet.h @@ -326,7 +326,6 @@ typedef const char *comm_addr_to_string_fn(void *commst, struct comm_if { void *st; int32_t min_start_pad; - int32_t min_end_pad; comm_request_notify_fn *request_notify; comm_release_notify_fn *release_notify; comm_sendmsg_fn *sendmsg; @@ -364,8 +363,8 @@ struct site_if { /* TRANSFORM interface */ /* A reversable transformation. Transforms buffer in-place; may add - data to start or end. Maximum amount of data to be added specified - in max_start_pad and max_end_pad. (Reverse transformations decrease + data to start or end. Maximum amount of data to be added before + the packet specified in max_start_pad. (Reverse transformations decrease length, of course.) Transformations may be key-dependent, in which case key material is passed in at initialisation time. They may also depend on internal factors (eg. time) and keep internal @@ -401,8 +400,7 @@ struct transform_inst_if { struct transform_if { void *st; - int32_t max_start_pad; /* these three are all <<< INT_MAX */ - int32_t max_end_pad; + int32_t max_start_pad; /* these two are both <<< INT_MAX */ int32_t keylen; /* 0 means give the transform exactly as much as there is */ transform_createinstance_fn *create; }; @@ -425,8 +423,7 @@ typedef void netlink_deliver_fn(void *st, struct buffer_if *buf); #define MAXIMUM_LINK_QUALITY 3 typedef void netlink_link_quality_fn(void *st, uint32_t quality); typedef void netlink_register_fn(void *st, netlink_deliver_fn *deliver, - void *dst, int32_t max_start_pad, - int32_t max_end_pad); + void *dst, int32_t max_start_pad); typedef void netlink_output_config_fn(void *st, struct buffer_if *buf); typedef bool_t netlink_check_config_fn(void *st, struct buffer_if *buf); typedef void netlink_set_mtu_fn(void *st, int32_t new_mtu); diff --git a/site.c b/site.c index f9a005a..2cb53f6 100644 --- a/site.c +++ b/site.c @@ -1703,13 +1703,11 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, worst_##pad=thispad; \ } COMPUTE_WORST(min_start_pad) - COMPUTE_WORST(min_end_pad) /* We need to register the remote networks with the netlink device */ st->netlink->reg(st->netlink->st, site_outgoing, st, st->transform->max_start_pad+(4*4)+ - worst_min_start_pad, - st->transform->max_end_pad+worst_min_end_pad); + worst_min_start_pad); for (i=0; incomms; i++) st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming); diff --git a/transform-cbcmac.c b/transform-cbcmac.c index 5fb66ba..6920165 100644 --- a/transform-cbcmac.c +++ b/transform-cbcmac.c @@ -263,7 +263,6 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, st->ops.st=st; st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV, 4byte IV */ - st->ops.max_end_pad=16; /* 16byte CBCMAC */ /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits for CBCMAC-IV, and 32 bits for init sequence number */ diff --git a/transform-eax.c b/transform-eax.c index 5c7a120..89c46c8 100644 --- a/transform-eax.c +++ b/transform-eax.c @@ -293,7 +293,6 @@ static list_t *transform_apply(closure_t *self, struct cloc loc, st->p.padding_mask = padding_round-1; st->ops.max_start_pad=0; - st->ops.max_end_pad= padding_round + st->p.tag_length + SEQLEN; st->ops.keylen=0; st->ops.create=transform_create; diff --git a/udp.c b/udp.c index 483ed37..12fcfe8 100644 --- a/udp.c +++ b/udp.c @@ -289,7 +289,6 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context, st->cl.interface=&st->ops; st->ops.st=st; st->ops.min_start_pad=0; - st->ops.min_end_pad=0; st->ops.request_notify=request_notify; st->ops.release_notify=release_notify; st->ops.sendmsg=udp_sendmsg; -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Wed Jul 31 16:19:25 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Wed, 31 Jul 2013 16:19:25 +0100 Subject: [PATCH v3 00/41] Security and reliability fixes In-Reply-To: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> References: <1374774067-11296-1-git-send-email-ijackson@chiark.greenend.org.uk> Message-ID: <20985.11005.875623.904360@chiark.greenend.org.uk> Ian Jackson writes ("[PATCH v3 00/41] Security and reliability fixes"): > This series fixes several security problems, some serious, and a > number of other bugs. ... > If all goes well, and subject to comments, I plan to push this to > master in the middle of next week and start beta-testing it on chiark. I have now done this. The new version is running on chiark. I will upgrade xenophobe too, probably this evening. If that doesn't show up any problems I will make a tag in the git tree and send a release anouncement for a beta. Ian. From ijackson at chiark.greenend.org.uk Thu Aug 1 17:38:48 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Thu, 1 Aug 2013 17:38:48 +0100 Subject: [PATCH] netlink: Safely discard short packets Message-ID: <1375375128-14361-1-git-send-email-ijackson@chiark.greenend.org.uk> Short packets arriving at the netlink should not be processed. Previously, we suffered buffer read overruns. In principle this might be some kind of security problem, as it might make it possible to read and have returned parts of the buffer which were used previously for other data. I haven't analysed this possibility in any detail. Signed-off-by: Ian Jackson --- netlink.c | 20 +++++++++++++++++++- 1 files changed, 19 insertions(+), 1 deletions(-) diff --git a/netlink.c b/netlink.c index bc70757..af6434f 100644 --- a/netlink.c +++ b/netlink.c @@ -293,6 +293,7 @@ static bool_t netlink_icmp_may_reply(struct buffer_if *buf) struct icmphdr *icmph; uint32_t source; + if (buf->size < (int)sizeof(struct icmphdr)) return False; iph=(struct iphdr *)buf->start; icmph=(struct icmphdr *)buf->start; if (iph->protocol==1) { @@ -338,6 +339,7 @@ static bool_t netlink_icmp_may_reply(struct buffer_if *buf) */ static uint16_t netlink_icmp_reply_len(struct buffer_if *buf) { + if (buf->size < (int)sizeof(struct iphdr)) return 0; struct iphdr *iph=(struct iphdr *)buf->start; uint16_t hlen,plen; @@ -354,11 +356,11 @@ static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf, struct netlink_client *client, uint8_t type, uint8_t code) { - struct iphdr *iph=(struct iphdr *)buf->start; struct icmphdr *h; uint16_t len; if (netlink_icmp_may_reply(buf)) { + struct iphdr *iph=(struct iphdr *)buf->start; len=netlink_icmp_reply_len(buf); h=netlink_icmp_tmpl(st,ntohl(iph->saddr),len); h->type=type; h->code=code; @@ -389,6 +391,7 @@ static bool_t netlink_check(struct netlink *st, struct buffer_if *buf, return False; \ }while(0) + if (buf->size < (int)sizeof(struct iphdr)) BAD("len %"PRIu32"",buf->size); struct iphdr *iph=(struct iphdr *)buf->start; int32_t len; @@ -413,6 +416,13 @@ static void netlink_packet_deliver(struct netlink *st, struct netlink_client *client, struct buffer_if *buf) { + if (buf->size < (int)sizeof(struct iphdr)) { + Message(M_ERR,"%s: trying to deliver a too-short packet" + " from %s!\n",st->name, client?client->name:"(local)"); + BUF_FREE(buf); + return; + } + struct iphdr *iph=(struct iphdr *)buf->start; uint32_t dest=ntohl(iph->daddr); uint32_t source=ntohl(iph->saddr); @@ -530,6 +540,7 @@ static void netlink_packet_forward(struct netlink *st, struct netlink_client *client, struct buffer_if *buf) { + if (buf->size < (int)sizeof(struct iphdr)) return; struct iphdr *iph=(struct iphdr *)buf->start; BUF_ASSERT_USED(buf); @@ -559,6 +570,12 @@ static void netlink_packet_local(struct netlink *st, st->localcount++; + if (buf->size < (int)sizeof(struct icmphdr)) { + Message(M_WARNING,"%s: short packet addressed to secnet; " + "ignoring it\n",st->name); + BUF_FREE(buf); + return; + } h=(struct icmphdr *)buf->start; if ((ntohs(h->iph.frag_off)&0xbfff)!=0) { @@ -614,6 +631,7 @@ static void netlink_incoming(struct netlink *st, struct netlink_client *client, BUF_FREE(buf); return; } + assert(buf->size >= (int)sizeof(struct icmphdr)); iph=(struct iphdr *)buf->start; source=ntohl(iph->saddr); -- 1.7.2.5 From ijackson at chiark.greenend.org.uk Fri Aug 2 11:10:08 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Fri, 2 Aug 2013 11:10:08 +0100 Subject: secnet 0.3.0~beta2 In-Reply-To: References: Message-ID: <20987.34176.635574.77678@chiark.greenend.org.uk> Simon Tatham writes ("Re: secnet 0.3.0~beta2"): > Ian Jackson wrote: > > When you have upgraded, you should make a change to your secnet.conf > > file, as follows: > > +transform eax-serpent { }, serpent256-cbc { } > > -transform serpent256-cbc { > > - max-sequence-skew 10; > > -}; > > Regrettably, I think there's a typo here - surely the added line > should end with a semicolon as the removed section does? Indeed. That'll teach me to edit diffs by hand. Ian. From ijackson at chiark.greenend.org.uk Mon Aug 5 11:51:46 2013 From: ijackson at chiark.greenend.org.uk (Ian Jackson) Date: Mon, 5 Aug 2013 11:51:46 +0100 Subject: [PATCH] site: Initialise st->scratch with SETUP_BUFFER_LEN space. In-Reply-To: References: Message-ID: <1375699906-12915-1-git-send-email-ijackson@chiark.greenend.org.uk> Otherwise, if we're unlucky, we end up trying to construt a PROD packet before we have ever used buffer_copy on scratch, which causes an assertion failure ("buf->size <= buf->len - amount" at util.c:257). Reported-by: Simon Tatham Signed-off-by: Ian Jackson --- debian/changelog | 7 +++++++ site.c | 2 +- 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/debian/changelog b/debian/changelog index ea1d421..9c75165 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +secnet (0.3.0~beta3) unstable; urgency=low + + * New upstream version. + - Stability bugfix: properly initialise site's scratch buffer. + + -- + secnet (0.3.0~beta2) unstable; urgency=low * New upstream version. diff --git a/site.c b/site.c index 0b39232..324a206 100644 --- a/site.c +++ b/site.c @@ -1808,7 +1808,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, buffer_new(&st->buffer,SETUP_BUFFER_LEN); - buffer_new(&st->scratch,0); + buffer_new(&st->scratch,SETUP_BUFFER_LEN); BUF_ALLOC(&st->scratch,"site:scratch"); /* We are interested in poll(), but only for timeouts. We don't have -- 1.7.2.5