Test of tinydtls over cellular
Dependencies: VodafoneUSBModem mbed-rtos mbed tinydtls
Revision 0:6ae42a2aff75, committed 2013-10-09
- Comitter:
- ashleymills
- Date:
- Wed Oct 09 14:48:52 2013 +0000
- Child:
- 1:1dd9b8218515
- Commit message:
- Test program for mbed port of tinydtls
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VodafoneUSBModem.lib Wed Oct 09 14:48:52 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/VodafoneUSBModem/#7b311719374d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,16 @@
+#include "mbed.h"
+#include "rtos.h"
+#include "VodafoneUSBModem.h"
+#include "bsd_socket.h"
+#include "dtls.h"
+
+DigitalOut myled(LED1);
+
+int main() {
+ while(1) {
+ myled = 1;
+ wait(0.2);
+ myled = 0;
+ wait(0.2);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Wed Oct 09 14:48:52 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#ee87e782d34f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Oct 09 14:48:52 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/aes/rijndael.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,1277 @@
+/* $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);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/aes/rijndael.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,65 @@
+/* $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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/alert.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,62 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/ccm.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,306 @@
+/* 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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tinydtls/ccm.h Wed Oct 09 14:48:52 2013 +0000 @@ -0,0 +1,70 @@ +/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tinydtls/config.h Wed Oct 09 14:48:52 2013 +0000 @@ -0,0 +1,149 @@ +/* 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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/crypto.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,317 @@
+/* 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;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/crypto.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,298 @@
+/* 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_ */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/debug.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,254 @@
+/* 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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/debug.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,53 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/dtls.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,2495 @@
+/* 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
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/dtls.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,674 @@
+/* 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
+ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/dtls_time.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,92 @@
+/* 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 */
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/dtls_time.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,78 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/global.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,208 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/hmac.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,169 @@
+/* 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/hmac.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,149 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/netq.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,127 @@
+/* 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);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/netq.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,84 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/numeric.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,110 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/peer.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,101 @@
+/* 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;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/peer.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,101 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/prng.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,89 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/sha2/sha2.c Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,1095 @@
+/*
+ * 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/sha2/sha2.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,218 @@
+/*
+ * 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__ */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/state.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,60 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/t_list.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,145 @@
+/* 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_ */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/uthash.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,972 @@
+/*
+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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tinydtls/utlist.h Wed Oct 09 14:48:52 2013 +0000
@@ -0,0 +1,490 @@
+/*
+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 */
+