Test of tinydtls over cellular
Dependencies: VodafoneUSBModem mbed-rtos mbed tinydtls
Revision 1:1dd9b8218515, committed 2013-10-11
- Comitter:
- ashleymills
- Date:
- Fri Oct 11 14:01:57 2013 +0000
- Parent:
- 0:6ae42a2aff75
- Child:
- 2:fe574f2c2b6a
- Commit message:
- Minor change.
Changed in this revision
--- a/main.cpp Wed Oct 09 14:48:52 2013 +0000 +++ b/main.cpp Fri Oct 11 14:01:57 2013 +0000 @@ -1,16 +1,300 @@ +#define __DEBUG__ 4 + +#ifndef __MODULE__ +#define __MODULE__ "main.cpp" +#endif + #include "mbed.h" #include "rtos.h" +#include "bsd_socket.h" + +#include <dtls.h> +#include "global.h" +#include "debug.h" +#include "errno.h" + #include "VodafoneUSBModem.h" -#include "bsd_socket.h" -#include "dtls.h" - DigitalOut myled(LED1); +void fail(int code) { + while(1) { + myled = !myled; + Thread::wait(100); + } +} + +/* This function is the "key store" for tinyDTLS. It is called to + * retrieve a key for the given identiy within this particular + * session. */ +int get_key(struct dtls_context_t *ctx, + const session_t *session, + const unsigned char *id, size_t id_len, + const dtls_key_t **result) { + DBG("get_key called"); + + static const dtls_key_t psk = { + .type = DTLS_KEY_PSK, + .key.psk.id = (unsigned char *)"Client_identity", + .key.psk.id_length = 15, + .key.psk.key = (unsigned char *)"secretPSK", + .key.psk.key_length = 9 + }; + + *result = &psk; + return 0; +} + +//#define APN_GDSP +#define APN_CONTRACT + +#ifdef APN_GDSP + #define APN "ppinternetd.gdsp" + #define APN_USERNAME "" + #define APN_PASSWORD "" +#endif + +#ifdef APN_CONTRACT + #define APN "internet" + #define APN_USERNAME "web" + #define APN_PASSWORD "web" +#endif + +// globals +int gDTLSConnected = 0; +sockaddr_in bindAddr,serverAddress; + +// this is used to setup sockaddr_in structures for a remote host +// it also listens for incoming UDP packets on the local interface on port +bool connectToSocketUDP(char *ipAddress, int port, int *sockfd) { + *sockfd = -1; + // create the socket + if((*sockfd=socket(AF_INET,SOCK_DGRAM,0))<0) { + DBG("Error opening socket"); + return false; + } + socklen_t sockAddrInLen = sizeof(struct sockaddr_in); + + // bind socket to 11111 + memset(&bindAddr, 0x00, sockAddrInLen); + bindAddr.sin_family = AF_INET; // IP family + bindAddr.sin_port = htons(port); + bindAddr.sin_addr.s_addr = IPADDR_ANY; // 32 bit IP representation + // call bind + if(bind(*sockfd,(const struct sockaddr *)&bindAddr,sockAddrInLen)!=0) { + DBG("Error binding socket"); + perror(NULL); + } + + INFO("UDP socket created and bound to: %s:%d",inet_ntoa(bindAddr.sin_addr),ntohs(bindAddr.sin_port)); + + // create the socket address + memset(&serverAddress, 0x00, sizeof(struct sockaddr_in)); + serverAddress.sin_addr.s_addr = inet_addr(ipAddress); + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(port); + + // do socket connect + //LOG("Connecting socket to %s:%d", inet_ntoa(serverAddress.sin_addr), ntohs(serverAddress.sin_port)); + if(connect(*sockfd, (const struct sockaddr *)&serverAddress, sizeof(serverAddress))<0) { + shutdown(*sockfd,SHUT_RDWR); + close(*sockfd); + DBG("Could not connect"); + return false; + } + return true; +} +// this is a required callback for tinydtls it is called +// whenever tinydtls handles a raw buffer through dtls_handle_message. +// tinydtls extracts the unencrypted data and passes it onto this function +int read_from_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) { + DBG("read_from_peer called"); + size_t i; + for (i = 0; i < len; i++) + printf("%c", data[i]); + return 0; +} + +/// this is a required callback for tinydtls it is called +// whenever tinydtls needs to send a raw buffer (i.e whenever dtls_write is called by the application) +int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) { + DBG("send_to_peer called"); + int fd = *(int *)dtls_get_app_data(ctx); + return sendto(fd, data, len, MSG_DONTWAIT, + &session->addr.sa, session->size); +} + +// this is used to handle incoming packets for tinydtls +// raw buffers are passed to dtls_handle_message, who +// processes them and passes the data onto the read callback +int dtls_handle_read(struct dtls_context_t *ctx) { + DBG("dtls_handle_read called"); + int fd; + session_t session; + #define MAX_READ_BUF 256 + static uint8 buf[MAX_READ_BUF]; + int len; + + fd = *(int *)dtls_get_app_data(ctx); + + memset(&session, 0, sizeof(session_t)); + session.size = sizeof(session.addr); + len = recvfrom(fd, buf, MAX_READ_BUF, 0, + &session.addr.sa, &session.size); + + if(len < 0) { + DBG("Got nothing from read"); + perror("recvfrom"); + return -1; + } else { + #if __DEBUG__ > 0 + unsigned char addrbuf[72]; + dsrv_print_addr(&session, addrbuf, sizeof(addrbuf)); + DBG("Got %d bytes from %s", len, (char *)addrbuf); + dump((unsigned char *)&session, sizeof(session_t)); + DBGX("\r\n"); + dump(buf, len); + DBGX("\r\n"); + #endif + } + + return dtls_handle_message(ctx, &session, buf, len); +} + +// callback called on tinydtls events (currently only ever called for DTLS_EVENT_CONNECTED) +int event_handler( + struct dtls_context_t *ctx, + session_t *session, + dtls_alert_level_t level, + unsigned short code) { + DBG("DTLS SESSION SETUP COMPLETE"); + gDTLSConnected = 1; + return 0; +} + +// structure for required tinydtls callbacks +static dtls_handler_t cb = { + .write = send_to_peer, + .read = read_from_peer, + .event = event_handler, + .get_key = get_key +}; + int main() { - while(1) { - myled = 1; - wait(0.2); - myled = 0; - wait(0.2); + DBG_INIT(); + DBG_SET_SPEED(115200); + DBG_SET_NEWLINE("\r\n"); + + DBG("Tiny DTLS test"); + + // DTLS context struct + dtls_context_t *dtls_context = NULL; + int ret = 0, counter = 0; + fd_set rfds, wfds; + struct timeval timeout; + char outBuf[64]; + + // structure for getting address of incoming packets + sockaddr_in fromAddr; + socklen_t fromAddrLen = sizeof(struct sockaddr_in); + memset(&fromAddr,0x00,fromAddrLen); + + // connect to cellular network + VodafoneUSBModem modem; + modem.connect(APN,APN_USERNAME,APN_PASSWORD); + + // setup socket to remote server + int sockfd = NULL; + if(!connectToSocketUDP("109.74.199.96", 5683, &sockfd)) { + DBG("Error connecting to socket"); + fail(1); + } + DBG("\"Connected\" to UDP socket"); + int on = 1; + if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) { + DBG("setsockopt SO_REUSEADDR: %s", strerror(errno)); + } + + // tinydtls stuff + + // destination address is stored in a session type + session_t dst; + memset(&dst, 0, sizeof(session_t)); + dst.size = sizeof(sockaddr_in); + serverAddress.sin_len = dst.size; + memcpy(&dst.addr.sa, &serverAddress, dst.size); + //dst.addr.sin.sin_port = htons(4433); + + // dtls init must always be called for memory allocation + dtls_init(); + dtls_set_log_level(LOG_DEBUG); + // setup DTLS context + DBG("Creating DTLS context"); + dtls_context = dtls_new_context(&sockfd); + if(!dtls_context) { + DBG("Cannot create context"); + fail(3); } + DBG("DTLS context created"); + + // forced to use this call back system + + dtls_set_handler(dtls_context, &cb); + + DBG("Issuing dtls_connect"); + ret = dtls_connect(dtls_context, &dst); + if(ret<0) { + DBG("Error in dtls_connect: %d",ret); + modem.disconnect(); + fail(4); + } + if(ret==0) { + DBG("Channel already exists"); + modem.disconnect(); + fail(5); + } + DBG("dtls_connect successfull"); + while (1) { + // setup file descriptor lists for select + FD_ZERO(&rfds); + FD_ZERO(&wfds); + //FD_SET(fileno(stdin), &rfds); + FD_SET(sockfd, &rfds); + // FD_SET(sockfd, &wfds); + + timeout.tv_sec = 5; + timeout.tv_usec = 0; + + int result = select(sockfd+1, &rfds, &wfds, 0, &timeout); + + if(result < 0) { // error + if (errno != EINTR) + perror("select"); + } else if (result == 0) { + // timeout + DBG("select timeout"); + // if we are connected, send some random data (every time select times out) + // heh, abusing select as a timer + if(gDTLSConnected) { + sprintf(outBuf,"This is a pointless test message: %d\r\n",counter++); + dtls_write(dtls_context, &dst, (uint8 *)outBuf, strlen(outBuf)); + //try_send(dtls_context, &dst); + } + } else { + // OK + // check which file descriptor had an event + if(FD_ISSET(sockfd, &wfds)) { + // FIXME (from tinydtls) + } else if (FD_ISSET(sockfd, &rfds)) + if(dtls_handle_read(dtls_context)<0) { + modem.disconnect(); + fail(6); + } + } + //else if (FD_ISSET(fileno(stdin), &rfds)) + //handle_stdin(); + //} + + + } + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tinydtls.lib Fri Oct 11 14:01:57 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/ashleymills/code/tinydtls/#bc8a649bad13
--- a/tinydtls/aes/rijndael.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1277 +0,0 @@ -/* $OpenBSD: rijndael.c,v 1.19 2008/06/09 07:49:45 djm Exp $ */ - -/** - * rijndael-alg-fst.c - * - * @version 3.0 (December 2000) - * - * Optimised ANSI C code for the Rijndael cipher (now AES) - * - * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be> - * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be> - * @author Paulo Barreto <paulo.barreto@terra.com.br> - * - * 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 "config.h" -#ifndef MBED -#include <sys/param.h> -#endif - -/* #include <sys/systm.h> */ - -#include "rijndael.h" - -#undef FULL_UNROLL - -/* -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 aes_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 aes_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 aes_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 aes_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 aes_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 aes_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 aes_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 aes_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 aes_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 aes_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 aes_u32 rcon[] = { - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ -}; - -#define GETU32(pt) (((aes_u32)(pt)[0] << 24) ^ ((aes_u32)(pt)[1] << 16) ^ ((aes_u32)(pt)[2] << 8) ^ ((aes_u32)(pt)[3])) -#define PUTU32(ct, st) { (ct)[0] = (aes_u8)((st) >> 24); (ct)[1] = (aes_u8)((st) >> 16); (ct)[2] = (aes_u8)((st) >> 8); (ct)[3] = (aes_u8)(st); } - -/** - * Expand the cipher key into the encryption key schedule. - * - * @return the number of rounds for the given cipher key size. - */ -int -rijndaelKeySetupEnc(aes_u32 rk[/*4*(Nr + 1)*/], const aes_u8 cipherKey[], int keyBits) -{ - int i = 0; - aes_u32 temp; - - rk[0] = GETU32(cipherKey ); - rk[1] = GETU32(cipherKey + 4); - rk[2] = GETU32(cipherKey + 8); - rk[3] = GETU32(cipherKey + 12); - if (keyBits == 128) { - for (;;) { - 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 10; - } - rk += 4; - } - } - rk[4] = GETU32(cipherKey + 16); - rk[5] = GETU32(cipherKey + 20); - if (keyBits == 192) { - for (;;) { - 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 12; - } - rk[10] = rk[ 4] ^ rk[ 9]; - rk[11] = rk[ 5] ^ rk[10]; - rk += 6; - } - } - rk[6] = GETU32(cipherKey + 24); - rk[7] = GETU32(cipherKey + 28); - if (keyBits == 256) { - for (;;) { - 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 14; - } - 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; -} - -#ifdef WITH_AES_DECRYPT -/** - * Expand the cipher key into the decryption key schedule. - * - * @return the number of rounds for the given cipher key size. - */ -int -rijndaelKeySetupDec(aes_u32 rk[/*4*(Nr + 1)*/], const aes_u8 cipherKey[], int keyBits) -{ - int Nr, i, j; - aes_u32 temp; - - /* expand the cipher key: */ - Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); - - /* invert the order of the round keys: */ - for (i = 0, j = 4*Nr; 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 < Nr; 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 Nr; -} -#endif - -void -rijndaelEncrypt(const aes_u32 rk[/*4*(Nr + 1)*/], int Nr, const aes_u8 pt[16], - aes_u8 ct[16]) -{ - aes_u32 s0, s1, s2, s3, t0, t1, t2, t3; -#ifndef FULL_UNROLL - int r; -#endif /* ?FULL_UNROLL */ - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(pt ) ^ rk[0]; - s1 = GETU32(pt + 4) ^ rk[1]; - s2 = GETU32(pt + 8) ^ rk[2]; - s3 = GETU32(pt + 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 (Nr > 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 (Nr > 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 += Nr << 2; -#else /* !FULL_UNROLL */ - /* - * Nr - 1 full rounds: - */ - r = Nr >> 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(ct , s0); - s1 = - (Te4[(t1 >> 24) ] & 0xff000000) ^ - (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ - (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t0 ) & 0xff] & 0x000000ff) ^ - rk[1]; - PUTU32(ct + 4, s1); - s2 = - (Te4[(t2 >> 24) ] & 0xff000000) ^ - (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ - (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t1 ) & 0xff] & 0x000000ff) ^ - rk[2]; - PUTU32(ct + 8, s2); - s3 = - (Te4[(t3 >> 24) ] & 0xff000000) ^ - (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ - (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t2 ) & 0xff] & 0x000000ff) ^ - rk[3]; - PUTU32(ct + 12, s3); -} - -#ifdef WITH_AES_DECRYPT -static void -rijndaelDecrypt(const aes_u32 rk[/*4*(Nr + 1)*/], int Nr, const aes_u8 ct[16], - aes_u8 pt[16]) -{ - aes_u32 s0, s1, s2, s3, t0, t1, t2, t3; -#ifndef FULL_UNROLL - int r; -#endif /* ?FULL_UNROLL */ - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(ct ) ^ rk[0]; - s1 = GETU32(ct + 4) ^ rk[1]; - s2 = GETU32(ct + 8) ^ rk[2]; - s3 = GETU32(ct + 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 (Nr > 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 (Nr > 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 += Nr << 2; -#else /* !FULL_UNROLL */ - /* - * Nr - 1 full rounds: - */ - r = Nr >> 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(pt , s0); - s1 = - (Td4[(t1 >> 24) ] & 0xff000000) ^ - (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ - (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t2 ) & 0xff] & 0x000000ff) ^ - rk[1]; - PUTU32(pt + 4, s1); - s2 = - (Td4[(t2 >> 24) ] & 0xff000000) ^ - (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ - (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t3 ) & 0xff] & 0x000000ff) ^ - rk[2]; - PUTU32(pt + 8, s2); - s3 = - (Td4[(t3 >> 24) ] & 0xff000000) ^ - (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ - (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t0 ) & 0xff] & 0x000000ff) ^ - rk[3]; - PUTU32(pt + 12, s3); -} -#endif - -/* setup key context for encryption only */ -int -rijndael_set_key_enc_only(rijndael_ctx *ctx, const u_char *key, int bits) -{ - int rounds; - - rounds = rijndaelKeySetupEnc(ctx->ek, key, bits); - if (rounds == 0) - return -1; - - ctx->Nr = rounds; -#ifdef WITH_AES_DECRYPT - ctx->enc_only = 1; -#endif - - return 0; -} - -#ifdef WITH_AES_DECRYPT -/* setup key context for both encryption and decryption */ -int -rijndael_set_key(rijndael_ctx *ctx, const u_char *key, int bits) -{ - int rounds; - - rounds = rijndaelKeySetupEnc(ctx->ek, key, bits); - if (rounds == 0) - return -1; - if (rijndaelKeySetupDec(ctx->dk, key, bits) != rounds) - return -1; - - ctx->Nr = rounds; - ctx->enc_only = 0; - - return 0; -} - -void -rijndael_decrypt(rijndael_ctx *ctx, const u_char *src, u_char *dst) -{ - rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst); -} -#endif - -void -rijndael_encrypt(rijndael_ctx *ctx, const u_char *src, u_char *dst) -{ - rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst); -}
--- a/tinydtls/aes/rijndael.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* $OpenBSD: rijndael.h,v 1.13 2008/06/09 07:49:45 djm Exp $ */ - -/** - * rijndael-alg-fst.h - * - * @version 3.0 (December 2000) - * - * Optimised ANSI C code for the Rijndael cipher (now AES) - * - * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be> - * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be> - * @author Paulo Barreto <paulo.barreto@terra.com.br> - * - * 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 __RIJNDAEL_H -#define __RIJNDAEL_H - -#define AES_MAXKEYBITS (256) -#define AES_MAXKEYBYTES (AES_MAXKEYBITS/8) -/* for 256-bit keys, fewer for less */ -#define AES_MAXROUNDS 14 - -/* bergmann: to avoid conflicts with typedefs from certain Contiki platforms, - * the following type names have been prefixed with "aes_": */ -typedef unsigned char u_char; -typedef unsigned char aes_u8; -typedef unsigned short aes_u16; -typedef unsigned int aes_u32; - -/* The structure for key information */ -typedef struct { -#ifdef WITH_AES_DECRYPT - int enc_only; /* context contains only encrypt schedule */ -#endif - int Nr; /* key-length-dependent number of rounds */ - aes_u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */ -#ifdef WITH_AES_DECRYPT - aes_u32 dk[4*(AES_MAXROUNDS + 1)]; /* decrypt key schedule */ -#endif -} rijndael_ctx; - -int rijndael_set_key(rijndael_ctx *, const u_char *, int); -int rijndael_set_key_enc_only(rijndael_ctx *, const u_char *, int); -void rijndael_decrypt(rijndael_ctx *, const u_char *, u_char *); -void rijndael_encrypt(rijndael_ctx *, const u_char *, u_char *); - -int rijndaelKeySetupEnc(unsigned int [], const unsigned char [], int); -int rijndaelKeySetupDec(unsigned int [], const unsigned char [], int); -void rijndaelEncrypt(const unsigned int [], int, const unsigned char [], - unsigned char []); - -#endif /* __RIJNDAEL_H */
--- a/tinydtls/alert.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* alert.h -- DTLS alert protocol - * - * Copyright (C) 2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * @file alert.h - * @brief DTLS alert protocol - */ - -#ifndef _ALERT_H_ -#define _ALERT_H_ - -#include "config.h" - -typedef enum { - DTLS_ALERT_LEVEL_WARNING=1, - DTLS_ALERT_LEVEL_FATAL=2 -} dtls_alert_level_t; - -typedef enum { - DTLS_ALERT_CLOSE=0, - DTLS_ALERT_UNEXPECTED_MESSAGE=10, - DTLS_ALERT_BAD_RECORD_MAC=20, - DTLS_ALERT_RECORD_OVERFLOW=22, - DTLS_ALERT_DECOMPRESSION_FAILURE=30, - DTLS_ALERT_HANDSHAKE_FAILURE=40, - DTLS_ALERT_ILLEGAL_PARAMETER=47, - DTLS_ALERT_ACCESS_DENIED=49, - DTLS_ALERT_DECODE_ERROR=50, - DTLS_ALERT_DECRYPT_ERROR=51, - DTLS_ALERT_PROTOCOL_VERSION=70, - DTLS_ALERT_INSUFFICIENT_SECURITY=70, - DTLS_ALERT_INTERNAL_ERROR=80, - DTLS_ALERT_USER_CANCELED=90, - DTLS_ALERT_NO_RENEGOTIATION=100, - DTLS_ALERT_UNSUPPORTED_EXTENSION=110 -} dtls_alert_t; - -#define DTLS_EVENT_CONNECTED 0x01DE - -#endif /* _ALERT_H_ */
--- a/tinydtls/ccm.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,306 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <string.h> - -#include "global.h" -#include "numeric.h" -#include "ccm.h" - -#define CCM_FLAGS(A,M,L) (((A > 0) << 6) | (((M - 2)/2) << 3) | (L - 1)) - -#define MASK_L(_L) ((1 << 8 * _L) - 1) - -#define SET_COUNTER(A,L,cnt,C) { \ - int i; \ - memset((A) + DTLS_CCM_BLOCKSIZE - (L), 0, (L)); \ - (C) = (cnt) & MASK_L(L); \ - for (i = DTLS_CCM_BLOCKSIZE - 1; (C) && (i > (L)); --i, (C) >>= 8) \ - (A)[i] |= (C) & 0xFF; \ - } - -static inline void -block0(size_t M, /* number of auth bytes */ - size_t L, /* number of bytes to encode message length */ - size_t la, /* l(a) octets additional authenticated data */ - size_t lm, /* l(m) message length */ - unsigned char N[DTLS_CCM_BLOCKSIZE], - unsigned char *result) { - int i; - - result[0] = CCM_FLAGS(la, M, L); - - /* copy the nonce */ - memcpy(result + 1, N, DTLS_CCM_BLOCKSIZE - L); - - for (i=0; i < L; i++) { - result[15-i] = lm & 0xff; - lm >>= 8; - } -} - -/** - * Creates the CBC-MAC for the additional authentication data that - * is sent in cleartext. - * - * \param ctx The crypto context for the AES encryption. - * \param msg The message starting with the additional authentication data. - * \param la The number of additional authentication bytes in \p msg. - * \param B The input buffer for crypto operations. When this function - * is called, \p B must be initialized with \c B0 (the first - * authentication block. - * \param X The output buffer where the result of the CBC calculation - * is placed. - * \return The result is written to \p X. - */ -void -add_auth_data(rijndael_ctx *ctx, const unsigned char *msg, size_t la, - unsigned char B[DTLS_CCM_BLOCKSIZE], - unsigned char X[DTLS_CCM_BLOCKSIZE]) { - size_t i,j; - - rijndael_encrypt(ctx, B, X); - - memset(B, 0, DTLS_CCM_BLOCKSIZE); - - if (!la) - return; - -#ifndef WITH_CONTIKI - if (la < 0xFF00) { /* 2^16 - 2^8 */ - j = 2; - dtls_int_to_uint16(B, la); - } else if (la <= UINT32_MAX) { - j = 6; - dtls_int_to_uint16(B, 0xFFFE); - dtls_int_to_uint32(B+2, la); - } else { - j = 10; - dtls_int_to_uint16(B, 0xFFFF); - dtls_ulong_to_uint64(B+2, la); - } -#else /* WITH_CONTIKI */ - /* With Contiki, we are building for small devices and thus - * anticipate that the number of additional authentication bytes - * will not exceed 65280 bytes (0xFF00) and we can skip the - * workarounds required for j=6 and j=10 on devices with a word size - * of 32 bits or 64 bits, respectively. - */ - - assert(la < 0xFF00); - j = 2; - dtls_int_to_uint16(B, la); -#endif /* WITH_CONTIKI */ - - i = min(DTLS_CCM_BLOCKSIZE - j, la); - memcpy(B + j, msg, i); - la -= i; - msg += i; - - memxor(B, X, DTLS_CCM_BLOCKSIZE); - - rijndael_encrypt(ctx, B, X); - - while (la > DTLS_CCM_BLOCKSIZE) { - for (i = 0; i < DTLS_CCM_BLOCKSIZE; ++i) - B[i] = X[i] ^ *msg++; - la -= DTLS_CCM_BLOCKSIZE; - - rijndael_encrypt(ctx, B, X); - } - - if (la) { - memset(B, 0, DTLS_CCM_BLOCKSIZE); - memcpy(B, msg, la); - memxor(B, X, DTLS_CCM_BLOCKSIZE); - - rijndael_encrypt(ctx, B, X); - } -} - -static inline void -encrypt(rijndael_ctx *ctx, size_t L, unsigned long counter, - unsigned char *msg, size_t len, - unsigned char A[DTLS_CCM_BLOCKSIZE], - unsigned char S[DTLS_CCM_BLOCKSIZE]) { - - static unsigned long C; - - SET_COUNTER(A, L, counter, C); - rijndael_encrypt(ctx, A, S); - memxor(msg, S, len); -} - -static inline void -mac(rijndael_ctx *ctx, - unsigned char *msg, size_t len, - unsigned char B[DTLS_CCM_BLOCKSIZE], - unsigned char X[DTLS_CCM_BLOCKSIZE]) { - size_t i; - - for (i = 0; i < len; ++i) - B[i] = X[i] ^ msg[i]; - - rijndael_encrypt(ctx, B, X); - -} - -long int -dtls_ccm_encrypt_message(rijndael_ctx *ctx, size_t M, size_t L, - unsigned char N[DTLS_CCM_BLOCKSIZE], - unsigned char *msg, size_t lm, - const unsigned char *aad, size_t la) { - size_t i, len; - unsigned long C; - unsigned long counter = 1; /* \bug does not work correctly on ia32 when - lm >= 2^16 */ - unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */ - unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */ - unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */ - unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */ - - len = lm; /* save original length */ - /* create the initial authentication block B0 */ - block0(M, L, la, lm, N, B); - add_auth_data(ctx, aad, la, B, X); - - /* initialize block template */ - A[0] = L-1; - - /* copy the nonce */ - memcpy(A + 1, N, DTLS_CCM_BLOCKSIZE - L); - - while (lm >= DTLS_CCM_BLOCKSIZE) { - /* calculate MAC */ - mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X); - - /* encrypt */ - encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S); - - /* update local pointers */ - lm -= DTLS_CCM_BLOCKSIZE; - msg += DTLS_CCM_BLOCKSIZE; - counter++; - } - - if (lm) { - /* Calculate MAC. The remainder of B must be padded with zeroes, so - * B is constructed to contain X ^ msg for the first lm bytes (done in - * mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes - * (i.e., we can use memcpy() here). - */ - memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm); - mac(ctx, msg, lm, B, X); - - /* encrypt */ - encrypt(ctx, L, counter, msg, lm, A, S); - - /* update local pointers */ - msg += lm; - } - - /* calculate S_0 */ - SET_COUNTER(A, L, 0, C); - rijndael_encrypt(ctx, A, S); - - for (i = 0; i < M; ++i) - *msg++ = X[i] ^ S[i]; - - return len + M; -} - -long int -dtls_ccm_decrypt_message(rijndael_ctx *ctx, size_t M, size_t L, - unsigned char N[DTLS_CCM_BLOCKSIZE], - unsigned char *msg, size_t lm, - const unsigned char *aad, size_t la) { - - size_t len; - unsigned long C; - unsigned long counter = 1; /* \bug does not work correctly on ia32 when - lm >= 2^16 */ - unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */ - unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */ - unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */ - unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */ - - if (lm < M) - goto error; - - len = lm; /* save original length */ - lm -= M; /* detract MAC size*/ - - /* create the initial authentication block B0 */ - block0(M, L, la, lm, N, B); - add_auth_data(ctx, aad, la, B, X); - - /* initialize block template */ - A[0] = L-1; - - /* copy the nonce */ - memcpy(A + 1, N, DTLS_CCM_BLOCKSIZE - L); - - while (lm >= DTLS_CCM_BLOCKSIZE) { - /* decrypt */ - encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S); - - /* calculate MAC */ - mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X); - - /* update local pointers */ - lm -= DTLS_CCM_BLOCKSIZE; - msg += DTLS_CCM_BLOCKSIZE; - counter++; - } - - if (lm) { - /* decrypt */ - encrypt(ctx, L, counter, msg, lm, A, S); - - /* Calculate MAC. Note that msg ends in the MAC so we must - * construct B to contain X ^ msg for the first lm bytes (done in - * mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes - * (i.e., we can use memcpy() here). - */ - memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm); - mac(ctx, msg, lm, B, X); - - /* update local pointers */ - msg += lm; - } - - /* calculate S_0 */ - SET_COUNTER(A, L, 0, C); - rijndael_encrypt(ctx, A, S); - - memxor(msg, S, M); - - /* return length if MAC is valid, otherwise continue with error handling */ - if (memcmp(X, msg, M) == 0) - return len - M; - - error: - return -1; -}
--- a/tinydtls/ccm.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _CCM_H_ -#define _CCM_H_ - -#include "config.h" -#include "aes/rijndael.h" - -/* implementation of Counter Mode CBC-MAC, RFC 3610 */ - -#define DTLS_CCM_BLOCKSIZE 16 /**< size of hmac blocks */ -#define DTLS_CCM_MAX 16 /**< max number of bytes in digest */ -#define DTLS_CCM_NONCE_SIZE 12 /**< size of nonce */ - -/** - * Authenticates and encrypts a message using AES in CCM mode. Please - * see also RFC 3610 for the meaning of \p M, \p L, \p lm and \p la. - * - * \param ctx The initialized rijndael_ctx object to be used for AES operations. - * \param M The number of authentication octets. - * \param L The number of bytes used to encode the message length. - * \param N The nonce value to use. You must provide \c DTLS_CCM_BLOCKSIZE - * nonce octets, although only the first \c 16 - \p L are used. - * \param msg The message to encrypt. The first \p la octets are additional - * authentication data that will be cleartext. Note that the - * encryption operation modifies the contents of \p msg and adds - * \p M bytes MAC. Therefore, the buffer must be at least - * \p lm + \p M bytes large. - * \param lm The actual length of \p msg. - * \param aad A pointer to the additional authentication data (can be \c NULL if - * \p la is zero). - * \param la The number of additional authentication octets (may be zero). - * \return FIXME - */ -long int -dtls_ccm_encrypt_message(rijndael_ctx *ctx, size_t M, size_t L, - unsigned char N[DTLS_CCM_BLOCKSIZE], - unsigned char *msg, size_t lm, - const unsigned char *aad, size_t la); - -long int -dtls_ccm_decrypt_message(rijndael_ctx *ctx, size_t M, size_t L, - unsigned char N[DTLS_CCM_BLOCKSIZE], - unsigned char *msg, size_t lm, - const unsigned char *aad, size_t la); - -#endif /* _CCM_H_ */
--- a/tinydtls/config.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Define if building universal (internal helper macro) */ -/* #undef AC_APPLE_UNIVERSAL_BUILD */ - -/* Define to 1 if you have the <arpa/inet.h> header file. */ -//#define HAVE_ARPA_INET_H 1 - -#define MBED 1 - -/* Define to 1 if you have the <assert.h> header file. */ -#define HAVE_ASSERT_H 1 - -/* Define to 1 if you have the <fcntl.h> header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the `fls' function. */ -/* #undef HAVE_FLS */ - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#define HAVE_MALLOC 1 - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memset' function. */ -#define HAVE_MEMSET 1 - -/* Define to 1 if you have the <netdb.h> header file. */ -//#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the <netinet/in.h> header file. */ -//#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if struct sockaddr_in6 has a member sin6_len. */ -/* #undef HAVE_SOCKADDR_IN6_SIN6_LEN */ - -/* Define to 1 if you have the `socket' function. */ -#define HAVE_SOCKET 1 - -/* Define to 1 if you have the <stddef.h> header file. */ -#define HAVE_STDDEF_H 1 - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strnlen' function. */ -#define HAVE_STRNLEN 1 - -/* Define to 1 if you have the <sys/param.h> header file. */ -//#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the <sys/socket.h> header file. */ -//#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -//#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the <time.h> header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -#ifndef PACKAGE_BUGREPORT -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" -#endif /* PACKAGE_BUGREPORT */ - -#ifndef PACKAGE_NAME -/* Define to the full name of this package. */ -#define PACKAGE_NAME "tinydtls" -#endif /* PACKAGE_NAME */ - -#ifndef PACKAGE_STRING -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "tinydtls 0.4.0" -#endif /* PACKAGE_STRING */ - -#ifndef PACKAGE_TARNAME -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "tinydtls" -#endif /* PACKAGE_TARNAME */ - -#ifndef PACKAGE_URL -/* Define to the home page for this package. */ -#define PACKAGE_URL "" -#endif /* PACKAGE_URL */ - -#ifndef PACKAGE_VERSION -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.4.0" -#endif /* PACKAGE_VERSION */ - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -/* # undef WORDS_BIGENDIAN */ -# endif -#endif - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif - -/* Define to rpl_malloc if the replacement function should be used. */ -/* #undef malloc */ - -/* Define to `unsigned int' if <sys/types.h> does not define. */ -/* #undef size_t */
--- a/tinydtls/crypto.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,317 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <stdio.h> -#ifdef HAVE_ASSERT_H -#include <assert.h> -#endif - -//#include "global.h" -#include "debug.h" -#include "numeric.h" -#include "dtls.h" -#include "crypto.h" -#include "ccm.h" - -#ifndef WITH_CONTIKI -#include <stdlib.h> - -static inline dtls_cipher_context_t * -dtls_cipher_context_new() { - return (dtls_cipher_context_t *)malloc(sizeof(dtls_cipher_context_t)); -} - -static inline void -dtls_cipher_context_free(dtls_cipher_context_t *ctx) { - free(ctx); -} -#else /* WITH_CONTIKI */ -MEMB(cipher_storage, dtls_cipher_context_t, DTLS_CIPHER_CONTEXT_MAX); - -static inline dtls_cipher_context_t * -dtls_cipher_context_new() { - return (dtls_cipher_context_t *)memb_alloc(&cipher_storage); -} - -static inline void -dtls_cipher_context_free(dtls_cipher_context_t *ctx) { - if (ctx) - memb_free(&cipher_storage, ctx); -} -#endif /* WITH_CONTIKI */ - -extern void dtls_hmac_storage_init(); - -void crypto_init() { - dtls_hmac_storage_init(); - -#ifdef WITH_CONTIKI - memb_init(&cipher_storage); -#endif /* WITH_CONTIKI */ -} - -#ifndef NDEBUG -extern void dump(unsigned char *, size_t); -#endif - -#define HMAC_UPDATE_SEED(Context,Seed,Length) \ - if (Seed) dtls_hmac_update(Context, (Seed), (Length)) - -size_t -dtls_p_hash(dtls_hashfunc_t h, - const unsigned char *key, size_t keylen, - const unsigned char *label, size_t labellen, - const unsigned char *random1, size_t random1len, - const unsigned char *random2, size_t random2len, - unsigned char *buf, size_t buflen) { - dtls_hmac_context_t *hmac_a, *hmac_p; - - unsigned char A[DTLS_HMAC_DIGEST_SIZE]; - unsigned char tmp[DTLS_HMAC_DIGEST_SIZE]; - size_t dlen; /* digest length */ - size_t len = 0; /* result length */ - - hmac_a = dtls_hmac_new(key, keylen); - if (!hmac_a) - return 0; - - /* calculate A(1) from A(0) == seed */ - HMAC_UPDATE_SEED(hmac_a, label, labellen); - HMAC_UPDATE_SEED(hmac_a, random1, random1len); - HMAC_UPDATE_SEED(hmac_a, random2, random2len); - - dlen = dtls_hmac_finalize(hmac_a, A); - - hmac_p = dtls_hmac_new(key, keylen); - if (!hmac_p) - goto error; - - while (len + dlen < buflen) { - - /* FIXME: rewrite loop to avoid superflous call to dtls_hmac_init() */ - dtls_hmac_init(hmac_p, key, keylen); - dtls_hmac_update(hmac_p, A, dlen); - - HMAC_UPDATE_SEED(hmac_p, label, labellen); - HMAC_UPDATE_SEED(hmac_p, random1, random1len); - HMAC_UPDATE_SEED(hmac_p, random2, random2len); - - len += dtls_hmac_finalize(hmac_p, tmp); - memcpy(buf, tmp, dlen); - buf += dlen; - - /* calculate A(i+1) */ - dtls_hmac_init(hmac_a, key, keylen); - dtls_hmac_update(hmac_a, A, dlen); - dtls_hmac_finalize(hmac_a, A); - } - - dtls_hmac_init(hmac_p, key, keylen); - dtls_hmac_update(hmac_p, A, dlen); - - HMAC_UPDATE_SEED(hmac_p, label, labellen); - HMAC_UPDATE_SEED(hmac_p, random1, random1len); - HMAC_UPDATE_SEED(hmac_p, random2, random2len); - - dtls_hmac_finalize(hmac_p, tmp); - memcpy(buf, tmp, buflen - len); - - error: - dtls_hmac_free(hmac_a); - dtls_hmac_free(hmac_p); - - return buflen; -} - -size_t -dtls_prf(const unsigned char *key, size_t keylen, - const unsigned char *label, size_t labellen, - const unsigned char *random1, size_t random1len, - const unsigned char *random2, size_t random2len, - unsigned char *buf, size_t buflen) { - - /* Clear the result buffer */ - memset(buf, 0, buflen); - return dtls_p_hash(HASH_SHA256, - key, keylen, - label, labellen, - random1, random1len, - random2, random2len, - buf, buflen); -} - -void -dtls_mac(dtls_hmac_context_t *hmac_ctx, - const unsigned char *record, - const unsigned char *packet, size_t length, - unsigned char *buf) { - uint16 L; - dtls_int_to_uint16(L, length); - - assert(hmac_ctx); - dtls_hmac_update(hmac_ctx, record +3, sizeof(uint16) + sizeof(uint48)); - dtls_hmac_update(hmac_ctx, record, sizeof(uint8) + sizeof(uint16)); - dtls_hmac_update(hmac_ctx, L, sizeof(uint16)); - dtls_hmac_update(hmac_ctx, packet, length); - - dtls_hmac_finalize(hmac_ctx, buf); -} - -static inline void -dtls_ccm_init(aes128_ccm_t *ccm_ctx, unsigned char *N, size_t length) { - assert(ccm_ctx); - - if (length < DTLS_CCM_BLOCKSIZE) - memset(ccm_ctx->N + length, 0, DTLS_CCM_BLOCKSIZE - length); - - memcpy(ccm_ctx->N, N, DTLS_CCM_BLOCKSIZE); -} - -size_t -dtls_ccm_encrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, size_t srclen, - unsigned char *buf, - const unsigned char *aad, size_t la) { - long int len; - - assert(ccm_ctx); - - len = dtls_ccm_encrypt_message(&ccm_ctx->ctx, 8 /* M */, - max(2, 15 - DTLS_CCM_NONCE_SIZE), - ccm_ctx->N, - buf, srclen, - aad, la); - return len; -} - -size_t -dtls_ccm_decrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, - size_t srclen, unsigned char *buf, - const unsigned char *aad, size_t la) { - long int len; - - assert(ccm_ctx); - - len = dtls_ccm_decrypt_message(&ccm_ctx->ctx, 8 /* M */, - max(2, 15 - DTLS_CCM_NONCE_SIZE), - ccm_ctx->N, - buf, srclen, - aad, la); - return len; -} - -size_t -dtls_pre_master_secret(unsigned char *key, size_t keylen, - unsigned char *result) { - unsigned char *p = result; - - dtls_int_to_uint16(p, keylen); - p += sizeof(uint16); - - memset(p, 0, keylen); - p += keylen; - - memcpy(p, result, sizeof(uint16)); - p += sizeof(uint16); - - memcpy(p, key, keylen); - - return (sizeof(uint16) + keylen) << 1; -} - -void -dtls_cipher_set_iv(dtls_cipher_context_t *ctx, - unsigned char *iv, size_t length) { - assert(ctx); - dtls_ccm_init(&ctx->data, iv, length); -} - -dtls_cipher_context_t * -dtls_cipher_new(dtls_cipher_t cipher, - unsigned char *key, size_t keylen) { - dtls_cipher_context_t *cipher_context = NULL; - - cipher_context = dtls_cipher_context_new(); - if (!cipher_context) { - warn("cannot allocate cipher_context\r\n"); - return NULL; - } - - switch (cipher) { - case TLS_PSK_WITH_AES_128_CCM_8: { - aes128_ccm_t *ccm_ctx = &cipher_context->data; - - if (rijndael_set_key_enc_only(&ccm_ctx->ctx, key, 8 * keylen) < 0) { - /* cleanup everything in case the key has the wrong size */ - warn("cannot set rijndael key\n"); - goto error; - } - break; - } - default: - warn("unknown cipher %04x\n", cipher); - goto error; - } - - return cipher_context; - error: - dtls_cipher_context_free(cipher_context); - return NULL; -} - -void -dtls_cipher_free(dtls_cipher_context_t *cipher_context) { - dtls_cipher_context_free(cipher_context); -} - -int -dtls_encrypt(dtls_cipher_context_t *ctx, - const unsigned char *src, size_t length, - unsigned char *buf, - const unsigned char *aad, size_t la) { - if (ctx) { - if (src != buf) - memmove(buf, src, length); - return dtls_ccm_encrypt(&ctx->data, src, length, buf, - aad, la); - } - - return -1; -} - -int -dtls_decrypt(dtls_cipher_context_t *ctx, - const unsigned char *src, size_t length, - unsigned char *buf, - const unsigned char *aad, size_t la) { - if (ctx) { - if (src != buf) - memmove(buf, src, length); - return dtls_ccm_decrypt(&ctx->data, src, length, buf, - aad, la); - } - - return -1; -} -
--- a/tinydtls/crypto.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,298 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _CRYPTO_H_ -#define _CRYPTO_H_ - -#include "config.h" - -#include <stdlib.h> /* for rand() and srand() */ - -#include "aes/rijndael.h" - -#include "prng.h" -#include "global.h" -#include "numeric.h" -#include "hmac.h" -#include "ccm.h" - -/* TLS_PSK_WITH_AES_128_CCM_8 */ -#define DTLS_MAC_KEY_LENGTH 0 -#define DTLS_KEY_LENGTH 16 /* AES-128 */ -#define DTLS_BLK_LENGTH 16 /* AES-128 */ -#define DTLS_MAC_LENGTH DTLS_HMAC_DIGEST_SIZE -#define DTLS_IV_LENGTH 4 /* length of nonce_explicit */ - -/** - * Maximum size of the generated keyblock. Note that MAX_KEYBLOCK_LENGTH must - * be large enough to hold the pre_master_secret, i.e. twice the length of the - * pre-shared key + 1. - */ -#define MAX_KEYBLOCK_LENGTH \ - (2 * DTLS_MAC_KEY_LENGTH + 2 * DTLS_KEY_LENGTH + 2 * DTLS_IV_LENGTH) - -/** Length of DTLS master_secret */ -#define DTLS_MASTER_SECRET_LENGTH 48 - -#ifndef DTLS_CIPHER_CONTEXT_MAX -#define DTLS_CIPHER_CONTEXT_MAX 4 -#endif - -typedef enum { AES128=0 -} dtls_crypto_alg; - -/** Crypto context for TLS_PSK_WITH_AES_128_CCM_8 cipher suite. */ -typedef struct { - rijndael_ctx ctx; /**< AES-128 encryption context */ - unsigned char N[DTLS_CCM_BLOCKSIZE]; /**< nonce */ -} aes128_ccm_t; - -typedef struct dtls_cipher_context_t { - /** numeric identifier of this cipher suite in host byte order. */ - dtls_cipher_t code; - aes128_ccm_t data; /**< The crypto context */ -} dtls_cipher_context_t; - -typedef enum { DTLS_CLIENT=0, DTLS_SERVER } dtls_peer_type; - -typedef struct { - uint8 client_random[32]; /**< client random gmt and bytes */ - - dtls_peer_type role; /**< denotes if the remote peer is DTLS_CLIENT or DTLS_SERVER */ - unsigned char compression; /**< compression method */ - - dtls_cipher_t cipher; /**< cipher type */ - - /** the session's master secret */ - uint8 master_secret[DTLS_MASTER_SECRET_LENGTH]; - - /** - * The key block generated from PRF applied to client and server - * random bytes. The actual size is given by the selected cipher and - * can be calculated using dtls_kb_size(). Use \c dtls_kb_ macros to - * access the components of the key block. - */ - uint8 key_block[MAX_KEYBLOCK_LENGTH]; - - dtls_cipher_context_t *read_cipher; /**< decryption context */ - dtls_cipher_context_t *write_cipher; /**< encryption context */ -} dtls_security_parameters_t; - -/* The following macros provide access to the components of the - * key_block in the security parameters. */ - -#define dtls_kb_client_mac_secret(Param) ((Param)->key_block) -#define dtls_kb_server_mac_secret(Param) \ - (dtls_kb_client_mac_secret(Param) + DTLS_MAC_KEY_LENGTH) -#define dtls_kb_remote_mac_secret(Param) \ - ((Param)->role == DTLS_CLIENT \ - ? dtls_kb_client_mac_secret(Param) \ - : dtls_kb_server_mac_secret(Param)) -#define dtls_kb_local_mac_secret(Param) \ - ((Param)->role == DTLS_SERVER \ - ? dtls_kb_client_mac_secret(Param) \ - : dtls_kb_server_mac_secret(Param)) -#define dtls_kb_mac_secret_size(Param) DTLS_MAC_KEY_LENGTH -#define dtls_kb_client_write_key(Param) \ - (dtls_kb_server_mac_secret(Param) + DTLS_MAC_KEY_LENGTH) -#define dtls_kb_server_write_key(Param) \ - (dtls_kb_client_write_key(Param) + DTLS_KEY_LENGTH) -#define dtls_kb_remote_write_key(Param) \ - ((Param)->role == DTLS_CLIENT \ - ? dtls_kb_client_write_key(Param) \ - : dtls_kb_server_write_key(Param)) -#define dtls_kb_local_write_key(Param) \ - ((Param)->role == DTLS_SERVER \ - ? dtls_kb_client_write_key(Param) \ - : dtls_kb_server_write_key(Param)) -#define dtls_kb_key_size(Param) DTLS_KEY_LENGTH -#define dtls_kb_client_iv(Param) \ - (dtls_kb_server_write_key(Param) + DTLS_KEY_LENGTH) -#define dtls_kb_server_iv(Param) \ - (dtls_kb_client_iv(Param) + DTLS_IV_LENGTH) -#define dtls_kb_remote_iv(Param) \ - ((Param)->role == DTLS_CLIENT \ - ? dtls_kb_client_iv(Param) \ - : dtls_kb_server_iv(Param)) -#define dtls_kb_local_iv(Param) \ - ((Param)->role == DTLS_SERVER \ - ? dtls_kb_client_iv(Param) \ - : dtls_kb_server_iv(Param)) -#define dtls_kb_iv_size(Param) DTLS_IV_LENGTH - -#define dtls_kb_size(Param) \ - (2 * (dtls_kb_mac_secret_size(Param) + \ - dtls_kb_key_size(Param) + dtls_kb_iv_size(Param))) - -/* just for consistency */ -#define dtls_kb_digest_size(Param) DTLS_MAC_LENGTH - -/** - * Expands the secret and key to a block of DTLS_HMAC_MAX - * size according to the algorithm specified in section 5 of - * RFC 4346. - * - * \param h Identifier of the hash function to use. - * \param key The secret. - * \param keylen Length of \p key. - * \param seed The seed. - * \param seedlen Length of \p seed. - * \param buf Output buffer where the result is XORed into - * The buffe must be capable to hold at least - * \p buflen bytes. - * \return The actual number of bytes written to \p buf or 0 - * on error. - */ -size_t dtls_p_hash(dtls_hashfunc_t h, - const unsigned char *key, size_t keylen, - const unsigned char *label, size_t labellen, - const unsigned char *random1, size_t random1len, - const unsigned char *random2, size_t random2len, - unsigned char *buf, size_t buflen); - -/** - * This function implements the TLS PRF for DTLS_VERSION. For version - * 1.0, the PRF is P_MD5 ^ P_SHA1 while version 1.2 uses - * P_SHA256. Currently, the actual PRF is selected at compile time. - */ -size_t dtls_prf(const unsigned char *key, size_t keylen, - const unsigned char *label, size_t labellen, - const unsigned char *random1, size_t random1len, - const unsigned char *random2, size_t random2len, - unsigned char *buf, size_t buflen); - -/** - * Calculates MAC for record + cleartext packet and places the result - * in \p buf. The given \p hmac_ctx must be initialized with the HMAC - * function to use and the proper secret. As the DTLS mac calculation - * requires data from the record header, \p record must point to a - * buffer of at least \c sizeof(dtls_record_header_t) bytes. Usually, - * the remaining packet will be encrypted, therefore, the cleartext - * is passed separately in \p packet. - * - * \param hmac_ctx The HMAC context to use for MAC calculation. - * \param record The record header. - * \param packet Cleartext payload to apply the MAC to. - * \param length Size of \p packet. - * \param buf A result buffer that is large enough to hold - * the generated digest. - */ -void dtls_mac(dtls_hmac_context_t *hmac_ctx, - const unsigned char *record, - const unsigned char *packet, size_t length, - unsigned char *buf); - -/** - * Encrypts the specified \p src of given \p length, writing the - * result to \p buf. The cipher implementation may add more data to - * the result buffer such as an initialization vector or padding - * (e.g. for block cipers in CBC mode). The caller therefore must - * ensure that \p buf provides sufficient storage to hold the result. - * Usually this means ( 2 + \p length / blocksize ) * blocksize. The - * function returns a value less than zero on error or otherwise the - * number of bytes written. - * - * \param ctx The cipher context to use. - * \param src The data to encrypt. - * \param length The actual size of of \p src. - * \param buf The result buffer. \p src and \p buf must not - * overlap. - * \param aad additional data for AEAD ciphers - * \param aad_length actual size of @p aad - * \return The number of encrypted bytes on success, less than zero - * otherwise. - */ -int dtls_encrypt(dtls_cipher_context_t *ctx, - const unsigned char *src, size_t length, - unsigned char *buf, - const unsigned char *aad, size_t aad_length); - -/** - * Decrypts the given buffer \p src of given \p length, writing the - * result to \p buf. The function returns \c -1 in case of an error, - * or the number of bytes written. Note that for block ciphers, \p - * length must be a multiple of the cipher's block size. A return - * value between \c 0 and the actual length indicates that only \c n-1 - * block have been processed. Unlike dtls_encrypt(), the source - * and destination of dtls_decrypt() may overlap. - * - * \param ctx The cipher context to use. - * \param src The buffer to decrypt. - * \param length The length of the input buffer. - * \param buf The result buffer. - * \param aad additional authentication data for AEAD ciphers - * \param aad_length actual size of @p aad - * \return Less than zero on error, the number of decrypted bytes - * otherwise. - */ -int dtls_decrypt(dtls_cipher_context_t *ctx, - const unsigned char *src, size_t length, - unsigned char *buf, - const unsigned char *a_data, size_t a_data_length); - -/* helper functions */ - -/** - * Generates pre_master_sercet from given PSK and fills the result - * according to the "plain PSK" case in section 2 of RFC 4279. - * Diffie-Hellman and RSA key exchange are currently not supported. - * - * @param key The shared key. - * @param keylen Length of @p key in bytes. - * @param result The derived pre master secret. - * @return The actual length of @p result. - */ -size_t dtls_pre_master_secret(unsigned char *key, size_t keylen, - unsigned char *result); - -/** - * Creates a new dtls_cipher_context_t object for given @c cipher. - * The storage allocated for this object must be released using - * dtls_cipher_free(). - * - * @param code Code of the requested cipher (host byte order) - * @param key The encryption and decryption key. - * @param keylen Actual length of @p key. - * @return A new dtls_cipher_context_t object or @c NULL in case - * something went wrong (e.g. insufficient memory or wrong - * key length) - */ -dtls_cipher_context_t *dtls_cipher_new(dtls_cipher_t code, - unsigned char *key, size_t keylen); - -/** - * Releases the storage allocated by dtls_cipher_new() for @p cipher_context - */ -void dtls_cipher_free(dtls_cipher_context_t *cipher_context); - - -/** - * Initializes the given cipher context @p ctx with the initialization - * vector @p iv of length @p length. */ -void dtls_cipher_set_iv(dtls_cipher_context_t *ctx, - unsigned char *iv, size_t length); - -#endif /* _CRYPTO_H_ */ -
--- a/tinydtls/debug.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,254 +0,0 @@ -/* debug.c -- debug utilities - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#if defined(HAVE_ASSERT_H) && !defined(assert) -#include <assert.h> -#endif - -#include <stdarg.h> -#include <string.h> -#include <stdio.h> - -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif - -#ifdef HAVE_TIME_H -#include <time.h> -#endif - -#include "global.h" -#include "debug.h" - -#ifdef WITH_CONTIKI -# ifndef DEBUG -# define DEBUG DEBUG_PRINT -# endif /* DEBUG */ -#include "net/uip-debug.h" -#else -#define PRINTF(...) -#endif - -static int maxlog = LOG_WARN; /* default maximum log level */ - -log_t -dtls_get_log_level() { - return maxlog; -} - -void -dtls_set_log_level(log_t level) { - maxlog = level; -} - -/* this array has the same order as the type log_t */ -static char *loglevels[] = { - "EMRG", "ALRT", "CRIT", "WARN", "NOTE", "INFO", "DEBG" -}; - -#ifdef HAVE_TIME_H - -static inline size_t -print_timestamp(char *s, size_t len, time_t t) { - struct tm *tmp; - tmp = localtime(&t); - return strftime(s, len, "%b %d %H:%M:%S", tmp); -} - -#else /* alternative implementation: just print the timestamp */ - -static inline size_t -print_timestamp(char *s, size_t len, clock_time_t t) { -#ifdef HAVE_SNPRINTF - return snprintf(s, len, "%u.%03u", - (unsigned int)(t / CLOCK_SECOND), - (unsigned int)(t % CLOCK_SECOND)); -#else /* HAVE_SNPRINTF */ - /* @todo do manual conversion of timestamp */ - return 0; -#endif /* HAVE_SNPRINTF */ -} - -#endif /* HAVE_TIME_H */ - -#ifndef HAVE_STRNLEN -/** - * A length-safe strlen() fake. - * - * @param s The string to count characters != 0. - * @param maxlen The maximum length of @p s. - * - * @return The length of @p s. - */ -static inline size_t -strnlen(const char *s, size_t maxlen) { - size_t n = 0; - while(*s++ && n < maxlen) - ++n; - return n; -} -#endif /* HAVE_STRNLEN */ - -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif - -size_t -dsrv_print_addr(const session_t *addr, unsigned char *buf, size_t len) { -#ifdef HAVE_ARPA_INET_H - const void *addrptr = NULL; - in_port_t port; - unsigned char *p = buf; - - switch (addr->addr.sa.sa_family) { - case AF_INET: - addrptr = &addr->addr.sin.sin_addr; - port = ntohs(addr->addr.sin.sin_port); - break; - case AF_INET6: - if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */ - return 0; - - *p++ = '['; - - addrptr = &addr->addr.sin6.sin6_addr; - port = ntohs(addr->addr.sin6.sin6_port); - - break; - default: - memcpy(buf, "(unknown address type)", min(22, len)); - return min(22, len); - } - - if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)p, len) == 0) { - perror("dsrv_print_addr"); - return 0; - } - - p += strnlen((char *)p, len); - - if (addr->addr.sa.sa_family == AF_INET6) { - if (p < buf + len) { - *p++ = ']'; - } else - return 0; - } - - p += snprintf((char *)p, buf + len - p + 1, ":%d", port); - - return buf + len - p; -#else /* HAVE_ARPA_INET_H */ -# if WITH_CONTIKI - unsigned char *p = buf; - uint8_t i; -# if WITH_UIP6 - const unsigned char hex[] = "0123456789ABCDEF"; - - if (len < 41) - return 0; - - *p++ = '['; - - for (i=0; i < 8; i += 4) { - *p++ = hex[(addr->addr.u16[i] & 0xf000) >> 24]; - *p++ = hex[(addr->addr.u16[i] & 0x0f00) >> 16]; - *p++ = hex[(addr->addr.u16[i] & 0x00f0) >> 8]; - *p++ = hex[(addr->addr.u16[i] & 0x000f)]; - *p++ = ':'; - } - *(p-1) = ']'; -# else /* WITH_UIP6 */ -# warning "IPv4 network addresses will not be included in debug output" - - if (len < 21) - return 0; -# endif /* WITH_UIP6 */ - if (buf + len - p < 6) - return 0; - -#ifdef HAVE_SNPRINTF - p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port)); -#else /* HAVE_SNPRINTF */ - /* @todo manual conversion of port number */ -#endif /* HAVE_SNPRINTF */ - - return buf + len - p; -# else /* WITH_CONTIKI */ - /* TODO: output addresses manually */ -# warning "inet_ntop() not available, network addresses will not be included in debug output" -# endif /* WITH_CONTIKI */ - return 0; -#endif -} - -#ifndef WITH_CONTIKI -void -dsrv_log(log_t level, char *format, ...) { - static char timebuf[32]; - va_list ap; - FILE *log_fd; - - if (maxlog < level) - return; - - log_fd = level <= LOG_CRIT ? stderr : stdout; - - if (print_timestamp(timebuf,sizeof(timebuf), time(NULL))) - fprintf(log_fd, "%s ", timebuf); - - if (level >= 0 && level <= LOG_DEBUG) - printf("%s ", loglevels[level]); - - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - fflush(stdout); -} -#else /* WITH_CONTIKI */ -void -dsrv_log(log_t level, char *format, ...) { - static char timebuf[32]; - va_list ap; - - if (maxlog < level) - return; - - if (print_timestamp(timebuf,sizeof(timebuf), clock_time())) - PRINTF("%s ", timebuf); - - if (level >= 0 && level <= LOG_DEBUG) - PRINTF("%s ", loglevels[level]); - - va_start(ap, format); -#ifdef HAVE_VPRINTF - vprintf(format, ap); -#else - PRINTF(format, ap); -#endif - va_end(ap); -} -#endif /* WITH_CONTIKI */
--- a/tinydtls/debug.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* debug.h -- debug utilities - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _DEBUG_H_ -#define _DEBUG_H_ - -#include "config.h" - -/** Pre-defined log levels akin to what is used in \b syslog. */ -typedef enum { LOG_EMERG=0, LOG_ALERT, LOG_CRIT, LOG_WARN, - LOG_NOTICE, LOG_INFO, LOG_DEBUG -} log_t; - -/** Returns the current log level. */ -log_t dtls_get_log_level(); - -/** Sets the log level to the specified value. */ -void dtls_set_log_level(log_t level); - -/** - * Writes the given text to \c stdout. The text is output only when \p - * level is below or equal to the log level that set by - * set_log_level(). */ -void dsrv_log(log_t level, char *format, ...); - -/* A set of convenience macros for common log levels. */ -#define info(...) dsrv_log(LOG_INFO, __VA_ARGS__) -#define warn(...) dsrv_log(LOG_WARN, __VA_ARGS__) -#define debug(...) dsrv_log(LOG_DEBUG, __VA_ARGS__) - -#endif /* _DEBUG_H_ */
--- a/tinydtls/dtls.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2495 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" - -#include "dtls_time.h" - -#include <stdio.h> -#include <stdlib.h> -#ifdef HAVE_ASSERT_H -#include <assert.h> -#endif -#ifndef WITH_CONTIKI -#include <stdlib.h> -#include "uthash.h" -#else /* WITH_CONTIKI */ -# ifndef NDEBUG -# define DEBUG DEBUG_PRINT -# include "net/uip-debug.h" -# endif /* NDEBUG */ -#endif /* WITH_CONTIKI */ - -#include "debug.h" -#include "numeric.h" -#include "netq.h" -#include "dtls.h" - - -#ifdef WITH_SHA256 -# include "sha2/sha2.h" -#endif - -//#include "bsd_socket.h" - -#define dtls_set_version(H,V) dtls_int_to_uint16(&(H)->version, (V)) -#define dtls_set_content_type(H,V) ((H)->content_type = (V) & 0xff) -#define dtls_set_length(H,V) ((H)->length = (V)) - -#define dtls_get_content_type(H) ((H)->content_type & 0xff) -#define dtls_get_version(H) dtls_uint16_to_int(&(H)->version) -#define dtls_get_epoch(H) dtls_uint16_to_int(&(H)->epoch) -#define dtls_get_sequence_number(H) dtls_uint48_to_ulong(&(H)->sequence_number) -#define dtls_get_fragment_length(H) dtls_uint24_to_int(&(H)->fragment_length) - -#ifndef WITH_CONTIKI -#define HASH_FIND_PEER(head,sess,out) \ - HASH_FIND(hh,head,sess,sizeof(session_t),out) -#define HASH_ADD_PEER(head,sess,add) \ - HASH_ADD(hh,head,sess,sizeof(session_t),add) -#define HASH_DEL_PEER(head,delptr) \ - HASH_DELETE(hh,head,delptr) -#endif /* WITH_CONTIKI */ - -#define DTLS_RH_LENGTH sizeof(dtls_record_header_t) -#define DTLS_HS_LENGTH sizeof(dtls_handshake_header_t) -#define DTLS_CH_LENGTH sizeof(dtls_client_hello_t) /* no variable length fields! */ -#define DTLS_HV_LENGTH sizeof(dtls_hello_verify_t) -#define DTLS_SH_LENGTH (2 + 32 + 1 + 2 + 1) -#define DTLS_CKX_LENGTH 1 -#define DTLS_FIN_LENGTH 12 - -#define HS_HDR_LENGTH DTLS_RH_LENGTH + DTLS_HS_LENGTH -#define HV_HDR_LENGTH HS_HDR_LENGTH + DTLS_HV_LENGTH - -#define HIGH(V) (((V) >> 8) & 0xff) -#define LOW(V) ((V) & 0xff) - -#define DTLS_RECORD_HEADER(M) ((dtls_record_header_t *)(M)) -#define DTLS_HANDSHAKE_HEADER(M) ((dtls_handshake_header_t *)(M)) - -#define HANDSHAKE(M) ((dtls_handshake_header_t *)((M) + DTLS_RH_LENGTH)) -#define CLIENTHELLO(M) ((dtls_client_hello_t *)((M) + HS_HDR_LENGTH)) - -#define IS_HELLOVERIFY(M,L) \ - ((L) >= DTLS_HS_LENGTH + DTLS_HV_LENGTH && (M)[0] == DTLS_HT_HELLO_VERIFY_REQUEST) -#define IS_SERVERHELLO(M,L) \ - ((L) >= DTLS_HS_LENGTH + 6 && (M)[0] == DTLS_HT_SERVER_HELLO) -#define IS_SERVERHELLODONE(M,L) \ - ((L) >= DTLS_HS_LENGTH && (M)[0] == DTLS_HT_SERVER_HELLO_DONE) -#define IS_FINISHED(M,L) \ - ((L) >= DTLS_HS_LENGTH + DTLS_FIN_LENGTH && (M)[0] == DTLS_HT_FINISHED) - -/* The length check here should work because dtls_*_to_int() works on - * unsigned char. Otherwise, broken messages could cause severe - * trouble. Note that this macro jumps out of the current program flow - * when the message is too short. Beware! - */ -#define SKIP_VAR_FIELD(P,L,T) { \ - if (L < dtls_ ## T ## _to_int(P) + sizeof(T)) \ - goto error; \ - L -= dtls_ ## T ## _to_int(P) + sizeof(T); \ - P += dtls_ ## T ## _to_int(P) + sizeof(T); \ - } - -uint8 _clear[DTLS_MAX_BUF]; /* target buffer message decryption */ -uint8 _buf[DTLS_MAX_BUF]; /* target buffer for several crypto operations */ - -#ifndef NDEBUG -void hexdump(const unsigned char *packet, int length); -void dump(unsigned char *buf, size_t len); -#endif - -/* some constants for the PRF */ -#define PRF_LABEL(Label) prf_label_##Label -#define PRF_LABEL_SIZE(Label) (sizeof(PRF_LABEL(Label)) - 1) - -static const unsigned char prf_label_master[] = "master secret"; -static const unsigned char prf_label_key[] = "key expansion"; -static const unsigned char prf_label_client[] = "client"; -static const unsigned char prf_label_server[] = "server"; -static const unsigned char prf_label_finished[] = " finished"; - -extern void netq_init(); -extern void crypto_init(); -extern void peer_init(); - -dtls_context_t the_dtls_context; - -void -dtls_init() { - dtls_clock_init(); - netq_init(); - crypto_init(); - peer_init(); -} - -/* Calls cb_alert() with given arguments if defined, otherwise an - * error message is logged and the result is -1. This is just an - * internal helper. - */ -#define CALL(Context, which, ...) \ - ((Context)->h && (Context)->h->which \ - ? (Context)->h->which((Context), ##__VA_ARGS__) \ - : -1) - -/** - * Sends the fragment of length \p buflen given in \p buf to the - * specified \p peer. The data will be MAC-protected and encrypted - * according to the selected cipher and split into one or more DTLS - * records of the specified \p type. This function returns the number - * of bytes that were sent, or \c -1 if an error occurred. - * - * \param ctx The DTLS context to use. - * \param peer The remote peer. - * \param type The content type of the record. - * \param buf The data to send. - * \param buflen The actual length of \p buf. - * \return Less than zero on error, the number of bytes written otherwise. - */ -int dtls_send(dtls_context_t *ctx, dtls_peer_t *peer, unsigned char type, - uint8 *buf, size_t buflen); - -/** - * Stops ongoing retransmissions of handshake messages for @p peer. - */ -void dtls_stop_retransmission(dtls_context_t *context, dtls_peer_t *peer); - -dtls_peer_t * -dtls_get_peer(const dtls_context_t *ctx, const session_t *session) { - dtls_peer_t *p = NULL; - -#ifndef WITH_CONTIKI - HASH_FIND_PEER(ctx->peers, session, p); -#else /* WITH_CONTIKI */ - for (p = list_head(ctx->peers); p; p = list_item_next(p)) - if (dtls_session_equals(&p->session, session)) - return p; -#endif /* WITH_CONTIKI */ - - return p; -} - -void -dtls_add_peer(dtls_context_t *ctx, dtls_peer_t *peer) { -#ifndef WITH_CONTIKI - HASH_ADD_PEER(ctx->peers, session, peer); -#else /* WITH_CONTIKI */ - list_add(ctx->peers, peer); -#endif /* WITH_CONTIKI */ -} - -int -dtls_write(struct dtls_context_t *ctx, - session_t *dst, uint8 *buf, size_t len) { - - dtls_peer_t *peer = dtls_get_peer(ctx, dst); - - /* Check if peer connection already exists */ - if (!peer) { /* no ==> create one */ - int res; - - /* dtls_connect() returns a value greater than zero if a new - * connection attempt is made, 0 for session reuse. */ - res = dtls_connect(ctx, dst); - - return (res >= 0) ? 0 : res; - } else { /* a session exists, check if it is in state connected */ - - if (peer->state != DTLS_STATE_CONNECTED) { - return 0; - } else { - return dtls_send(ctx, peer, DTLS_CT_APPLICATION_DATA, buf, len); - } - } -} - -int -dtls_get_cookie(uint8 *msg, int msglen, uint8 **cookie) { - /* To access the cookie, we have to determine the session id's - * length and skip the whole thing. */ - if (msglen < DTLS_HS_LENGTH + DTLS_CH_LENGTH + sizeof(uint8) - || dtls_uint16_to_int(msg + DTLS_HS_LENGTH) != DTLS_VERSION) - return -1; - msglen -= DTLS_HS_LENGTH + DTLS_CH_LENGTH; - msg += DTLS_HS_LENGTH + DTLS_CH_LENGTH; - - SKIP_VAR_FIELD(msg, msglen, uint8); /* skip session id */ - - if (msglen < (*msg & 0xff) + sizeof(uint8)) - return -1; - - *cookie = msg + sizeof(uint8); - return dtls_uint8_to_int(msg); - - error: - return -1; -} - -int -dtls_create_cookie(dtls_context_t *ctx, - session_t *session, - uint8 *msg, int msglen, - uint8 *cookie, int *clen) { - unsigned char buf[DTLS_HMAC_MAX]; - size_t len, e; - - /* create cookie with HMAC-SHA256 over: - * - SECRET - * - session parameters (only IP address?) - * - client version - * - random gmt and bytes - * - session id - * - cipher_suites - * - compression method - */ - - /* We use our own buffer as hmac_context instead of a dynamic buffer - * created by dtls_hmac_new() to separate storage space for cookie - * creation from storage that is used in real sessions. Note that - * the buffer size must fit with the default hash algorithm (see - * implementation of dtls_hmac_context_new()). */ - - dtls_hmac_context_t hmac_context; - dtls_hmac_init(&hmac_context, ctx->cookie_secret, DTLS_COOKIE_SECRET_LENGTH); - - dtls_hmac_update(&hmac_context, - (unsigned char *)&session->addr, session->size); - - /* feed in the beginning of the Client Hello up to and including the - session id */ - e = sizeof(dtls_client_hello_t); - e += (*(msg + DTLS_HS_LENGTH + e) & 0xff) + sizeof(uint8); - - dtls_hmac_update(&hmac_context, msg + DTLS_HS_LENGTH, e); - - /* skip cookie bytes and length byte */ - e += *(uint8 *)(msg + DTLS_HS_LENGTH + e) & 0xff; - e += sizeof(uint8); - - dtls_hmac_update(&hmac_context, - msg + DTLS_HS_LENGTH + e, - dtls_get_fragment_length(DTLS_HANDSHAKE_HEADER(msg)) - e); - - len = dtls_hmac_finalize(&hmac_context, buf); - - if (len < *clen) { - memset(cookie + len, 0, *clen - len); - *clen = len; - } - - memcpy(cookie, buf, *clen); - return 1; -} - -#ifdef DTLS_CHECK_CONTENTTYPE -/* used to check if a received datagram contains a DTLS message */ -static char const content_types[] = { - DTLS_CT_CHANGE_CIPHER_SPEC, - DTLS_CT_ALERT, - DTLS_CT_HANDSHAKE, - DTLS_CT_APPLICATION_DATA, - 0 /* end marker */ -}; -#endif - -/** - * Checks if \p msg points to a valid DTLS record. If - * - */ -static unsigned int -is_record(uint8 *msg, int msglen) { - unsigned int rlen = 0; - - if (msglen >= DTLS_RH_LENGTH /* FIXME allow empty records? */ -#ifdef DTLS_CHECK_CONTENTTYPE - && strchr(content_types, msg[0]) -#endif - && msg[1] == HIGH(DTLS_VERSION) - && msg[2] == LOW(DTLS_VERSION)) - { - rlen = DTLS_RH_LENGTH + - dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->length); - - /* we do not accept wrong length field in record header */ - if (rlen > msglen) - rlen = 0; - } - - return rlen; -} - -/** - * Initializes \p buf as record header. The caller must ensure that \p - * buf is capable of holding at least \c sizeof(dtls_record_header_t) - * bytes. Increments sequence number counter of \p peer. - * \return pointer to the next byte after the written header - */ -static inline uint8 * -dtls_set_record_header(uint8 type, dtls_peer_t *peer, uint8 *buf) { - - dtls_int_to_uint8(buf, type); - buf += sizeof(uint8); - - dtls_int_to_uint16(buf, DTLS_VERSION); - buf += sizeof(uint16); - - if (peer) { - memcpy(buf, &peer->epoch, sizeof(uint16) + sizeof(uint48)); - - /* increment record sequence counter by 1 */ - inc_uint(uint48, peer->rseq); - } else { - memset(buf, 0, sizeof(uint16) + sizeof(uint48)); - } - - buf += sizeof(uint16) + sizeof(uint48); - - memset(buf, 0, sizeof(uint16)); - return buf + sizeof(uint16); -} - -/** - * Initializes \p buf as handshake header. The caller must ensure that \p - * buf is capable of holding at least \c sizeof(dtls_handshake_header_t) - * bytes. Increments message sequence number counter of \p peer. - * \return pointer to the next byte after \p buf - */ -static inline uint8 * -dtls_set_handshake_header(uint8 type, dtls_peer_t *peer, - int length, - int frag_offset, int frag_length, - uint8 *buf) { - - dtls_int_to_uint8(buf, type); - buf += sizeof(uint8); - - dtls_int_to_uint24(buf, length); - buf += sizeof(uint24); - - if (peer) { - /* increment handshake message sequence counter by 1 */ - inc_uint(uint16, peer->hs_state.mseq); - - /* and copy the result to buf */ - memcpy(buf, &peer->hs_state.mseq, sizeof(uint16)); - } else { - memset(buf, 0, sizeof(uint16)); - } - buf += sizeof(uint16); - - dtls_int_to_uint24(buf, frag_offset); - buf += sizeof(uint24); - - dtls_int_to_uint24(buf, frag_length); - buf += sizeof(uint24); - - return buf; -} - -/** - * Checks a received Client Hello message for a valid cookie. When the - * Client Hello contains no cookie, the function fails and a Hello - * Verify Request is sent to the peer (using the write callback function - * registered with \p ctx). The return value is \c -1 on error, \c 0 when - * undecided, and \c 1 if the Client Hello was good. - * - * \param ctx The DTLS context. - * \param peer The remote party we are talking to, if any. - * \param session Transport address of the remote peer. - * \param msg The received datagram. - * \param msglen Length of \p msg. - * \return \c 1 if msg is a Client Hello with a valid cookie, \c 0 or - * \c -1 otherwise. - */ -int -dtls_verify_peer(dtls_context_t *ctx, - dtls_peer_t *peer, - session_t *session, - uint8 *record, - uint8 *data, size_t data_length) { - - int len = DTLS_COOKIE_LENGTH; - uint8 *cookie, *p; -#undef mycookie -#define mycookie (ctx->sendbuf + HV_HDR_LENGTH) - - /* check if we can access at least all fields from the handshake header */ - if (record[0] == DTLS_CT_HANDSHAKE - && data_length >= DTLS_HS_LENGTH - && data[0] == DTLS_HT_CLIENT_HELLO) { - - /* Store cookie where we can reuse it for the HelloVerify request. */ - if (dtls_create_cookie(ctx, session, data, data_length, - mycookie, &len) < 0) - return -1; -/* #ifndef NDEBUG */ -/* debug("create cookie: "); */ -/* dump(mycookie, len); */ -/* printf("\n"); */ -/* #endif */ - assert(len == DTLS_COOKIE_LENGTH); - - /* Perform cookie check. */ - len = dtls_get_cookie(data, data_length, &cookie); - -/* #ifndef NDEBUG */ -/* debug("compare with cookie: "); */ -/* dump(cookie, len); */ -/* printf("\n"); */ -/* #endif */ - - /* check if cookies match */ - if (len == DTLS_COOKIE_LENGTH && memcmp(cookie, mycookie, len) == 0) { - debug("found matching cookie\n"); - return 1; - } - if (len > 0) { - debug("invalid cookie"); -#ifndef NDEBUG - dump(cookie, len); - printf("\n"); -#endif - } - /* ClientHello did not contain any valid cookie, hence we send a - * HelloVerify request. */ - - p = dtls_set_handshake_header(DTLS_HT_HELLO_VERIFY_REQUEST, - peer, DTLS_HV_LENGTH + DTLS_COOKIE_LENGTH, - 0, DTLS_HV_LENGTH + DTLS_COOKIE_LENGTH, - ctx->sendbuf + DTLS_RH_LENGTH); - - dtls_int_to_uint16(p, DTLS_VERSION); - p += sizeof(uint16); - - dtls_int_to_uint8(p, DTLS_COOKIE_LENGTH); - p += sizeof(uint8); - - assert(p == mycookie); - - p += DTLS_COOKIE_LENGTH; - - if (!peer) { - /* It's an initial ClientHello, so we set the record header - * manually and send the HelloVerify request using the - * registered write callback. */ - - dtls_set_record_header(DTLS_CT_HANDSHAKE, NULL, ctx->sendbuf); - /* set packet length */ - dtls_int_to_uint16(ctx->sendbuf + 11, - p - (ctx->sendbuf + DTLS_RH_LENGTH)); - - (void)CALL(ctx, write, session, ctx->sendbuf, p - ctx->sendbuf); - } else { - if (peer->epoch) { - debug("renegotiation, therefore we accept it anyway:"); - return 1; - } - - if (dtls_send(ctx, peer, DTLS_CT_HANDSHAKE, - ctx->sendbuf + DTLS_RH_LENGTH, - p - (ctx->sendbuf + DTLS_RH_LENGTH)) < 0) { - warn("cannot send HelloVerify request\n"); - return -1; - } - } - - return 0; /* HelloVerify is sent, now we cannot do anything but wait */ - } - - return -1; /* not a ClientHello, signal error */ -#undef mycookie -} - -/** only one compression method is currently defined */ -uint8 compression_methods[] = { - TLS_COMP_NULL -}; - -/** - * Returns @c 1 if @p code is a cipher suite other than @c - * TLS_NULL_WITH_NULL_NULL that we recognize. - * - * @param code The cipher suite identifier to check - * @return @c 1 iff @p code is recognized, - */ -static inline int -known_cipher(dtls_cipher_t code) { - return code == TLS_PSK_WITH_AES_128_CCM_8; -} - -int -calculate_key_block(dtls_context_t *ctx, - dtls_security_parameters_t *config, - const dtls_key_t *key, - unsigned char client_random[32], - unsigned char server_random[32]) { - unsigned char *pre_master_secret; - size_t pre_master_len = 0; - pre_master_secret = config->key_block; - - assert(key); - switch (key->type) { - case DTLS_KEY_PSK: { - /* Temporarily use the key_block storage space for the pre master secret. */ - pre_master_len = dtls_pre_master_secret(key->key.psk.key, key->key.psk.key_length, - pre_master_secret); - - break; - } - default: - debug("calculate_key_block: unknown key type\n"); - return 0; - } - -/* #ifndef NDEBUG */ -/* { */ -/* int i; */ - -/* printf("client_random:"); */ -/* for (i = 0; i < 32; ++i) */ -/* printf(" %02x", client_random[i]); */ -/* printf("\n"); */ - -/* printf("server_random:"); */ -/* for (i = 0; i < 32; ++i) */ -/* printf(" %02x", server_random[i]); */ -/* printf("\n"); */ - -/* printf("psk: (%lu bytes):", key->key.psk.key_length); */ -/* hexdump(key->key.psk.key, key->key.psk.key_length); */ -/* printf("\n"); */ - -/* printf("pre_master_secret: (%lu bytes):", pre_master_len); */ -/* for (i = 0; i < pre_master_len; ++i) */ -/* printf(" %02x", pre_master_secret[i]); */ -/* printf("\n"); */ -/* } */ -/* #endif /\* NDEBUG *\/ */ - - dtls_prf(pre_master_secret, pre_master_len, - PRF_LABEL(master), PRF_LABEL_SIZE(master), - client_random, 32, - server_random, 32, - config->master_secret, - DTLS_MASTER_SECRET_LENGTH); - -/* #ifndef NDEBUG */ -/* { */ -/* int i; */ -/* printf("master_secret (%d bytes):", DTLS_MASTER_SECRET_LENGTH); */ -/* for (i = 0; i < DTLS_MASTER_SECRET_LENGTH; ++i) */ -/* printf(" %02x", config->master_secret[i]); */ -/* printf("\n"); */ -/* } */ -/* #endif /\* NDEBUG *\/ */ - - /* create key_block from master_secret - * key_block = PRF(master_secret, - "key expansion" + server_random + client_random) */ - - dtls_prf(config->master_secret, - DTLS_MASTER_SECRET_LENGTH, - PRF_LABEL(key), PRF_LABEL_SIZE(key), - server_random, 32, - client_random, 32, - config->key_block, - dtls_kb_size(config)); - -/* #ifndef NDEBUG */ -/* { */ -/* printf("key_block (%d bytes):\n", dtls_kb_size(config)); */ -/* printf(" client_MAC_secret:\t"); */ -/* dump(dtls_kb_client_mac_secret(config), */ -/* dtls_kb_mac_secret_size(config)); */ -/* printf("\n"); */ - -/* printf(" server_MAC_secret:\t"); */ -/* dump(dtls_kb_server_mac_secret(config), */ -/* dtls_kb_mac_secret_size(config)); */ -/* printf("\n"); */ - -/* printf(" client_write_key:\t"); */ -/* dump(dtls_kb_client_write_key(config), */ -/* dtls_kb_key_size(config)); */ -/* printf("\n"); */ - -/* printf(" server_write_key:\t"); */ -/* dump(dtls_kb_server_write_key(config), */ -/* dtls_kb_key_size(config)); */ -/* printf("\n"); */ - -/* printf(" client_IV:\t\t"); */ -/* dump(dtls_kb_client_iv(config), */ -/* dtls_kb_iv_size(config)); */ -/* printf("\n"); */ - -/* printf(" server_IV:\t\t"); */ -/* dump(dtls_kb_server_iv(config), */ -/* dtls_kb_iv_size(config)); */ -/* printf("\n"); */ - - -/* } */ -/* #endif */ - return 1; -} - -/** - * Updates the security parameters of given \p peer. As this must be - * done before the new configuration is activated, it changes the - * OTHER_CONFIG only. When the ClientHello handshake message in \p - * data does not contain a cipher suite or compression method, it is - * copied from the CURRENT_CONFIG. - * - * \param ctx The current DTLS context. - * \param peer The remote peer whose security parameters are about to change. - * \param data The handshake message with a ClientHello. - * \param data_length The actual size of \p data. - * \return \c 0 if an error occurred, \c 1 otherwise. - */ -int -dtls_update_parameters(dtls_context_t *ctx, - dtls_peer_t *peer, - uint8 *data, size_t data_length) { - int i, j; - int ok; - dtls_security_parameters_t *config = OTHER_CONFIG(peer); - - assert(config); - assert(data_length > DTLS_HS_LENGTH + DTLS_CH_LENGTH); - - /* debug("dtls_update_parameters: msglen is %d\n", data_length); */ - - /* skip the handshake header and client version information */ - data += DTLS_HS_LENGTH + sizeof(uint16); - data_length -= DTLS_HS_LENGTH + sizeof(uint16); - - /* store client random in config - * FIXME: if we send the ServerHello here, we do not need to store - * the client's random bytes */ - memcpy(config->client_random, data, sizeof(config->client_random)); - data += sizeof(config->client_random); - data_length -= sizeof(config->client_random); - - /* Caution: SKIP_VAR_FIELD may jump to error: */ - SKIP_VAR_FIELD(data, data_length, uint8); /* skip session id */ - SKIP_VAR_FIELD(data, data_length, uint8); /* skip cookie */ - - i = dtls_uint16_to_int(data); - if (data_length < i + sizeof(uint16)) { - /* Looks like we do not have a cipher nor compression. This is ok - * for renegotiation, but not for the initial handshake. */ - - if (CURRENT_CONFIG(peer)->cipher == TLS_NULL_WITH_NULL_NULL) - goto error; - - config->cipher = CURRENT_CONFIG(peer)->cipher; - config->compression = CURRENT_CONFIG(peer)->compression; - - return 1; - } - - data += sizeof(uint16); - data_length -= sizeof(uint16) + i; - - ok = 0; - while (i && !ok) { - config->cipher = dtls_uint16_to_int(data); - ok = known_cipher(config->cipher); - i -= sizeof(uint16); - data += sizeof(uint16); - } - - /* skip remaining ciphers */ - data += i; - - if (!ok) { - /* reset config cipher to a well-defined value */ - config->cipher = TLS_NULL_WITH_NULL_NULL; - return 0; - } - - if (data_length < sizeof(uint8)) { - /* no compression specified, take the current compression method */ - config->compression = CURRENT_CONFIG(peer)->compression; - return 1; - } - - i = dtls_uint8_to_int(data); - if (data_length < i + sizeof(uint8)) - goto error; - - data += sizeof(uint8); - data_length -= sizeof(uint8) + i; - - ok = 0; - while (i && !ok) { - for (j = 0; j < sizeof(compression_methods) / sizeof(uint8); ++j) - if (dtls_uint8_to_int(data) == compression_methods[j]) { - config->compression = compression_methods[j]; - ok = 1; - } - i -= sizeof(uint8); - data += sizeof(uint8); - } - - return ok; - error: - warn("ClientHello too short (%d bytes)\n", data_length); - return 0; -} - -static inline int -check_client_keyexchange(dtls_context_t *ctx, - dtls_peer_t *peer, - uint8 *data, size_t length) { - return length >= DTLS_CKX_LENGTH && data[0] == DTLS_HT_CLIENT_KEY_EXCHANGE; -} - -static int -check_ccs(dtls_context_t *ctx, - dtls_peer_t *peer, - uint8 *record, uint8 *data, size_t data_length) { - - if (DTLS_RECORD_HEADER(record)->content_type != DTLS_CT_CHANGE_CIPHER_SPEC - || data_length < 1 || data[0] != 1) - return 0; - - /* set crypto context for TLS_PSK_WITH_AES_128_CCM_8 */ - /* client */ - dtls_cipher_free(OTHER_CONFIG(peer)->read_cipher); - - assert(OTHER_CONFIG(peer)->cipher != TLS_NULL_WITH_NULL_NULL); - OTHER_CONFIG(peer)->read_cipher = - dtls_cipher_new(OTHER_CONFIG(peer)->cipher, - dtls_kb_client_write_key(OTHER_CONFIG(peer)), - dtls_kb_key_size(OTHER_CONFIG(peer))); - - if (!OTHER_CONFIG(peer)->read_cipher) { - warn("cannot create read cipher\n"); - return 0; - } - - dtls_cipher_set_iv(OTHER_CONFIG(peer)->read_cipher, - dtls_kb_client_iv(OTHER_CONFIG(peer)), - dtls_kb_iv_size(OTHER_CONFIG(peer))); - - /* server */ - dtls_cipher_free(OTHER_CONFIG(peer)->write_cipher); - - OTHER_CONFIG(peer)->write_cipher = - dtls_cipher_new(OTHER_CONFIG(peer)->cipher, - dtls_kb_server_write_key(OTHER_CONFIG(peer)), - dtls_kb_key_size(OTHER_CONFIG(peer))); - - if (!OTHER_CONFIG(peer)->write_cipher) { - warn("cannot create write cipher\n"); - return 0; - } - - dtls_cipher_set_iv(OTHER_CONFIG(peer)->write_cipher, - dtls_kb_server_iv(OTHER_CONFIG(peer)), - dtls_kb_iv_size(OTHER_CONFIG(peer))); - - return 1; -} - -#ifndef NDEBUG -extern size_t dsrv_print_addr(const session_t *, unsigned char *, size_t); -#endif - -static inline void -update_hs_hash(dtls_peer_t *peer, uint8 *data, size_t length) { -/* #ifndef NDEBUG */ -/* printf("add MAC data: "); */ -/* dump(data, length); */ -/* printf("\n"); */ -/* #endif */ - dtls_hash_update(&peer->hs_state.hs_hash, data, length); -} - -static inline size_t -finalize_hs_hash(dtls_peer_t *peer, uint8 *buf) { - return dtls_hash_finalize(buf, &peer->hs_state.hs_hash); -} - -static inline void -clear_hs_hash(dtls_peer_t *peer) { - assert(peer); - dtls_hash_init(&peer->hs_state.hs_hash); -} - -/** - *Checks if \p record + \p data contain a Finished message with valid - * verify_data. - * - * \param ctx The current DTLS context. - * \param peer The remote peer of the security association. - * \param record The message record header. - * \param rlen The actual length of \p record. - * \param data The cleartext payload of the message. - * \param data_length Actual length of \p data. - * \return \c 1 if the Finished message is valid, \c 0 otherwise. - */ -static int -check_finished(dtls_context_t *ctx, dtls_peer_t *peer, - uint8 *record, uint8 *data, size_t data_length) { - size_t digest_length, label_size; - const unsigned char *label; - unsigned char buf[DTLS_HMAC_MAX]; - - /* Use a union here to ensure that sufficient stack space is - * reserved. As statebuf and verify_data are not used at the same - * time, we can re-use the storage safely. - */ - union { - unsigned char statebuf[DTLS_HASH_CTX_SIZE]; - unsigned char verify_data[DTLS_FIN_LENGTH]; - } b; - - debug("check Finish message\n"); - if (record[0] != DTLS_CT_HANDSHAKE || !IS_FINISHED(data, data_length)) { - debug("failed\n"); - return 0; - } - - /* temporarily store hash status for roll-back after finalize */ - memcpy(b.statebuf, &peer->hs_state.hs_hash, DTLS_HASH_CTX_SIZE); - - digest_length = finalize_hs_hash(peer, buf); - /* clear_hash(); */ - - /* restore hash status */ - memcpy(&peer->hs_state.hs_hash, b.statebuf, DTLS_HASH_CTX_SIZE); - - if (CURRENT_CONFIG(peer)->role == DTLS_SERVER) { - label = PRF_LABEL(server); - label_size = PRF_LABEL_SIZE(server); - } else { /* client */ - label = PRF_LABEL(client); - label_size = PRF_LABEL_SIZE(client); - } - - dtls_prf(CURRENT_CONFIG(peer)->master_secret, - DTLS_MASTER_SECRET_LENGTH, - label, label_size, - PRF_LABEL(finished), PRF_LABEL_SIZE(finished), - buf, digest_length, - b.verify_data, sizeof(b.verify_data)); - -/* #ifndef NDEBUG */ -/* printf("d:\t"); dump(data + DTLS_HS_LENGTH, sizeof(b.verify_data)); printf("\n"); */ -/* printf("v:\t"); dump(b.verify_data, sizeof(b.verify_data)); printf("\n"); */ -/* #endif */ - return - memcmp(data + DTLS_HS_LENGTH, b.verify_data, sizeof(b.verify_data)) == 0; -} - -/** - * Prepares the payload given in \p data for sending with - * dtls_send(). The \p data is encrypted and compressed according to - * the current security parameters of \p peer. The result of this - * operation is put into \p sendbuf with a prepended record header of - * type \p type ready for sending. As some cipher suites add a MAC - * before encryption, \p data must be large enough to hold this data - * as well (usually \c dtls_kb_digest_size(CURRENT_CONFIG(peer)). - * - * \param peer The remote peer the packet will be sent to. - * \param type The content type of this record. - * \param data The payload to send. - * \param data_length The size of \p data. - * \param sendbuf The output buffer where the encrypted record - * will be placed. - * \param rlen This parameter must be initialized with the - * maximum size of \p sendbuf and will be updated - * to hold the actual size of the stored packet - * on success. On error, the value of \p rlen is - * undefined. - * \return Less than zero on error, or greater than zero success. - */ -int -dtls_prepare_record(dtls_peer_t *peer, - unsigned char type, - uint8 *data, size_t data_length, - uint8 *sendbuf, size_t *rlen) { - uint8 *p; - int res; - - /* check the minimum that we need for packets that are not encrypted */ - if (*rlen < DTLS_RH_LENGTH + data_length) { - debug("dtls_prepare_record: send buffer too small\n"); - return -1; - } - - p = dtls_set_record_header(type, peer, sendbuf); - - if (CURRENT_CONFIG(peer)->cipher == TLS_NULL_WITH_NULL_NULL) { - /* no cipher suite */ - memcpy(p, data, data_length); - res = data_length; - } else { /* TLS_PSK_WITH_AES_128_CCM_8 */ - dtls_cipher_context_t *cipher_context; - - /** - * length of additional_data for the AEAD cipher which consists of - * seq_num(2+6) + type(1) + version(2) + length(2) - */ -#define A_DATA_LEN 13 -#define A_DATA N - unsigned char N[max(DTLS_CCM_BLOCKSIZE, A_DATA_LEN)]; - - if (*rlen < sizeof(dtls_record_header_t) + data_length + 8) { - warn("dtls_prepare_record(): send buffer too small\n"); - return -1; - } - - debug("dtls_prepare_record(): encrypt using TLS_PSK_WITH_AES_128_CCM_8\n"); - - /* set nonce - from http://tools.ietf.org/html/draft-mcgrew-tls-aes-ccm-03: - struct { - case client: - uint32 client_write_IV; // low order 32-bits - case server: - uint32 server_write_IV; // low order 32-bits - uint64 seq_num; - } CCMNonce. - - In DTLS, the 64-bit seq_num is the 16-bit epoch concatenated with the - 48-bit seq_num. - */ - - memcpy(p, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); - memcpy(p + 8, data, data_length); - - memset(N, 0, DTLS_CCM_BLOCKSIZE); - memcpy(N, dtls_kb_local_iv(CURRENT_CONFIG(peer)), - dtls_kb_iv_size(CURRENT_CONFIG(peer))); - memcpy(N + dtls_kb_iv_size(CURRENT_CONFIG(peer)), p, 8); /* epoch + seq_num */ - - cipher_context = CURRENT_CONFIG(peer)->write_cipher; - - if (!cipher_context) { - warn("no write_cipher available!\n"); - return -1; - } -/* #ifndef NDEBUG */ -/* printf("nonce:\t"); */ -/* dump(N, DTLS_CCM_BLOCKSIZE); */ -/* printf("\nkey:\t"); */ -/* dump(dtls_kb_local_write_key(CURRENT_CONFIG(peer)), */ -/* dtls_kb_key_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ -/* #endif */ - dtls_cipher_set_iv(cipher_context, N, DTLS_CCM_BLOCKSIZE); - - /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3: - * - * additional_data = seq_num + TLSCompressed.type + - * TLSCompressed.version + TLSCompressed.length; - */ - memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */ - memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */ - dtls_int_to_uint16(A_DATA + 11, data_length); /* length */ - - res = dtls_encrypt(cipher_context, p + 8, data_length, p + 8, - A_DATA, A_DATA_LEN); - - if (res < 0) - return -1; - -/* #ifndef NDEBUG */ -/* dump(p, res + 8); */ -/* printf("\n"); */ -/* #endif */ - res += 8; /* increment res by size of nonce_explicit */ - } - - /* fix length of fragment in sendbuf */ - dtls_int_to_uint16(sendbuf + 11, res); - - *rlen = DTLS_RH_LENGTH + res; - return 1; -} - -/** - * Returns true if the message @p Data is a handshake message that - * must be included in the calculation of verify_data in the Finished - * message. - * - * @param Type The message type. Only handshake messages but the initial - * Client Hello and Hello Verify Request are included in the hash, - * @param Data The PDU to examine. - * @param Length The length of @p Data. - * - * @return @c 1 if @p Data must be included in hash, @c 0 otherwise. - * - * @hideinitializer - */ -#define MUST_HASH(Type, Data, Length) \ - ((Type) == DTLS_CT_HANDSHAKE && \ - ((Data) != NULL) && ((Length) > 0) && \ - ((Data)[0] != DTLS_HT_HELLO_VERIFY_REQUEST) && \ - ((Data)[0] != DTLS_HT_CLIENT_HELLO || \ - ((Length) >= HS_HDR_LENGTH && \ - (dtls_uint16_to_int(DTLS_RECORD_HEADER(Data)->epoch > 0) || \ - (dtls_uint16_to_int(HANDSHAKE(Data)->message_seq) > 0))))) - -/** - * Sends the data passed in @p buf as a DTLS record of type @p type to - * the given peer. The data will be encrypted and compressed according - * to the security parameters for @p peer. - * - * @param ctx The DTLS context in effect. - * @param peer The remote party where the packet is sent. - * @param type The content type of this record. - * @param buf The data to send. - * @param buflen The number of bytes to send from @p buf. - * @return Less than zero in case of an error or the number of - * bytes that have been sent otherwise. - */ -int -dtls_send(dtls_context_t *ctx, dtls_peer_t *peer, - unsigned char type, - uint8 *buf, size_t buflen) { - - /* We cannot use ctx->sendbuf here as it is reserved for collecting - * the input for this function, i.e. buf == ctx->sendbuf. - * - * TODO: check if we can use the receive buf here. This would mean - * that we might not be able to handle multiple records stuffed in - * one UDP datagram */ - unsigned char sendbuf[DTLS_MAX_BUF]; - size_t len = sizeof(sendbuf); - int res; - - res = dtls_prepare_record(peer, type, buf, buflen, sendbuf, &len); - - if (res < 0) - return res; - - /* if (peer && MUST_HASH(peer, type, buf, buflen)) */ - /* update_hs_hash(peer, buf, buflen); */ - -/* #ifndef NDEBUG */ -/* debug("send %d bytes\n", buflen); */ -/* hexdump(sendbuf, sizeof(dtls_record_header_t)); */ -/* printf("\n"); */ -/* hexdump(buf, buflen); */ -/* printf("\n"); */ -/* #endif */ - - if (type == DTLS_CT_HANDSHAKE && buf[0] != DTLS_HT_HELLO_VERIFY_REQUEST) { - /* copy handshake messages other than HelloVerify into retransmit buffer */ - netq_t *n = netq_node_new(); - if (n) { - dtls_tick_t now; - dtls_ticks(&now); - n->t = now + 2 * CLOCK_SECOND; - n->retransmit_cnt = 0; - n->timeout = 2 * CLOCK_SECOND; - n->peer = peer; - n->length = buflen; - memcpy(n->data, buf, buflen); - - if (!netq_insert_node((netq_t **)ctx->sendqueue, n)) { - warn("cannot add packet to retransmit buffer\n"); - netq_node_free(n); -#ifdef WITH_CONTIKI - } else { - /* must set timer within the context of the retransmit process */ - PROCESS_CONTEXT_BEGIN(&dtls_retransmit_process); - etimer_set(&ctx->retransmit_timer, n->timeout); - PROCESS_CONTEXT_END(&dtls_retransmit_process); -#else /* WITH_CONTIKI */ - debug("copied to sendqueue\n"); -#endif /* WITH_CONTIKI */ - } - } else - warn("retransmit buffer full\n"); - } - - /* FIXME: copy to peer's sendqueue (after fragmentation if - * necessary) and initialize retransmit timer */ - res = CALL(ctx, write, &peer->session, sendbuf, len); - - /* Guess number of bytes application data actually sent: - * dtls_prepare_record() tells us in len the number of bytes to - * send, res will contain the bytes actually sent. */ - return res <= 0 ? res : buflen - (len - res); -} - -static inline int -dtls_alert(dtls_context_t *ctx, dtls_peer_t *peer, dtls_alert_level_t level, - dtls_alert_t description) { - uint8_t msg[] = { level, description }; - - dtls_send(ctx, peer, DTLS_CT_ALERT, msg, sizeof(msg)); - return 0; -} - -int -dtls_close(dtls_context_t *ctx, const session_t *remote) { - int res = -1; - dtls_peer_t *peer; - - peer = dtls_get_peer(ctx, remote); - - if (peer) { - res = dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_CLOSE); - /* indicate tear down */ - peer->state = DTLS_STATE_CLOSING; - } - return res; -} - -int -dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) { - - static uint8 buf[DTLS_MAX_BUF]; - uint8 *p = buf, *q = ctx->sendbuf; - size_t qlen = sizeof(ctx->sendbuf); - int res; - const dtls_key_t *key; - dtls_tick_t now; - - /* Ensure that the largest message to create fits in our source - * buffer. (The size of the destination buffer is checked by the - * encoding function, so we do not need to guess.) */ - assert(sizeof(buf) >= - DTLS_RH_LENGTH + DTLS_HS_LENGTH + DTLS_SH_LENGTH + 20); - - if (CALL(ctx, get_key, &peer->session, NULL, 0, &key) < 0) { - debug("dtls_send_server_hello(): no key for session available\n"); - return -1; - } - - /* Handshake header */ - p = dtls_set_handshake_header(DTLS_HT_SERVER_HELLO, - peer, - DTLS_SH_LENGTH, - 0, DTLS_SH_LENGTH, - buf); - - /* ServerHello */ - dtls_int_to_uint16(p, DTLS_VERSION); - p += sizeof(uint16); - - /* Set server random: First 4 bytes are the server's Unix timestamp, - * followed by 28 bytes of generate random data. */ - dtls_ticks(&now); - dtls_int_to_uint32(p, now / CLOCK_SECOND); - prng(p + 4, 28); - - if (!calculate_key_block(ctx, OTHER_CONFIG(peer), key, - OTHER_CONFIG(peer)->client_random, p)) - return -1; - - p += 32; - - *p++ = 0; /* no session id */ - - if (OTHER_CONFIG(peer)->cipher != TLS_NULL_WITH_NULL_NULL) { - /* selected cipher suite */ - dtls_int_to_uint16(p, OTHER_CONFIG(peer)->cipher); - p += sizeof(uint16); - - /* selected compression method */ - if (OTHER_CONFIG(peer)->compression >= 0) - *p++ = compression_methods[OTHER_CONFIG(peer)->compression]; - - /* FIXME: if key->psk.id != NULL we need the server key exchange */ - - /* update the finish hash - (FIXME: better put this in generic record_send function) */ - update_hs_hash(peer, buf, p - buf); - } - - res = dtls_prepare_record(peer, DTLS_CT_HANDSHAKE, - buf, p - buf, - q, &qlen); - if (res < 0) { - debug("dtls_server_hello: cannot prepare ServerHello record\n"); - return res; - } - - q += qlen; - qlen = sizeof(ctx->sendbuf) - qlen; - - /* ServerHelloDone - * - * Start message construction at beginning of buffer. */ - p = dtls_set_handshake_header(DTLS_HT_SERVER_HELLO_DONE, - peer, - 0, /* ServerHelloDone has no extra fields */ - 0, 0, /* ServerHelloDone has no extra fields */ - buf); - - /* update the finish hash - (FIXME: better put this in generic record_send function) */ - update_hs_hash(peer, buf, p - buf); - - res = dtls_prepare_record(peer, DTLS_CT_HANDSHAKE, - buf, p - buf, - q, &qlen); - if (res < 0) { - debug("dtls_server_hello: cannot prepare ServerHelloDone record\n"); - return res; - } - - return CALL(ctx, write, &peer->session, - ctx->sendbuf, (q + qlen) - ctx->sendbuf); -} - -static inline int -dtls_send_ccs(dtls_context_t *ctx, dtls_peer_t *peer) { - ctx->sendbuf[0] = 1; - return dtls_send(ctx, peer, DTLS_CT_CHANGE_CIPHER_SPEC, ctx->sendbuf, 1); -} - - -int -dtls_send_kx(dtls_context_t *ctx, dtls_peer_t *peer, int is_client) { - const dtls_key_t *key; - uint8 *p = ctx->sendbuf; - size_t size; - int ht = is_client - ? DTLS_HT_CLIENT_KEY_EXCHANGE - : DTLS_HT_SERVER_KEY_EXCHANGE; - unsigned char *id = NULL; - size_t id_len = 0; - - if (CALL(ctx, get_key, &peer->session, NULL, 0, &key) < 0) { - dsrv_log(LOG_CRIT, "no key to send in kx\n"); - return -2; - } - - assert(key); - - switch (key->type) { - case DTLS_KEY_PSK: { - id_len = key->key.psk.id_length; - id = key->key.psk.id; - break; - } - default: - dsrv_log(LOG_CRIT, "key type not supported\n"); - return -3; - } - - size = id_len + sizeof(uint16); - p = dtls_set_handshake_header(ht, peer, size, 0, size, p); - - dtls_int_to_uint16(p, id_len); - memcpy(p + sizeof(uint16), id, id_len); - - p += size; - - update_hs_hash(peer, ctx->sendbuf, p - ctx->sendbuf); - return dtls_send(ctx, peer, DTLS_CT_HANDSHAKE, - ctx->sendbuf, p - ctx->sendbuf); -} - -#define msg_overhead(Peer,Length) (DTLS_RH_LENGTH + \ - ((Length + dtls_kb_iv_size(CURRENT_CONFIG(Peer)) + \ - dtls_kb_digest_size(CURRENT_CONFIG(Peer))) / \ - DTLS_BLK_LENGTH + 1) * DTLS_BLK_LENGTH) - -int -dtls_send_server_finished(dtls_context_t *ctx, dtls_peer_t *peer) { - - int length; - uint8 buf[DTLS_HMAC_MAX]; - uint8 *p = ctx->sendbuf; - - /* FIXME: adjust message overhead calculation */ - assert(msg_overhead(peer, DTLS_HS_LENGTH + DTLS_FIN_LENGTH) - < sizeof(ctx->sendbuf)); - - p = dtls_set_handshake_header(DTLS_HT_FINISHED, - peer, DTLS_FIN_LENGTH, 0, DTLS_FIN_LENGTH, p); - - length = finalize_hs_hash(peer, buf); - - dtls_prf(CURRENT_CONFIG(peer)->master_secret, - DTLS_MASTER_SECRET_LENGTH, - PRF_LABEL(server), PRF_LABEL_SIZE(server), - PRF_LABEL(finished), PRF_LABEL_SIZE(finished), - buf, length, - p, DTLS_FIN_LENGTH); - -/* #ifndef NDEBUG */ -/* printf("server finished MAC:\t"); */ -/* dump(p, DTLS_FIN_LENGTH); */ -/* printf("\n"); */ -/* #endif */ - - p += DTLS_FIN_LENGTH; - - return dtls_send(ctx, peer, DTLS_CT_HANDSHAKE, - ctx->sendbuf, p - ctx->sendbuf); -} - -static int -check_server_hello(dtls_context_t *ctx, - dtls_peer_t *peer, - uint8 *data, size_t data_length) { - dtls_hello_verify_t *hv; - uint8 *p = ctx->sendbuf; - size_t size; - int res; - const dtls_key_t *key; - - /* This function is called when we expect a ServerHello (i.e. we - * have sent a ClientHello). We might instead receive a HelloVerify - * request containing a cookie. If so, we must repeat the - * ClientHello with the given Cookie. - */ - - if (IS_SERVERHELLO(data, data_length)) { - debug("handle ServerHello\n"); - - update_hs_hash(peer, data, data_length); - - /* FIXME: check data_length before accessing fields */ - - /* Get the server's random data and store selected cipher suite - * and compression method (like dtls_update_parameters(). - * Then calculate master secret and wait for ServerHelloDone. When received, - * send ClientKeyExchange (?) and ChangeCipherSpec + ClientFinished. */ - - /* check server version */ - data += DTLS_HS_LENGTH; - data_length -= DTLS_HS_LENGTH; - - if (dtls_uint16_to_int(data) != DTLS_VERSION) { - dsrv_log(LOG_ALERT, "unknown DTLS version\n"); - goto error; - } - - data += sizeof(uint16); /* skip version field */ - data_length -= sizeof(uint16); - - /* FIXME: check PSK hint */ - if (CALL(ctx, get_key, &peer->session, NULL, 0, &key) < 0 - || !calculate_key_block(ctx, OTHER_CONFIG(peer), key, - OTHER_CONFIG(peer)->client_random, data)) { - goto error; - } - /* store server random data */ - - /* memcpy(OTHER_CONFIG(peer)->server_random, data, */ - /* sizeof(OTHER_CONFIG(peer)->server_random)); */ - data += sizeof(OTHER_CONFIG(peer)->client_random); - data_length -= sizeof(OTHER_CONFIG(peer)->client_random); - - SKIP_VAR_FIELD(data, data_length, uint8); /* skip session id */ - - /* Check cipher suite. As we offer all we have, it is sufficient - * to check if the cipher suite selected by the server is in our - * list of known cipher suites. Subsets are not supported. */ - OTHER_CONFIG(peer)->cipher = dtls_uint16_to_int(data); - if (!known_cipher(OTHER_CONFIG(peer)->cipher)) { - dsrv_log(LOG_ALERT, "unsupported cipher 0x%02x 0x%02x\n", - data[0], data[1]); - goto error; - } - data += sizeof(uint16); - data_length -= sizeof(uint16); - - /* Check if NULL compression was selected. We do not know any other. */ - if (dtls_uint8_to_int(data) != TLS_COMP_NULL) { - dsrv_log(LOG_ALERT, "unsupported compression method 0x%02x\n", data[0]); - goto error; - } - - return 1; - } - - if (!IS_HELLOVERIFY(data, data_length)) { - debug("no HelloVerify\n"); - return 0; - } - - hv = (dtls_hello_verify_t *)(data + DTLS_HS_LENGTH); - - /* FIXME: dtls_send_client_hello(ctx,peer,cookie) */ - size = DTLS_CH_LENGTH + 8 + dtls_uint8_to_int(&hv->cookie_length); - - p = dtls_set_handshake_header(DTLS_HT_CLIENT_HELLO, peer, - size, 0, size, p); - - dtls_int_to_uint16(p, DTLS_VERSION); - p += sizeof(uint16); - - /* we must use the same Client Random as for the previous request */ - memcpy(p, OTHER_CONFIG(peer)->client_random, - sizeof(OTHER_CONFIG(peer)->client_random)); - p += sizeof(OTHER_CONFIG(peer)->client_random); - - /* session id (length 0) */ - dtls_int_to_uint8(p, 0); - p += sizeof(uint8); - - dtls_int_to_uint8(p, dtls_uint8_to_int(&hv->cookie_length)); - p += sizeof(uint8); - memcpy(p, hv->cookie, dtls_uint8_to_int(&hv->cookie_length)); - p += dtls_uint8_to_int(&hv->cookie_length); - - /* add known cipher(s) */ - dtls_int_to_uint16(p, 2); - p += sizeof(uint16); - - dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8); - p += sizeof(uint16); - - /* compression method */ - dtls_int_to_uint8(p, 1); - p += sizeof(uint8); - - dtls_int_to_uint8(p, 0); - p += sizeof(uint8); - - update_hs_hash(peer, ctx->sendbuf, p - ctx->sendbuf); - - res = dtls_send(ctx, peer, DTLS_CT_HANDSHAKE, ctx->sendbuf, - p - ctx->sendbuf); - if (res < 0) - warn("cannot send ClientHello\n"); - - error: - return 0; -} - -static int -check_server_hellodone(dtls_context_t *ctx, - dtls_peer_t *peer, - uint8 *data, size_t data_length) { - - /* calculate master key, send CCS */ - if (!IS_SERVERHELLODONE(data, data_length)) - return 0; - - update_hs_hash(peer, data, data_length); - - /* set crypto context for TLS_PSK_WITH_AES_128_CCM_8 */ - /* client */ - dtls_cipher_free(OTHER_CONFIG(peer)->read_cipher); - - assert(OTHER_CONFIG(peer)->cipher != TLS_NULL_WITH_NULL_NULL); - OTHER_CONFIG(peer)->read_cipher = - dtls_cipher_new(OTHER_CONFIG(peer)->cipher, - dtls_kb_server_write_key(OTHER_CONFIG(peer)), - dtls_kb_key_size(OTHER_CONFIG(peer))); - - if (!OTHER_CONFIG(peer)->read_cipher) { - warn("cannot create read cipher\n"); - return 0; - } - - dtls_cipher_set_iv(OTHER_CONFIG(peer)->read_cipher, - dtls_kb_server_iv(OTHER_CONFIG(peer)), - dtls_kb_iv_size(OTHER_CONFIG(peer))); - - /* server */ - dtls_cipher_free(OTHER_CONFIG(peer)->write_cipher); - - OTHER_CONFIG(peer)->write_cipher = - dtls_cipher_new(OTHER_CONFIG(peer)->cipher, - dtls_kb_client_write_key(OTHER_CONFIG(peer)), - dtls_kb_key_size(OTHER_CONFIG(peer))); - - if (!OTHER_CONFIG(peer)->write_cipher) { - dtls_cipher_free(OTHER_CONFIG(peer)->read_cipher); - warn("cannot create write cipher\n"); - return 0; - } - - dtls_cipher_set_iv(OTHER_CONFIG(peer)->write_cipher, - dtls_kb_client_iv(OTHER_CONFIG(peer)), - dtls_kb_iv_size(OTHER_CONFIG(peer))); - - /* send ClientKeyExchange */ - if (dtls_send_kx(ctx, peer, 1) < 0) { - debug("cannot send KeyExchange message\n"); - return 0; - } - - /* and switch cipher suite */ - if (dtls_send_ccs(ctx, peer) < 0) { - debug("cannot send CCS message\n"); - return 0; - } - - SWITCH_CONFIG(peer); - inc_uint(uint16, peer->epoch); - memset(peer->rseq, 0, sizeof(peer->rseq)); -/* #ifndef NDEBUG */ -/* { */ -/* printf("key_block:\n"); */ -/* printf(" client_MAC_secret:\t"); */ -/* dump(dtls_kb_client_mac_secret(CURRENT_CONFIG(peer)), */ -/* dtls_kb_mac_secret_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" server_MAC_secret:\t"); */ -/* dump(dtls_kb_server_mac_secret(CURRENT_CONFIG(peer)), */ -/* dtls_kb_mac_secret_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" client_write_key:\t"); */ -/* dump(dtls_kb_client_write_key(CURRENT_CONFIG(peer)), */ -/* dtls_kb_key_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" server_write_key:\t"); */ -/* dump(dtls_kb_server_write_key(CURRENT_CONFIG(peer)), */ -/* dtls_kb_key_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" client_IV:\t\t"); */ -/* dump(dtls_kb_client_iv(CURRENT_CONFIG(peer)), */ -/* dtls_kb_iv_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" server_IV:\t\t"); */ -/* dump(dtls_kb_server_iv(CURRENT_CONFIG(peer)), */ -/* dtls_kb_iv_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - - -/* } */ -/* #endif */ - - /* Client Finished */ - { - debug ("send Finished\n"); - int length; - uint8 buf[DTLS_HMAC_MAX]; - uint8 *p = ctx->sendbuf; - - unsigned char statebuf[DTLS_HASH_CTX_SIZE]; - - /* FIXME: adjust message overhead calculation */ - assert(msg_overhead(peer, DTLS_HS_LENGTH + DTLS_FIN_LENGTH) - < sizeof(ctx->sendbuf)); - - p = dtls_set_handshake_header(DTLS_HT_FINISHED, - peer, DTLS_FIN_LENGTH, - 0, DTLS_FIN_LENGTH, p); - - /* temporarily store hash status for roll-back after finalize */ - memcpy(statebuf, &peer->hs_state.hs_hash, DTLS_HASH_CTX_SIZE); - - length = finalize_hs_hash(peer, buf); - - /* restore hash status */ - memcpy(&peer->hs_state.hs_hash, statebuf, DTLS_HASH_CTX_SIZE); - - dtls_prf(CURRENT_CONFIG(peer)->master_secret, - DTLS_MASTER_SECRET_LENGTH, - PRF_LABEL(client), PRF_LABEL_SIZE(client), - PRF_LABEL(finished), PRF_LABEL_SIZE(finished), - buf, length, - p, DTLS_FIN_LENGTH); - - p += DTLS_FIN_LENGTH; - - update_hs_hash(peer, ctx->sendbuf, p - ctx->sendbuf); - if (dtls_send(ctx, peer, DTLS_CT_HANDSHAKE, - ctx->sendbuf, p - ctx->sendbuf) < 0) { - dsrv_log(LOG_ALERT, "cannot send Finished message\n"); - return 0; - } - } - return 1; -} - -int -decrypt_verify(dtls_peer_t *peer, - uint8 *packet, size_t length, - uint8 **cleartext, size_t *clen) { - int ok = 0; - - *cleartext = (uint8 *)packet + sizeof(dtls_record_header_t); - *clen = length - sizeof(dtls_record_header_t); - - if (CURRENT_CONFIG(peer)->cipher == TLS_NULL_WITH_NULL_NULL) { - /* no cipher suite selected */ - return 1; - } else { /* TLS_PSK_WITH_AES_128_CCM_8 */ - dtls_cipher_context_t *cipher_context; - /** - * length of additional_data for the AEAD cipher which consists of - * seq_num(2+6) + type(1) + version(2) + length(2) - */ -#define A_DATA_LEN 13 -#define A_DATA N - unsigned char N[max(DTLS_CCM_BLOCKSIZE, A_DATA_LEN)]; - long int len; - - - if (*clen < 16) /* need at least IV and MAC */ - return -1; - - memset(N, 0, DTLS_CCM_BLOCKSIZE); - memcpy(N, dtls_kb_remote_iv(CURRENT_CONFIG(peer)), - dtls_kb_iv_size(CURRENT_CONFIG(peer))); - - /* read epoch and seq_num from message */ - memcpy(N + dtls_kb_iv_size(CURRENT_CONFIG(peer)), *cleartext, 8); - *cleartext += 8; - *clen -= 8; - - cipher_context = CURRENT_CONFIG(peer)->read_cipher; - - if (!cipher_context) { - warn("no read_cipher available!\n"); - return 0; - } - -/* #ifndef NDEBUG */ -/* printf("nonce:\t"); */ -/* dump(N, DTLS_CCM_BLOCKSIZE); */ -/* printf("\nkey:\t"); */ -/* dump(dtls_kb_remote_write_key(CURRENT_CONFIG(peer)), */ -/* dtls_kb_key_size(CURRENT_CONFIG(peer))); */ -/* printf("\nciphertext:\n"); */ -/* dump(*cleartext, *clen); */ -/* printf("\n"); */ -/* #endif */ - - dtls_cipher_set_iv(cipher_context, N, DTLS_CCM_BLOCKSIZE); - - /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3: - * - * additional_data = seq_num + TLSCompressed.type + - * TLSCompressed.version + TLSCompressed.length; - */ - memcpy(A_DATA, &DTLS_RECORD_HEADER(packet)->epoch, 8); /* epoch and seq_num */ - memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(packet)->content_type, 3); /* type and version */ - dtls_int_to_uint16(A_DATA + 11, *clen - 8); /* length without nonce_explicit */ - - len = dtls_decrypt(cipher_context, *cleartext, *clen, *cleartext, - A_DATA, A_DATA_LEN); - - ok = len >= 0; - if (!ok) - warn("decryption failed\n"); - else { -/* #ifndef NDEBUG */ -/* printf("decrypt_verify(): found %ld bytes cleartext\n", len); */ -/* #endif */ - *clen = len; - } -/* #ifndef NDEBUG */ -/* printf("\ncleartext:\n"); */ -/* dump(*cleartext, *clen); */ -/* printf("\n"); */ -/* #endif */ - } - - return ok; -} - - -int -handle_handshake(dtls_context_t *ctx, dtls_peer_t *peer, - uint8 *record_header, uint8 *data, size_t data_length) { - - /* The following switch construct handles the given message with - * respect to the current internal state for this peer. In case of - * error, it is left with return 0. */ - - switch (peer->state) { - - /************************************************************************ - * Client states - ************************************************************************/ - - case DTLS_STATE_CLIENTHELLO: - /* here we expect a HelloVerify or ServerHello */ - - debug("DTLS_STATE_CLIENTHELLO\n"); - if (check_server_hello(ctx, peer, data, data_length)) { - peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; - /* update_hs_hash(peer, data, data_length); */ - } - - break; - - case DTLS_STATE_WAIT_SERVERHELLODONE: - /* expect a ServerHelloDone */ - - debug("DTLS_STATE_WAIT_SERVERHELLODONE\n"); - - if (check_server_hellodone(ctx, peer, data, data_length)) { - peer->state = DTLS_STATE_WAIT_SERVERFINISHED; - /* update_hs_hash(peer, data, data_length); */ - } - - break; - - case DTLS_STATE_WAIT_SERVERFINISHED: - /* expect a Finished message from server */ - - debug("DTLS_STATE_WAIT_SERVERFINISHED\n"); - if (check_finished(ctx, peer, record_header, data, data_length)) { - debug("finished!\n"); - peer->state = DTLS_STATE_CONNECTED; - } - - break; - - /************************************************************************ - * Server states - ************************************************************************/ - - case DTLS_STATE_SERVERHELLO: - /* here we expect a ClientHello */ - /* handle ClientHello, update msg and msglen and goto next if not finished */ - - debug("DTLS_STATE_SERVERHELLO\n"); - if (!check_client_keyexchange(ctx, peer, data, data_length)) { - warn("check_client_keyexchange failed (%d, %d)\n", data_length, data[0]); - return 0; /* drop it, whatever it is */ - } - - update_hs_hash(peer, data, data_length); - peer->state = DTLS_STATE_KEYEXCHANGE; - break; - - case DTLS_STATE_WAIT_FINISHED: - debug("DTLS_STATE_WAIT_FINISHED\n"); - if (check_finished(ctx, peer, record_header, data, data_length)) { - debug("finished!\n"); - - /* send ServerFinished */ - update_hs_hash(peer, data, data_length); - - if (dtls_send_server_finished(ctx, peer) > 0) { - peer->state = DTLS_STATE_CONNECTED; - } else { - warn("sending server Finished failed\n"); - } - } else { - /* send alert */ - } - break; - - case DTLS_STATE_CONNECTED: - /* At this point, we have a good relationship with this peer. This - * state is left for re-negotiation of key material. */ - - debug("DTLS_STATE_CONNECTED\n"); - - /* renegotiation */ - if (dtls_verify_peer(ctx, peer, &peer->session, - record_header, data, data_length) > 0) { - - clear_hs_hash(peer); - - if (!dtls_update_parameters(ctx, peer, data, data_length)) { - - warn("error updating security parameters\n"); - dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_WARNING, - DTLS_ALERT_NO_RENEGOTIATION); - return 0; - } - - /* update finish MAC */ - update_hs_hash(peer, data, data_length); - - if (dtls_send_server_hello(ctx, peer) > 0) - peer->state = DTLS_STATE_SERVERHELLO; - - /* after sending the ServerHelloDone, we expect the - * ClientKeyExchange (possibly containing the PSK id), - * followed by a ChangeCipherSpec and an encrypted Finished. - */ - } - - break; - - case DTLS_STATE_INIT: /* these states should not occur here */ - case DTLS_STATE_KEYEXCHANGE: - default: - dsrv_log(LOG_CRIT, "unhandled state %d\n", peer->state); - assert(0); - } - - return 1; -} - -int -handle_ccs(dtls_context_t *ctx, dtls_peer_t *peer, - uint8 *record_header, uint8 *data, size_t data_length) { - - /* A CCS message is handled after a KeyExchange message was - * received from the client. When security parameters have been - * updated successfully and a ChangeCipherSpec message was sent - * by ourself, the security context is switched and the record - * sequence number is reset. */ - - if (peer->state != DTLS_STATE_KEYEXCHANGE - || !check_ccs(ctx, peer, record_header, data, data_length)) { - /* signal error? */ - warn("expected ChangeCipherSpec during handshake\n"); - return 0; - - } - - /* send change cipher spec message and switch to new configuration */ - if (dtls_send_ccs(ctx, peer) < 0) { - warn("cannot send CCS message"); - return 0; - } - - SWITCH_CONFIG(peer); - inc_uint(uint16, peer->epoch); - memset(peer->rseq, 0, sizeof(peer->rseq)); - - peer->state = DTLS_STATE_WAIT_FINISHED; - -/* #ifndef NDEBUG */ -/* { */ -/* printf("key_block:\n"); */ -/* printf(" client_MAC_secret:\t"); */ -/* dump(dtls_kb_client_mac_secret(CURRENT_CONFIG(peer)), */ -/* dtls_kb_mac_secret_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" server_MAC_secret:\t"); */ -/* dump(dtls_kb_server_mac_secret(CURRENT_CONFIG(peer)), */ -/* dtls_kb_mac_secret_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" client_write_key:\t"); */ -/* dump(dtls_kb_client_write_key(CURRENT_CONFIG(peer)), */ -/* dtls_kb_key_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" server_write_key:\t"); */ -/* dump(dtls_kb_server_write_key(CURRENT_CONFIG(peer)), */ -/* dtls_kb_key_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" client_IV:\t\t"); */ -/* dump(dtls_kb_client_iv(CURRENT_CONFIG(peer)), */ -/* dtls_kb_iv_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - -/* printf(" server_IV:\t\t"); */ -/* dump(dtls_kb_server_iv(CURRENT_CONFIG(peer)), */ -/* dtls_kb_iv_size(CURRENT_CONFIG(peer))); */ -/* printf("\n"); */ - - -/* } */ -/* #endif */ - - return 1; -} - -/** - * Handles incoming Alert messages. This function returns \c 1 if the - * connection should be closed and the peer is to be invalidated. - */ -int -handle_alert(dtls_context_t *ctx, dtls_peer_t *peer, - uint8 *record_header, uint8 *data, size_t data_length) { - int free_peer = 0; /* indicates whether to free peer */ - - if (data_length < 2) - return 0; - - info("** Alert: level %d, description %d\n", data[0], data[1]); - - /* The peer object is invalidated for FATAL alerts and close - * notifies. This is done in two steps.: First, remove the object - * from our list of peers. After that, the event handler callback is - * invoked with the still existing peer object. Finally, the storage - * used by peer is released. - */ - if (data[0] == DTLS_ALERT_LEVEL_FATAL || data[1] == DTLS_ALERT_CLOSE) { - dsrv_log(LOG_ALERT, "%d invalidate peer\n", data[1]); - -#ifndef WITH_CONTIKI - HASH_DEL_PEER(ctx->peers, peer); -#else /* WITH_CONTIKI */ - list_remove(ctx->peers, peer); - -/* #ifndef NDEBUG */ -/* PRINTF("removed peer ["); */ -/* PRINT6ADDR(&peer->session.addr); */ -/* PRINTF("]:%d\n", uip_ntohs(peer->session.port)); */ -/* #endif */ -#endif /* WITH_CONTIKI */ - - free_peer = 1; - - } - - (void)CALL(ctx, event, &peer->session, - (dtls_alert_level_t)data[0], (unsigned short)data[1]); - switch (data[1]) { - case DTLS_ALERT_CLOSE: - /* If state is DTLS_STATE_CLOSING, we have already sent a - * close_notify so, do not send that again. */ - if (peer->state != DTLS_STATE_CLOSING) { - peer->state = DTLS_STATE_CLOSING; - dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_CLOSE); - } else - peer->state = DTLS_STATE_CLOSED; - break; - default: - ; - } - - if (free_peer) { - dtls_stop_retransmission(ctx, peer); - dtls_free_peer(peer); - } - - return free_peer; -} - -/** - * Handles incoming data as DTLS message from given peer. - */ -int -dtls_handle_message(dtls_context_t *ctx, - session_t *session, - uint8 *msg, int msglen) { - dtls_peer_t *peer = NULL; - unsigned int rlen; /* record length */ - uint8 *data; /* (decrypted) payload */ - size_t data_length; /* length of decrypted payload - (without MAC and padding) */ - - /* check if we have DTLS state for addr/port/ifindex */ - peer = dtls_get_peer(ctx, session); - -#ifndef NDEBUG - if (peer) { - unsigned char addrbuf[72]; - - dsrv_print_addr(session, addrbuf, sizeof(addrbuf)); - debug("found peer %s\n", addrbuf); - } -#endif /* NDEBUG */ - - if (!peer) { - - /* get first record from client message */ - rlen = is_record(msg, msglen); - assert(rlen <= msglen); - - if (!rlen) { -#ifndef NDEBUG - if (msglen > 3) - debug("dropped invalid message %02x%02x%02x%02x\n", msg[0], msg[1], msg[2], msg[3]); - else - debug("dropped invalid message (less than four bytes)\n"); -#endif - return 0; - } - - /* is_record() ensures that msg contains at least a record header */ - data = msg + DTLS_RH_LENGTH; - data_length = rlen - DTLS_RH_LENGTH; - - /* When no DTLS state exists for this peer, we only allow a - Client Hello message with - - a) a valid cookie, or - b) no cookie. - - Anything else will be rejected. Fragementation is not allowed - here as it would require peer state as well. - */ - - if (dtls_verify_peer(ctx, NULL, session, msg, data, data_length) <= 0) { - warn("cannot verify peer\n"); - return -1; - } - - /* msg contains a Client Hello with a valid cookie, so we can - safely create the server state machine and continue with - the handshake. */ - - peer = dtls_new_peer(session); - if (!peer) { - dsrv_log(LOG_ALERT, "cannot create peer"); - /* FIXME: signal internal error */ - return -1; - } - - /* Initialize record sequence number to 1 for new peers. The first - * record with sequence number 0 is a stateless Hello Verify Request. - */ - peer->rseq[5] = 1; - - /* First negotiation step: check for PSK - * - * Note that we already have checked that msg is a Handshake - * message containing a ClientHello. dtls_get_cipher() therefore - * does not check again. - */ - if (!dtls_update_parameters(ctx, peer, - msg + DTLS_RH_LENGTH, rlen - DTLS_RH_LENGTH)) { - - warn("error updating security parameters\n"); - /* FIXME: send handshake failure Alert */ - dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL, - DTLS_ALERT_HANDSHAKE_FAILURE); - dtls_free_peer(peer); - return -1; - } - -#ifndef WITH_CONTIKI - HASH_ADD_PEER(ctx->peers, session, peer); -#else /* WITH_CONTIKI */ - list_add(ctx->peers, peer); -#endif /* WITH_CONTIKI */ - - /* update finish MAC */ - update_hs_hash(peer, msg + DTLS_RH_LENGTH, rlen - DTLS_RH_LENGTH); - - if (dtls_send_server_hello(ctx, peer) > 0) - peer->state = DTLS_STATE_SERVERHELLO; - - /* after sending the ServerHelloDone, we expect the - * ClientKeyExchange (possibly containing the PSK id), - * followed by a ChangeCipherSpec and an encrypted Finished. - */ - - msg += rlen; - msglen -= rlen; - } else { - debug("found peer\n"); - } - - /* At this point peer contains a state machine to handle the - received message. */ - - assert(peer); - - /* FIXME: check sequence number of record and drop message if the - * number is not exactly the last number that we have responded to + 1. - * Otherwise, stop retransmissions for this specific peer and - * continue processing. */ - dtls_stop_retransmission(ctx, peer); - - while ((rlen = is_record(msg,msglen))) { - - debug("got packet %d (%d bytes)\n", msg[0], rlen); - /* skip packet if it is from a different epoch */ - if (memcmp(DTLS_RECORD_HEADER(msg)->epoch, - peer->epoch, sizeof(uint16)) != 0) - goto next; - - if (!decrypt_verify(peer, msg, rlen, &data, &data_length)) { - info("decrypt_verify() failed\n"); - goto next; - } - -/* #ifndef NDEBUG */ -/* hexdump(msg, sizeof(dtls_record_header_t)); */ -/* printf("\n"); */ -/* hexdump(data, data_length); */ -/* printf("\n"); */ -/* #endif */ - - /* Handle received record according to the first byte of the - * message, i.e. the subprotocol. We currently do not support - * combining multiple fragments of one type into a single - * record. */ - - switch (msg[0]) { - - case DTLS_CT_CHANGE_CIPHER_SPEC: - handle_ccs(ctx, peer, msg, data, data_length); - break; - - case DTLS_CT_ALERT: - if (handle_alert(ctx, peer, msg, data, data_length)) { - /* handle alert has invalidated peer */ - peer = NULL; - return 0; - } - - case DTLS_CT_HANDSHAKE: - handle_handshake(ctx, peer, msg, data, data_length); - if (peer->state == DTLS_STATE_CONNECTED) { - /* stop retransmissions */ - dtls_stop_retransmission(ctx, peer); - CALL(ctx, event, &peer->session, 0, DTLS_EVENT_CONNECTED); - } - break; - - case DTLS_CT_APPLICATION_DATA: - info("** application data:\n"); - CALL(ctx, read, &peer->session, data, data_length); - break; - default: - info("dropped unknown message of type %d\n",msg[0]); - } - - next: - /* advance msg by length of ciphertext */ - msg += rlen; - msglen -= rlen; - } - - return 0; -} - -dtls_context_t * -dtls_new_context(void *app_data) { - dtls_context_t *c; - dtls_tick_t now; -#ifndef WITH_CONTIKI - FILE *urandom = fopen("/dev/urandom", "r"); - unsigned char buf[sizeof(unsigned long)]; -#endif /* WITH_CONTIKI */ - - dtls_ticks(&now); -#ifdef WITH_CONTIKI - /* FIXME: need something better to init PRNG here */ - prng_init(now); -#else /* WITH_CONTIKI */ - if (!urandom) { - dsrv_log(LOG_EMERG, "cannot initialize PRNG\n"); - return NULL; - } - - if (fread(buf, 1, sizeof(buf), urandom) != sizeof(buf)) { - dsrv_log(LOG_EMERG, "cannot initialize PRNG\n"); - return NULL; - } - - fclose(urandom); - prng_init((unsigned long)*buf); -#endif /* WITH_CONTIKI */ - - c = &the_dtls_context; - - memset(c, 0, sizeof(dtls_context_t)); - c->app = app_data; - - LIST_STRUCT_INIT(c, sendqueue); - -#ifdef WITH_CONTIKI - LIST_STRUCT_INIT(c, peers); - /* LIST_STRUCT_INIT(c, key_store); */ - - process_start(&dtls_retransmit_process, (char *)c); - PROCESS_CONTEXT_BEGIN(&dtls_retransmit_process); - /* the retransmit timer must be initialized to some large value */ - etimer_set(&c->retransmit_timer, 0xFFFF); - PROCESS_CONTEXT_END(&coap_retransmit_process); -#endif /* WITH_CONTIKI */ - - if (prng(c->cookie_secret, DTLS_COOKIE_SECRET_LENGTH)) - c->cookie_secret_age = now; - else - goto error; - - return c; - - error: - dsrv_log(LOG_ALERT, "cannot create DTLS context"); - if (c) - dtls_free_context(c); - return NULL; -} - -void dtls_free_context(dtls_context_t *ctx) { - dtls_peer_t *p; - -#ifndef WITH_CONTIKI - dtls_peer_t *tmp; - - if (ctx->peers) { - HASH_ITER(hh, ctx->peers, p, tmp) { - dtls_free_peer(p); - } - } -#else /* WITH_CONTIKI */ - int i; - - p = (dtls_peer_t *)peer_storage.mem; - for (i = 0; i < peer_storage.num; ++i, ++p) { - if (peer_storage.count[i]) - dtls_free_peer(p); - } -#endif /* WITH_CONTIKI */ -} - -int -dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer) { - uint8 *p = ctx->sendbuf; - size_t size; - int res; - dtls_tick_t now; - - assert(peer); - if (!peer) - return -1; - - /* check if the same peer is already in our list */ - if (peer == dtls_get_peer(ctx, &peer->session)) { - debug("found peer, try to re-connect\n"); - /* FIXME: send HelloRequest if we are server, - ClientHello with good cookie if client */ - return 0; - } - - /* set peer role to server: */ - OTHER_CONFIG(peer)->role = DTLS_SERVER; - CURRENT_CONFIG(peer)->role = DTLS_SERVER; - - dtls_add_peer(ctx, peer); - - /* send ClientHello with some Cookie */ - - /* add to size: - * 1. length of session id (including length field) - * 2. length of cookie (including length field) - * 3. cypher suites - * 4. compression methods - */ - size = DTLS_CH_LENGTH + 8; - - /* force sending 0 as handshake message sequence number by setting - * peer to NULL */ - p = dtls_set_handshake_header(DTLS_HT_CLIENT_HELLO, NULL, - size, 0, size, p); - - dtls_int_to_uint16(p, DTLS_VERSION); - p += sizeof(uint16); - - dtls_ticks(&now); - /* Set client random: First 4 bytes are the client's Unix timestamp, - * followed by 28 bytes of generate random data. */ - dtls_int_to_uint32(&OTHER_CONFIG(peer)->client_random, - now / DTLS_TICKS_PER_SECOND); - prng(OTHER_CONFIG(peer)->client_random + sizeof(uint32), - sizeof(OTHER_CONFIG(peer)->client_random) - sizeof(uint32)); - memcpy(p, OTHER_CONFIG(peer)->client_random, - sizeof(OTHER_CONFIG(peer)->client_random)); - p += 32; - - /* session id (length 0) */ - dtls_int_to_uint8(p, 0); - p += sizeof(uint8); - - dtls_int_to_uint8(p, 0); - p += sizeof(uint8); - - /* add supported cipher suite */ - dtls_int_to_uint16(p, 2); - p += sizeof(uint16); - - dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8); - p += sizeof(uint16); - - /* compression method */ - dtls_int_to_uint8(p, 1); - p += sizeof(uint8); - - dtls_int_to_uint8(p, TLS_COMP_NULL); - p += sizeof(uint8); - - res = dtls_send(ctx, peer, DTLS_CT_HANDSHAKE, ctx->sendbuf, - p - ctx->sendbuf); - if (res < 0) - warn("cannot send ClientHello\n"); - else - peer->state = DTLS_STATE_CLIENTHELLO; - - return res; -} - -int -dtls_connect(dtls_context_t *ctx, const session_t *dst) { - dtls_peer_t *peer; - - peer = dtls_get_peer(ctx, dst); - - if (!peer) - peer = dtls_new_peer(dst); - - if (!peer) { - dsrv_log(LOG_CRIT, "cannot create new peer\n"); - return -1; - } - - return dtls_connect_peer(ctx, peer); -} - -void -dtls_retransmit(dtls_context_t *context, netq_t *node) { - if (!context || !node) - return; - - /* re-initialize timeout when maximum number of retransmissions are not reached yet */ - if (node->retransmit_cnt < DTLS_DEFAULT_MAX_RETRANSMIT) { - unsigned char sendbuf[DTLS_MAX_BUF]; - size_t len = sizeof(sendbuf); - - node->retransmit_cnt++; - node->t += (node->timeout << node->retransmit_cnt); - netq_insert_node((netq_t **)context->sendqueue, node); - - debug("** retransmit packet\n"); - - if (dtls_prepare_record(node->peer, DTLS_CT_HANDSHAKE, - node->data, node->length, - sendbuf, &len) > 0) { - -#ifndef NDEBUG - if (dtls_get_log_level() >= LOG_DEBUG) { - debug("retransmit %d bytes\n", len); - hexdump(sendbuf, sizeof(dtls_record_header_t)); - printf("\n"); - hexdump(node->data, node->length); - printf("\n"); - } -#endif - - (void)CALL(context, write, &node->peer->session, sendbuf, len); - } - return; - } - - /* no more retransmissions, remove node from system */ - - debug("** removed transaction\n"); - - /* And finally delete the node */ - netq_node_free(node); -} - -void -dtls_stop_retransmission(dtls_context_t *context, dtls_peer_t *peer) { - void *node; - node = list_head((list_t)context->sendqueue); - - while (node) { - if (dtls_session_equals(&((netq_t *)node)->peer->session, - &peer->session)) { - void *tmp = node; - node = list_item_next(node); - list_remove((list_t)context->sendqueue, tmp); - netq_node_free((netq_t *)tmp); - } else - node = list_item_next(node); - } -} - -void -dtls_check_retransmit(dtls_context_t *context, clock_time_t *next) { - dtls_tick_t now; - netq_t *node = netq_head((netq_t **)context->sendqueue); - - dtls_ticks(&now); - while (node && node->t <= now) { - netq_pop_first((netq_t **)context->sendqueue); - dtls_retransmit(context, node); - node = netq_head((netq_t **)context->sendqueue); - } - - if (next && node) - *next = node->t; -} - -#ifdef WITH_CONTIKI -/*---------------------------------------------------------------------------*/ -/* message retransmission */ -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(dtls_retransmit_process, ev, data) -{ - clock_time_t now; - netq_t *node; - - PROCESS_BEGIN(); - - debug("Started DTLS retransmit process\r\n"); - - while(1) { - PROCESS_YIELD(); - if (ev == PROCESS_EVENT_TIMER) { - if (etimer_expired(&the_dtls_context.retransmit_timer)) { - - node = list_head(the_dtls_context.sendqueue); - - now = clock_time(); - while (node && node->t <= now) { - dtls_retransmit(&the_dtls_context, list_pop(the_dtls_context.sendqueue)); - node = list_head(the_dtls_context.sendqueue); - } - - /* need to set timer to some value even if no nextpdu is available */ - etimer_set(&the_dtls_context.retransmit_timer, - node ? node->t - now : 0xFFFF); - } - } - } - - PROCESS_END(); -} -#endif /* WITH_CONTIKI */ - -#ifndef NDEBUG -/** dumps packets in usual hexdump format */ -void hexdump(const unsigned char *packet, int length) { - int n = 0; - - while (length--) { - if (n % 16 == 0) - printf("%08X ",n); - - printf("%02X ", *packet++); - - n++; - if (n % 8 == 0) { - if (n % 16 == 0) - printf("\n"); - else - printf(" "); - } - } -} - -/** dump as narrow string of hex digits */ -void dump(unsigned char *buf, size_t len) { - while (len--) - printf("%02x", *buf++); -} -#endif -
--- a/tinydtls/dtls.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,674 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * @file dtls.h - * @brief High level DTLS API and visible structures. - */ - -#ifndef _DTLS_H_ -#define _DTLS_H_ - -#include <stdint.h> - -#include "t_list.h" -#include "state.h" -#include "peer.h" - -#ifndef WITH_CONTIKI -#include "uthash.h" -#endif /* WITH_CONTIKI */ - -#include "alert.h" -#include "crypto.h" -#include "hmac.h" - -#include "config.h" -#include "global.h" -#include "dtls_time.h" - -#ifndef DTLSv12 -#define DTLS_VERSION 0xfeff /* DTLS v1.1 */ -#else -#define DTLS_VERSION 0xfefd /* DTLS v1.2 */ -#endif - -/** Known compression methods - * - * \hideinitializer - */ -#define TLS_COMP_NULL 0x00 /* NULL compression */ - -typedef enum { - DTLS_KEY_INVALID=0, DTLS_KEY_PSK=1, DTLS_KEY_RPK=2 -} dtls_key_type_t; - -typedef struct dtls_key_t { - dtls_key_type_t type; - union { - struct dtls_psk_t { - unsigned char *id; /**< psk identity */ - size_t id_length; /**< length of psk identity */ - unsigned char *key; /**< key data */ - size_t key_length; /**< length of key */ - } psk; - } key; -} dtls_key_t; - -/** Length of the secret that is used for generating Hello Verify cookies. */ -#define DTLS_COOKIE_SECRET_LENGTH 12 - -struct dtls_context_t; - -/** - * This structure contains callback functions used by tinydtls to - * communicate with the application. At least the write function must - * be provided. It is called by the DTLS state machine to send packets - * over the network. The read function is invoked to deliver decrypted - * and verfified application data. The third callback is an event - * handler function that is called when alert messages are encountered - * or events generated by the library have occured. - */ -typedef struct { - /** - * Called from dtls_handle_message() to send DTLS packets over the - * network. The callback function must use the network interface - * denoted by session->ifindex to send the data. - * - * @param ctx The current DTLS context. - * @param session The session object, including the address of the - * remote peer where the data shall be sent. - * @param buf The data to send. - * @param len The actual length of @p buf. - * @return The callback function must return the number of bytes - * that were sent, or a value less than zero to indicate an - * error. - */ - int (*write)(struct dtls_context_t *ctx, - session_t *session, uint8 *buf, size_t len); - - /** - * Called from dtls_handle_message() deliver application data that was - * received on the given session. The data is delivered only after - * decryption and verification have succeeded. - * - * @param ctx The current DTLS context. - * @param session The session object, including the address of the - * data's origin. - * @param buf The received data packet. - * @param len The actual length of @p buf. - * @return ignored - */ - int (*read)(struct dtls_context_t *ctx, - session_t *session, uint8 *buf, size_t len); - - /** - * The event handler is called when a message from the alert - * protocol is received or the state of the DTLS session changes. - * - * @param ctx The current dtls context. - * @param session The session object that was affected. - * @param level The alert level or @c 0 when an event ocurred that - * is not an alert. - * @param code Values less than @c 256 indicate alerts, while - * @c 256 or greater indicate internal DTLS session changes. - * @return ignored - */ - int (*event)(struct dtls_context_t *ctx, session_t *session, - dtls_alert_level_t level, unsigned short code); - - /** - * Called during handshake to lookup the key for @p id in @p - * session. If found, the key must be stored in @p result and - * the return value must be @c 0. If not found, @p result is - * undefined and the return value must be less than zero. - * - * @param ctx The current dtls context. - * @param session The session where the key will be used. - * @param id The identity of the communicating peer. This value is - * @c NULL when the DTLS engine requests the local - * id/key pair to use for session setup. - * @param id_len The actual length of @p id - * @param result Must be set to the key object to use.for the given - * session. - * @return @c 0 if result is set, or less than zero on error. - */ - int (*get_key)(struct dtls_context_t *ctx, - const session_t *session, - const unsigned char *id, size_t id_len, - const dtls_key_t **result); -} dtls_handler_t; - -/** Holds global information of the DTLS engine. */ -typedef struct dtls_context_t { - unsigned char cookie_secret[DTLS_COOKIE_SECRET_LENGTH]; - clock_time_t cookie_secret_age; /**< the time the secret has been generated */ - -#ifndef WITH_CONTIKI - dtls_peer_t *peers; /**< peer hash map */ -#else /* WITH_CONTIKI */ - LIST_STRUCT(peers); - - struct etimer retransmit_timer; /**< fires when the next packet must be sent */ -#endif /* WITH_CONTIKI */ - - LIST_STRUCT(sendqueue); /**< the packets to send */ - - void *app; /**< application-specific data */ - - dtls_handler_t *h; /**< callback handlers */ - - unsigned char readbuf[DTLS_MAX_BUF]; - unsigned char sendbuf[DTLS_MAX_BUF]; -} dtls_context_t; - -/** - * This function initializes the tinyDTLS memory management and must - * be called first. - */ -void dtls_init(); - -/** - * Creates a new context object. The storage allocated for the new - * object must be released with dtls_free_context(). */ -dtls_context_t *dtls_new_context(void *app_data); - -/** Releases any storage that has been allocated for \p ctx. */ -void dtls_free_context(dtls_context_t *ctx); - -#define dtls_set_app_data(CTX,DATA) ((CTX)->app = (DATA)) -#define dtls_get_app_data(CTX) ((CTX)->app) - -/** Sets the callback handler object for @p ctx to @p h. */ -static inline void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) { - ctx->h = h; -} - -/** - * Establishes a DTLS channel with the specified remote peer @p dst. - * This function returns @c 0 if that channel already exists, a value - * greater than zero when a new ClientHello message was sent, and - * a value less than zero on error. - * - * @param ctx The DTLS context to use. - * @param dst The remote party to connect to. - * @return A value less than zero on error, greater or equal otherwise. - */ -int dtls_connect(dtls_context_t *ctx, const session_t *dst); - -/** - * Establishes a DTLS channel with the specified remote peer. - * This function returns @c 0 if that channel already exists, a value - * greater than zero when a new ClientHello message was sent, and - * a value less than zero on error. - * - * @param ctx The DTLS context to use. - * @param peer The peer object that describes the session. - * @return A value less than zero on error, greater or equal otherwise. - */ -int dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer); - -/** - * Closes the DTLS connection associated with @p remote. This function - * returns zero on success, and a value less than zero on error. - */ -int dtls_close(dtls_context_t *ctx, const session_t *remote); - -/** - * Writes the application data given in @p buf to the peer specified - * by @p session. - * - * @param ctx The DTLS context to use. - * @param session The remote transport address and local interface. - * @param buf The data to write. - * @param len The actual length of @p data. - * - * @return The number of bytes written or @c -1 on error. - */ -int dtls_write(struct dtls_context_t *ctx, session_t *session, - uint8 *buf, size_t len); - -/** - * Checks sendqueue of given DTLS context object for any outstanding - * packets to be transmitted. - * - * @param context The DTLS context object to use. - * @param next If not NULL, @p next is filled with the timestamp - * of the next scheduled retransmission, or @c 0 when no packets are - * waiting. - */ -void dtls_check_retransmit(dtls_context_t *context, clock_time_t *next); - -#define DTLS_COOKIE_LENGTH 16 - -#define DTLS_CT_CHANGE_CIPHER_SPEC 20 -#define DTLS_CT_ALERT 21 -#define DTLS_CT_HANDSHAKE 22 -#define DTLS_CT_APPLICATION_DATA 23 - -/** Generic header structure of the DTLS record layer. */ -typedef struct { - uint8 content_type; /**< content type of the included message */ - uint16 version; /**< Protocol version */ - uint16 epoch; /**< counter for cipher state changes */ - uint48 sequence_number; /**< sequence number */ - uint16 length; /**< length of the following fragment */ - /* fragment */ -} dtls_record_header_t; - -/* Handshake types */ - -#define DTLS_HT_HELLO_REQUEST 0 -#define DTLS_HT_CLIENT_HELLO 1 -#define DTLS_HT_SERVER_HELLO 2 -#define DTLS_HT_HELLO_VERIFY_REQUEST 3 -#define DTLS_HT_CERTIFICATE 11 -#define DTLS_HT_SERVER_KEY_EXCHANGE 12 -#define DTLS_HT_CERTIFICATE_REQUEST 13 -#define DTLS_HT_SERVER_HELLO_DONE 14 -#define DTLS_HT_CERTIFICATE_VERIFY 15 -#define DTLS_HT_CLIENT_KEY_EXCHANGE 16 -#define DTLS_HT_FINISHED 20 - -/** Header structure for the DTLS handshake protocol. */ -typedef struct { - uint8 msg_type; /**< Type of handshake message (one of DTLS_HT_) */ - uint24 length; /**< length of this message */ - uint16 message_seq; /**< Message sequence number */ - uint24 fragment_offset; /**< Fragment offset. */ - uint24 fragment_length; /**< Fragment length. */ - /* body */ -} dtls_handshake_header_t; - -/** Structure of the Client Hello message. */ -typedef struct { - uint16 version; /**< Client version */ - uint32 gmt_random; /**< GMT time of the random byte creation */ - unsigned char random[28]; /**< Client random bytes */ - /* session id (up to 32 bytes) */ - /* cookie (up to 32 bytes) */ - /* cipher suite (2 to 2^16 -1 bytes) */ - /* compression method */ -} dtls_client_hello_t; - -/** Structure of the Hello Verify Request. */ -typedef struct { - uint16 version; /**< Server version */ - uint8 cookie_length; /**< Length of the included cookie */ - uint8 cookie[]; /**< up to 32 bytes making up the cookie */ -} dtls_hello_verify_t; - -#if 0 -/** - * Checks a received DTLS record for consistency and eventually decrypt, - * verify, decompress and reassemble the contained fragment for - * delivery to high-lever clients. - * - * \param state The DTLS record state for the current session. - * \param - */ -int dtls_record_read(dtls_state_t *state, uint8 *msg, int msglen); -#endif - -/** - * Retrieves a pointer to the cookie contained in a Client Hello message. - * - * \param hello_msg Points to the received Client Hello message - * \param msglen Length of \p hello_msg - * \param cookie Is set to the beginning of the cookie in the message if - * found. Undefined if this function returns \c 0. - * \return \c 0 if no cookie was found, < 0 on error. On success, the return - * value reflects the cookie's length. - */ -int dtls_get_cookie(uint8 *hello_msg, int msglen, uint8 **cookie); - -/** - * Handles incoming data as DTLS message from given peer. - * - * @param ctx The dtls context to use. - * @param session The current session - * @param msg The received data - * @param msglen The actual length of @p msg. - * @return A value less than zero on error, zero on success. - */ -int dtls_handle_message(dtls_context_t *ctx, session_t *session, - uint8 *msg, int msglen); - -/** - * Check if @p session is associated with a peer object in @p context. - * This function returns a pointer to the peer if found, NULL otherwise. - * - * @param context The DTLS context to search. - * @param session The remote address and local interface - * @return A pointer to the peer associated with @p session or NULL if - * none exists. - */ -dtls_peer_t *dtls_get_peer(const dtls_context_t *context, - const session_t *session); - - -#endif /* _DTLS_H_ */ - -/** - * @mainpage - * - * @author Olaf Bergmann, TZI Uni Bremen - * - * This library provides a very simple datagram server with DTLS - * support. It is designed to support session multiplexing in - * single-threaded applications and thus targets specifically on - * embedded systems. - * - * @section license License - * - * This software is under the <a - * href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>. - * - * @subsection uthash UTHash - * - * This library uses <a href="http://uthash.sourceforge.net/">uthash</a> to manage - * its peers (not used for Contiki). @b uthash uses the <b>BSD revised license</b>, see - * <a href="http://uthash.sourceforge.net/license.html">http://uthash.sourceforge.net/license.html</a>. - * - * @subsection sha256 Aaron D. Gifford's SHA256 Implementation - * - * tinyDTLS provides HMAC-SHA256 with BSD-licensed code from Aaron D. Gifford, - * see <a href="http://www.aarongifford.com/">www.aarongifford.com</a>. - * - * @subsection aes Rijndael Implementation From OpenBSD - * - * The AES implementation is taken from rijndael.{c,h} contained in the crypto - * sub-system of the OpenBSD operating system. It is copyright by Vincent Rijmen, * - * Antoon Bosselaers and Paulo Barreto. See <a - * href="http://www.openbsd.org/cgi-bin/cvsweb/src/sys/crypto/rijndael.c">rijndael.c</a> - * for License info. - * - * @section download Getting the Files - * - * You can get the sources either from the <a - * href="http://sourceforge.net/projects/tinydtls/files">downloads</a> section or - * through git from the <a - * href="http://sourceforge.net/projects/tinydtls/develop">project develop page</a>. - * - * @section config Configuration - * - * Use @c configure to set up everything for a successful build. For Contiki, use the - * option @c --with-contiki. - * - * @section build Building - * - * After configuration, just type - * @code -make - * @endcode - * optionally followed by - * @code -make install - * @endcode - * The Contiki version is integrated with the Contiki build system, hence you do not - * need to invoke @c make explicitely. Just add @c tinydtls to the variable @c APPS - * in your @c Makefile. - * - * @addtogroup dtls_usage DTLS Usage - * - * @section dtls_server_example DTLS Server Example - * - * This section shows how to use the DTLS library functions to setup a - * simple secure UDP echo server. The application is responsible for the - * entire network communication and thus will look like a usual UDP - * server with socket creation and binding and a typical select-loop as - * shown below. The minimum configuration required for DTLS is the - * creation of the dtls_context_t using dtls_new_context(), and a callback - * for sending data. Received packets are read by the application and - * passed to dtls_handle_message() as shown in @ref dtls_read_cb. - * For any useful communication to happen, read and write call backs - * and a key management function should be registered as well. - * - * @code - dtls_context_t *the_context = NULL; - int fd, result; - - static dtls_handler_t cb = { - .write = send_to_peer, - .read = read_from_peer, - .event = NULL, - .get_key = get_key - }; - - fd = socket(...); - if (fd < 0 || bind(fd, ...) < 0) - exit(-1); - - the_context = dtls_new_context(&fd); - dtls_set_handler(the_context, &cb); - - while (1) { - ...initialize fd_set rfds and timeout ... - result = select(fd+1, &rfds, NULL, 0, NULL); - - if (FD_ISSET(fd, &rfds)) - dtls_handle_read(the_context); - } - - dtls_free_context(the_context); - * @endcode - * - * @subsection dtls_read_cb The Read Callback - * - * The DTLS library expects received raw data to be passed to - * dtls_handle_message(). The application is responsible for - * filling a session_t structure with the address data of the - * remote peer as illustrated by the following example: - * - * @code -int dtls_handle_read(struct dtls_context_t *ctx) { - int *fd; - session_t session; - static uint8 buf[DTLS_MAX_BUF]; - int len; - - fd = dtls_get_app_data(ctx); - - assert(fd); - - session.size = sizeof(session.addr); - len = recvfrom(*fd, buf, sizeof(buf), 0, &session.addr.sa, &session.size); - - return len < 0 ? len : dtls_handle_message(ctx, &session, buf, len); -} - * @endcode - * - * Once a new DTLS session was established and DTLS ApplicationData has been - * received, the DTLS server invokes the read callback with the MAC-verified - * cleartext data as its argument. A read callback for a simple echo server - * could look like this: - * @code -int read_from_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) { - return dtls_write(ctx, session, data, len); -} - * @endcode - * - * @subsection dtls_send_cb The Send Callback - * - * The callback function send_to_peer() is called whenever data must be - * sent over the network. Here, the sendto() system call is used to - * transmit data within the given session. The socket descriptor required - * by sendto() has been registered as application data when the DTLS context - * was created with dtls_new_context(). - * Note that it is on the application to buffer the data when it cannot be - * sent at the time this callback is invoked. The following example thus - * is incomplete as it would have to deal with EAGAIN somehow. - * @code -int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) { - int fd = *(int *)dtls_get_app_data(ctx); - return sendto(fd, data, len, MSG_DONTWAIT, &session->addr.sa, session->size); -} - * @endcode - * - * @subsection dtls_get_key The Key Storage - * - * When a new DTLS session is created, the library must ask the application - * for keying material. To do so, it invokes the registered call-back function - * get_key() with the current context and session information as parameter. - * When the function is called with the @p id parameter set, the result must - * point to a dtls_key_t structure for the given identity. When @p id is - * @c NULL, the function must pick a suitable identity and return a pointer to - * the corresponding dtls_key_t structure. The following example shows a - * simple key storage for a pre-shared key for @c Client_identity: - * - * @code -int get_key(struct dtls_context_t *ctx, - const session_t *session, - const unsigned char *id, size_t id_len, - const dtls_key_t **result) { - - static const dtls_key_t psk = { - .type = DTLS_KEY_PSK, - .key.psk.id = (unsigned char *)"my identity", - .key.psk.id_length = 11, - .key.psk.key = (unsigned char *)"secret", - .key.psk.key_length = 6 - }; - - *result = &psk; - return 0; -} - * @endcode - * - * @subsection dtls_events The Event Notifier - * - * Applications that want to be notified whenever the status of a DTLS session - * has changed can register an event handling function with the field @c event - * in the dtls_handler_t structure (see \ref dtls_server_example). The call-back - * function is called for alert messages and internal state changes. For alert - * messages, the argument @p level will be set to a value greate than zero, and - * @p code will indicate the notification code. For internal events, @p level - * is @c 0, and @p code a value greater than @c 255. - * - * Currently, the only defined internal event is @c DTLS_EVENT_CONNECTED. It - * indicates successful establishment of a new DTLS channel. - * - * @code -int handle_event(struct dtls_context_t *ctx, session_t *session, - dtls_alert_level_t level, unsigned short code) { - ... do something with event ... - return 0; -} - * @endcode - * - * @section dtls_client_example DTLS Client Example - * - * A DTLS client is constructed like a server but needs to actively setup - * a new session by calling dtls_connect() at some point. As this function - * usually returns before the new DTLS channel is established, the application - * must register an event handler and wait for @c DTLS_EVENT_CONNECT before - * it can send data over the DTLS channel. - * - */ - -/** - * @addtogroup contiki Contiki - * - * To use tinyDTLS as Contiki application, place the source code in the directory - * @c apps/tinydtls in the Contiki source tree and invoke configure with the option - * @c --with-contiki. This will create the tinydtls Makefile and config.h from the - * templates @c Makefile.contiki and @c config.h.contiki instead of the usual - * templates ending in @c .in. - * - * Then, create a Contiki project with @c APPS += tinydtls in its Makefile. A sample - * server could look like this (with read_from_peer() and get_key() as shown above). - * - * @code -#include "contiki.h" - -#include "config.h" -#include "dtls.h" - -#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) -#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) - -int send_to_peer(struct dtls_context_t *, session_t *, uint8 *, size_t); - -static struct uip_udp_conn *server_conn; -static dtls_context_t *dtls_context; - -static dtls_handler_t cb = { - .write = send_to_peer, - .read = read_from_peer, - .event = NULL, - .get_key = get_key -}; - -PROCESS(server_process, "DTLS server process"); -AUTOSTART_PROCESSES(&server_process); - -PROCESS_THREAD(server_process, ev, data) -{ - PROCESS_BEGIN(); - - dtls_init(); - - server_conn = udp_new(NULL, 0, NULL); - udp_bind(server_conn, UIP_HTONS(5684)); - - dtls_context = dtls_new_context(server_conn); - if (!dtls_context) { - dsrv_log(LOG_EMERG, "cannot create context\n"); - PROCESS_EXIT(); - } - - dtls_set_handler(dtls_context, &cb); - - while(1) { - PROCESS_WAIT_EVENT(); - if(ev == tcpip_event && uip_newdata()) { - session_t session; - - uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr); - session.port = UIP_UDP_BUF->srcport; - session.size = sizeof(session.addr) + sizeof(session.port); - - dtls_handle_message(ctx, &session, uip_appdata, uip_datalen()); - } - } - - PROCESS_END(); -} - -int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) { - struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx); - - uip_ipaddr_copy(&conn->ripaddr, &session->addr); - conn->rport = session->port; - - uip_udp_packet_send(conn, data, len); - - memset(&conn->ripaddr, 0, sizeof(server_conn->ripaddr)); - memset(&conn->rport, 0, sizeof(conn->rport)); - - return len; -} - * @endcode - */
--- a/tinydtls/dtls_time.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * @file dtls_time.c - * @brief Clock Handling - */ - -#include "dtls_time.h" -#include "bsd_socket.h" - -#ifdef MBED -/** - * gettimeofday() not in mbed - */ -void gettimeofday(struct timeval* t, void* timezone) -{ - t->tv_sec = time(NULL); - t->tv_usec = 0; /* 1sec precision only */ - -} - -#endif - -#ifdef WITH_CONTIKI -clock_time_t dtls_clock_offset; - -void -dtls_clock_init(void) { - clock_init(); - dtls_clock_offset = clock_time(); -} - -void -dtls_ticks(dtls_tick_t *t) { - *t = clock_time(); -} - -#else /* WITH_CONTIKI */ - -time_t dtls_clock_offset; - -void -dtls_clock_init(void) { -#ifdef HAVE_TIME_H - dtls_clock_offset = time(NULL); -#else -# ifdef __GNUC__ - /* Issue a warning when using gcc. Other prepropressors do - * not seem to have a similar feature. */ -# warning "cannot initialize clock" -# endif - dtls_clock_offset = 0; -#endif -} - -void dtls_ticks(dtls_tick_t *t) { -#ifdef HAVE_SYS_TIME_H - struct timeval tv; - gettimeofday(&tv, NULL); - *t = (tv.tv_sec - dtls_clock_offset) * DTLS_TICKS_PER_SECOND - + (tv.tv_usec * DTLS_TICKS_PER_SECOND / 1000000); -#else -#error "clock not implemented" -#endif -} - -#endif /* WITH_CONTIKI */ - -
--- a/tinydtls/dtls_time.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * @file dtls_time.h - * @brief Clock Handling - */ - -#ifndef _DTLS_TIME_H_ -#define _DTLS_TIME_H_ - -#include "config.h" - -#ifdef HAVE_SYS_TIME_H -#ifndef MBED -#include <sys/time.h> -#else -#include <time.h> -#endif -#endif /* HAVE_SYS_TIME_H */ - -/** - * @defgroup clock Clock Handling - * Default implementation of internal clock. You should redefine this if - * you do not have time() and gettimeofday(). - * @{ - */ - -#ifdef WITH_CONTIKI -#include "clock.h" - -typedef clock_time_t dtls_tick_t; -#else /* WITH_CONTIKI */ - -#ifdef HAVE_TIME_H -#include <time.h> -#endif - -#ifndef CLOCK_SECOND -# define CLOCK_SECOND 1000 -#endif - -typedef unsigned int dtls_tick_t; - -#endif /* WITH_CONTIKI */ - -#ifndef DTLS_TICKS_PER_SECOND -#define DTLS_TICKS_PER_SECOND CLOCK_SECOND -#endif /* DTLS_TICKS_PER_SECOND */ - -void dtls_clock_init(void); -void dtls_ticks(dtls_tick_t *t); - -/** @} */ - -#endif /* _DTLS_TIME_H_ */
--- a/tinydtls/global.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,208 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _GLOBAL_H_ -#define _GLOBAL_H_ - -#include "config.h" - -#ifdef HAVE_ASSERT_H -#include <assert.h> -#else -#ifndef assert -#warning "assertions are disabled" -# define assert(x) -#endif -#endif - -#include <string.h> -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif - -#ifdef MBED -//#include "lwip/inet.h" -#include "lwip/sockets.h" -#include "lwip/netdb.h" -#endif - -#ifndef DTLSv12 -/* The current version of tinyDTLS supports DTLSv1.2 only. */ -#define DTLSv12 1 -#endif - -#ifndef WITH_SHA256 -/* The current version of tinyDTLS supports DTLSv1.2 with SHA256 PRF - only. */ -#define WITH_SHA256 1 -#endif - -#ifndef WITH_CONTIKI -typedef unsigned int clock_time_t; -#else /* WITH_CONTIKI */ -#include "uip.h" -typedef struct { - unsigned char size; - uip_ipaddr_t addr; - unsigned short port; - int ifindex; -} __uip_session_t; -#define session_t __uip_session_t - -#define _dtls_address_equals_impl(A,B) \ - ((A)->size == (B)->size \ - && (A)->port == (B)->port \ - && uip_ipaddr_cmp(&((A)->addr),&((B)->addr)) \ - && (A)->ifindex == (B)->ifindex) - -#endif /* WITH_CONTIKI */ - -/** multi-purpose address abstraction */ -#ifndef session_t -typedef struct __session_t { - socklen_t size; /**< size of addr */ - union { - struct sockaddr sa; - //struct sockaddr_storage st; - struct sockaddr_in sin; - //struct sockaddr_in6 sin6; - } addr; - int ifindex; -} __session_t; - -#define session_t __session_t - - - -static inline int -_dtls_address_equals_impl(const session_t *a, - const session_t *b) { - if (a->ifindex != b->ifindex || - a->size != b->size || a->addr.sa.sa_family != b->addr.sa.sa_family) - return 0; - - /* need to compare only relevant parts of sockaddr_in6 */ - switch (a->addr.sa.sa_family) { - case AF_INET: - return - a->addr.sin.sin_port == b->addr.sin.sin_port && - memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr, - sizeof(struct in_addr)) == 0; - /* - case AF_INET6: - return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port && - memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr, - sizeof(struct in6_addr)) == 0; - */ - default: /* fall through and signal error */ - ; - } - return 0; -} -#endif /* session_t */ - -/* Define our own types as at least uint32_t does not work on my amd64. */ - -typedef unsigned char uint8; -typedef unsigned char uint16[2]; -typedef unsigned char uint24[3]; -typedef unsigned char uint32[4]; -typedef unsigned char uint48[6]; - -#ifndef HAVE_STR -typedef struct { - size_t length; /* length of string */ - unsigned char *s; /* string data */ -} str; -#endif - -#ifndef DTLS_MAX_BUF -/** Maximum size of DTLS message. */ -#define DTLS_MAX_BUF 256 -#endif - -#ifndef DTLS_DEFAULT_MAX_RETRANSMIT -/** Number of message retransmissions. */ -#define DTLS_DEFAULT_MAX_RETRANSMIT 5 -#endif - -/** Known cipher suites.*/ -typedef enum { - TLS_NULL_WITH_NULL_NULL = 0x0000, /**< NULL cipher */ - TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8 /**< see RFC 6655 */ -} dtls_cipher_t; - -/** - * XORs \p n bytes byte-by-byte starting at \p y to the memory area - * starting at \p x. */ -static inline void -memxor(unsigned char *x, const unsigned char *y, size_t n) { - while(n--) { - *x ^= *y; - x++; y++; - } -} - -#ifdef HAVE_FLS -#define dtls_fls(i) fls(i) -#else -static inline int -dtls_fls(unsigned int i) { - int n; - for (n = 0; i; n++) - i >>= 1; - return n; -} -#endif /* HAVE_FLS */ - -/** - * Resets the given session_t object @p sess to its default - * values. In particular, the member rlen must be initialized to the - * available size for storing addresses. - * - * @param sess The session_t object to initialize. - */ -static inline void -dtls_session_init(session_t *sess) { - assert(sess); - memset(sess, 0, sizeof(session_t)); - sess->size = sizeof(sess->addr); -} - -static inline int -dtls_session_equals(const session_t *a, const session_t *b) { - assert(a); assert(b); - return _dtls_address_equals_impl(a, b); -} -#endif /* _GLOBAL_H_ */
--- a/tinydtls/hmac.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifdef HAVE_ASSERT_H -#include <assert.h> -#endif - -#include "debug.h" -#include "hmac.h" -/* use malloc()/free() on platforms other than Contiki */ -#ifndef WITH_CONTIKI -#include <stdlib.h> - -static inline dtls_hmac_context_t * -dtls_hmac_context_new() { - return (dtls_hmac_context_t *)malloc(sizeof(dtls_hmac_context_t)); -} - -static inline void -dtls_hmac_context_free(dtls_hmac_context_t *ctx) { - free(ctx); -} - -#else /* WITH_CONTIKI */ -#include "memb.h" -MEMB(hmac_context_storage, dtls_hmac_context_t, DTLS_HASH_MAX); - -static inline dtls_hmac_context_t * -dtls_hmac_context_new() { - return (dtls_hmac_context_t *)memb_alloc(&hmac_context_storage); -} - -static inline void -dtls_hmac_context_free(dtls_hmac_context_t *ctx) { - memb_free(&hmac_context_storage, ctx); -} -#endif /* WITH_CONTIKI */ - -void -dtls_hmac_storage_init() { -#ifdef WITH_CONTIKI - memb_init(&hmac_context_storage); -#endif /* WITH_CONTIKI */ -} - -void -dtls_hmac_update(dtls_hmac_context_t *ctx, - const unsigned char *input, size_t ilen) { - assert(ctx); - dtls_hash_update(&ctx->data, input, ilen); -} - -dtls_hmac_context_t * -dtls_hmac_new(const unsigned char *key, size_t klen) { - dtls_hmac_context_t *ctx; - - ctx = dtls_hmac_context_new(); - if (ctx) - dtls_hmac_init(ctx, key, klen); - - return ctx; -} - -void -dtls_hmac_init(dtls_hmac_context_t *ctx, const unsigned char *key, size_t klen) { - int i; - - assert(ctx); - - memset(ctx, 0, sizeof(dtls_hmac_context_t)); - - if (klen > DTLS_HMAC_BLOCKSIZE) { - dtls_hash_init(&ctx->data); - dtls_hash_update(&ctx->data, key, klen); - dtls_hash_finalize(ctx->pad, &ctx->data); - } else - memcpy(ctx->pad, key, klen); - - /* create ipad: */ - for (i=0; i < DTLS_HMAC_BLOCKSIZE; ++i) - ctx->pad[i] ^= 0x36; - - dtls_hash_init(&ctx->data); - dtls_hmac_update(ctx, ctx->pad, DTLS_HMAC_BLOCKSIZE); - - /* create opad by xor-ing pad[i] with 0x36 ^ 0x5C: */ - for (i=0; i < DTLS_HMAC_BLOCKSIZE; ++i) - ctx->pad[i] ^= 0x6A; -} - -void -dtls_hmac_free(dtls_hmac_context_t *ctx) { - if (ctx) - dtls_hmac_context_free(ctx); -} - -int -dtls_hmac_finalize(dtls_hmac_context_t *ctx, unsigned char *result) { - unsigned char buf[DTLS_HMAC_DIGEST_SIZE]; - size_t len; - - assert(ctx); - assert(result); - - len = dtls_hash_finalize(buf, &ctx->data); - - dtls_hash_init(&ctx->data); - dtls_hash_update(&ctx->data, ctx->pad, DTLS_HMAC_BLOCKSIZE); - dtls_hash_update(&ctx->data, buf, len); - - len = dtls_hash_finalize(result, &ctx->data); - - return len; -} - -#ifdef HMAC_TEST -#include <stdio.h> - -int main(int argc, char **argv) { - static unsigned char buf[DTLS_HMAC_DIGEST_SIZE]; - size_t len, i; - dtls_hmac_context_t *ctx; - - if (argc < 3) { - fprintf(stderr, "usage: %s key text", argv[0]); - return -1; - } - - dtls_hmac_storage_init(); - ctx = dtls_hmac_new(argv[1], strlen(argv[1])); - assert(ctx); - dtls_hmac_update(ctx, argv[2], strlen(argv[2])); - - len = dtls_hmac_finalize(ctx, buf); - - for(i = 0; i < len; i++) - printf("%02x", buf[i]); - printf("\n"); - - dtls_hmac_free(ctx); - - return 0; -} -#endif
--- a/tinydtls/hmac.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _HMAC_H_ -#define _HMAC_H_ - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#include "global.h" - -#ifdef WITH_SHA256 -/** Aaron D. Gifford's implementation of SHA256 - * see http://www.aarongifford.com/ */ -#include "sha2/sha2.h" - -typedef SHA256_CTX dtls_hash_ctx; -typedef dtls_hash_ctx *dtls_hash_t; -#define DTLS_HASH_CTX_SIZE sizeof(SHA256_CTX) - -static inline void -dtls_hash_init(dtls_hash_t ctx) { - SHA256_Init((SHA256_CTX *)ctx); -} - -static inline void -dtls_hash_update(dtls_hash_t ctx, const unsigned char *input, size_t len) { - SHA256_Update((SHA256_CTX *)ctx, input, len); -} - -static inline size_t -dtls_hash_finalize(unsigned char *buf, dtls_hash_t ctx) { - SHA256_Final(buf, (SHA256_CTX *)ctx); - return SHA256_DIGEST_LENGTH; -} -#endif /* WITH_SHA256 */ - -/** - * \defgroup HMAC Keyed-Hash Message Authentication Code (HMAC) - * NIST Standard FIPS 198 describes the Keyed-Hash Message Authentication - * Code (HMAC) which is used as hash function for the DTLS PRF. - * @{ - */ - -#define DTLS_HMAC_BLOCKSIZE 64 /**< size of hmac blocks */ -#define DTLS_HMAC_DIGEST_SIZE 32 /**< digest size (for SHA-256) */ -#define DTLS_HMAC_MAX 64 /**< max number of bytes in digest */ - -/** - * List of known hash functions for use in dtls_hmac_init(). The - * identifiers are the same as the HashAlgorithm defined in - * <a href="http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1" - * >Section 7.4.1.4.1 of RFC 5246</a>. - */ -typedef enum { - HASH_NONE=0, HASH_MD5=1, HASH_SHA1=2, HASH_SHA224=3, - HASH_SHA256=4, HASH_SHA384=5, HASH_SHA512=6 -} dtls_hashfunc_t; - -/** - * Context for HMAC generation. This object is initialized with - * dtls_hmac_init() and must be passed to dtls_hmac_update() and - * dtls_hmac_finalize(). Once, finalized, the component \c H is - * invalid and must be initialized again with dtls_hmac_init() before - * the structure can be used again. - */ -typedef struct { - unsigned char pad[DTLS_HMAC_BLOCKSIZE]; /**< ipad and opad storage */ - dtls_hash_ctx data; /**< context for hash function */ -} dtls_hmac_context_t; - -/** - * Initializes an existing HMAC context. - * - * @param ctx The HMAC context to initialize. - * @param key The secret key. - * @param klen The length of @p key. - */ -void dtls_hmac_init(dtls_hmac_context_t *ctx, const unsigned char *key, size_t klen); - -/** - * Allocates a new HMAC context \p ctx with the given secret key. - * This function returns \c 1 if \c ctx has been set correctly, or \c - * 0 or \c -1 otherwise. Note that this function allocates new storage - * that must be released by dtls_hmac_free(). - * - * \param key The secret key. - * \param klen The length of \p key. - * \return A new dtls_hmac_context_t object or @c NULL on error - */ -dtls_hmac_context_t *dtls_hmac_new(const unsigned char *key, size_t klen); - -/** - * Releases the storage for @p ctx that has been allocated by - * dtls_hmac_new(). - * - * @param ctx The dtls_hmac_context_t to free. - */ -void dtls_hmac_free(dtls_hmac_context_t *ctx); - -/** - * Updates the HMAC context with data from \p input. - * - * \param ctx The HMAC context. - * \param input The input data. - * \param ilen Size of \p input. - */ -void dtls_hmac_update(dtls_hmac_context_t *ctx, - const unsigned char *input, size_t ilen); - -/** - * Completes the HMAC generation and writes the result to the given - * output parameter \c result. The buffer must be large enough to hold - * the message digest created by the actual hash function. If in - * doubt, use \c DTLS_HMAC_MAX. The function returns the number of - * bytes written to \c result. - * - * \param ctx The HMAC context. - * \param result Output parameter where the MAC is written to. - * \return Length of the MAC written to \p result. - */ -int dtls_hmac_finalize(dtls_hmac_context_t *ctx, unsigned char *result); - -/**@}*/ - -#endif /* _HMAC_H_ */
--- a/tinydtls/netq.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* netq.h -- Simple packet queue - * - * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org> - * - * This file is part of the library tinyDTLS. Please see the file - * LICENSE for terms of use. - */ - -//#include "netinet/in.h" -#include "debug.h" -#include "netq.h" - - -#ifdef HAVE_ASSERT_H -#include <assert.h> -#else -#ifndef assert -#warning "assertions are disabled" -# define assert(x) -#endif -#endif - -#include "t_list.h" - -#ifndef WITH_CONTIKI -#include <stdlib.h> - -static inline netq_t * -netq_malloc_node() { - return (netq_t *)malloc(sizeof(netq_t)); -} - -static inline void -netq_free_node(netq_t *node) { - free(node); -} - -/* FIXME: implement Contiki's list functions using utlist.h */ - -#else /* WITH_CONTIKI */ -#include "memb.h" - -MEMB(netq_storage, netq_t, NETQ_MAXCNT); - -static inline netq_t * -netq_malloc_node() { - return (netq_t *)memb_alloc(&netq_storage); -} - -static inline void -netq_free_node(netq_t *node) { - memb_free(&netq_storage, node); -} -#endif /* WITH_CONTIKI */ - -void -netq_init() { -#ifdef WITH_CONTIKI - memb_init(&netq_storage); -#endif /* WITH_CONTIKI */ -} - -int -netq_insert_node(netq_t **queue, netq_t *node) { - netq_t *p; - - assert(queue); - assert(node); - - p = (netq_t *)list_head((list_t)queue); - while(p && p->t <= node->t) - p = list_item_next(p); - - if (p) - list_insert((list_t)queue, p, node); - else - list_push((list_t)queue, node); - - return 1; -} - -netq_t * -netq_head(netq_t **queue) { - if (!queue) - return NULL; - - return list_head((list_t)queue); -} - -netq_t *netq_pop_first(netq_t **queue) { - if (!queue) - return NULL; - - return list_pop((list_t)queue); -} - -netq_t * -netq_node_new() { - netq_t *node; - node = netq_malloc_node(); - -#ifndef NDEBUG - if (!node) - dsrv_log(LOG_WARN, "netq_node_new: malloc\n"); -#endif - - if (node) - memset(node, 0, sizeof(netq_t)); - - return node; -} - -void -netq_node_free(netq_t *node) { - if (node) - netq_free_node(node); -} - -void -netq_delete_all(netq_t *queue) { - netq_t *p; - if (queue) { - while((p = list_pop((list_t)&queue))) - netq_free_node(p); - } -} -
--- a/tinydtls/netq.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* netq.h -- Simple packet queue - * - * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org> - * - * This file is part of the library tinyDTLS. Please see the file - * LICENSE for terms of use. - */ - -#ifndef _NETQ_H_ -#define _NETQ_H_ - -#include "config.h" -#include "global.h" -//#include "dtls.h" -#include "time.h" -#include "peer.h" - -/** - * \defgroup netq Network Packet Queue - * The netq utility functions implement an ordered queue of data packets - * to send over the network and can also be used to queue received packets - * from the network. - * @{ - */ - -#ifndef NETQ_MAXCNT -#define NETQ_MAXCNT 4 /**< maximum number of elements in netq structure */ -#endif - -/** - * Datagrams in the netq_t structure have a fixed maximum size of - * DTLS_MAX_BUF to simplify memory management on constrained nodes. */ -typedef unsigned char netq_packet_t[DTLS_MAX_BUF]; - -typedef struct netq_t { - struct netq_t *next; - - clock_time_t t; /**< when to send PDU for the next time */ - unsigned char retransmit_cnt; /**< retransmission counter, will be removed when zero */ - unsigned int timeout; /**< randomized timeout value */ - - dtls_peer_t *peer; /**< remote address */ - - size_t length; /**< actual length of data */ - netq_packet_t data; /**< the datagram to send */ -} netq_t; - -/** - * Adds a node to the given queue, ordered by their time-stamp t. - * This function returns @c 0 on error, or non-zero if @p node has - * been added successfully. - * - * @param queue A pointer to the queue head where @p node will be added. - * @param node The new item to add. - * @return @c 0 on error, or non-zero if the new item was added. - */ -int netq_insert_node(netq_t **queue, netq_t *node); - -/** Destroys specified node and releases any memory that was allocated - * for the associated datagram. */ -void netq_node_free(netq_t *node); - -/** Removes all items from given queue and frees the allocated storage */ -void netq_delete_all(netq_t *queue); - -/** Creates a new node suitable for adding to a netq_t queue. */ -netq_t *netq_node_new(); - -/** - * Returns a pointer to the first item in given queue or NULL if - * empty. - */ -netq_t *netq_head(netq_t **queue); - -/** - * Removes the first item in given queue and returns a pointer to the - * removed element. If queue is empty when netq_pop_first() is called, - * this function returns NULL. - */ -netq_t *netq_pop_first(netq_t **queue); - -/**@}*/ - -#endif /* _NETQ_H_ */
--- a/tinydtls/numeric.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _NUMERIC_H_ -#define _NUMERIC_H_ - -#include <stdint.h> - -#ifndef min -#define min(A,B) ((A) <= (B) ? (A) : (B)) -#endif - -#ifndef max -#define max(A,B) ((A) < (B) ? (B) : (A)) -#endif - -/** - * Increments given \p Var of type \p Type by \c 1. - * - * \hideinitializer - */ -#define inc_uint(Type,Var) { \ - int i = sizeof(Type); \ - while (i && !++((Var)[--i])); \ - } - -/* this one is for consistency... */ -#define dtls_int_to_uint8(Field,Value) do { \ - *(unsigned char*)(Field) = (Value) & 0xff; \ - } while(0) - -#define dtls_int_to_uint16(Field,Value) do { \ - *(unsigned char*)(Field) = ((Value) >> 8) & 0xff; \ - *(((unsigned char*)(Field))+1) = ((Value) & 0xff); \ - } while(0) - -#define dtls_int_to_uint24(Field,Value) do { \ - *(unsigned char*)(Field) = ((Value) >> 16) & 0xff; \ - dtls_int_to_uint16((((unsigned char*)(Field))+1),Value); \ - } while(0) - -#define dtls_int_to_uint32(Field,Value) do { \ - *(unsigned char*)(Field) = ((Value) >> 24) & 0xff; \ - *(((unsigned char*)(Field))+1) = ((Value) >> 16) & 0xff; \ - *(((unsigned char*)(Field))+2) = ((Value) >> 8) & 0xff; \ - *(((unsigned char*)(Field))+3) = (Value) & 0xff; \ - } while(0) - -#define dtls_ulong_to_uint48(Field,Value) do { \ - *(unsigned char*)(Field) = ((Value) >> 40) & 0xff; \ - *(((unsigned char*)(Field))+1) = ((Value) >> 32) & 0xff; \ - *(((unsigned char*)(Field))+2) = ((Value) >> 24) & 0xff; \ - *(((unsigned char*)(Field))+3) = ((Value) >> 16) & 0xff; \ - *(((unsigned char*)(Field))+4) = ((Value) >> 8) & 0xff; \ - *(((unsigned char*)(Field))+5) = (Value) & 0xff; \ - } while(0) - -#define dtls_ulong_to_uint64(Field,Value) do { \ - *(unsigned char*)(Field) = ((Value) >> 56) & 0xff; \ - *(((unsigned char*)(Field))+1) = ((Value) >> 48) & 0xff; \ - *(((unsigned char*)(Field))+2) = ((Value) >> 40) & 0xff; \ - *(((unsigned char*)(Field))+3) = ((Value) >> 32) & 0xff; \ - *(((unsigned char*)(Field))+4) = ((Value) >> 24) & 0xff; \ - *(((unsigned char*)(Field))+5) = ((Value) >> 16) & 0xff; \ - *(((unsigned char*)(Field))+6) = ((Value) >> 8) & 0xff; \ - *(((unsigned char*)(Field))+7) = (Value) & 0xff; \ - } while(0) - -#define dtls_uint8_to_int(Field) \ - (*(unsigned char*)(Field) & 0xFF) - -#define dtls_uint16_to_int(Field) \ - (((*(unsigned char*)(Field)) << 8) | (*(((unsigned char*)(Field))+1))) - -#define dtls_uint24_to_int(Field) \ - (((*(((unsigned char*)(Field)))) << 16) \ - | ((*(((unsigned char*)(Field))+1)) << 8) \ - | ((*(((unsigned char*)(Field))+2)))) - -#define dtls_uint48_to_ulong(Field) \ - (((uint64_t) *(unsigned char*)(Field)) << 40) \ - | (((uint64_t) *(((unsigned char*)(Field))+1)) << 32) \ - | (((uint64_t) *(((unsigned char*)(Field))+2)) << 24) \ - | (((uint64_t) *(((unsigned char*)(Field))+3)) << 16) \ - | (((uint64_t) *(((unsigned char*)(Field))+4)) << 8) \ - | (((uint64_t) *(((unsigned char*)(n))+5))) - -#endif /* _NUMERIC_H_ */
--- a/tinydtls/peer.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "peer.h" -#include "debug.h" - -#ifndef NDEBUG -#include <stdio.h> - -extern size_t dsrv_print_addr(const session_t *addr, unsigned char *buf, - size_t len); -#endif /* NDEBUG */ - -#ifndef WITH_CONTIKI -void peer_init() -{ -} - -static inline dtls_peer_t * -dtls_malloc_peer() { - return (dtls_peer_t *)malloc(sizeof(dtls_peer_t)); -} - -void -dtls_free_peer(dtls_peer_t *peer) { - free(peer); -} -#else /* WITH_CONTIKI */ -PROCESS(dtls_retransmit_process, "DTLS retransmit process"); - -#include "memb.h" -MEMB(peer_storage, dtls_peer_t, DTLS_PEER_MAX); - -void -peer_init() { - memb_init(&peer_storage); -} - -static inline dtls_peer_t * -dtls_malloc_peer() { - return memb_alloc(&peer_storage); -} - -void -dtls_free_peer(dtls_peer_t *peer) { - memb_free(&peer_storage, peer); -} -#endif /* WITH_CONTIKI */ - -dtls_peer_t * -dtls_new_peer(const session_t *session) { - dtls_peer_t *peer; - - peer = dtls_malloc_peer(); - if (peer) { - memset(peer, 0, sizeof(dtls_peer_t)); - memcpy(&peer->session, session, sizeof(session_t)); - -#ifndef NDEBUG - if (dtls_get_log_level() >= LOG_DEBUG) { - unsigned char addrbuf[72]; - dsrv_print_addr(session, addrbuf, sizeof(addrbuf)); - printf("dtls_new_peer: %s\n", addrbuf); - } -#endif - /* initially allow the NULL cipher */ - CURRENT_CONFIG(peer)->cipher = TLS_NULL_WITH_NULL_NULL; - - /* initialize the handshake hash wrt. the hard-coded DTLS version */ - debug("DTLSv12: initialize HASH_SHA256\n"); - /* TLS 1.2: PRF(secret, label, seed) = P_<hash>(secret, label + seed) */ - /* FIXME: we use the default SHA256 here, might need to support other - hash functions as well */ - dtls_hash_init(&peer->hs_state.hs_hash); - } - - return peer; -} -
--- a/tinydtls/peer.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * @file peer.h - * @brief information about peers in a DTLS session - */ - -#ifndef _PEER_H_ -#define _PEER_H_ - -#include "config.h" -#include "global.h" - -#include "state.h" -#include "crypto.h" - -#ifndef WITH_CONTIKI -#include "uthash.h" -#endif /* WITH_CONTIKI */ - -/** - * Holds security parameters, local state and the transport address - * for each peer. */ -typedef struct dtls_peer_t { -#ifndef WITH_CONTIKI - UT_hash_handle hh; -#else /* WITH_CONTIKI */ - struct dtls_peer_t *next; -#endif /* WITH_CONTIKI */ - - session_t session; /**< peer address and local interface */ - - dtls_state_t state; /**< DTLS engine state */ - uint16 epoch; /**< counter for cipher state changes*/ - uint48 rseq; /**< sequence number of last record sent */ - - dtls_hs_state_t hs_state; /**< handshake protocol status */ - - dtls_security_parameters_t security_params[2]; - int config; /**< denotes which security params are in effect */ - /* FIXME: check if we can use epoch for this */ -} dtls_peer_t; - -/** - * Creates a new peer for given @p session. The current configuration - * is initialized with the cipher suite TLS_NULL_WITH_NULL_NULL (i.e. - * no security at all). This function returns a pointer to the new - * peer or NULL on error. The caller is responsible for releasing the - * storage allocated for this peer using dtls_free_peer(). - * - * @param session The remote peer's address and local interface index. - * @return A pointer to a newly created and initialized peer object - * or NULL on error. - */ -dtls_peer_t *dtls_new_peer(const session_t *session); - -/** Releases the storage allocated to @p peer. */ -void dtls_free_peer(dtls_peer_t *peer); - -/** Returns the current state of @p peer. */ -static inline dtls_state_t dtls_peer_state(const dtls_peer_t *peer) { - return peer->state; -} - -/** - * Checks if given @p peer is connected. This function returns - * @c 1 if connected, or @c 0 otherwise. - */ -static inline int dtls_peer_is_connected(const dtls_peer_t *peer) { - return peer->state == DTLS_STATE_CONNECTED; -} - -#define CURRENT_CONFIG(Peer) (&(Peer)->security_params[(Peer)->config]) -#define OTHER_CONFIG(Peer) (&(Peer)->security_params[!((Peer)->config & 0x01)]) - -#define SWITCH_CONFIG(Peer) ((Peer)->config = !((Peer)->config & 0x01)) - -#endif /* _PEER_H_ */
--- a/tinydtls/prng.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* prng.h -- Pseudo Random Numbers - * - * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org> - * - * This file is part of the library tinydtls. Please see - * README for terms of use. - */ - -/** - * @file prng.h - * @brief Pseudo Random Numbers - */ - -#ifndef _DTLS_PRNG_H_ -#define _DTLS_PRNG_H_ - -#include "config.h" - -/** - * @defgroup prng Pseudo Random Numbers - * @{ - */ - -#ifndef WITH_CONTIKI -#include <stdlib.h> - -/** - * Fills \p buf with \p len random bytes. This is the default - * implementation for prng(). You might want to change prng() to use - * a better PRNG on your specific platform. - */ -static inline int -dtls_prng_impl(unsigned char *buf, size_t len) { - while (len--) - *buf++ = rand() & 0xFF; - return 1; -} -#else /* WITH_CONTIKI */ -#include <string.h> - -#ifdef HAVE_PRNG -extern int contiki_prng_impl(unsigned char *buf, size_t len); -#else -/** - * Fills \p buf with \p len random bytes. This is the default - * implementation for prng(). You might want to change prng() to use - * a better PRNG on your specific platform. - */ -static inline int -contiki_prng_impl(unsigned char *buf, size_t len) { - unsigned short v = random_rand(); - while (len > sizeof(v)) { - memcpy(buf, &v, sizeof(v)); - len -= sizeof(v); - buf += sizeof(v); - v = random_rand(); - } - - memcpy(buf, &v, len); - return 1; -} -#endif /* HAVE_PRNG */ - -#define prng(Buf,Length) contiki_prng_impl((Buf), (Length)) -#define prng_init(Value) random_init((unsigned short)(Value)) -#endif /* WITH_CONTIKI */ - -#ifndef prng -/** - * Fills \p Buf with \p Length bytes of random data. - * - * @hideinitializer - */ -#define prng(Buf,Length) dtls_prng_impl((Buf), (Length)) -#endif - -#ifndef prng_init -/** - * Called to set the PRNG seed. You may want to re-define this to - * allow for a better PRNG. - * - * @hideinitializer - */ -#define prng_init(Value) srand((unsigned long)(Value)) -#endif - -/** @} */ - -#endif /* _DTLS_PRNG_H_ */
--- a/tinydtls/sha2/sha2.c Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1095 +0,0 @@ -/* - * FILE: sha2.c - * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ - * - * Copyright (c) 2000-2001, Aaron D. Gifford - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 AUTHOR OR CONTRIBUTOR(S) 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. - * - * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ - */ - -#include "../config.h" -#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */ -#ifdef HAVE_ASSERT_H -#include <assert.h> /* assert() */ -#endif -#include "sha2.h" - -/* - * ASSERT NOTE: - * Some sanity checking code is included using assert(). On my FreeBSD - * system, this additional code can be removed by compiling with NDEBUG - * defined. Check your own systems manpage on assert() to see how to - * compile WITHOUT the sanity checking code on your system. - * - * UNROLLED TRANSFORM LOOP NOTE: - * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform - * loop version for the hash transform rounds (defined using macros - * later in this file). Either define on the command line, for example: - * - * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c - * - * or define below: - * - * #define SHA2_UNROLL_TRANSFORM - * - */ - - -/*** SHA-256/384/512 Machine Architecture Definitions *****************/ -/* - * BYTE_ORDER NOTE: - * - * Please make sure that your system defines BYTE_ORDER. If your - * architecture is little-endian, make sure it also defines - * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are - * equivilent. - * - * If your system does not define the above, then you can do so by - * hand like this: - * - * #define LITTLE_ENDIAN 1234 - * #define BIG_ENDIAN 4321 - * - * And for little-endian machines, add: - * - * #define BYTE_ORDER LITTLE_ENDIAN - * - * Or for big-endian machines: - * - * #define BYTE_ORDER BIG_ENDIAN - * - * The FreeBSD machine this was written on defines BYTE_ORDER - * appropriately by including <sys/types.h> (which in turn includes - * <machine/endian.h> where the appropriate definitions are actually - * made). - */ - -/* bergmann: define LITTLE_ENDIAN and BIG_ENDIAN to ease autoconf: */ -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#endif -#ifndef BIG_ENDIAN -#define BIG_ENDIAN 4321 -#endif - -#ifndef BYTE_ORDER -# ifdef WORDS_BIGENDIAN -# define BYTE_ORDER BIG_ENDIAN -# else /* WORDS_BIGENDIAN */ -# define BYTE_ORDER LITTLE_ENDIAN -# endif -#endif - -#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) -#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN -#endif - -/* - * Define the followingsha2_* types to types of the correct length on - * the native archtecture. Most BSD systems and Linux define u_intXX_t - * types. Machines with very recent ANSI C headers, can use the - * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H - * during compile or in the sha.h header file. - * - * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t - * will need to define these three typedefs below (and the appropriate - * ones in sha.h too) by hand according to their system architecture. - * - * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t - * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. - */ -#ifdef SHA2_USE_INTTYPES_H - -typedef uint8_t sha2_byte; /* Exactly 1 byte */ -typedef uint32_t sha2_word32; /* Exactly 4 bytes */ -typedef uint64_t sha2_word64; /* Exactly 8 bytes */ - -#else /* SHA2_USE_INTTYPES_H */ - -typedef u_int8_t sha2_byte; /* Exactly 1 byte */ -typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ -typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ - -#endif /* SHA2_USE_INTTYPES_H */ - - -/*** SHA-256/384/512 Various Length Definitions ***********************/ -/* NOTE: Most of these are in sha2.h */ -#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) -#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) -#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) - - -/*** ENDIAN REVERSAL MACROS *******************************************/ -#if BYTE_ORDER == LITTLE_ENDIAN -#define REVERSE32(w,x) { \ - sha2_word32 tmp = (w); \ - tmp = (tmp >> 16) | (tmp << 16); \ - (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ -} -#define REVERSE64(w,x) { \ - sha2_word64 tmp = (w); \ - tmp = (tmp >> 32) | (tmp << 32); \ - tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ - ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ - (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ - ((tmp & 0x0000ffff0000ffffULL) << 16); \ -} -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -/* - * Macro for incrementally adding the unsigned 64-bit integer n to the - * unsigned 128-bit integer (represented using a two-element array of - * 64-bit words): - */ -#define ADDINC128(w,n) { \ - (w)[0] += (sha2_word64)(n); \ - if ((w)[0] < (n)) { \ - (w)[1]++; \ - } \ -} - -/* - * Macros for copying blocks of memory and for zeroing out ranges - * of memory. Using these macros makes it easy to switch from - * using memset()/memcpy() and using bzero()/bcopy(). - * - * Please define either SHA2_USE_MEMSET_MEMCPY or define - * SHA2_USE_BZERO_BCOPY depending on which function set you - * choose to use: - */ -#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) -/* Default to memset()/memcpy() if no option is specified */ -#define SHA2_USE_MEMSET_MEMCPY 1 -#endif -#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) -/* Abort with an error if BOTH options are defined */ -#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! -#endif - -#ifdef SHA2_USE_MEMSET_MEMCPY -#define MEMSET_BZERO(p,l) memset((p), 0, (l)) -#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) -#endif -#ifdef SHA2_USE_BZERO_BCOPY -#define MEMSET_BZERO(p,l) bzero((p), (l)) -#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) -#endif - - -/*** THE SIX LOGICAL FUNCTIONS ****************************************/ -/* - * Bit shifting and rotation (used by the six SHA-XYZ logical functions: - * - * NOTE: The naming of R and S appears backwards here (R is a SHIFT and - * S is a ROTATION) because the SHA-256/384/512 description document - * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this - * same "backwards" definition. - */ -/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ -#define R(b,x) ((x) >> (b)) -/* 32-bit Rotate-right (used in SHA-256): */ -#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) -/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ -#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) - -/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ -#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) -#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) - -/* Four of six logical functions used in SHA-256: */ -#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) -#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) -#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) -#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) - -/* Four of six logical functions used in SHA-384 and SHA-512: */ -#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) -#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) -#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) -#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) - -/*** INTERNAL FUNCTION PROTOTYPES *************************************/ -/* NOTE: These should not be accessed directly from outside this - * library -- they are intended for private internal visibility/use - * only. - */ -void SHA512_Last(SHA512_CTX*); -void SHA256_Transform(SHA256_CTX*, const sha2_word32*); -void SHA512_Transform(SHA512_CTX*, const sha2_word64*); - -#ifdef WITH_SHA256 -/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ -/* Hash constant words K for SHA-256: */ -const static sha2_word32 K256[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, - 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, - 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, - 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, - 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, - 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, - 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, - 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, - 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, - 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, - 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, - 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, - 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; - -/* Initial hash value H for SHA-256: */ -const static sha2_word32 sha256_initial_hash_value[8] = { - 0x6a09e667UL, - 0xbb67ae85UL, - 0x3c6ef372UL, - 0xa54ff53aUL, - 0x510e527fUL, - 0x9b05688cUL, - 0x1f83d9abUL, - 0x5be0cd19UL -}; -#endif - -#if defined(WITH_SHA384) || defined(WITH_SHA512) -/* Hash constant words K for SHA-384 and SHA-512: */ -const static sha2_word64 K512[80] = { - 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, - 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, - 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, - 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, - 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, - 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, - 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, - 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, - 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, - 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, - 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, - 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, - 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, - 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, - 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, - 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, - 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, - 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, - 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, - 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, - 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, - 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, - 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, - 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, - 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL -}; -#endif - -#ifdef WITH_SHA384 -/* Initial hash value H for SHA-384 */ -const static sha2_word64 sha384_initial_hash_value[8] = { - 0xcbbb9d5dc1059ed8ULL, - 0x629a292a367cd507ULL, - 0x9159015a3070dd17ULL, - 0x152fecd8f70e5939ULL, - 0x67332667ffc00b31ULL, - 0x8eb44a8768581511ULL, - 0xdb0c2e0d64f98fa7ULL, - 0x47b5481dbefa4fa4ULL -}; -#endif - -#ifdef WITH_SHA512 -/* Initial hash value H for SHA-512 */ -const static sha2_word64 sha512_initial_hash_value[8] = { - 0x6a09e667f3bcc908ULL, - 0xbb67ae8584caa73bULL, - 0x3c6ef372fe94f82bULL, - 0xa54ff53a5f1d36f1ULL, - 0x510e527fade682d1ULL, - 0x9b05688c2b3e6c1fULL, - 0x1f83d9abfb41bd6bULL, - 0x5be0cd19137e2179ULL -}; -#endif - -/* - * Constant used by SHA256/384/512_End() functions for converting the - * digest to a readable hexadecimal character string: - */ -static const char *sha2_hex_digits = "0123456789abcdef"; - - -/*** SHA-256: *********************************************************/ -#ifdef WITH_SHA256 -void SHA256_Init(SHA256_CTX* context) { - if (context == (SHA256_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); - context->bitcount = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-256 round macros: */ - -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE32(*data++, W256[j]); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + W256[j]; \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + (W256[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND256(a,b,c,d,e,f,g,h) \ - s0 = W256[(j+1)&0x0f]; \ - s0 = sigma0_256(s0); \ - s1 = W256[(j+14)&0x0f]; \ - s1 = sigma1_256(s1); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, *W256; - int j; - - W256 = (sha2_word32*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { - /* Rounds 0 to 15 (unrolled): */ - ROUND256_0_TO_15(a,b,c,d,e,f,g,h); - ROUND256_0_TO_15(h,a,b,c,d,e,f,g); - ROUND256_0_TO_15(g,h,a,b,c,d,e,f); - ROUND256_0_TO_15(f,g,h,a,b,c,d,e); - ROUND256_0_TO_15(e,f,g,h,a,b,c,d); - ROUND256_0_TO_15(d,e,f,g,h,a,b,c); - ROUND256_0_TO_15(c,d,e,f,g,h,a,b); - ROUND256_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds to 64: */ - do { - ROUND256(a,b,c,d,e,f,g,h); - ROUND256(h,a,b,c,d,e,f,g); - ROUND256(g,h,a,b,c,d,e,f); - ROUND256(f,g,h,a,b,c,d,e); - ROUND256(e,f,g,h,a,b,c,d); - ROUND256(d,e,f,g,h,a,b,c); - ROUND256(c,d,e,f,g,h,a,b); - ROUND256(b,c,d,e,f,g,h,a); - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, T2, *W256; - int j; - - W256 = (sha2_word32*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { -#if BYTE_ORDER == LITTLE_ENDIAN - /* Copy data while converting to host byte order */ - REVERSE32(*data++,W256[j]); - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* Apply the SHA-256 compression function to update a..h with copy */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W256[(j+1)&0x0f]; - s0 = sigma0_256(s0); - s1 = W256[(j+14)&0x0f]; - s1 = sigma1_256(s1); - - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); - - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA256_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); - context->bitcount += freespace << 3; - len -= freespace; - data += freespace; - SHA256_Transform(context, (sha2_word32*)context->buffer); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); - context->bitcount += len << 3; - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA256_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - SHA256_Transform(context, (sha2_word32*)data); - context->bitcount += SHA256_BLOCK_LENGTH << 3; - len -= SHA256_BLOCK_LENGTH; - data += SHA256_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - context->bitcount += len << 3; - } - /* Clean up: */ - usedspace = freespace = 0; -} - -void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { - sha2_word32 *d = (sha2_word32*)digest; - unsigned int usedspace; - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount,context->bitcount); -#endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA256_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - } - } else { - /* Set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } - /* Set the bit count: */ - *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; - - /* Final transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); - -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE32(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); -#endif - } - - /* Clean up state data: */ - MEMSET_BZERO(context, sizeof(context)); - usedspace = 0; -} - -char *SHA256_End(SHA256_CTX* context, char buffer[]) { - sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0); - - if (buffer != (char*)0) { - SHA256_Final(digest, context); - - for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(context)); - } - MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); - return buffer; -} - -char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { - SHA256_CTX context; - - SHA256_Init(&context); - SHA256_Update(&context, data, len); - return SHA256_End(&context, digest); -} -#endif - -/*** SHA-512: *********************************************************/ -#ifdef WITH_SHA512 -void SHA512_Init(SHA512_CTX* context) { - if (context == (SHA512_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); - context->bitcount[0] = context->bitcount[1] = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-512 round macros: */ -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE64(*data++, W512[j]); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ - K512[j] + W512[j]; \ - (d) += T1, \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ - j++ - - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ - K512[j] + (W512[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ - -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND512(a,b,c,d,e,f,g,h) \ - s0 = W512[(j+1)&0x0f]; \ - s0 = sigma0_512(s0); \ - s1 = W512[(j+14)&0x0f]; \ - s1 = sigma1_512(s1); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ - (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ - -void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { - sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; - int j; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { - ROUND512_0_TO_15(a,b,c,d,e,f,g,h); - ROUND512_0_TO_15(h,a,b,c,d,e,f,g); - ROUND512_0_TO_15(g,h,a,b,c,d,e,f); - ROUND512_0_TO_15(f,g,h,a,b,c,d,e); - ROUND512_0_TO_15(e,f,g,h,a,b,c,d); - ROUND512_0_TO_15(d,e,f,g,h,a,b,c); - ROUND512_0_TO_15(c,d,e,f,g,h,a,b); - ROUND512_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds up to 79: */ - do { - ROUND512(a,b,c,d,e,f,g,h); - ROUND512(h,a,b,c,d,e,f,g); - ROUND512(g,h,a,b,c,d,e,f); - ROUND512(f,g,h,a,b,c,d,e); - ROUND512(e,f,g,h,a,b,c,d); - ROUND512(d,e,f,g,h,a,b,c); - ROUND512(c,d,e,f,g,h,a,b); - ROUND512(b,c,d,e,f,g,h,a); - } while (j < 80); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { - sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; - int j; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - REVERSE64(*data++, W512[j]); - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* Apply the SHA-512 compression function to update a..h with copy */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W512[(j+1)&0x0f]; - s0 = sigma0_512(s0); - s1 = W512[(j+14)&0x0f]; - s1 = sigma1_512(s1); - - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + - (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 80); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); - - usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA512_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); - ADDINC128(context->bitcount, freespace << 3); - len -= freespace; - data += freespace; - SHA512_Transform(context, (sha2_word64*)context->buffer); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); - ADDINC128(context->bitcount, len << 3); - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA512_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - SHA512_Transform(context, (sha2_word64*)data); - ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); - len -= SHA512_BLOCK_LENGTH; - data += SHA512_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - ADDINC128(context->bitcount, len << 3); - } - /* Clean up: */ - usedspace = freespace = 0; -} - -void SHA512_Last(SHA512_CTX* context) { - unsigned int usedspace; - - usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount[0],context->bitcount[0]); - REVERSE64(context->bitcount[1],context->bitcount[1]); -#endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA512_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - SHA512_Transform(context, (sha2_word64*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); - } - } else { - /* Prepare for final transform: */ - MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } - /* Store the length of input data (in bits): */ - *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; - *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; - - /* Final transform: */ - SHA512_Transform(context, (sha2_word64*)context->buffer); -} - -void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { - sha2_word64 *d = (sha2_word64*)digest; - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - SHA512_Last(context); - - /* Save the hash data for output: */ -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE64(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); -#endif - } - - /* Zero out state data */ - MEMSET_BZERO(context, sizeof(context)); -} - -char *SHA512_End(SHA512_CTX* context, char buffer[]) { - sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0); - - if (buffer != (char*)0) { - SHA512_Final(digest, context); - - for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(context)); - } - MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); - return buffer; -} - -char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { - SHA512_CTX context; - - SHA512_Init(&context); - SHA512_Update(&context, data, len); - return SHA512_End(&context, digest); -} -#endif - -/*** SHA-384: *********************************************************/ -#ifdef WITH_SHA384 -void SHA384_Init(SHA384_CTX* context) { - if (context == (SHA384_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); - context->bitcount[0] = context->bitcount[1] = 0; -} - -void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { - SHA512_Update((SHA512_CTX*)context, data, len); -} - -void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { - sha2_word64 *d = (sha2_word64*)digest; - - /* Sanity check: */ - assert(context != (SHA384_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - SHA512_Last((SHA512_CTX*)context); - - /* Save the hash data for output: */ -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 6; j++) { - REVERSE64(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); -#endif - } - - /* Zero out state data */ - MEMSET_BZERO(context, sizeof(context)); -} - -char *SHA384_End(SHA384_CTX* context, char buffer[]) { - sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA384_CTX*)0); - - if (buffer != (char*)0) { - SHA384_Final(digest, context); - - for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(context)); - } - MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); - return buffer; -} - -char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { - SHA384_CTX context; - - SHA384_Init(&context); - SHA384_Update(&context, data, len); - return SHA384_End(&context, digest); -} -#endif
--- a/tinydtls/sha2/sha2.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - * FILE: sha2.h - * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ - * - * Copyright (c) 2000-2001, Aaron D. Gifford - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 AUTHOR OR CONTRIBUTOR(S) 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. - * - * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ - */ - -#ifndef __SHA2_H__ -#define __SHA2_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#define WITH_SHA256 1 -/* - * Import u_intXX_t size_t type definitions from system headers. You - * may need to change this, or define these things yourself in this - * file. - */ -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#define SHA2_USE_INTTYPES_H - -#ifdef SHA2_USE_INTTYPES_H - -#include <inttypes.h> - -#endif /* SHA2_USE_INTTYPES_H */ - - -/*** SHA-256/384/512 Various Length Definitions ***********************/ -#define SHA256_BLOCK_LENGTH 64 -#define SHA256_DIGEST_LENGTH 32 -#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) -#define SHA384_BLOCK_LENGTH 128 -#define SHA384_DIGEST_LENGTH 48 -#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) -#define SHA512_BLOCK_LENGTH 128 -#define SHA512_DIGEST_LENGTH 64 -#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) - - -/*** SHA-256/384/512 Context Structures *******************************/ -/* NOTE: If your architecture does not define either u_intXX_t types or - * uintXX_t (from inttypes.h), you may need to define things by hand - * for your system: - */ -#if 0 -typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ -typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ -typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ -#endif -/* - * Most BSD systems already define u_intXX_t types, as does Linux. - * Some systems, however, like Compaq's Tru64 Unix instead can use - * uintXX_t types defined by very recent ANSI C standards and included - * in the file: - * - * #include <inttypes.h> - * - * If you choose to use <inttypes.h> then please define: - * - * #define SHA2_USE_INTTYPES_H - * - * Or on the command line during compile: - * - * cc -DSHA2_USE_INTTYPES_H ... - */ -#ifdef SHA2_USE_INTTYPES_H - -typedef struct _SHA256_CTX { - uint32_t state[8]; - uint64_t bitcount; - uint8_t buffer[SHA256_BLOCK_LENGTH]; -} SHA256_CTX; -typedef struct _SHA512_CTX { - uint64_t state[8]; - uint64_t bitcount[2]; - uint8_t buffer[SHA512_BLOCK_LENGTH]; -} SHA512_CTX; - -#else /* SHA2_USE_INTTYPES_H */ - -typedef struct _SHA256_CTX { - u_int32_t state[8]; - u_int64_t bitcount; - u_int8_t buffer[SHA256_BLOCK_LENGTH]; -} SHA256_CTX; -typedef struct _SHA512_CTX { - u_int64_t state[8]; - u_int64_t bitcount[2]; - u_int8_t buffer[SHA512_BLOCK_LENGTH]; -} SHA512_CTX; - -#endif /* SHA2_USE_INTTYPES_H */ - -typedef SHA512_CTX SHA384_CTX; - - -/*** SHA-256/384/512 Function Prototypes ******************************/ -#ifndef NOPROTO -#ifdef SHA2_USE_INTTYPES_H - -#ifdef WITH_SHA256 -void SHA256_Init(SHA256_CTX *); -void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t); -void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); -char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); -char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); -#endif - -#ifdef WITH_SHA384 -void SHA384_Init(SHA384_CTX*); -void SHA384_Update(SHA384_CTX*, const uint8_t*, size_t); -void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); -char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); -char* SHA384_Data(const uint8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); -#endif - -#ifdef WITH_SHA512 -void SHA512_Init(SHA512_CTX*); -void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t); -void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); -char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); -char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); -#endif - -#else /* SHA2_USE_INTTYPES_H */ - -#ifdef WITH_SHA256 -void SHA256_Init(SHA256_CTX *); -void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t); -void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); -char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); -char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); -#endif - -#ifdef WITH_SHA384 -void SHA384_Init(SHA384_CTX*); -void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t); -void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); -char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); -char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); -#endif - -#ifdef WITH_SHA512 -void SHA512_Init(SHA512_CTX*); -void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t); -void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); -char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); -char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); -#endif - -#endif /* SHA2_USE_INTTYPES_H */ - -#else /* NOPROTO */ - -#ifdef WITH_SHA256 -void SHA256_Init(); -void SHA256_Update(); -void SHA256_Final(); -char* SHA256_End(); -char* SHA256_Data(); -#endif - -#ifdef WITH_SHA384 -void SHA384_Init(); -void SHA384_Update(); -void SHA384_Final(); -char* SHA384_End(); -char* SHA384_Data(); -#endif - -#ifdef WITH_SHA512 -void SHA512_Init(); -void SHA512_Update(); -void SHA512_Final(); -char* SHA512_End(); -char* SHA512_Data(); -#endif - -#endif /* NOPROTO */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __SHA2_H__ */ -
--- a/tinydtls/state.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* dtls -- a very basic DTLS implementation - * - * Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * @file state.h - * @brief state information for DTLS FSM - */ - -#ifndef _STATE_H_ -#define _STATE_H_ - -#include "config.h" -#include "global.h" -#include "hmac.h" - -typedef enum { - DTLS_STATE_INIT = 0, DTLS_STATE_SERVERHELLO, DTLS_STATE_KEYEXCHANGE, - DTLS_STATE_WAIT_FINISHED, DTLS_STATE_FINISHED, - /* client states */ - DTLS_STATE_CLIENTHELLO, DTLS_STATE_WAIT_SERVERHELLODONE, - DTLS_STATE_WAIT_SERVERFINISHED, - - DTLS_STATE_CONNECTED, - DTLS_STATE_CLOSING, - DTLS_STATE_CLOSED, -} dtls_state_t; - -typedef struct { - uint24 mseq; /**< handshake message sequence number counter */ - - /** pending config that is updated during handshake */ - /* FIXME: dtls_security_parameters_t pending_config; */ - - /* temporary storage for the final handshake hash */ - dtls_hash_ctx hs_hash; -} dtls_hs_state_t; - -#endif /* _STATE_H_ */
--- a/tinydtls/t_list.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -/* t_list -- tinydtls lists - * - * Copyright (C) 2012 Olaf Bergmann <bergmann@tzi.org> - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * @file t_list.h - * @brief Wrappers for list structures and functions - */ - -#ifndef _DTLS_LIST_H_ -#define _DTLS_LIST_H_ - -#ifndef WITH_CONTIKI -#include "uthash.h" -#include "utlist.h" - -/* We define list structures and utility functions to be compatible - * with Contiki list structures. The Contiki list API is part of the - * Contiki operating system, and therefore the following licensing - * terms apply (taken from contiki/core/lib/list.h): - * - * Copyright (c) 2004, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE 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. - * - * This file is part of the Contiki operating system. - * - * Author: Adam Dunkels <adam@sics.se> - * - * $ Id: list.h,v 1.5 2010/09/13 13:31:00 adamdunkels Exp $ - */ - -typedef void **list_t; -struct list { - struct list *next; -}; - -#define LIST_CONCAT(s1, s2) s1##s2 - -#define LIST_STRUCT(name) \ - void *LIST_CONCAT(name, _list); \ - list_t name - -#define LIST_STRUCT_INIT(struct_ptr, name) { \ - (struct_ptr)->name = &((struct_ptr)->LIST_CONCAT(name,_list)); \ - (struct_ptr)->LIST_CONCAT(name,_list) = NULL; \ - } - -static inline void * -list_head(list_t list) { - return *list; -} - -static inline void -list_remove(list_t list, void *item) { - LL_DELETE(*(struct list **)list, (struct list *)item); -} - -static inline void -list_add(list_t list, void *item) { - list_remove(list, item); - LL_APPEND(*(struct list **)list, (struct list *)item); -} - -static inline void -list_push(list_t list, void *item) { - LL_PREPEND(*(struct list **)list, (struct list *)item); -} - -static inline void * -list_pop(list_t list) { - struct list *l; - l = (struct list*)*list; - if(l) - list_remove(list, l); - - return l; -} - -static inline void -list_insert(list_t list, void *previtem, void *newitem) { - if(previtem == NULL) { - list_push(list, newitem); - } else { - ((struct list *)newitem)->next = ((struct list *)previtem)->next; - ((struct list *)previtem)->next = (struct list *)newitem; - } -} - -static inline void * -list_item_next(void *item) -{ - return item == NULL? NULL: ((struct list *)item)->next; -} - -#else /* WITH_CONTIKI */ -#include "list.h" -#endif /* WITH_CONTIKI */ - -#endif /* _DTLS_LIST_H_ */ -
--- a/tinydtls/uthash.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,972 +0,0 @@ -/* -Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER -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 UTHASH_H -#define UTHASH_H - -#include <string.h> /* memcmp,strlen */ -#include <stddef.h> /* ptrdiff_t */ - -/* These macros use decltype or the earlier __typeof GNU extension. - As decltype is only available in newer compilers (VS2010 or gcc 4.3+ - when compiling c++ source) this code uses whatever method is needed - or, for VS2008 where neither is available, uses casting workarounds. */ -#ifdef _MSC_VER /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ -#define DECLTYPE(x) (decltype(x)) -#else /* VS2008 or older (or VS2010 in C mode) */ -#define NO_DECLTYPE -#define DECLTYPE(x) -#endif -#else /* GNU, Sun and other compilers */ -#define DECLTYPE(x) (__typeof(x)) -#endif - -#ifdef NO_DECLTYPE -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - char **_da_dst = (char**)(&(dst)); \ - *_da_dst = (char*)(src); \ -} while(0) -#else -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - (dst) = DECLTYPE(dst)(src); \ -} while(0) -#endif - -/* a number of the hash function use uint32_t which isn't defined on win32 */ -#ifdef _MSC_VER -typedef unsigned int uint32_t; -#else -#include <inttypes.h> /* uint32_t */ -#endif - -#define UTHASH_VERSION 1.9.3 - -#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ -#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ -#define uthash_free(ptr,sz) free(ptr) /* free fcn */ - -#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ -#define uthash_expand_fyi(tbl) /* can be defined to log expands */ - -/* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ -#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ - -/* calculate the element whose hash handle address is hhe */ -#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) - -#define HASH_FIND(hh,head,keyptr,keylen,out) \ -do { \ - unsigned _hf_bkt,_hf_hashv; \ - out=NULL; \ - if (head) { \ - HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ - if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ - HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ - keyptr,keylen,out); \ - } \ - } \ -} while (0) - -#ifdef HASH_BLOOM -#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) -#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) -#define HASH_BLOOM_MAKE(tbl) \ -do { \ - (tbl)->bloom_nbits = HASH_BLOOM; \ - (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ - if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ - memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ - (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ -} while (0); - -#define HASH_BLOOM_FREE(tbl) \ -do { \ - uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ -} while (0); - -#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) -#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) - -#define HASH_BLOOM_ADD(tbl,hashv) \ - HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) - -#define HASH_BLOOM_TEST(tbl,hashv) \ - HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) - -#else -#define HASH_BLOOM_MAKE(tbl) -#define HASH_BLOOM_FREE(tbl) -#define HASH_BLOOM_ADD(tbl,hashv) -#define HASH_BLOOM_TEST(tbl,hashv) (1) -#endif - -#define HASH_MAKE_TABLE(hh,head) \ -do { \ - (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ - sizeof(UT_hash_table)); \ - if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ - memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ - (head)->hh.tbl->tail = &((head)->hh); \ - (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ - (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ - (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ - (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ - memset((head)->hh.tbl->buckets, 0, \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - HASH_BLOOM_MAKE((head)->hh.tbl); \ - (head)->hh.tbl->signature = HASH_SIGNATURE; \ -} while(0) - -#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ - HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) - -#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ -do { \ - unsigned _ha_bkt; \ - (add)->hh.next = NULL; \ - (add)->hh.key = (char*)keyptr; \ - (add)->hh.keylen = keylen_in; \ - if (!(head)) { \ - head = (add); \ - (head)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh,head); \ - } else { \ - (head)->hh.tbl->tail->next = (add); \ - (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ - (head)->hh.tbl->tail = &((add)->hh); \ - } \ - (head)->hh.tbl->num_items++; \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ - (add)->hh.hashv, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ - HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ - HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ - HASH_FSCK(hh,head); \ -} while(0) - -#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ -do { \ - bkt = ((hashv) & ((num_bkts) - 1)); \ -} while(0) - -/* delete "delptr" from the hash table. - * "the usual" patch-up process for the app-order doubly-linked-list. - * The use of _hd_hh_del below deserves special explanation. - * These used to be expressed using (delptr) but that led to a bug - * if someone used the same symbol for the head and deletee, like - * HASH_DELETE(hh,users,users); - * We want that to work, but by changing the head (users) below - * we were forfeiting our ability to further refer to the deletee (users) - * in the patch-up process. Solution: use scratch space to - * copy the deletee pointer, then the latter references are via that - * scratch pointer rather than through the repointed (users) symbol. - */ -#define HASH_DELETE(hh,head,delptr) \ -do { \ - unsigned _hd_bkt; \ - struct UT_hash_handle *_hd_hh_del; \ - if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - head = NULL; \ - } else { \ - _hd_hh_del = &((delptr)->hh); \ - if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ - (head)->hh.tbl->tail = \ - (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ - (head)->hh.tbl->hho); \ - } \ - if ((delptr)->hh.prev) { \ - ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ - (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ - } else { \ - DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ - } \ - if (_hd_hh_del->next) { \ - ((UT_hash_handle*)((char*)_hd_hh_del->next + \ - (head)->hh.tbl->hho))->prev = \ - _hd_hh_del->prev; \ - } \ - HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ - (head)->hh.tbl->num_items--; \ - } \ - HASH_FSCK(hh,head); \ -} while (0) - - -/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ -#define HASH_FIND_STR(head,findstr,out) \ - HASH_FIND(hh,head,findstr,strlen(findstr),out) -#define HASH_ADD_STR(head,strfield,add) \ - HASH_ADD(hh,head,strfield,strlen(add->strfield),add) -#define HASH_FIND_INT(head,findint,out) \ - HASH_FIND(hh,head,findint,sizeof(int),out) -#define HASH_ADD_INT(head,intfield,add) \ - HASH_ADD(hh,head,intfield,sizeof(int),add) -#define HASH_FIND_PTR(head,findptr,out) \ - HASH_FIND(hh,head,findptr,sizeof(void *),out) -#define HASH_ADD_PTR(head,ptrfield,add) \ - HASH_ADD(hh,head,ptrfield,sizeof(void *),add) -#define HASH_DEL(head,delptr) \ - HASH_DELETE(hh,head,delptr) - -/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. - * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. - */ -#ifdef HASH_DEBUG -#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) -#define HASH_FSCK(hh,head) \ -do { \ - unsigned _bkt_i; \ - unsigned _count, _bkt_count; \ - char *_prev; \ - struct UT_hash_handle *_thh; \ - if (head) { \ - _count = 0; \ - for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ - _bkt_count = 0; \ - _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ - _prev = NULL; \ - while (_thh) { \ - if (_prev != (char*)(_thh->hh_prev)) { \ - HASH_OOPS("invalid hh_prev %p, actual %p\n", \ - _thh->hh_prev, _prev ); \ - } \ - _bkt_count++; \ - _prev = (char*)(_thh); \ - _thh = _thh->hh_next; \ - } \ - _count += _bkt_count; \ - if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ - HASH_OOPS("invalid bucket count %d, actual %d\n", \ - (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ - } \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("invalid hh item count %d, actual %d\n", \ - (head)->hh.tbl->num_items, _count ); \ - } \ - /* traverse hh in app order; check next/prev integrity, count */ \ - _count = 0; \ - _prev = NULL; \ - _thh = &(head)->hh; \ - while (_thh) { \ - _count++; \ - if (_prev !=(char*)(_thh->prev)) { \ - HASH_OOPS("invalid prev %p, actual %p\n", \ - _thh->prev, _prev ); \ - } \ - _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ - _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ - (head)->hh.tbl->hho) : NULL ); \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("invalid app item count %d, actual %d\n", \ - (head)->hh.tbl->num_items, _count ); \ - } \ - } \ -} while (0) -#else -#define HASH_FSCK(hh,head) -#endif - -/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to - * the descriptor to which this macro is defined for tuning the hash function. - * The app can #include <unistd.h> to get the prototype for write(2). */ -#ifdef HASH_EMIT_KEYS -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ -do { \ - unsigned _klen = fieldlen; \ - write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ - write(HASH_EMIT_KEYS, keyptr, fieldlen); \ -} while (0) -#else -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) -#endif - -/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ -#ifdef HASH_FUNCTION -#define HASH_FCN HASH_FUNCTION -#else -#define HASH_FCN HASH_JEN -#endif - -/* The Bernstein hash function, used in Perl prior to v5.6 */ -#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _hb_keylen=keylen; \ - char *_hb_key=(char*)(key); \ - (hashv) = 0; \ - while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ - bkt = (hashv) & (num_bkts-1); \ -} while (0) - - -/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at - * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ -#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _sx_i; \ - char *_hs_key=(char*)(key); \ - hashv = 0; \ - for(_sx_i=0; _sx_i < keylen; _sx_i++) \ - hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ - bkt = hashv & (num_bkts-1); \ -} while (0) - -#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _fn_i; \ - char *_hf_key=(char*)(key); \ - hashv = 2166136261UL; \ - for(_fn_i=0; _fn_i < keylen; _fn_i++) \ - hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ - bkt = hashv & (num_bkts-1); \ -} while(0); - -#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _ho_i; \ - char *_ho_key=(char*)(key); \ - hashv = 0; \ - for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ - hashv += _ho_key[_ho_i]; \ - hashv += (hashv << 10); \ - hashv ^= (hashv >> 6); \ - } \ - hashv += (hashv << 3); \ - hashv ^= (hashv >> 11); \ - hashv += (hashv << 15); \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -#define HASH_JEN_MIX(a,b,c) \ -do { \ - a -= b; a -= c; a ^= ( c >> 13 ); \ - b -= c; b -= a; b ^= ( a << 8 ); \ - c -= a; c -= b; c ^= ( b >> 13 ); \ - a -= b; a -= c; a ^= ( c >> 12 ); \ - b -= c; b -= a; b ^= ( a << 16 ); \ - c -= a; c -= b; c ^= ( b >> 5 ); \ - a -= b; a -= c; a ^= ( c >> 3 ); \ - b -= c; b -= a; b ^= ( a << 10 ); \ - c -= a; c -= b; c ^= ( b >> 15 ); \ -} while (0) - -#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _hj_i,_hj_j,_hj_k; \ - char *_hj_key=(char*)(key); \ - hashv = 0xfeedbeef; \ - _hj_i = _hj_j = 0x9e3779b9; \ - _hj_k = keylen; \ - while (_hj_k >= 12) { \ - _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ - + ( (unsigned)_hj_key[2] << 16 ) \ - + ( (unsigned)_hj_key[3] << 24 ) ); \ - _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ - + ( (unsigned)_hj_key[6] << 16 ) \ - + ( (unsigned)_hj_key[7] << 24 ) ); \ - hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ - + ( (unsigned)_hj_key[10] << 16 ) \ - + ( (unsigned)_hj_key[11] << 24 ) ); \ - \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - \ - _hj_key += 12; \ - _hj_k -= 12; \ - } \ - hashv += keylen; \ - switch ( _hj_k ) { \ - case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ - case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ - case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ - case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ - case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ - case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ - case 5: _hj_j += _hj_key[4]; \ - case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ - case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ - case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ - case 1: _hj_i += _hj_key[0]; \ - } \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -/* The Paul Hsieh hash function */ -#undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) -#endif - -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ - +(uint32_t)(((const uint8_t *)(d))[0]) ) -#endif -#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ -do { \ - char *_sfh_key=(char*)(key); \ - uint32_t _sfh_tmp, _sfh_len = keylen; \ - \ - int _sfh_rem = _sfh_len & 3; \ - _sfh_len >>= 2; \ - hashv = 0xcafebabe; \ - \ - /* Main loop */ \ - for (;_sfh_len > 0; _sfh_len--) { \ - hashv += get16bits (_sfh_key); \ - _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ - hashv = (hashv << 16) ^ _sfh_tmp; \ - _sfh_key += 2*sizeof (uint16_t); \ - hashv += hashv >> 11; \ - } \ - \ - /* Handle end cases */ \ - switch (_sfh_rem) { \ - case 3: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 16; \ - hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ - hashv += hashv >> 11; \ - break; \ - case 2: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 11; \ - hashv += hashv >> 17; \ - break; \ - case 1: hashv += *_sfh_key; \ - hashv ^= hashv << 10; \ - hashv += hashv >> 1; \ - } \ - \ - /* Force "avalanching" of final 127 bits */ \ - hashv ^= hashv << 3; \ - hashv += hashv >> 5; \ - hashv ^= hashv << 4; \ - hashv += hashv >> 17; \ - hashv ^= hashv << 25; \ - hashv += hashv >> 6; \ - bkt = hashv & (num_bkts-1); \ -} while(0); - -#ifdef HASH_USING_NO_STRICT_ALIASING -/* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads. - * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. - * So MurmurHash comes in two versions, the faster unaligned one and the slower - * aligned one. We only use the faster one on CPU's where we know it's safe. - * - * Note the preprocessor built-in defines can be emitted using: - * - * gcc -m64 -dM -E - < /dev/null (on gcc) - * cc -## a.c (where a.c is a simple test file) (Sun Studio) - */ -#if (defined(__i386__) || defined(__x86_64__)) -#define HASH_MUR HASH_MUR_UNALIGNED -#else -#define HASH_MUR HASH_MUR_ALIGNED -#endif - -/* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */ -#define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \ -do { \ - const unsigned int _mur_m = 0x5bd1e995; \ - const int _mur_r = 24; \ - hashv = 0xcafebabe ^ keylen; \ - char *_mur_key = (char *)(key); \ - uint32_t _mur_tmp, _mur_len = keylen; \ - \ - for (;_mur_len >= 4; _mur_len-=4) { \ - _mur_tmp = *(uint32_t *)_mur_key; \ - _mur_tmp *= _mur_m; \ - _mur_tmp ^= _mur_tmp >> _mur_r; \ - _mur_tmp *= _mur_m; \ - hashv *= _mur_m; \ - hashv ^= _mur_tmp; \ - _mur_key += 4; \ - } \ - \ - switch(_mur_len) \ - { \ - case 3: hashv ^= _mur_key[2] << 16; \ - case 2: hashv ^= _mur_key[1] << 8; \ - case 1: hashv ^= _mur_key[0]; \ - hashv *= _mur_m; \ - }; \ - \ - hashv ^= hashv >> 13; \ - hashv *= _mur_m; \ - hashv ^= hashv >> 15; \ - \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -/* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */ -#define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \ -do { \ - const unsigned int _mur_m = 0x5bd1e995; \ - const int _mur_r = 24; \ - hashv = 0xcafebabe ^ (keylen); \ - char *_mur_key = (char *)(key); \ - uint32_t _mur_len = keylen; \ - int _mur_align = (int)_mur_key & 3; \ - \ - if (_mur_align && (_mur_len >= 4)) { \ - unsigned _mur_t = 0, _mur_d = 0; \ - switch(_mur_align) { \ - case 1: _mur_t |= _mur_key[2] << 16; \ - case 2: _mur_t |= _mur_key[1] << 8; \ - case 3: _mur_t |= _mur_key[0]; \ - } \ - _mur_t <<= (8 * _mur_align); \ - _mur_key += 4-_mur_align; \ - _mur_len -= 4-_mur_align; \ - int _mur_sl = 8 * (4-_mur_align); \ - int _mur_sr = 8 * _mur_align; \ - \ - for (;_mur_len >= 4; _mur_len-=4) { \ - _mur_d = *(unsigned *)_mur_key; \ - _mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ - unsigned _mur_k = _mur_t; \ - _mur_k *= _mur_m; \ - _mur_k ^= _mur_k >> _mur_r; \ - _mur_k *= _mur_m; \ - hashv *= _mur_m; \ - hashv ^= _mur_k; \ - _mur_t = _mur_d; \ - _mur_key += 4; \ - } \ - _mur_d = 0; \ - if(_mur_len >= _mur_align) { \ - switch(_mur_align) { \ - case 3: _mur_d |= _mur_key[2] << 16; \ - case 2: _mur_d |= _mur_key[1] << 8; \ - case 1: _mur_d |= _mur_key[0]; \ - } \ - unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ - _mur_k *= _mur_m; \ - _mur_k ^= _mur_k >> _mur_r; \ - _mur_k *= _mur_m; \ - hashv *= _mur_m; \ - hashv ^= _mur_k; \ - _mur_k += _mur_align; \ - _mur_len -= _mur_align; \ - \ - switch(_mur_len) \ - { \ - case 3: hashv ^= _mur_key[2] << 16; \ - case 2: hashv ^= _mur_key[1] << 8; \ - case 1: hashv ^= _mur_key[0]; \ - hashv *= _mur_m; \ - } \ - } else { \ - switch(_mur_len) \ - { \ - case 3: _mur_d ^= _mur_key[2] << 16; \ - case 2: _mur_d ^= _mur_key[1] << 8; \ - case 1: _mur_d ^= _mur_key[0]; \ - case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ - hashv *= _mur_m; \ - } \ - } \ - \ - hashv ^= hashv >> 13; \ - hashv *= _mur_m; \ - hashv ^= hashv >> 15; \ - } else { \ - for (;_mur_len >= 4; _mur_len-=4) { \ - unsigned _mur_k = *(unsigned*)_mur_key; \ - _mur_k *= _mur_m; \ - _mur_k ^= _mur_k >> _mur_r; \ - _mur_k *= _mur_m; \ - hashv *= _mur_m; \ - hashv ^= _mur_k; \ - _mur_key += 4; \ - } \ - switch(_mur_len) \ - { \ - case 3: hashv ^= _mur_key[2] << 16; \ - case 2: hashv ^= _mur_key[1] << 8; \ - case 1: hashv ^= _mur_key[0]; \ - hashv *= _mur_m; \ - } \ - \ - hashv ^= hashv >> 13; \ - hashv *= _mur_m; \ - hashv ^= hashv >> 15; \ - } \ - bkt = hashv & (num_bkts-1); \ -} while(0) -#endif /* HASH_USING_NO_STRICT_ALIASING */ - -/* key comparison function; return 0 if keys equal */ -#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) - -/* iterate over items in a known bucket to find desired item */ -#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ -do { \ - if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ - else out=NULL; \ - while (out) { \ - if (out->hh.keylen == keylen_in) { \ - if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ - } \ - if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ - else out = NULL; \ - } \ -} while(0) - -/* add an item to a bucket */ -#define HASH_ADD_TO_BKT(head,addhh) \ -do { \ - head.count++; \ - (addhh)->hh_next = head.hh_head; \ - (addhh)->hh_prev = NULL; \ - if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ - (head).hh_head=addhh; \ - if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ - && (addhh)->tbl->noexpand != 1) { \ - HASH_EXPAND_BUCKETS((addhh)->tbl); \ - } \ -} while(0) - -/* remove an item from a given bucket */ -#define HASH_DEL_IN_BKT(hh,head,hh_del) \ - (head).count--; \ - if ((head).hh_head == hh_del) { \ - (head).hh_head = hh_del->hh_next; \ - } \ - if (hh_del->hh_prev) { \ - hh_del->hh_prev->hh_next = hh_del->hh_next; \ - } \ - if (hh_del->hh_next) { \ - hh_del->hh_next->hh_prev = hh_del->hh_prev; \ - } - -/* Bucket expansion has the effect of doubling the number of buckets - * and redistributing the items into the new buckets. Ideally the - * items will distribute more or less evenly into the new buckets - * (the extent to which this is true is a measure of the quality of - * the hash function as it applies to the key domain). - * - * With the items distributed into more buckets, the chain length - * (item count) in each bucket is reduced. Thus by expanding buckets - * the hash keeps a bound on the chain length. This bounded chain - * length is the essence of how a hash provides constant time lookup. - * - * The calculation of tbl->ideal_chain_maxlen below deserves some - * explanation. First, keep in mind that we're calculating the ideal - * maximum chain length based on the *new* (doubled) bucket count. - * In fractions this is just n/b (n=number of items,b=new num buckets). - * Since the ideal chain length is an integer, we want to calculate - * ceil(n/b). We don't depend on floating point arithmetic in this - * hash, so to calculate ceil(n/b) with integers we could write - * - * ceil(n/b) = (n/b) + ((n%b)?1:0) - * - * and in fact a previous version of this hash did just that. - * But now we have improved things a bit by recognizing that b is - * always a power of two. We keep its base 2 log handy (call it lb), - * so now we can write this with a bit shift and logical AND: - * - * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) - * - */ -#define HASH_EXPAND_BUCKETS(tbl) \ -do { \ - unsigned _he_bkt; \ - unsigned _he_bkt_i; \ - struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ - UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ - _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ - 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ - memset(_he_new_buckets, 0, \ - 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - tbl->ideal_chain_maxlen = \ - (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ - ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ - tbl->nonideal_items = 0; \ - for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ - { \ - _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ - while (_he_thh) { \ - _he_hh_nxt = _he_thh->hh_next; \ - HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ - _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ - if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ - tbl->nonideal_items++; \ - _he_newbkt->expand_mult = _he_newbkt->count / \ - tbl->ideal_chain_maxlen; \ - } \ - _he_thh->hh_prev = NULL; \ - _he_thh->hh_next = _he_newbkt->hh_head; \ - if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ - _he_thh; \ - _he_newbkt->hh_head = _he_thh; \ - _he_thh = _he_hh_nxt; \ - } \ - } \ - uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ - tbl->num_buckets *= 2; \ - tbl->log2_num_buckets++; \ - tbl->buckets = _he_new_buckets; \ - tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ - (tbl->ineff_expands+1) : 0; \ - if (tbl->ineff_expands > 1) { \ - tbl->noexpand=1; \ - uthash_noexpand_fyi(tbl); \ - } \ - uthash_expand_fyi(tbl); \ -} while(0) - - -/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ -/* Note that HASH_SORT assumes the hash handle name to be hh. - * HASH_SRT was added to allow the hash handle name to be passed in. */ -#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) -#define HASH_SRT(hh,head,cmpfcn) \ -do { \ - unsigned _hs_i; \ - unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ - struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ - if (head) { \ - _hs_insize = 1; \ - _hs_looping = 1; \ - _hs_list = &((head)->hh); \ - while (_hs_looping) { \ - _hs_p = _hs_list; \ - _hs_list = NULL; \ - _hs_tail = NULL; \ - _hs_nmerges = 0; \ - while (_hs_p) { \ - _hs_nmerges++; \ - _hs_q = _hs_p; \ - _hs_psize = 0; \ - for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ - _hs_psize++; \ - _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ - ((void*)((char*)(_hs_q->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - if (! (_hs_q) ) break; \ - } \ - _hs_qsize = _hs_insize; \ - while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ - if (_hs_psize == 0) { \ - _hs_e = _hs_q; \ - _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ - ((void*)((char*)(_hs_q->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - _hs_qsize--; \ - } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ - _hs_e = _hs_p; \ - _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ - ((void*)((char*)(_hs_p->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - _hs_psize--; \ - } else if (( \ - cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ - ) <= 0) { \ - _hs_e = _hs_p; \ - _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ - ((void*)((char*)(_hs_p->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - _hs_psize--; \ - } else { \ - _hs_e = _hs_q; \ - _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ - ((void*)((char*)(_hs_q->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - _hs_qsize--; \ - } \ - if ( _hs_tail ) { \ - _hs_tail->next = ((_hs_e) ? \ - ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ - } else { \ - _hs_list = _hs_e; \ - } \ - _hs_e->prev = ((_hs_tail) ? \ - ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ - _hs_tail = _hs_e; \ - } \ - _hs_p = _hs_q; \ - } \ - _hs_tail->next = NULL; \ - if ( _hs_nmerges <= 1 ) { \ - _hs_looping=0; \ - (head)->hh.tbl->tail = _hs_tail; \ - DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ - } \ - _hs_insize *= 2; \ - } \ - HASH_FSCK(hh,head); \ - } \ -} while (0) - -/* This function selects items from one hash into another hash. - * The end result is that the selected items have dual presence - * in both hashes. There is no copy of the items made; rather - * they are added into the new hash through a secondary hash - * hash handle that must be present in the structure. */ -#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ -do { \ - unsigned _src_bkt, _dst_bkt; \ - void *_last_elt=NULL, *_elt; \ - UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ - ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ - if (src) { \ - for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ - for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ - _src_hh; \ - _src_hh = _src_hh->hh_next) { \ - _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ - if (cond(_elt)) { \ - _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ - _dst_hh->key = _src_hh->key; \ - _dst_hh->keylen = _src_hh->keylen; \ - _dst_hh->hashv = _src_hh->hashv; \ - _dst_hh->prev = _last_elt; \ - _dst_hh->next = NULL; \ - if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ - if (!dst) { \ - DECLTYPE_ASSIGN(dst,_elt); \ - HASH_MAKE_TABLE(hh_dst,dst); \ - } else { \ - _dst_hh->tbl = (dst)->hh_dst.tbl; \ - } \ - HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ - HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ - (dst)->hh_dst.tbl->num_items++; \ - _last_elt = _elt; \ - _last_elt_hh = _dst_hh; \ - } \ - } \ - } \ - } \ - HASH_FSCK(hh_dst,dst); \ -} while (0) - -#define HASH_CLEAR(hh,head) \ -do { \ - if (head) { \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head)=NULL; \ - } \ -} while(0) - -#ifdef NO_DECLTYPE -#define HASH_ITER(hh,head,el,tmp) \ -for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ - el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) -#else -#define HASH_ITER(hh,head,el,tmp) \ -for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ - el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) -#endif - -/* obtain a count of items in the hash */ -#define HASH_COUNT(head) HASH_CNT(hh,head) -#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) - -typedef struct UT_hash_bucket { - struct UT_hash_handle *hh_head; - unsigned count; - - /* expand_mult is normally set to 0. In this situation, the max chain length - * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If - * the bucket's chain exceeds this length, bucket expansion is triggered). - * However, setting expand_mult to a non-zero value delays bucket expansion - * (that would be triggered by additions to this particular bucket) - * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. - * (The multiplier is simply expand_mult+1). The whole idea of this - * multiplier is to reduce bucket expansions, since they are expensive, in - * situations where we know that a particular bucket tends to be overused. - * It is better to let its chain length grow to a longer yet-still-bounded - * value, than to do an O(n) bucket expansion too often. - */ - unsigned expand_mult; - -} UT_hash_bucket; - -/* random signature used only to find hash tables in external analysis */ -#define HASH_SIGNATURE 0xa0111fe1 -#define HASH_BLOOM_SIGNATURE 0xb12220f2 - -typedef struct UT_hash_table { - UT_hash_bucket *buckets; - unsigned num_buckets, log2_num_buckets; - unsigned num_items; - struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ - ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ - - /* in an ideal situation (all buckets used equally), no bucket would have - * more than ceil(#items/#buckets) items. that's the ideal chain length. */ - unsigned ideal_chain_maxlen; - - /* nonideal_items is the number of items in the hash whose chain position - * exceeds the ideal chain maxlen. these items pay the penalty for an uneven - * hash distribution; reaching them in a chain traversal takes >ideal steps */ - unsigned nonideal_items; - - /* ineffective expands occur when a bucket doubling was performed, but - * afterward, more than half the items in the hash had nonideal chain - * positions. If this happens on two consecutive expansions we inhibit any - * further expansion, as it's not helping; this happens when the hash - * function isn't a good fit for the key domain. When expansion is inhibited - * the hash will still work, albeit no longer in constant time. */ - unsigned ineff_expands, noexpand; - - uint32_t signature; /* used only to find hash tables in external analysis */ -#ifdef HASH_BLOOM - uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ - uint8_t *bloom_bv; - char bloom_nbits; -#endif - -} UT_hash_table; - -typedef struct UT_hash_handle { - struct UT_hash_table *tbl; - void *prev; /* prev element in app order */ - void *next; /* next element in app order */ - struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ - struct UT_hash_handle *hh_next; /* next hh in bucket order */ - void *key; /* ptr to enclosing struct's key */ - unsigned keylen; /* enclosing struct's key len */ - unsigned hashv; /* result of hash-fcn(key) */ -} UT_hash_handle; - -#endif /* UTHASH_H */
--- a/tinydtls/utlist.h Wed Oct 09 14:48:52 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,490 +0,0 @@ -/* -Copyright (c) 2007-2010, Troy D. Hanson http://uthash.sourceforge.net -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER -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 UTLIST_H -#define UTLIST_H - -#define UTLIST_VERSION 1.9.1 - -/* - * This file contains macros to manipulate singly and doubly-linked lists. - * - * 1. LL_ macros: singly-linked lists. - * 2. DL_ macros: doubly-linked lists. - * 3. CDL_ macros: circular doubly-linked lists. - * - * To use singly-linked lists, your structure must have a "next" pointer. - * To use doubly-linked lists, your structure must "prev" and "next" pointers. - * Either way, the pointer to the head of the list must be initialized to NULL. - * - * ----------------.EXAMPLE ------------------------- - * struct item { - * int id; - * struct item *prev, *next; - * } - * - * struct item *list = NULL: - * - * int main() { - * struct item *item; - * ... allocate and populate item ... - * DL_APPEND(list, item); - * } - * -------------------------------------------------- - * - * For doubly-linked lists, the append and delete macros are O(1) - * For singly-linked lists, append and delete are O(n) but prepend is O(1) - * The sort macro is O(n log(n)) for all types of single/double/circular lists. - */ - -/* These macros use decltype or the earlier __typeof GNU extension. - As decltype is only available in newer compilers (VS2010 or gcc 4.3+ - when compiling c++ code), this code uses whatever method is needed - or, for VS2008 where neither is available, uses casting workarounds. */ -#ifdef _MSC_VER /* MS compiler */ -#if _MSC_VER >= 1600 && __cplusplus /* VS2010 and newer in C++ mode */ -#define LDECLTYPE(x) decltype(x) -#else /* VS2008 or older (or VS2010 in C mode) */ -#define NO_DECLTYPE -#define LDECLTYPE(x) char* -#endif -#else /* GNU, Sun and other compilers */ -#define LDECLTYPE(x) __typeof(x) -#endif - -/* for VS2008 we use some workarounds to get around the lack of decltype, - * namely, we always reassign our tmp variable to the list head if we need - * to dereference its prev/next pointers, and save/restore the real head.*/ -#ifdef NO_DECLTYPE -#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } -#define _NEXT(elt,list) ((char*)((list)->next)) -#define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } -#define _PREV(elt,list) ((char*)((list)->prev)) -#define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } -#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } -#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } -#else -#define _SV(elt,list) -#define _NEXT(elt,list) ((elt)->next) -#define _NEXTASGN(elt,list,to) ((elt)->next)=(to) -#define _PREV(elt,list) ((elt)->prev) -#define _PREVASGN(elt,list,to) ((elt)->prev)=(to) -#define _RS(list) -#define _CASTASGN(a,b) (a)=(b) -#endif - -/****************************************************************************** - * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * - * Unwieldy variable names used here to avoid shadowing passed-in variables. * - *****************************************************************************/ -#define LL_SORT(list, cmp) \ -do { \ - LDECLTYPE(list) _ls_p; \ - LDECLTYPE(list) _ls_q; \ - LDECLTYPE(list) _ls_e; \ - LDECLTYPE(list) _ls_tail; \ - LDECLTYPE(list) _ls_oldhead; \ - LDECLTYPE(list) _tmp; \ - int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ - if (list) { \ - _ls_insize = 1; \ - _ls_looping = 1; \ - while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - _CASTASGN(_ls_oldhead,list); \ - list = NULL; \ - _ls_tail = NULL; \ - _ls_nmerges = 0; \ - while (_ls_p) { \ - _ls_nmerges++; \ - _ls_q = _ls_p; \ - _ls_psize = 0; \ - for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ - _ls_psize++; \ - _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ - if (!_ls_q) break; \ - } \ - _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ - if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ - } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ - } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ - } else { \ - _CASTASGN(list,_ls_e); \ - } \ - _ls_tail = _ls_e; \ - } \ - _ls_p = _ls_q; \ - } \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ - if (_ls_nmerges <= 1) { \ - _ls_looping=0; \ - } \ - _ls_insize *= 2; \ - } \ - } else _tmp=NULL; /* quiet gcc unused variable warning */ \ -} while (0) - -#define DL_SORT(list, cmp) \ -do { \ - LDECLTYPE(list) _ls_p; \ - LDECLTYPE(list) _ls_q; \ - LDECLTYPE(list) _ls_e; \ - LDECLTYPE(list) _ls_tail; \ - LDECLTYPE(list) _ls_oldhead; \ - LDECLTYPE(list) _tmp; \ - int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ - if (list) { \ - _ls_insize = 1; \ - _ls_looping = 1; \ - while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - _CASTASGN(_ls_oldhead,list); \ - list = NULL; \ - _ls_tail = NULL; \ - _ls_nmerges = 0; \ - while (_ls_p) { \ - _ls_nmerges++; \ - _ls_q = _ls_p; \ - _ls_psize = 0; \ - for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ - _ls_psize++; \ - _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ - if (!_ls_q) break; \ - } \ - _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ - if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ - } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ - } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ - } else { \ - _CASTASGN(list,_ls_e); \ - } \ - _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ - _ls_tail = _ls_e; \ - } \ - _ls_p = _ls_q; \ - } \ - _CASTASGN(list->prev, _ls_tail); \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ - if (_ls_nmerges <= 1) { \ - _ls_looping=0; \ - } \ - _ls_insize *= 2; \ - } \ - } else _tmp=NULL; /* quiet gcc unused variable warning */ \ -} while (0) - -#define CDL_SORT(list, cmp) \ -do { \ - LDECLTYPE(list) _ls_p; \ - LDECLTYPE(list) _ls_q; \ - LDECLTYPE(list) _ls_e; \ - LDECLTYPE(list) _ls_tail; \ - LDECLTYPE(list) _ls_oldhead; \ - LDECLTYPE(list) _tmp; \ - LDECLTYPE(list) _tmp2; \ - int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ - if (list) { \ - _ls_insize = 1; \ - _ls_looping = 1; \ - while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - _CASTASGN(_ls_oldhead,list); \ - list = NULL; \ - _ls_tail = NULL; \ - _ls_nmerges = 0; \ - while (_ls_p) { \ - _ls_nmerges++; \ - _ls_q = _ls_p; \ - _ls_psize = 0; \ - for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ - _ls_psize++; \ - _SV(_ls_q,list); \ - if (_NEXT(_ls_q,list) == _ls_oldhead) { \ - _ls_q = NULL; \ - } else { \ - _ls_q = _NEXT(_ls_q,list); \ - } \ - _RS(list); \ - if (!_ls_q) break; \ - } \ - _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ - if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ - if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ - if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ - } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ - if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ - } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ - if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ - } else { \ - _CASTASGN(list,_ls_e); \ - } \ - _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ - _ls_tail = _ls_e; \ - } \ - _ls_p = _ls_q; \ - } \ - _CASTASGN(list->prev,_ls_tail); \ - _CASTASGN(_tmp2,list); \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list); \ - if (_ls_nmerges <= 1) { \ - _ls_looping=0; \ - } \ - _ls_insize *= 2; \ - } \ - } else _tmp=NULL; /* quiet gcc unused variable warning */ \ -} while (0) - -/****************************************************************************** - * singly linked list macros (non-circular) * - *****************************************************************************/ -#define LL_PREPEND(head,add) \ -do { \ - (add)->next = head; \ - head = add; \ -} while (0) - -#define LL_APPEND(head,add) \ -do { \ - LDECLTYPE(head) _tmp; \ - (add)->next=NULL; \ - if (head) { \ - _tmp = head; \ - while (_tmp->next) { _tmp = _tmp->next; } \ - _tmp->next=(add); \ - } else { \ - (head)=(add); \ - } \ -} while (0) - -#define LL_DELETE(head,del) \ -do { \ - LDECLTYPE(head) _tmp; \ - if ((head) == (del)) { \ - (head)=(head)->next; \ - } else { \ - _tmp = head; \ - while (_tmp->next && (_tmp->next != (del))) { \ - _tmp = _tmp->next; \ - } \ - if (_tmp->next) { \ - _tmp->next = ((del)->next); \ - } \ - } \ -} while (0) - -/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ -#define LL_APPEND_VS2008(head,add) \ -do { \ - if (head) { \ - (add)->next = head; /* use add->next as a temp variable */ \ - while ((add)->next->next) { (add)->next = (add)->next->next; } \ - (add)->next->next=(add); \ - } else { \ - (head)=(add); \ - } \ - (add)->next=NULL; \ -} while (0) - -#define LL_DELETE_VS2008(head,del) \ -do { \ - if ((head) == (del)) { \ - (head)=(head)->next; \ - } else { \ - char *_tmp = (char*)(head); \ - while (head->next && (head->next != (del))) { \ - head = head->next; \ - } \ - if (head->next) { \ - head->next = ((del)->next); \ - } \ - { \ - char **_head_alias = (char**)&(head); \ - *_head_alias = _tmp; \ - } \ - } \ -} while (0) -#ifdef NO_DECLTYPE -#undef LL_APPEND -#define LL_APPEND LL_APPEND_VS2008 -#undef LL_DELETE -#define LL_DELETE LL_DELETE_VS2008 -#endif -/* end VS2008 replacements */ - -#define LL_FOREACH(head,el) \ - for(el=head;el;el=el->next) - -#define LL_FOREACH_SAFE(head,el,tmp) \ - for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) - -#define LL_SEARCH_SCALAR(head,out,field,val) \ -do { \ - LL_FOREACH(head,out) { \ - if ((out)->field == (val)) break; \ - } \ -} while(0) - -#define LL_SEARCH(head,out,elt,cmp) \ -do { \ - LL_FOREACH(head,out) { \ - if ((cmp(out,elt))==0) break; \ - } \ -} while(0) - -/****************************************************************************** - * doubly linked list macros (non-circular) * - *****************************************************************************/ -#define DL_PREPEND(head,add) \ -do { \ - (add)->next = head; \ - if (head) { \ - (add)->prev = (head)->prev; \ - (head)->prev = (add); \ - } else { \ - (add)->prev = (add); \ - } \ - (head) = (add); \ -} while (0) - -#define DL_APPEND(head,add) \ -do { \ - if (head) { \ - (add)->prev = (head)->prev; \ - (head)->prev->next = (add); \ - (head)->prev = (add); \ - (add)->next = NULL; \ - } else { \ - (head)=(add); \ - (head)->prev = (head); \ - (head)->next = NULL; \ - } \ -} while (0); - -#define DL_DELETE(head,del) \ -do { \ - if ((del)->prev == (del)) { \ - (head)=NULL; \ - } else if ((del)==(head)) { \ - (del)->next->prev = (del)->prev; \ - (head) = (del)->next; \ - } else { \ - (del)->prev->next = (del)->next; \ - if ((del)->next) { \ - (del)->next->prev = (del)->prev; \ - } else { \ - (head)->prev = (del)->prev; \ - } \ - } \ -} while (0); - - -#define DL_FOREACH(head,el) \ - for(el=head;el;el=el->next) - -/* this version is safe for deleting the elements during iteration */ -#define DL_FOREACH_SAFE(head,el,tmp) \ - for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) - -/* these are identical to their singly-linked list counterparts */ -#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR -#define DL_SEARCH LL_SEARCH - -/****************************************************************************** - * circular doubly linked list macros * - *****************************************************************************/ -#define CDL_PREPEND(head,add) \ -do { \ - if (head) { \ - (add)->prev = (head)->prev; \ - (add)->next = (head); \ - (head)->prev = (add); \ - (add)->prev->next = (add); \ - } else { \ - (add)->prev = (add); \ - (add)->next = (add); \ - } \ -(head)=(add); \ -} while (0) - -#define CDL_DELETE(head,del) \ -do { \ - if ( ((head)==(del)) && ((head)->next == (head))) { \ - (head) = 0L; \ - } else { \ - (del)->next->prev = (del)->prev; \ - (del)->prev->next = (del)->next; \ - if ((del) == (head)) (head)=(del)->next; \ - } \ -} while (0); - -#define CDL_FOREACH(head,el) \ - for(el=head;el;el=(el->next==head ? 0L : el->next)) - -#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ - for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ - (el) && ((tmp2)=(el)->next, 1); \ - ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) - -#define CDL_SEARCH_SCALAR(head,out,field,val) \ -do { \ - CDL_FOREACH(head,out) { \ - if ((out)->field == (val)) break; \ - } \ -} while(0) - -#define CDL_SEARCH(head,out,elt,cmp) \ -do { \ - CDL_FOREACH(head,out) { \ - if ((cmp(out,elt))==0) break; \ - } \ -} while(0) - -#endif /* UTLIST_H */ -