Ethernet test for tinydtls-0.5.0
Dependencies: EthernetInterface mbed-rtos mbed tinydtls
Fork of tinydtls_test_ethernet by
Revision 0:6ae42a2aff75, committed 2013-10-09
- Comitter:
- ashleymills
- Date:
- Wed Oct 09 14:48:52 2013 +0000
- Child:
- 1:391ec57807fa
- 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 */ +