CyaSSL is an SSL library for devices like mbed.

Dependents:   cyassl-client Sync

Files at this revision

API Documentation at this revision

Comitter:
toddouska
Date:
Sat Feb 05 01:09:17 2011 +0000
Commit message:
Beta Version

Changed in this revision

aes.c Show annotated file Show diff for this revision Revisions of this file
arc4.c Show annotated file Show diff for this revision Revisions of this file
arc4.h Show annotated file Show diff for this revision Revisions of this file
asn.c Show annotated file Show diff for this revision Revisions of this file
asn.h Show annotated file Show diff for this revision Revisions of this file
coding.c Show annotated file Show diff for this revision Revisions of this file
coding.h Show annotated file Show diff for this revision Revisions of this file
ctc_aes.h Show annotated file Show diff for this revision Revisions of this file
ctc_dh.h Show annotated file Show diff for this revision Revisions of this file
ctc_dsa.h Show annotated file Show diff for this revision Revisions of this file
ctc_hmac.h Show annotated file Show diff for this revision Revisions of this file
ctc_md4.h Show annotated file Show diff for this revision Revisions of this file
ctc_md5.h Show annotated file Show diff for this revision Revisions of this file
ctc_ripemd.h Show annotated file Show diff for this revision Revisions of this file
ctc_rsa.h Show annotated file Show diff for this revision Revisions of this file
ctc_sha.h Show annotated file Show diff for this revision Revisions of this file
cyassl_error.h Show annotated file Show diff for this revision Revisions of this file
cyassl_int.c Show annotated file Show diff for this revision Revisions of this file
cyassl_int.h Show annotated file Show diff for this revision Revisions of this file
cyassl_io.c Show annotated file Show diff for this revision Revisions of this file
des3.c Show annotated file Show diff for this revision Revisions of this file
des3.h Show annotated file Show diff for this revision Revisions of this file
error.h Show annotated file Show diff for this revision Revisions of this file
hc128.h Show annotated file Show diff for this revision Revisions of this file
hmac.c Show annotated file Show diff for this revision Revisions of this file
integer.c Show annotated file Show diff for this revision Revisions of this file
integer.h Show annotated file Show diff for this revision Revisions of this file
keys.c Show annotated file Show diff for this revision Revisions of this file
md4.c Show annotated file Show diff for this revision Revisions of this file
md5.c Show annotated file Show diff for this revision Revisions of this file
misc.c Show annotated file Show diff for this revision Revisions of this file
misc.h Show annotated file Show diff for this revision Revisions of this file
mpi_class.h Show annotated file Show diff for this revision Revisions of this file
mpi_superclass.h Show annotated file Show diff for this revision Revisions of this file
os_settings.h Show annotated file Show diff for this revision Revisions of this file
pwdbased.c Show annotated file Show diff for this revision Revisions of this file
pwdbased.h Show annotated file Show diff for this revision Revisions of this file
rabbit.c Show annotated file Show diff for this revision Revisions of this file
rabbit.h Show annotated file Show diff for this revision Revisions of this file
random.c Show annotated file Show diff for this revision Revisions of this file
random.h Show annotated file Show diff for this revision Revisions of this file
rsa.c Show annotated file Show diff for this revision Revisions of this file
sha.c Show annotated file Show diff for this revision Revisions of this file
sha256.c Show annotated file Show diff for this revision Revisions of this file
sha256.h Show annotated file Show diff for this revision Revisions of this file
sha512.h Show annotated file Show diff for this revision Revisions of this file
ssl.c Show annotated file Show diff for this revision Revisions of this file
ssl.h Show annotated file Show diff for this revision Revisions of this file
tfm.h Show annotated file Show diff for this revision Revisions of this file
tls.c Show annotated file Show diff for this revision Revisions of this file
types.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 5045d2638c29 aes.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aes.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,1308 @@
+/* aes.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef NO_AES
+
+#include "ctc_aes.h"
+#ifdef NO_INLINE
+    #include "misc.h"
+#else
+    #include "misc.c"
+#endif
+
+
+static const word32 rcon[] = {
+    0x01000000, 0x02000000, 0x04000000, 0x08000000,
+    0x10000000, 0x20000000, 0x40000000, 0x80000000,
+    0x1B000000, 0x36000000, 
+    /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+
+static const word32 Te[5][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,
+},
+{
+    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,
+},
+{
+    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,
+},
+{
+    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,
+},
+{
+    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 word32 Td[5][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,
+},
+{
+    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,
+},
+{
+    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,
+},
+{
+    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,
+},
+{
+    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,
+}
+};
+
+
+
+#define GETBYTE(x, y) (word32)((byte)((x) >> (8 * (y))))
+
+
+#ifdef CYASSL_AESNI
+
+#define cpuid(func,ax,bx,cx,dx)\
+        __asm__ __volatile__ ("cpuid":\
+                       "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
+
+static int Check_CPU_support_AES()
+{
+    unsigned int a,b,c,d;
+    cpuid(1,a,b,c,d);
+
+    if (c & 0x2000000)
+        return 1;
+
+    return 0;
+}
+
+static int checkAESNI = 0;
+static int haveAESNI  = 0;
+
+
+void AES_CBC_encrypt(const unsigned char* in, unsigned char* out,
+                     unsigned char* ivec, unsigned long length,
+                     const unsigned char* KS, int nr);
+
+
+void AES_CBC_decrypt(const unsigned char* in, unsigned char* out,
+                     unsigned char* ivec, unsigned long length,
+                     const unsigned char* KS, int nr);
+
+void AES_128_Key_Expansion(const unsigned char* userkey, 
+                           unsigned char* key_schedule);
+
+void AES_192_Key_Expansion(const unsigned char* userkey, 
+                           unsigned char* key_schedule);
+
+void AES_256_Key_Expansion(const unsigned char* userkey, 
+                           unsigned char* key_schedule);
+
+
+int AES_set_encrypt_key (const unsigned char *userKey, const int bits,
+                         Aes* aes)
+{ 
+    if (!userKey || !aes)
+        return -1;
+    
+    if (bits == 128) {
+       AES_128_Key_Expansion (userKey,(byte*)aes->key); aes->rounds = 10;
+       return 0;
+    }
+    else if (bits == 192) {
+       AES_192_Key_Expansion (userKey,(byte*)aes->key); aes->rounds = 12;
+       return 0;
+    }
+    else if (bits == 256) {
+       AES_256_Key_Expansion (userKey,(byte*)aes->key); aes->rounds = 14;
+       return 0;
+    }
+    return -1;
+}
+
+
+int AES_set_decrypt_key (const unsigned char* userKey, const int bits,
+                         Aes* aes)
+{
+    int nr;
+    Aes temp_key;
+    __m128i *Key_Schedule = (__m128i*)aes->key;
+    __m128i *Temp_Key_Schedule = (__m128i*)temp_key.key;
+    
+    if (!userKey || !aes)
+        return -1;
+
+    if (AES_set_encrypt_key(userKey,bits,&temp_key) == -1)
+        return -1;
+
+    nr = temp_key.rounds;
+    aes->rounds = nr;
+
+    Key_Schedule[nr] = Temp_Key_Schedule[0];
+    Key_Schedule[nr-1] = _mm_aesimc_si128(Temp_Key_Schedule[1]);
+    Key_Schedule[nr-2] = _mm_aesimc_si128(Temp_Key_Schedule[2]);
+    Key_Schedule[nr-3] = _mm_aesimc_si128(Temp_Key_Schedule[3]);
+    Key_Schedule[nr-4] = _mm_aesimc_si128(Temp_Key_Schedule[4]);
+    Key_Schedule[nr-5] = _mm_aesimc_si128(Temp_Key_Schedule[5]);
+    Key_Schedule[nr-6] = _mm_aesimc_si128(Temp_Key_Schedule[6]);
+    Key_Schedule[nr-7] = _mm_aesimc_si128(Temp_Key_Schedule[7]);
+    Key_Schedule[nr-8] = _mm_aesimc_si128(Temp_Key_Schedule[8]);
+    Key_Schedule[nr-9] = _mm_aesimc_si128(Temp_Key_Schedule[9]);
+    
+    if(nr>10) {
+        Key_Schedule[nr-10] = _mm_aesimc_si128(Temp_Key_Schedule[10]);
+        Key_Schedule[nr-11] = _mm_aesimc_si128(Temp_Key_Schedule[11]);
+    }
+
+    if(nr>12) {
+        Key_Schedule[nr-12] = _mm_aesimc_si128(Temp_Key_Schedule[12]);
+        Key_Schedule[nr-13] = _mm_aesimc_si128(Temp_Key_Schedule[13]);
+    }
+
+    Key_Schedule[0] = Temp_Key_Schedule[nr];
+    
+    return 0;
+}
+
+
+
+#endif /* CYASSL_AESNI */
+
+
+int AesSetKey(Aes* aes, const byte* userKey, word32 keylen, const byte* iv,
+               int dir)
+{
+    word32 temp, *rk = aes->key;
+    unsigned int i = 0;
+
+    if (!((keylen == 16) || (keylen == 24) || (keylen == 32)))
+        return -1;
+
+#ifdef CYASSL_AESNI
+    if (checkAESNI == 0) {
+        haveAESNI  = Check_CPU_support_AES();
+        checkAESNI = 1;
+    }
+    if (haveAESNI) {
+        XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE);
+        if (dir == AES_ENCRYPTION)
+            return AES_set_encrypt_key(userKey, keylen * 8, aes);
+        else
+            return AES_set_decrypt_key(userKey, keylen * 8, aes);
+    }
+#endif /* CYASSL_AESNI */
+
+    aes->rounds = keylen/4 + 6;
+
+    XMEMCPY(rk, userKey, keylen);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(rk, rk, keylen);
+    #endif
+
+    switch(keylen)
+    {
+    case 16:
+        while (1)
+        {
+            temp  = rk[3];
+            rk[4] = rk[0] ^
+                (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^
+                (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^
+                (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^
+                (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^
+                rcon[i];
+            rk[5] = rk[1] ^ rk[4];
+            rk[6] = rk[2] ^ rk[5];
+            rk[7] = rk[3] ^ rk[6];
+            if (++i == 10)
+                break;
+            rk += 4;
+        }
+        break;
+
+    case 24:
+        while (1)  /* for (;;) here triggers a bug in VC60 SP4 w/ Pro Pack */
+        {
+            temp = rk[ 5];
+            rk[ 6] = rk[ 0] ^
+                (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^
+                (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^
+                (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^
+                (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^
+                rcon[i];
+            rk[ 7] = rk[ 1] ^ rk[ 6];
+            rk[ 8] = rk[ 2] ^ rk[ 7];
+            rk[ 9] = rk[ 3] ^ rk[ 8];
+            if (++i == 8)
+                break;
+            rk[10] = rk[ 4] ^ rk[ 9];
+            rk[11] = rk[ 5] ^ rk[10];
+            rk += 6;
+        }
+        break;
+
+    case 32:
+        while (1)
+        {
+            temp = rk[ 7];
+            rk[ 8] = rk[ 0] ^
+                (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^
+                (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^
+                (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^
+                (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^
+                rcon[i];
+            rk[ 9] = rk[ 1] ^ rk[ 8];
+            rk[10] = rk[ 2] ^ rk[ 9];
+            rk[11] = rk[ 3] ^ rk[10];
+            if (++i == 7)
+                break;
+            temp = rk[11];
+            rk[12] = rk[ 4] ^
+                (Te[4][GETBYTE(temp, 3)] & 0xff000000) ^
+                (Te[4][GETBYTE(temp, 2)] & 0x00ff0000) ^
+                (Te[4][GETBYTE(temp, 1)] & 0x0000ff00) ^
+                (Te[4][GETBYTE(temp, 0)] & 0x000000ff);
+            rk[13] = rk[ 5] ^ rk[12];
+            rk[14] = rk[ 6] ^ rk[13];
+            rk[15] = rk[ 7] ^ rk[14];
+
+            rk += 8;
+        }
+        break;
+    }
+
+    if (dir == AES_DECRYPTION)
+    {
+        unsigned int i, j;
+        rk = aes->key;
+
+        /* invert the order of the round keys: */
+        for (i = 0, j = 4* aes->rounds; i < j; i += 4, j -= 4) {
+            temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+            temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+            temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+            temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+        }
+        /* apply the inverse MixColumn transform to all round keys but the
+           first and the last: */
+        for (i = 1; i < aes->rounds; i++) {
+            rk += 4;
+            rk[0] =
+                Td[0][Te[4][GETBYTE(rk[0], 3)] & 0xff] ^
+                Td[1][Te[4][GETBYTE(rk[0], 2)] & 0xff] ^
+                Td[2][Te[4][GETBYTE(rk[0], 1)] & 0xff] ^
+                Td[3][Te[4][GETBYTE(rk[0], 0)] & 0xff];
+            rk[1] =
+                Td[0][Te[4][GETBYTE(rk[1], 3)] & 0xff] ^
+                Td[1][Te[4][GETBYTE(rk[1], 2)] & 0xff] ^
+                Td[2][Te[4][GETBYTE(rk[1], 1)] & 0xff] ^
+                Td[3][Te[4][GETBYTE(rk[1], 0)] & 0xff];
+            rk[2] =
+                Td[0][Te[4][GETBYTE(rk[2], 3)] & 0xff] ^
+                Td[1][Te[4][GETBYTE(rk[2], 2)] & 0xff] ^
+                Td[2][Te[4][GETBYTE(rk[2], 1)] & 0xff] ^
+                Td[3][Te[4][GETBYTE(rk[2], 0)] & 0xff];
+            rk[3] =
+                Td[0][Te[4][GETBYTE(rk[3], 3)] & 0xff] ^
+                Td[1][Te[4][GETBYTE(rk[3], 2)] & 0xff] ^
+                Td[2][Te[4][GETBYTE(rk[3], 1)] & 0xff] ^
+                Td[3][Te[4][GETBYTE(rk[3], 0)] & 0xff];
+        }
+    }
+    XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE);
+
+    return 0;
+}
+
+
+void AesEncrypt(Aes* aes, const byte* inBlock, byte* outBlock)
+{
+    word32 s0, s1, s2, s3;
+    word32 t0, t1, t2, t3;
+    word32 r = aes->rounds >> 1;
+
+    const word32* rk = aes->key;
+    /*
+     * map byte array block to cipher state
+     * and add initial round key:
+     */
+    XMEMCPY(&s0, inBlock,                  sizeof(s0));
+    XMEMCPY(&s1, inBlock + sizeof(s0),     sizeof(s1));
+    XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2));
+    XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3));
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    s0 ^= rk[0];
+    s1 ^= rk[1];
+    s2 ^= rk[2];
+    s3 ^= rk[3];
+   
+    /*
+     * Nr - 1 full rounds:
+     */
+
+    for (;;) {
+        t0 =
+            Te[0][GETBYTE(s0, 3)]  ^
+            Te[1][GETBYTE(s1, 2)]  ^
+            Te[2][GETBYTE(s2, 1)]  ^
+            Te[3][GETBYTE(s3, 0)]  ^
+            rk[4];
+        t1 =
+            Te[0][GETBYTE(s1, 3)]  ^
+            Te[1][GETBYTE(s2, 2)]  ^
+            Te[2][GETBYTE(s3, 1)]  ^
+            Te[3][GETBYTE(s0, 0)]  ^
+            rk[5];
+        t2 =
+            Te[0][GETBYTE(s2, 3)] ^
+            Te[1][GETBYTE(s3, 2)]  ^
+            Te[2][GETBYTE(s0, 1)]  ^
+            Te[3][GETBYTE(s1, 0)]  ^
+            rk[6];
+        t3 =
+            Te[0][GETBYTE(s3, 3)] ^
+            Te[1][GETBYTE(s0, 2)]  ^
+            Te[2][GETBYTE(s1, 1)]  ^
+            Te[3][GETBYTE(s2, 0)]  ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+        
+        s0 =
+            Te[0][GETBYTE(t0, 3)] ^
+            Te[1][GETBYTE(t1, 2)] ^
+            Te[2][GETBYTE(t2, 1)] ^
+            Te[3][GETBYTE(t3, 0)] ^
+            rk[0];
+        s1 =
+            Te[0][GETBYTE(t1, 3)] ^
+            Te[1][GETBYTE(t2, 2)] ^
+            Te[2][GETBYTE(t3, 1)] ^
+            Te[3][GETBYTE(t0, 0)] ^
+            rk[1];
+        s2 =
+            Te[0][GETBYTE(t2, 3)] ^
+            Te[1][GETBYTE(t3, 2)] ^
+            Te[2][GETBYTE(t0, 1)] ^
+            Te[3][GETBYTE(t1, 0)] ^
+            rk[2];
+        s3 =
+            Te[0][GETBYTE(t3, 3)] ^
+            Te[1][GETBYTE(t0, 2)] ^
+            Te[2][GETBYTE(t1, 1)] ^
+            Te[3][GETBYTE(t2, 0)] ^
+            rk[3];
+    }
+
+    /*
+     * apply last round and
+     * map cipher state to byte array block:
+     */
+
+    s0 =
+        (Te[4][GETBYTE(t0, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t1, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t2, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t3, 0)] & 0x000000ff) ^
+        rk[0];
+    s1 =
+        (Te[4][GETBYTE(t1, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t2, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t3, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t0, 0)] & 0x000000ff) ^
+        rk[1];
+    s2 =
+        (Te[4][GETBYTE(t2, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t3, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t0, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t1, 0)] & 0x000000ff) ^
+        rk[2];
+    s3 =
+        (Te[4][GETBYTE(t3, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t0, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t1, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t2, 0)] & 0x000000ff) ^
+        rk[3];
+
+    /* write out */
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    XMEMCPY(outBlock,                  &s0, sizeof(s0));
+    XMEMCPY(outBlock + sizeof(s0),     &s1, sizeof(s1));
+    XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2));
+    XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3));
+}
+
+
+void AesDecrypt(Aes* aes, const byte* inBlock, byte* outBlock)
+{
+    word32 s0, s1, s2, s3;
+    word32 t0, t1, t2, t3;
+    word32 r = aes->rounds >> 1;
+
+    const word32* rk = aes->key;
+    /*
+     * map byte array block to cipher state
+     * and add initial round key:
+     */
+    XMEMCPY(&s0, inBlock,                  sizeof(s0));
+    XMEMCPY(&s1, inBlock + sizeof(s0),     sizeof(s1));
+    XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2));
+    XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3));
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    s0 ^= rk[0];
+    s1 ^= rk[1];
+    s2 ^= rk[2];
+    s3 ^= rk[3];
+   
+    /*
+     * Nr - 1 full rounds:
+     */
+
+    for (;;) {
+        t0 =
+            Td[0][GETBYTE(s0, 3)] ^
+            Td[1][GETBYTE(s3, 2)] ^
+            Td[2][GETBYTE(s2, 1)] ^
+            Td[3][GETBYTE(s1, 0)] ^
+            rk[4];
+        t1 =
+            Td[0][GETBYTE(s1, 3)] ^
+            Td[1][GETBYTE(s0, 2)] ^
+            Td[2][GETBYTE(s3, 1)] ^
+            Td[3][GETBYTE(s2, 0)] ^
+            rk[5];
+        t2 =
+            Td[0][GETBYTE(s2, 3)] ^
+            Td[1][GETBYTE(s1, 2)] ^
+            Td[2][GETBYTE(s0, 1)] ^
+            Td[3][GETBYTE(s3, 0)] ^
+            rk[6];
+        t3 =
+            Td[0][GETBYTE(s3, 3)] ^
+            Td[1][GETBYTE(s2, 2)] ^
+            Td[2][GETBYTE(s1, 1)] ^
+            Td[3][GETBYTE(s0, 0)] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Td[0][GETBYTE(t0, 3)] ^
+            Td[1][GETBYTE(t3, 2)] ^
+            Td[2][GETBYTE(t2, 1)] ^
+            Td[3][GETBYTE(t1, 0)] ^
+            rk[0];
+        s1 =
+            Td[0][GETBYTE(t1, 3)] ^
+            Td[1][GETBYTE(t0, 2)] ^
+            Td[2][GETBYTE(t3, 1)] ^
+            Td[3][GETBYTE(t2, 0)] ^
+            rk[1];
+        s2 =
+            Td[0][GETBYTE(t2, 3)] ^
+            Td[1][GETBYTE(t1, 2)] ^
+            Td[2][GETBYTE(t0, 1)] ^
+            Td[3][GETBYTE(t3, 0)] ^
+            rk[2];
+        s3 =
+            Td[0][GETBYTE(t3, 3)] ^
+            Td[1][GETBYTE(t2, 2)] ^
+            Td[2][GETBYTE(t1, 1)] ^
+            Td[3][GETBYTE(t0, 0)] ^
+            rk[3];
+    }
+    /*
+     * apply last round and
+     * map cipher state to byte array block:
+     */
+    s0 =
+        (Td[4][GETBYTE(t0, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t3, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t2, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t1, 0)] & 0x000000ff) ^
+        rk[0];
+    s1 =
+        (Td[4][GETBYTE(t1, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t0, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t3, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t2, 0)] & 0x000000ff) ^
+        rk[1];
+    s2 =
+        (Td[4][GETBYTE(t2, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t1, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t0, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t3, 0)] & 0x000000ff) ^
+        rk[2];
+    s3 =
+        (Td[4][GETBYTE(t3, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t2, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t1, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t0, 0)] & 0x000000ff) ^
+        rk[3];
+
+    /* write out */
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    XMEMCPY(outBlock,                  &s0, sizeof(s0));
+    XMEMCPY(outBlock + sizeof(s0),     &s1, sizeof(s1));
+    XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2));
+    XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3));
+}
+
+
+void AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / AES_BLOCK_SIZE;
+
+#ifdef CYASSL_AESNI
+    if (haveAESNI) {
+        #ifdef DEBUG_AESNI
+            printf("about to aes cbc encrypt\n");
+            printf("in  = %p\n", in);
+            printf("out = %p\n", out);
+            printf("aes->key = %p\n", aes->key);
+            printf("aes->reg = %p\n", aes->reg);
+            printf("aes->rounds = %d\n", aes->rounds);
+            printf("sz = %d\n", sz);
+        #endif
+        AES_CBC_encrypt(in, out, (byte*)aes->reg, sz, (byte*)aes->key,
+                        aes->rounds);
+        /* store iv for next call */
+        XMEMCPY(aes->reg, out + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+        return;
+    }
+#endif
+
+    while (blocks--) {
+        xorbuf((byte*)aes->reg, in, AES_BLOCK_SIZE);
+        AesEncrypt(aes, (byte*)aes->reg, (byte*)aes->reg);
+        XMEMCPY(out, aes->reg, AES_BLOCK_SIZE);
+
+        out += AES_BLOCK_SIZE;
+        in  += AES_BLOCK_SIZE; 
+    }
+}
+
+
+void AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / AES_BLOCK_SIZE;
+
+#ifdef CYASSL_AESNI
+    if (haveAESNI) {
+        #ifdef DEBUG_AESNI
+            printf("about to aes cbc decrypt\n");
+            printf("in  = %p\n", in);
+            printf("out = %p\n", out);
+            printf("aes->key = %p\n", aes->key);
+            printf("aes->reg = %p\n", aes->reg);
+            printf("aes->rounds = %d\n", aes->rounds);
+            printf("sz = %d\n", sz);
+        #endif
+
+        /* if input and output same will overwirte input iv */
+        XMEMCPY(aes->tmp, in + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+        AES_CBC_decrypt(in, out, (byte*)aes->reg, sz, (byte*)aes->key,
+                        aes->rounds);
+        /* store iv for next call */
+        XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE);
+        return;
+    }
+#endif
+
+    while (blocks--) {
+        XMEMCPY(aes->tmp, in, AES_BLOCK_SIZE);
+        AesDecrypt(aes, (byte*)aes->tmp, out);
+        xorbuf(out, (byte*)aes->reg, AES_BLOCK_SIZE);
+        XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE);
+
+        out += AES_BLOCK_SIZE;
+        in  += AES_BLOCK_SIZE; 
+    }
+}
+
+
+#endif /* NO_AES */
+
diff -r 000000000000 -r 5045d2638c29 arc4.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arc4.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,76 @@
+/* arc4.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include "arc4.h"
+
+
+
+void Arc4SetKey(Arc4* arc4, const byte* key, word32 length)
+{
+    word32 i;
+    word32 keyIndex = 0, stateIndex = 0;
+
+    arc4->x = 1;
+    arc4->y = 0;
+
+    for (i = 0; i < ARC4_STATE_SIZE; i++)
+        arc4->state[i] = i;
+
+    for (i = 0; i < ARC4_STATE_SIZE; i++) {
+        word32 a = arc4->state[i];
+        stateIndex += key[keyIndex] + a;
+        stateIndex &= 0xFF;
+        arc4->state[i] = arc4->state[stateIndex];
+        arc4->state[stateIndex] = a;
+
+        if (++keyIndex >= length)
+            keyIndex = 0;
+    }
+}
+
+
+static INLINE word32 MakeByte(word32* x, word32* y, byte* s)
+{
+    word32 a = s[*x], b;
+    *y = (*y+a) & 0xff;
+
+    b = s[*y];
+    s[*x] = b;
+    s[*y] = a;
+    *x = (*x+1) & 0xff;
+
+    return s[(a+b) & 0xff];
+}
+
+
+void Arc4Process(Arc4* arc4, byte* out, const byte* in, word32 length)
+{
+    word32 x = arc4->x;
+    word32 y = arc4->y;
+
+    while(length--)
+        *out++ = *in++ ^ MakeByte(&x, &y, arc4->state);
+
+    arc4->x = x;
+    arc4->y = y;
+}
+
diff -r 000000000000 -r 5045d2638c29 arc4.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arc4.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,56 @@
+/* arc4.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_ARC4_H
+#define CTAO_CRYPT_ARC4_H
+
+
+#include "types.h"
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum {
+    ARC4_STATE_SIZE = 256
+};
+
+/* ARC4 encryption and decryption */
+typedef struct Arc4 {
+    byte x;
+    byte y;
+    byte state[ARC4_STATE_SIZE];
+} Arc4;
+
+void Arc4Process(Arc4*, byte*, const byte*, word32);
+void Arc4SetKey(Arc4*, const byte*, word32);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_ARC4_H */
+
diff -r 000000000000 -r 5045d2638c29 asn.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/asn.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,2648 @@
+/* asn.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef THREADX
+    #include "os.h"           /* dc_rtc_api needs    */
+    #include "dc_rtc_api.h"   /* to get current time */
+#endif
+#include "asn.h"
+#include "coding.h"
+#include "ctc_sha.h"
+#include "ctc_md5.h"
+#include "error.h"
+
+#ifdef HAVE_NTRU
+    #include "crypto_ntru.h"
+#endif
+
+
+#ifdef _MSC_VER
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */
+    #pragma warning(disable: 4996)
+#endif
+
+
+#ifndef TRUE
+enum {
+    FALSE = 0,
+    TRUE  = 1
+};
+#endif
+
+enum {
+    ISSUER  = 0,
+    SUBJECT = 1,
+
+    BEFORE  = 0,
+    AFTER   = 1
+};
+
+
+#ifdef THREADX
+    /* uses parital <time.h> structures */
+    #define XTIME(tl)  (0)
+    #define XGMTIME(c) my_gmtime((c))
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+#elif defined(MICRIUM)
+    #include <clk.h>
+    #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+        #define XVALIDATE_DATE(d, f, t) NetSecure_ValidDate((d), (f), (t))
+    #else
+        #define XVALIDATE_DATE(d, f, t) (0)
+    #endif
+    #define NO_TIME_H
+    /* since Micrium not defining XTIME or XGMTIME, CERT_GEN not available */
+#elif defined(USER_TIME)
+    /* no <time.h> strucutres used */
+    #define NO_TIME_H
+    /* user time, and gmtime compatible functions, there is a gmtime 
+       implementation here that WINCE uses, so really just need some ticks
+       since the EPOCH 
+    */
+#else
+    /* default */
+    /* uses complete <time.h> facility */
+    #include <time.h> 
+    #define XTIME(tl)  time((tl))
+    #define XGMTIME(c) gmtime((c))
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+#endif
+
+
+#ifdef _WIN32_WCE
+/* no time() or gmtime() even though in time.h header?? */
+
+#include <windows.h>
+
+
+time_t time(time_t* timer)
+{
+    SYSTEMTIME     sysTime;
+    FILETIME       fTime;
+    ULARGE_INTEGER intTime;
+    time_t         localTime;
+
+    if (timer == NULL)
+        timer = &localTime;
+
+    GetSystemTime(&sysTime);
+    SystemTimeToFileTime(&sysTime, &fTime);
+    
+    XMEMCPY(&intTime, &fTime, sizeof(FILETIME));
+    /* subtract EPOCH */
+    intTime.QuadPart -= 0x19db1ded53e8000;
+    /* to secs */
+    intTime.QuadPart /= 10000000;
+    *timer = (time_t)intTime.QuadPart;
+
+    return *timer;
+}
+
+
+
+struct tm* gmtime(const time_t* timer)
+{
+    #define YEAR0          1900
+    #define EPOCH_YEAR     1970
+    #define SECS_DAY       (24L * 60L * 60L)
+    #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) %400)))
+    #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
+
+    static const int _ytab[2][12] =
+    {
+        {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+        {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+    };
+
+    static struct tm st_time;
+    struct tm* ret = &st_time;
+    time_t time = *timer;
+    unsigned long dayclock, dayno;
+    int year = EPOCH_YEAR;
+
+    dayclock = (unsigned long)time % SECS_DAY;
+    dayno    = (unsigned long)time / SECS_DAY;
+
+    ret->tm_sec  =  dayclock % 60;
+    ret->tm_min  = (dayclock % 3600) / 60;
+    ret->tm_hour =  dayclock / 3600;
+    ret->tm_wday = (dayno + 4) % 7;        /* day 0 a Thursday */
+
+    while(dayno >= (unsigned long)YEARSIZE(year)) {
+        dayno -= YEARSIZE(year);
+        year++;
+    }
+
+    ret->tm_year = year - YEAR0;
+    ret->tm_yday = dayno;
+    ret->tm_mon  = 0;
+
+    while(dayno >= (unsigned long)_ytab[LEAPYEAR(year)][ret->tm_mon]) {
+        dayno -= _ytab[LEAPYEAR(year)][ret->tm_mon];
+        ret->tm_mon++;
+    }
+
+    ret->tm_mday  = ++dayno;
+    ret->tm_isdst = 0;
+
+    return ret;
+}
+
+#endif /* _WIN32_WCE */
+
+
+
+#ifdef  THREADX
+
+#define YEAR0          1900
+
+struct tm* my_gmtime(const time_t* timer)       /* has a gmtime() but hangs */
+{
+    static struct tm st_time;
+    struct tm* ret = &st_time;
+
+    DC_RTC_CALENDAR cal;
+    dc_rtc_time_get(&cal, TRUE);
+
+    ret->tm_year  = cal.year - YEAR0;       /* gm starts at 1900 */
+    ret->tm_mon   = cal.month - 1;          /* gm starts at 0 */
+    ret->tm_mday  = cal.day;
+    ret->tm_hour  = cal.hour;
+    ret->tm_min   = cal.minute;
+    ret->tm_sec   = cal.second;
+
+    return ret;
+}
+
+#endif /* THREADX */
+
+
+static INLINE word32 btoi(byte b)
+{
+    return b - 0x30;
+}
+
+
+/* two byte date/time, add to value */
+static INLINE void GetTime(int* value, const byte* date, int* idx)
+{
+    int i = *idx;
+
+    *value += btoi(date[i++]) * 10;
+    *value += btoi(date[i++]);
+
+    *idx = i;
+}
+
+
+#if defined(MICRIUM)
+
+static int NetSecure_ValidDate(CPU_INT08U *date, CPU_INT08U format,
+                               CPU_INT08U dateType)
+{
+    CLK_DATE_TIME   cert_date_time;
+    CLK_TS_SEC      cert_ts_sec;
+    CLK_TS_SEC      local_ts_sec;
+    CPU_INT32S      i;
+    CPU_INT32S      val;
+
+    local_ts_sec = Clk_GetTS();
+    XMEMSET(&cert_date_time, 0, sizeof(cert_date_time));
+
+    i = 0;
+    if (format == ASN_UTC_TIME) {
+        if (btoi(date[0]) >= 5)
+            cert_date_time.Yr = 1900;
+        else
+            cert_date_time.Yr = 2000;
+    }
+    else  { /* format == GENERALIZED_TIME */
+        cert_date_time.Yr += btoi(date[i++]) * 1000;
+        cert_date_time.Yr += btoi(date[i++]) * 100;
+    }
+
+    val = cert_date_time.Yr;
+    GetTime(&val,   date, &i);
+    cert_date_time.Yr =    (CLK_YR)val;
+
+    val = 0;
+    GetTime(&val, date, &i);   
+    cert_date_time.Month = (CLK_MONTH)val;
+  
+    val = 0;
+    GetTime(&val, date, &i);  
+    cert_date_time.Day =   (CLK_DAY)val;
+
+    val = 0;
+    GetTime(&val, date, &i);  
+    cert_date_time.Hr =    (CLK_HR)val;
+    
+    val = 0;
+    GetTime(&val, date, &i);  
+    cert_date_time.Min =   (CLK_MIN)val;
+    
+    val = 0;
+    GetTime(&val, date, &i);  
+    cert_date_time.Sec =   (CLK_SEC)val;
+
+    if (date[i] != 'Z')     /* only Zulu supported for this profile */
+        return 0;
+
+    cert_date_time.DayOfWk = 1;
+    cert_date_time.DayOfYr = 1;
+    Clk_DateTimeToTS(&cert_ts_sec, &cert_date_time);
+
+
+    if (dateType == BEFORE) {
+        if (local_ts_sec < cert_ts_sec)  /* If cert creation date after
+                                             current date...  */
+            return (DEF_FAIL);           /* ... report an error. */
+   } else {
+        if (local_ts_sec > cert_ts_sec)  /* If cert expiration date before
+                                           current date...  */
+            return (DEF_FAIL);           /* ... report an error. */
+   }
+
+    return (DEF_OK);
+}
+
+#endif /* MICRIUM */
+
+
+int GetLength(const byte* input, word32* inOutIdx, int* len)
+{
+    int     length = 0;
+    word32  i = *inOutIdx;
+
+    byte b = input[i++];
+    if (b >= ASN_LONG_LENGTH) {        
+        word32 bytes = b & 0x7F;
+
+        while (bytes--) {
+            b = input[i++];
+            length = (length << 8) | b;
+        }
+    }
+    else
+        length = b;
+    
+    *inOutIdx = i;
+    *len      = length;
+
+    return length;
+}
+
+
+int GetSequence(const byte* input, word32* inOutIdx, int* len)
+{
+    int    length = -1;
+    word32 idx    = *inOutIdx;
+
+    if (input[idx++] != (ASN_SEQUENCE | ASN_CONSTRUCTED) ||
+            GetLength(input, &idx, &length) < 0)
+        return ASN_PARSE_E;
+
+    *len      = length;
+    *inOutIdx = idx;
+
+    return length;
+}
+
+
+int GetSet(const byte* input, word32* inOutIdx, int* len)
+{
+    int    length = -1;
+    word32 idx    = *inOutIdx;
+
+    if (input[idx++] != (ASN_SET | ASN_CONSTRUCTED) ||
+            GetLength(input, &idx, &length) < 0)
+        return ASN_PARSE_E;
+
+    *len      = length;
+    *inOutIdx = idx;
+
+    return length;
+}
+
+
+/* winodws header clash for WinCE using GetVersion */
+int GetMyVersion(const byte* input, word32* inOutIdx, int* version)
+{
+    word32 idx = *inOutIdx;
+
+    if (input[idx++] != ASN_INTEGER)
+        return ASN_PARSE_E;
+
+    if (input[idx++] != 0x01)
+        return ASN_VERSION_E;
+
+    *version  = input[idx++];
+    *inOutIdx = idx;
+
+    return *version;
+}
+
+
+/* May not have one, not an error */
+int GetExplicitVersion(const byte* input, word32* inOutIdx, int* version)
+{
+    word32 idx = *inOutIdx;
+
+    if (input[idx++] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) {
+        *inOutIdx = ++idx;  /* eat header */
+        return GetMyVersion(input, inOutIdx, version);
+    }
+
+    /* go back as is */
+    *version = 0;
+
+    return 0;
+}
+
+
+int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx )
+{
+    word32 i = *inOutIdx;
+    byte   b = input[i++];
+    int    length;
+
+    if (b != ASN_INTEGER)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &i, &length) < 0)
+        return ASN_PARSE_E;
+
+    if ( (b = input[i++]) == 0x00)
+        length--;
+    else
+        i--;
+
+    mp_init(mpi); 
+    if (mp_read_unsigned_bin(mpi, (byte*)input + i, length) != 0) {
+        mp_clear(mpi);
+        return ASN_GETINT_E;
+    }
+
+    *inOutIdx = i + length;
+    return 0;
+}
+
+
+static int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid)
+{
+    int    length;
+    word32 i = *inOutIdx;
+    byte   b;
+    *oid = 0;
+    
+    if (GetSequence(input, &i, &length) < 0)
+        return ASN_PARSE_E;
+    
+    b = input[i++];
+    if (b != ASN_OBJECT_ID) 
+        return ASN_OBJECT_ID_E;
+    
+    if (GetLength(input, &i, &length) < 0)
+        return ASN_PARSE_E;
+    
+    while(length--)
+        *oid += input[i++];
+    /* just sum it up for now */
+    
+    /* could have NULL tag and 0 terminator, but may not */
+    b = input[i++];
+    
+    if (b == ASN_TAG_NULL) {
+        b = input[i++];
+        if (b != 0) 
+            return ASN_EXPECT_0_E;
+    }
+    else
+    /* go back, didn't have it */
+        i--;
+    
+    *inOutIdx = i;
+    
+    return 0;
+}
+
+
+int RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
+                        word32 inSz)
+{
+    word32 begin = *inOutIdx;
+    int    version, length;
+
+    if (GetSequence(input, inOutIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    if ((word32)length > (inSz - (*inOutIdx - begin)))
+        return ASN_INPUT_E;
+
+    if (GetMyVersion(input, inOutIdx, &version) < 0)
+        return ASN_PARSE_E;
+
+    key->type = RSA_PRIVATE;
+
+    if (GetInt(&key->n,  input, inOutIdx) < 0 ||
+        GetInt(&key->e,  input, inOutIdx) < 0 ||
+        GetInt(&key->d,  input, inOutIdx) < 0 ||
+        GetInt(&key->p,  input, inOutIdx) < 0 ||
+        GetInt(&key->q,  input, inOutIdx) < 0 ||
+        GetInt(&key->dP, input, inOutIdx) < 0 ||
+        GetInt(&key->dQ, input, inOutIdx) < 0 ||
+        GetInt(&key->u,  input, inOutIdx) < 0 )  return ASN_RSA_KEY_E;
+
+    return 0;
+}
+
+
+/* Remove PKCS8 header, move beginning of traditional to beginning of input */
+int ToTraditional(byte* input, word32 sz)
+{
+    word32 inOutIdx = 0, oid;
+    int    version, length;
+
+    if (GetSequence(input, &inOutIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    if ((word32)length > (sz - inOutIdx))
+        return ASN_INPUT_E;
+
+    if (GetMyVersion(input, &inOutIdx, &version) < 0)
+        return ASN_PARSE_E;
+    
+    if (GetAlgoId(input, &inOutIdx, &oid) < 0)
+        return ASN_PARSE_E;
+    
+    if (input[inOutIdx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+    
+    if (GetLength(input, &inOutIdx, &length) < 0)
+        return ASN_PARSE_E;
+    
+    if ((word32)length > (sz - inOutIdx))
+        return ASN_INPUT_E;
+    
+    XMEMMOVE(input, input + inOutIdx, length);
+
+    return 0;
+}
+
+
+int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
+                       word32 inSz)
+{
+    word32 begin = *inOutIdx;
+    int    length;
+    byte   b;
+
+    if (GetSequence(input, inOutIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    if ((word32)length > (inSz - (*inOutIdx - begin)))
+        return ASN_INPUT_E;
+
+    key->type = RSA_PUBLIC;
+    b = input[*inOutIdx];
+
+#ifdef OPENSSL_EXTRA    
+    if (b != ASN_INTEGER) {
+        /* not from decoded cert, will have algo id, skip past */
+        if (GetSequence(input, inOutIdx, &length) < 0)
+            return ASN_PARSE_E;
+        
+        b = input[(*inOutIdx)++];
+        if (b != ASN_OBJECT_ID) 
+            return ASN_OBJECT_ID_E;
+        
+        if (GetLength(input, inOutIdx, &length) < 0)
+            return ASN_PARSE_E;
+        
+        *inOutIdx += length;   /* skip past */
+        
+        /* could have NULL tag and 0 terminator, but may not */
+        b = input[(*inOutIdx)++];
+        
+        if (b == ASN_TAG_NULL) {
+            b = input[(*inOutIdx)++];
+            if (b != 0) 
+                return ASN_EXPECT_0_E;
+        }
+        else
+        /* go back, didn't have it */
+            (*inOutIdx)--;
+        
+        /* should have bit tag length and seq next */
+        b = input[(*inOutIdx)++];
+        if (b != ASN_BIT_STRING)
+            return ASN_BITSTR_E;
+        
+        if (GetLength(input, inOutIdx, &length) < 0)
+            return ASN_PARSE_E;
+        
+        /* could have 0 */
+        b = input[(*inOutIdx)++];
+        if (b != 0)
+            (*inOutIdx)--;
+        
+        if (GetSequence(input, inOutIdx, &length) < 0)
+            return ASN_PARSE_E;
+    }
+#endif /* OPENSSL_EXTRA */
+
+    if (GetInt(&key->n,  input, inOutIdx) < 0 ||
+        GetInt(&key->e,  input, inOutIdx) < 0 )  return ASN_RSA_KEY_E;
+
+    return 0;
+}
+
+
+#ifndef NO_DH
+
+int DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz)
+{
+    word32 begin = *inOutIdx;
+    int    length;
+
+    if (GetSequence(input, inOutIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    if ((word32)length > (inSz - (*inOutIdx - begin)))
+        return ASN_INPUT_E;
+
+    if (GetInt(&key->p,  input, inOutIdx) < 0 ||
+        GetInt(&key->g,  input, inOutIdx) < 0 )  return ASN_DH_KEY_E;
+
+    return 0;
+}
+
+int DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz)
+{
+    /* may have leading 0 */
+    if (p[0] == 0) {
+        pSz--; p++;
+    }
+
+    if (g[0] == 0) {
+        gSz--; g++;
+    }
+
+    mp_init(&key->p);
+    if (mp_read_unsigned_bin(&key->p, p, pSz) != 0) {
+        mp_clear(&key->p);
+        return ASN_DH_KEY_E;
+    }
+
+    mp_init(&key->g);
+    if (mp_read_unsigned_bin(&key->g, g, gSz) != 0) {
+        mp_clear(&key->p);
+        return ASN_DH_KEY_E;
+    }
+
+    return 0;
+}
+
+
+#endif /* NO_DH */
+
+
+#ifndef NO_DSA
+
+int DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key,
+                        word32 inSz)
+{
+    word32 begin = *inOutIdx;
+    int    length;
+
+    if (GetSequence(input, inOutIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    if ((word32)length > (inSz - (*inOutIdx - begin)))
+        return ASN_INPUT_E;
+
+    if (GetInt(&key->p,  input, inOutIdx) < 0 ||
+        GetInt(&key->q,  input, inOutIdx) < 0 ||
+        GetInt(&key->g,  input, inOutIdx) < 0 ||
+        GetInt(&key->y,  input, inOutIdx) < 0 )  return ASN_DH_KEY_E;
+
+    key->type = DSA_PUBLIC;
+    return 0;
+}
+
+
+int DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key,
+                        word32 inSz)
+{
+    word32 begin = *inOutIdx;
+    int    length, version;
+
+    if (GetSequence(input, inOutIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    if ((word32)length > (inSz - (*inOutIdx - begin)))
+        return ASN_INPUT_E;
+
+    if (GetMyVersion(input, inOutIdx, &version) < 0)
+        return ASN_PARSE_E;
+
+    if (GetInt(&key->p,  input, inOutIdx) < 0 ||
+        GetInt(&key->q,  input, inOutIdx) < 0 ||
+        GetInt(&key->g,  input, inOutIdx) < 0 ||
+        GetInt(&key->y,  input, inOutIdx) < 0 ||
+        GetInt(&key->x,  input, inOutIdx) < 0 )  return ASN_DH_KEY_E;
+
+    key->type = DSA_PRIVATE;
+    return 0;
+}
+
+#endif /* NO_DSA */
+
+
+void InitDecodedCert(DecodedCert* cert, byte* source, void* heap)
+{
+    cert->publicKey       = 0;
+    cert->pubKeyStored    = 0;
+    cert->signature       = 0;
+    cert->subjectCN       = 0;
+    cert->subjectCNLen    = 0;
+    cert->source          = source;  /* don't own */
+    cert->srcIdx          = 0;
+    cert->heap            = heap;
+#ifdef CYASSL_CERT_GEN
+    cert->subjectSN       = 0;
+    cert->subjectSNLen    = 0;
+    cert->subjectC        = 0;
+    cert->subjectCLen     = 0;
+    cert->subjectL        = 0;
+    cert->subjectLLen     = 0;
+    cert->subjectST       = 0;
+    cert->subjectSTLen    = 0;
+    cert->subjectO        = 0;
+    cert->subjectOLen     = 0;
+    cert->subjectOU       = 0;
+    cert->subjectOULen    = 0;
+    cert->subjectEmail    = 0;
+    cert->subjectEmailLen = 0;
+#endif /* CYASSL_CERT_GEN */
+}
+
+
+void FreeDecodedCert(DecodedCert* cert)
+{
+    if (cert->subjectCNLen == 0)  /* 0 means no longer pointer to raw, we own */
+        XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN);
+    if (cert->pubKeyStored == 1)
+        XFREE(cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+}
+
+
+static int GetCertHeader(DecodedCert* cert, word32 inSz)
+{
+    int    ret = 0, version, len;
+    word32 begin = cert->srcIdx;
+    mp_int mpi;
+
+    if (GetSequence(cert->source, &cert->srcIdx, &len) < 0)
+        return ASN_PARSE_E;
+
+    if ((word32)len > (inSz - (cert->srcIdx - begin))) return ASN_INPUT_E;
+
+    cert->certBegin = cert->srcIdx;
+
+    GetSequence(cert->source, &cert->srcIdx, &len);
+    cert->sigIndex = len + cert->srcIdx;
+
+    if (GetExplicitVersion(cert->source, &cert->srcIdx, &version) < 0)
+        return ASN_PARSE_E;
+
+    if (GetInt(&mpi, cert->source, &cert->srcIdx) < 0) 
+        ret = ASN_PARSE_E;
+
+    mp_clear(&mpi);
+    return ret;
+}
+
+
+static int StoreKey(DecodedCert* cert)
+{
+    int    length;
+    word32 read = cert->srcIdx;
+
+    if (cert->keyOID == NTRUk)
+        return 0;                /* already stored */
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length) < 0)
+        return ASN_PARSE_E;
+   
+    read = cert->srcIdx - read;
+    length += read;
+
+    while (read--)
+       cert->srcIdx--;
+
+    cert->pubKeySize = length;
+    cert->publicKey = cert->source + cert->srcIdx;
+    cert->srcIdx += length;
+
+    return 0;
+}
+
+
+static int GetKey(DecodedCert* cert)
+{
+    int length;
+#ifdef HAVE_NTRU
+    int tmpIdx = cert->srcIdx;
+#endif
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length) < 0)
+        return ASN_PARSE_E;
+    
+    if (GetAlgoId(cert->source, &cert->srcIdx, &cert->keyOID) < 0)
+        return ASN_PARSE_E;
+
+    if (cert->keyOID == RSAk) {
+        byte b = cert->source[cert->srcIdx++];
+        if (b != ASN_BIT_STRING)
+            return ASN_BITSTR_E;
+
+        if (GetLength(cert->source, &cert->srcIdx, &length) < 0)
+            return ASN_PARSE_E;
+        b = cert->source[cert->srcIdx++];
+        if (b != 0x00)
+            return ASN_EXPECT_0_E;
+    }
+    else if (cert->keyOID == DSAk )
+        ;   /* do nothing */
+#ifdef HAVE_NTRU
+    else if (cert->keyOID == NTRUk ) {
+        const byte* key = &cert->source[tmpIdx];
+        byte*       next = (byte*)key;
+        word16      keyLen;
+        byte        keyBlob[MAX_NTRU_KEY_SZ];
+
+        word32 rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key,
+                            &keyLen, NULL, &next);
+
+        if (rc != NTRU_OK)
+            return ASN_NTRU_KEY_E;
+        if (keyLen > sizeof(keyBlob))
+            return ASN_NTRU_KEY_E;
+
+        rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key, &keyLen,
+                                                                keyBlob, &next);
+        if (rc != NTRU_OK)
+            return ASN_NTRU_KEY_E;
+
+        if ( (next - key) < 0)
+            return ASN_NTRU_KEY_E;
+
+        cert->srcIdx = tmpIdx + (next - key);
+
+        cert->publicKey = (byte*) XMALLOC(keyLen, cert->heap,
+                                          DYNAMIC_TYPE_PUBLIC_KEY);
+        if (cert->publicKey == NULL)
+            return MEMORY_E;
+        memcpy(cert->publicKey, keyBlob, keyLen);
+        cert->pubKeyStored = 1;
+        cert->pubKeySize   = keyLen;
+    }
+#endif
+    else
+        return ASN_UNKNOWN_OID_E;
+    
+    return StoreKey(cert);
+}
+
+
+/* process NAME, either issuer or subject */
+static int GetName(DecodedCert* cert, int nameType)
+{
+    Sha    sha;
+    int    length;  /* length of all distinguished names */
+    int    dummy;
+    char* full = (nameType == ISSUER) ? cert->issuer : cert->subject;
+    word32 idx = 0;
+
+    InitSha(&sha);
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    length += cert->srcIdx;
+
+    while (cert->srcIdx < (word32)length) {
+        byte   b;
+        byte   joint[2];
+        int    oidSz;
+
+        if (GetSet(cert->source, &cert->srcIdx, &dummy) < 0)
+            return ASN_PARSE_E;
+
+        if (GetSequence(cert->source, &cert->srcIdx, &dummy) < 0)
+            return ASN_PARSE_E;
+
+        b = cert->source[cert->srcIdx++];
+        if (b != ASN_OBJECT_ID) 
+            return ASN_OBJECT_ID_E;
+
+        if (GetLength(cert->source, &cert->srcIdx, &oidSz) < 0)
+            return ASN_PARSE_E;
+
+        XMEMCPY(joint, &cert->source[cert->srcIdx], sizeof(joint));
+
+        /* v1 name types */
+        if (joint[0] == 0x55 && joint[1] == 0x04) {
+            byte   id;
+            byte   copy = FALSE;
+            int    strLen;
+
+            cert->srcIdx += 2;
+            id = cert->source[cert->srcIdx++]; 
+            b  = cert->source[cert->srcIdx++];    /* strType */
+
+            if (GetLength(cert->source, &cert->srcIdx, &strLen) < 0)
+                return ASN_PARSE_E;
+
+            if (strLen > (int)(ASN_NAME_MAX - idx))
+                return ASN_PARSE_E; 
+
+            if (4  > (ASN_NAME_MAX - idx))  /* make sure room for biggest */
+                return ASN_PARSE_E;         /* pre fix header too "/CN=" */
+
+            if (id == ASN_COMMON_NAME) {
+                if (nameType == SUBJECT) {
+                    cert->subjectCN = (char *)&cert->source[cert->srcIdx];
+                    cert->subjectCNLen = strLen;
+                }
+
+                XMEMCPY(&full[idx], "/CN=", 4);
+                idx += 4;
+                copy = TRUE;
+            }
+            else if (id == ASN_SUR_NAME) {
+                XMEMCPY(&full[idx], "/SN=", 4);
+                idx += 4;
+                copy = TRUE;
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectSN = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectSNLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_COUNTRY_NAME) {
+                XMEMCPY(&full[idx], "/C=", 3);
+                idx += 3;
+                copy = TRUE;
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectC = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectCLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_LOCALITY_NAME) {
+                XMEMCPY(&full[idx], "/L=", 3);
+                idx += 3;
+                copy = TRUE;
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectL = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectLLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_STATE_NAME) {
+                XMEMCPY(&full[idx], "/ST=", 4);
+                idx += 4;
+                copy = TRUE;
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectST = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectSTLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_ORG_NAME) {
+                XMEMCPY(&full[idx], "/O=", 3);
+                idx += 3;
+                copy = TRUE;
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectO = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectOLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_ORGUNIT_NAME) {
+                XMEMCPY(&full[idx], "/OU=", 4);
+                idx += 4;
+                copy = TRUE;
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectOU = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectOULen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+
+            if (copy) {
+                XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen);
+                idx += strLen;
+            }
+
+            ShaUpdate(&sha, &cert->source[cert->srcIdx], strLen);
+            cert->srcIdx += strLen;
+        }
+        else {
+            /* skip */
+            byte email = FALSE;
+            int  adv;
+
+            if (joint[0] == 0x2a && joint[1] == 0x86)  /* email id hdr */
+                email = TRUE;
+
+            cert->srcIdx += oidSz + 1;
+
+            if (GetLength(cert->source, &cert->srcIdx, &adv) < 0)
+                return ASN_PARSE_E;
+
+            if (adv > (int)(ASN_NAME_MAX - idx))
+                return ASN_PARSE_E; 
+
+            if (email) {
+                if (14 > (ASN_NAME_MAX - idx))
+                    return ASN_PARSE_E; 
+                XMEMCPY(&full[idx], "/emailAddress=", 14);
+                idx += 14;
+
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectEmail = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectEmailLen = adv;
+                }
+#endif /* CYASSL_CERT_GEN */
+
+                XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv);
+                idx += adv;
+            }
+
+            cert->srcIdx += adv;
+        }
+    }
+    full[idx++] = 0;
+
+    if (nameType == ISSUER)
+        ShaFinal(&sha, cert->issuerHash);
+    else
+        ShaFinal(&sha, cert->subjectHash);
+
+    return 0;
+}
+
+
+#ifndef NO_TIME_H
+
+/* to the second */
+static int DateGreaterThan(const struct tm* a, const struct tm* b)
+{
+    if (a->tm_year > b->tm_year)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon > b->tm_mon)
+        return 1;
+    
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+           a->tm_mday > b->tm_mday)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour > b->tm_hour)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
+        a->tm_min > b->tm_min)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
+        a->tm_min  == b->tm_min  && a->tm_sec > b->tm_sec)
+        return 1;
+
+    return 0; /* false */
+}
+
+
+static INLINE int DateLessThan(const struct tm* a, const struct tm* b)
+{
+    return !DateGreaterThan(a,b);
+}
+
+
+/* like atoi but only use first byte */
+/* Make sure before and after dates are valid */
+static int ValidateDate(const byte* date, byte format, int dateType)
+{
+    time_t ltime;
+    struct tm  certTime;
+    struct tm* localTime;
+    int    i = 0;
+
+    ltime = XTIME(0);
+    XMEMSET(&certTime, 0, sizeof(certTime));
+
+    if (format == ASN_UTC_TIME) {
+        if (btoi(date[0]) >= 5)
+            certTime.tm_year = 1900;
+        else
+            certTime.tm_year = 2000;
+    }
+    else  { /* format == GENERALIZED_TIME */
+        certTime.tm_year += btoi(date[i++]) * 1000;
+        certTime.tm_year += btoi(date[i++]) * 100;
+    }
+
+    GetTime(&certTime.tm_year, date, &i); certTime.tm_year -= 1900; /* adjust */
+    GetTime(&certTime.tm_mon,  date, &i); certTime.tm_mon  -= 1;    /* adjust */
+    GetTime(&certTime.tm_mday, date, &i);
+    GetTime(&certTime.tm_hour, date, &i); 
+    GetTime(&certTime.tm_min,  date, &i); 
+    GetTime(&certTime.tm_sec,  date, &i); 
+
+    if (date[i] != 'Z')     /* only Zulu supported for this profile */
+        return 0;
+
+    localTime = XGMTIME(&ltime);
+
+    if (dateType == BEFORE) {
+        if (DateLessThan(localTime, &certTime))
+            return 0;
+    }
+    else
+        if (DateGreaterThan(localTime, &certTime))
+            return 0;
+
+    return 1;
+}
+
+#endif /* NO_TIME_H */
+
+
+static int GetDate(DecodedCert* cert, int dateType)
+{
+    int    length;
+    byte   date[MAX_DATE_SIZE];
+    byte   b = cert->source[cert->srcIdx++];
+
+    if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME)
+        return ASN_TIME_E;
+
+    if (GetLength(cert->source, &cert->srcIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
+        return ASN_DATE_SZ_E;
+
+    XMEMCPY(date, &cert->source[cert->srcIdx], length);
+    cert->srcIdx += length;
+
+    if (!XVALIDATE_DATE(date, b, dateType)) {
+        if (dateType == BEFORE)
+            return ASN_BEFORE_DATE_E;
+        else
+            return ASN_AFTER_DATE_E;
+    }
+
+    return 0;
+}
+
+
+static int GetValidity(DecodedCert* cert, int verify)
+{
+    int length;
+    int badDate = 0;
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    if (GetDate(cert, BEFORE) < 0 && verify)
+        badDate = ASN_BEFORE_DATE_E;           /* continue parsing */
+    
+    if (GetDate(cert, AFTER) < 0 && verify)
+        return ASN_AFTER_DATE_E;
+   
+    if (badDate != 0)
+        return badDate;
+
+    return 0;
+}
+
+
+static int DecodeToKey(DecodedCert* cert, word32 inSz, int verify)
+{
+    int badDate = 0;
+    int ret;
+
+    if ( (ret = GetCertHeader(cert, inSz)) < 0)
+        return ret;
+
+    if ( (ret = GetAlgoId(cert->source, &cert->srcIdx,&cert->signatureOID)) < 0)
+        return ret;
+
+    if ( (ret = GetName(cert, ISSUER)) < 0)
+        return ret;
+
+    if ( (ret = GetValidity(cert, verify)) < 0)
+        badDate = ret;
+
+    if ( (ret = GetName(cert, SUBJECT)) < 0)
+        return ret;
+
+    if ( (ret = GetKey(cert)) < 0)
+        return ret;
+
+    if (badDate != 0)
+        return badDate;
+
+    return ret;
+}
+
+
+static int GetSignature(DecodedCert* cert)
+{
+    int    length;
+    byte   b = cert->source[cert->srcIdx++];
+
+    if (b != ASN_BIT_STRING)
+        return ASN_BITSTR_E;
+
+    if (GetLength(cert->source, &cert->srcIdx, &length) < 0)
+        return ASN_PARSE_E;
+
+    cert->sigLength = length;
+
+    b = cert->source[cert->srcIdx++];
+    if (b != 0x00)
+        return ASN_EXPECT_0_E;
+
+    cert->sigLength--;
+    cert->signature = &cert->source[cert->srcIdx];
+    cert->srcIdx += cert->sigLength;
+
+    return 0;
+}
+
+
+static word32 SetDigest(const byte* digest, word32 digSz, byte* output)
+{
+    output[0] = ASN_OCTET_STRING;
+    output[1] = digSz;
+    XMEMCPY(&output[2], digest, digSz);
+
+    return digSz + 2;
+} 
+
+
+static word32 BytePrecision(word32 value)
+{
+    word32 i;
+    for (i = sizeof(value); i; --i)
+        if (value >> (i - 1) * 8)
+            break;
+
+    return i;
+}
+
+
+static word32 SetLength(word32 length, byte* output)
+{
+    word32 i = 0, j;
+
+    if (length < ASN_LONG_LENGTH)
+        output[i++] = length;
+    else {
+        output[i++] = BytePrecision(length) | ASN_LONG_LENGTH;
+      
+        for (j = BytePrecision(length); j; --j) {
+            output[i] = length >> (j - 1) * 8;
+            i++;
+        }
+    }
+
+    return i;
+}
+
+
+static word32 SetSequence(word32 len, byte* output)
+{
+    output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
+    return SetLength(len, output + 1) + 1;
+}
+
+
+static word32 SetAlgoID(int algoOID, byte* output, int type)
+{
+    /* adding TAG_NULL and 0 to end */
+    
+    /* hashTypes */
+    static const byte shaAlgoID[] = { 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+                                      0x05, 0x00 };
+    static const byte md5AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                      0x02, 0x05, 0x05, 0x00  };
+    static const byte md2AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                      0x02, 0x02, 0x05, 0x00};
+
+    /* sigTypes */
+    static const byte md5wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                      0x01, 0x01, 0x04, 0x05, 0x00};
+
+    /* keyTypes */
+    static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                      0x01, 0x01, 0x01, 0x05, 0x00};
+
+    int    algoSz = 0;
+    word32 idSz, seqSz;
+    const  byte* algoName = 0;
+    byte ID_Length[MAX_LENGTH_SZ];
+    byte seqArray[MAX_SEQ_SZ + 1];  /* add object_id to end */
+
+    if (type == hashType) {
+        switch (algoOID) {
+        case SHAh:
+            algoSz = sizeof(shaAlgoID);
+            algoName = shaAlgoID;
+            break;
+
+        case MD2h:
+            algoSz = sizeof(md2AlgoID);
+            algoName = md2AlgoID;
+            break;
+
+        case MD5h:
+            algoSz = sizeof(md5AlgoID);
+            algoName = md5AlgoID;
+            break;
+
+        default:
+            return 0;  /* UNKOWN_HASH_E; */
+        }
+    }
+    else if (type == sigType) {    /* sigType */
+        switch (algoOID) {
+        case MD5wRSA:
+            algoSz = sizeof(md5wRSA_AlgoID);
+            algoName = md5wRSA_AlgoID;
+            break;
+
+        default:
+            return 0;  /* UNKOWN_HASH_E; */
+        }
+    }
+    else if (type == keyType) {    /* keyType */
+        switch (algoOID) {
+        case RSAk:
+            algoSz = sizeof(RSA_AlgoID);
+            algoName = RSA_AlgoID;
+            break;
+
+        default:
+            return 0;  /* UNKOWN_HASH_E; */
+        }
+    }
+    else
+        return 0;  /* UNKNOWN_TYPE */
+
+
+    idSz  = SetLength(algoSz - 2, ID_Length); /* don't include TAG_NULL/0 */
+    seqSz = SetSequence(idSz + algoSz + 1, seqArray);
+    seqArray[seqSz++] = ASN_OBJECT_ID;
+
+    XMEMCPY(output, seqArray, seqSz);
+    XMEMCPY(output + seqSz, ID_Length, idSz);
+    XMEMCPY(output + seqSz + idSz, algoName, algoSz);
+
+    return seqSz + idSz + algoSz;
+
+}
+
+
+word32 EncodeSignature(byte* out, const byte* digest, word32 digSz, int hashOID)
+{
+    byte digArray[MAX_ENCODED_DIG_SZ];
+    byte algoArray[MAX_ALGO_SZ];
+    byte seqArray[MAX_SEQ_SZ];
+    word32 encDigSz, algoSz, seqSz; 
+
+    encDigSz = SetDigest(digest, digSz, digArray);
+    algoSz   = SetAlgoID(hashOID, algoArray, hashType);
+    seqSz    = SetSequence(encDigSz + algoSz, seqArray);
+
+    XMEMCPY(out, seqArray, seqSz);
+    XMEMCPY(out + seqSz, algoArray, algoSz);
+    XMEMCPY(out + seqSz + algoSz, digArray, encDigSz);
+
+    return encDigSz + algoSz + seqSz;
+}
+                           
+
+/* return true (1) for Confirmation */
+static int ConfirmSignature(DecodedCert* cert, const byte* key, word32 keySz,
+                            word32 keyOID)
+{
+    byte digest[SHA_DIGEST_SIZE]; /* max size */
+    int  hashType, digestSz, ret;
+
+    if (cert->signatureOID == MD5wRSA) {
+        Md5 md5;
+        InitMd5(&md5);
+        Md5Update(&md5, cert->source + cert->certBegin,
+                  cert->sigIndex - cert->certBegin);
+        Md5Final(&md5, digest);
+        hashType = MD5h;
+        digestSz = MD5_DIGEST_SIZE;
+    }
+    else if (cert->signatureOID == SHAwRSA || cert->signatureOID == SHAwDSA) {
+        Sha sha;
+        InitSha(&sha);
+        ShaUpdate(&sha, cert->source + cert->certBegin,
+                  cert->sigIndex - cert->certBegin);
+        ShaFinal(&sha, digest);
+        hashType = SHAh;
+        digestSz = SHA_DIGEST_SIZE;
+    }
+    else
+        return 0; /* ASN_SIG_HASH_E; */
+
+    if (keyOID == RSAk) {
+        RsaKey pubKey;
+        byte   encodedSig[MAX_ENCODED_SIG_SZ];
+        byte   plain[MAX_ENCODED_SIG_SZ];
+        word32 idx = 0;
+        int    sigSz, verifySz;
+        byte*  out;
+
+        if (cert->sigLength > MAX_ENCODED_SIG_SZ)
+            return 0; /* the key is too big */
+            
+        InitRsaKey(&pubKey, cert->heap);
+        if (RsaPublicKeyDecode(key, &idx, &pubKey, keySz) < 0)
+            ret = 0; /* ASN_KEY_DECODE_E; */
+
+        else {
+            XMEMCPY(plain, cert->signature, cert->sigLength);
+            if ( (verifySz = RsaSSL_VerifyInline(plain, cert->sigLength, &out,
+                                           &pubKey)) < 0)
+                ret = 0; /* ASN_VERIFY_E; */
+            else {
+                /* make sure we're right justified */
+                sigSz = EncodeSignature(encodedSig, digest, digestSz, hashType);
+                if (sigSz != verifySz || XMEMCMP(out, encodedSig, sigSz) != 0)
+                    ret = 0; /* ASN_VERIFY_MATCH_E; */
+                else
+                    ret = 1; /* match */
+            }
+        }
+        FreeRsaKey(&pubKey);
+        return ret;
+    }
+    else
+        return 0; /* ASN_SIG_KEY_E; */
+}
+
+
+int ParseCert(DecodedCert* cert, word32 inSz, int type, int verify,
+              Signer* signers)
+{
+    int   ret;
+    char* ptr;
+
+    ret = ParseCertRelative(cert, inSz, type, verify, signers);
+    if (ret < 0)
+        return ret;
+
+    if (cert->subjectCNLen > 0) {
+        ptr = (char*) XMALLOC(cert->subjectCNLen + 1, cert->heap,
+                              DYNAMIC_TYPE_SUBJECT_CN);
+        if (ptr == NULL)
+            return MEMORY_E;
+        XMEMCPY(ptr, cert->subjectCN, cert->subjectCNLen);
+        ptr[cert->subjectCNLen] = '\0';
+        cert->subjectCN = ptr;
+        cert->subjectCNLen = 0;
+    }
+
+    if (cert->keyOID == RSAk && cert->pubKeySize > 0) {
+        ptr = (char*) XMALLOC(cert->pubKeySize, cert->heap,
+                              DYNAMIC_TYPE_PUBLIC_KEY);
+        if (ptr == NULL)
+            return MEMORY_E;
+        XMEMCPY(ptr, cert->publicKey, cert->pubKeySize);
+        cert->publicKey = (byte *)ptr;
+        cert->pubKeyStored = 1;
+    }
+
+    return ret;
+}
+
+
+int ParseCertRelative(DecodedCert* cert, word32 inSz, int type, int verify,
+              Signer* signers)
+{
+    word32 confirmOID;
+    int    ret;
+    int    badDate = 0;
+    int    confirm = 0;
+
+    if ((ret = DecodeToKey(cert, inSz, verify)) < 0) {
+        if (ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E)
+            badDate = ret;
+        else
+            return ret;
+    }
+
+    if (cert->srcIdx != cert->sigIndex)
+        cert->srcIdx =  cert->sigIndex;
+
+    if ((ret = GetAlgoId(cert->source, &cert->srcIdx, &confirmOID)) < 0)
+        return ret;
+
+    if ((ret = GetSignature(cert)) < 0)
+        return ret;
+
+    if (confirmOID != cert->signatureOID)
+        return ASN_SIG_OID_E;
+
+    if (verify && type != CA_TYPE) {
+        while (signers) {
+            if (XMEMCMP(cert->issuerHash, signers->hash, SHA_DIGEST_SIZE)
+                       == 0) {
+                /* other confirm */
+                if (!ConfirmSignature(cert, signers->publicKey,
+                                      signers->pubKeySize, signers->keyOID))
+                    return ASN_SIG_CONFIRM_E;
+                else {
+                    confirm = 1;
+                    break;
+                }
+            }
+            signers = signers->next;
+        }
+        if (!confirm)
+            return ASN_SIG_CONFIRM_E;
+    }
+    if (badDate != 0)
+        return badDate;
+
+    return 0;
+}
+
+
+Signer* MakeSigner(void* heap)
+{
+    Signer* signer = (Signer*) XMALLOC(sizeof(Signer), heap,
+                                       DYNAMIC_TYPE_SIGNER);
+    if (signer) {
+        signer->name      = 0;
+        signer->publicKey = 0;
+        signer->next      = 0;
+    }
+
+    return signer;
+}
+
+
+void FreeSigners(Signer* signer, void* heap)
+{
+    Signer* next = signer;
+
+    while( (signer = next) ) {
+        next = signer->next;
+        XFREE(signer->name, heap, DYNAMIC_TYPE_SUBJECT_CN);
+        XFREE(signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY);
+        XFREE(signer, heap, DYNAMIC_TYPE_SIGNER);
+    }
+}
+
+
+void CTaoCryptErrorString(int error, char* buffer)
+{
+    const int max = MAX_ERROR_SZ;   /* shorthand */
+
+#ifdef NO_ERROR_STRINGS
+
+    XSTRNCPY(buffer, "no support for error strings built in", max);
+
+#else
+
+    switch (error) {
+
+    case OPEN_RAN_E :        
+        XSTRNCPY(buffer, "opening random device error", max);
+        break;
+
+    case READ_RAN_E :
+        XSTRNCPY(buffer, "reading random device error", max);
+        break;
+
+    case WINCRYPT_E :
+        XSTRNCPY(buffer, "windows crypt init error", max);
+        break;
+
+    case CRYPTGEN_E : 
+        XSTRNCPY(buffer, "windows crypt generation error", max);
+        break;
+
+    case RAN_BLOCK_E : 
+        XSTRNCPY(buffer, "random device read would block error", max);
+        break;
+
+    case MP_INIT_E :
+        XSTRNCPY(buffer, "mp_init error state", max);
+        break;
+
+    case MP_READ_E :
+        XSTRNCPY(buffer, "mp_read error state", max);
+        break;
+
+    case MP_EXPTMOD_E :
+        XSTRNCPY(buffer, "mp_exptmod error state", max);
+        break;
+
+    case MP_TO_E :
+        XSTRNCPY(buffer, "mp_to_xxx error state, can't convert", max);
+        break;
+
+    case MP_SUB_E :
+        XSTRNCPY(buffer, "mp_sub error state, can't subtract", max);
+        break;
+
+    case MP_ADD_E :
+        XSTRNCPY(buffer, "mp_add error state, can't add", max);
+        break;
+
+    case MP_MUL_E :
+        XSTRNCPY(buffer, "mp_mul error state, can't multiply", max);
+        break;
+
+    case MP_MULMOD_E :
+        XSTRNCPY(buffer, "mp_mulmod error state, can't multiply mod", max);
+        break;
+
+    case MP_MOD_E :
+        XSTRNCPY(buffer, "mp_mod error state, can't mod", max);
+        break;
+
+    case MP_INVMOD_E :
+        XSTRNCPY(buffer, "mp_invmod error state, can't inv mod", max);
+        break; 
+        
+    case MP_CMP_E :
+        XSTRNCPY(buffer, "mp_cmp error state", max);
+        break; 
+        
+    case MEMORY_E :
+        XSTRNCPY(buffer, "out of memory error", max);
+        break;
+
+    case RSA_WRONG_TYPE_E :
+        XSTRNCPY(buffer, "RSA wrong block type for RSA function", max);
+        break; 
+
+    case RSA_BUFFER_E :
+        XSTRNCPY(buffer, "RSA buffer error, output too small or input too big",
+                max);
+        break; 
+
+    case BUFFER_E :
+        XSTRNCPY(buffer, "Buffer error, output too small or input too big", max);
+        break; 
+
+    case ALGO_ID_E :
+        XSTRNCPY(buffer, "Setting Cert AlogID error", max);
+        break; 
+
+    case PUBLIC_KEY_E :
+        XSTRNCPY(buffer, "Setting Cert Public Key error", max);
+        break; 
+
+    case DATE_E :
+        XSTRNCPY(buffer, "Setting Cert Date validity error", max);
+        break; 
+
+    case SUBJECT_E :
+        XSTRNCPY(buffer, "Setting Cert Subject name error", max);
+        break; 
+
+    case ISSUER_E :
+        XSTRNCPY(buffer, "Setting Cert Issuer name error", max);
+        break; 
+
+    case ASN_PARSE_E :
+        XSTRNCPY(buffer, "ASN parsing error, invalid input", max);
+        break;
+
+    case ASN_VERSION_E :
+        XSTRNCPY(buffer, "ASN version error, invalid number", max);
+        break;
+
+    case ASN_GETINT_E :
+        XSTRNCPY(buffer, "ASN get big int error, invalid data", max);
+        break;
+
+    case ASN_RSA_KEY_E :
+        XSTRNCPY(buffer, "ASN key init error, invalid input", max);
+        break;
+
+    case ASN_OBJECT_ID_E :
+        XSTRNCPY(buffer, "ASN object id error, invalid id", max);
+        break;
+
+    case ASN_TAG_NULL_E :
+        XSTRNCPY(buffer, "ASN tag error, not null", max);
+        break;
+
+    case ASN_EXPECT_0_E :
+        XSTRNCPY(buffer, "ASN expect error, not zero", max);
+        break;
+
+    case ASN_BITSTR_E :
+        XSTRNCPY(buffer, "ASN bit string error, wrong id", max);
+        break;
+
+    case ASN_UNKNOWN_OID_E :
+        XSTRNCPY(buffer, "ASN oid error, unknown sum id", max);
+        break;
+
+    case ASN_DATE_SZ_E :
+        XSTRNCPY(buffer, "ASN date error, bad size", max);
+        break;
+
+    case ASN_BEFORE_DATE_E :
+        XSTRNCPY(buffer, "ASN date error, current date before", max);
+        break;
+
+    case ASN_AFTER_DATE_E :
+        XSTRNCPY(buffer, "ASN date error, current date after", max);
+        break;
+
+    case ASN_SIG_OID_E :
+        XSTRNCPY(buffer, "ASN signature error, mismatched oid", max);
+        break;
+
+    case ASN_TIME_E :
+        XSTRNCPY(buffer, "ASN time error, unkown time type", max);
+        break;
+
+    case ASN_INPUT_E :
+        XSTRNCPY(buffer, "ASN input error, not enough data", max);
+        break;
+
+    case ASN_SIG_CONFIRM_E :
+        XSTRNCPY(buffer, "ASN sig error, confirm failure", max);
+        break;
+
+    case ASN_SIG_HASH_E :
+        XSTRNCPY(buffer, "ASN sig error, unsupported hash type", max);
+        break;
+
+    case ASN_SIG_KEY_E :
+        XSTRNCPY(buffer, "ASN sig error, unsupported key type", max);
+        break;
+
+    case ASN_DH_KEY_E :
+        XSTRNCPY(buffer, "ASN key init error, invalid input", max);
+        break;
+
+    case ASN_NTRU_KEY_E :
+        XSTRNCPY(buffer, "ASN NTRU key decode error, invalid input", max);
+        break;
+
+    default:
+        XSTRNCPY(buffer, "unknown error number", max);
+
+    }
+
+#endif /* NO_ERROR_STRINGS */
+
+}
+
+
+#if defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN)
+
+static int SetMyVersion(word32 version, byte* output, int header)
+{
+    int i = 0;
+
+    if (header) {
+        output[i++] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED;
+        output[i++] = ASN_BIT_STRING;
+    }
+    output[i++] = ASN_INTEGER;
+    output[i++] = 0x01;
+    output[i++] = version;
+
+    return i;
+}
+
+
+int DerToPem(const byte* der, word32 derSz, byte* output, word32 outSz,
+             int type)
+{
+    char header[80];
+    char footer[80];
+
+    int headerLen;
+    int footerLen;
+    int i;
+    int outLen;   /* return length or error */
+
+    if (type == CERT_TYPE) {
+        XSTRNCPY(header, "-----BEGIN CERTIFICATE-----\n", sizeof(header));
+        XSTRNCPY(footer, "-----END CERTIFICATE-----\n", sizeof(footer));
+    } else {
+        XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----\n", sizeof(header));
+        XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----\n", sizeof(footer));
+    }
+
+    headerLen = XSTRLEN(header);
+    footerLen = XSTRLEN(footer);
+
+    if (!der || !output)
+        return -1;
+
+    /* don't even try if outSz too short */
+    if (outSz < headerLen + footerLen + derSz)
+        return -1;
+
+    /* header */
+    XMEMCPY(output, header, headerLen);
+    i = headerLen;
+
+    /* body */
+    outLen = outSz;  /* input to Base64Encode */
+    if (Base64Encode(der, derSz, output + i, (word32*)&outLen) < 0)
+        return -1;
+    i += outLen;
+
+    /* footer */
+    if ( (i + footerLen) > (int)outSz)
+        return -1;
+    XMEMCPY(output + i, footer, footerLen);
+
+    return outLen + headerLen + footerLen;
+}
+
+
+#endif /* CYASSL_KEY_GEN || CYASSL_CERT_GEN */
+
+
+#ifdef CYASSL_KEY_GEN
+
+
+static mp_int* GetRsaInt(RsaKey* key, int index)
+{
+    if (index == 0)
+        return &key->n;
+    if (index == 1)
+        return &key->e;
+    if (index == 2)
+        return &key->d;
+    if (index == 3)
+        return &key->p;
+    if (index == 4)
+        return &key->q;
+    if (index == 5)
+        return &key->dP;
+    if (index == 6)
+        return &key->dQ;
+    if (index == 7)
+        return &key->u;
+
+    return NULL;
+}
+
+
+/* Convert RsaKey key to DER format, write to output (inLen), return bytes
+   written */
+int RsaKeyToDer(RsaKey* key, byte* output, word32 inLen)
+{
+    word32 seqSz, verSz, rawLen, intTotalLen = 0;
+    word32 sizes[RSA_INTS];
+    int    i, j, outLen;
+
+    byte seq[MAX_SEQ_SZ];
+    byte ver[MAX_VERSION_SZ];
+    byte tmps[RSA_INTS][MAX_RSA_INT_SZ];
+
+    if (!key || !output)
+        return -1;
+
+    if (key->type != RSA_PRIVATE)
+        return -1;
+
+    /* write all big ints from key to DER tmps */
+    for (i = 0; i < RSA_INTS; i++) {
+        mp_int* keyInt = GetRsaInt(key, i);
+        rawLen = mp_unsigned_bin_size(keyInt);
+
+        tmps[i][0] = ASN_INTEGER;
+        sizes[i] = SetLength(rawLen, tmps[i] + 1) + 1;  /* int tag */
+
+        if ( (sizes[i] + rawLen) < sizeof(tmps[i])) {
+            int err = mp_to_unsigned_bin(keyInt, tmps[i] + sizes[i]);
+            if (err == MP_OKAY) {
+                sizes[i] += rawLen;
+                intTotalLen += sizes[i];
+            }
+            else
+                return err;
+        }
+        else
+            return -1;
+    }
+
+    /* make headers */
+    verSz = SetMyVersion(0, ver, FALSE);
+    seqSz = SetSequence(verSz + intTotalLen, seq);
+
+    outLen = seqSz + verSz + intTotalLen;
+    if (outLen > (int)inLen)
+        return -1;
+
+    /* write to output */
+    XMEMCPY(output, seq, seqSz);
+    j = seqSz;
+    XMEMCPY(output + j, ver, verSz);
+    j += verSz;
+
+    for (i = 0; i < RSA_INTS; i++) {
+        XMEMCPY(output + j, tmps[i], sizes[i]);
+        j += sizes[i];
+    }
+
+    return outLen;
+}
+
+#endif /* CYASSL_KEY_GEN */
+
+
+#ifdef CYASSL_CERT_GEN
+
+/* Initialize and Set Certficate defaults:
+   version    = 3 (0x2)
+   serial     = 0
+   sigType    = MD5_WITH_RSA
+   issuer     = blank
+   daysValid  = 500
+   selfSigned = 1 (true) use subject as issuer
+   subject    = blank
+*/
+void InitCert(Cert* cert)
+{
+    cert->version    = 2;   /* version 3 is hex 2 */
+    cert->sigType    = MD5wRSA;
+    cert->daysValid  = 500;
+    cert->selfSigned = 1;
+    cert->bodySz     = 0;
+    cert->keyType    = RSA_KEY;
+    XMEMSET(cert->serial, 0, SERIAL_SIZE);
+
+    cert->issuer.country[0] = '\0';
+    cert->issuer.state[0] = '\0';
+    cert->issuer.locality[0] = '\0';
+    cert->issuer.sur[0] = '\0';
+    cert->issuer.org[0] = '\0';
+    cert->issuer.unit[0] = '\0';
+    cert->issuer.commonName[0] = '\0';
+    cert->issuer.email[0] = '\0';
+
+    cert->subject.country[0] = '\0';
+    cert->subject.state[0] = '\0';
+    cert->subject.locality[0] = '\0';
+    cert->subject.sur[0] = '\0';
+    cert->subject.org[0] = '\0';
+    cert->subject.unit[0] = '\0';
+    cert->subject.commonName[0] = '\0';
+    cert->subject.email[0] = '\0';
+}
+
+
+/* DER encoded x509 Certificate */
+typedef struct DerCert {
+    byte size[MAX_LENGTH_SZ];          /* length encoded */
+    byte version[MAX_VERSION_SZ];      /* version encoded */
+    byte serial[SERIAL_SIZE + MAX_LENGTH_SZ]; /* serial number encoded */
+    byte sigAlgo[MAX_ALGO_SZ];         /* signature algo encoded */
+    byte issuer[ASN_NAME_MAX];         /* issuer  encoded */
+    byte subject[ASN_NAME_MAX];        /* subject encoded */
+    byte validity[MAX_DATE_SIZE*2 + MAX_SEQ_SZ*2];  /* before and after dates */
+    byte publicKey[MAX_PUBLIC_KEY_SZ]; /* rsa / ntru public key encoded */
+    int  sizeSz;                       /* encoded size length */
+    int  versionSz;                    /* encoded version length */
+    int  serialSz;                     /* encoded serial length */
+    int  sigAlgoSz;                    /* enocded sig alog length */
+    int  issuerSz;                     /* encoded issuer length */
+    int  subjectSz;                    /* encoded subject length */
+    int  validitySz;                   /* encoded validity length */
+    int  publicKeySz;                  /* encoded public key length */
+    int  total;                        /* total encoded lengths */
+} DerCert;
+
+
+/* Write a set header to output */
+static word32 SetSet(word32 len, byte* output)
+{
+    output[0] = ASN_SET | ASN_CONSTRUCTED;
+    return SetLength(len, output + 1) + 1;
+}
+
+
+/* Write a serial number to output */
+static int SetSerial(const byte* serial, byte* output)
+{
+    int length = 0;
+
+    output[length++] = ASN_INTEGER;
+    length += SetLength(SERIAL_SIZE, &output[length]);
+    XMEMCPY(&output[length], serial, SERIAL_SIZE);
+
+    return length + SERIAL_SIZE;
+}
+
+
+/* Write a public RSA key to output */
+static int SetPublicKey(byte* output, RsaKey* key)
+{
+    byte n[MAX_RSA_INT_SZ];
+    byte e[MAX_RSA_E_SZ];
+    byte algo[MAX_ALGO_SZ];
+    byte seq[MAX_SEQ_SZ];
+    byte len[MAX_LENGTH_SZ + 1];  /* trailing 0 */
+    int  nSz;
+    int  eSz;
+    int  algoSz;
+    int  seqSz;
+    int  lenSz;
+    int  idx;
+    int  rawLen;
+
+    /* n */
+    rawLen = mp_unsigned_bin_size(&key->n);
+    n[0] = ASN_INTEGER;
+    nSz  = SetLength(rawLen, n + 1) + 1;  /* int tag */
+
+    if ( (nSz + rawLen) < sizeof(n)) {
+        int err = mp_to_unsigned_bin(&key->n, n + nSz);
+        if (err == MP_OKAY)
+            nSz += rawLen;
+        else
+            return MP_TO_E;
+    }
+    else
+        return BUFFER_E;
+
+    /* e */
+    rawLen = mp_unsigned_bin_size(&key->e);
+    e[0] = ASN_INTEGER;
+    eSz  = SetLength(rawLen, e + 1) + 1;  /* int tag */
+
+    if ( (eSz + rawLen) < sizeof(e)) {
+        int err = mp_to_unsigned_bin(&key->e, e + eSz);
+        if (err == MP_OKAY)
+            eSz += rawLen;
+        else
+            return MP_TO_E;
+    }
+    else
+        return BUFFER_E;
+
+    /* headers */
+    algoSz = SetAlgoID(RSAk, algo, keyType);
+    seqSz  = SetSequence(nSz + eSz, seq);
+    lenSz  = SetLength(seqSz + nSz + eSz + 1, len);
+    len[lenSz++] = 0;   /* trailing 0 */
+
+    /* write */
+    idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output);
+        /* 1 is for ASN_BIT_STRING */
+    /* algo */
+    XMEMCPY(output + idx, algo, algoSz);
+    idx += algoSz;
+    /* bit string */
+    output[idx++] = ASN_BIT_STRING;
+    /* length */
+    XMEMCPY(output + idx, len, lenSz);
+    idx += lenSz;
+    /* seq */
+    XMEMCPY(output + idx, seq, seqSz);
+    idx += seqSz;
+    /* n */
+    XMEMCPY(output + idx, n, nSz);
+    idx += nSz;
+    /* e */
+    XMEMCPY(output + idx, e, eSz);
+    idx += eSz;
+
+    return idx;
+}
+
+
+static INLINE byte itob(int number)
+{
+    return (byte)number + 0x30;
+}
+
+
+/* write time to output, format */
+static void SetTime(struct tm* date, byte* output)
+{
+    int i = 0;
+
+    output[i++] = itob((date->tm_year % 10000) / 1000);
+    output[i++] = itob((date->tm_year % 1000)  /  100);
+    output[i++] = itob((date->tm_year % 100)   /   10);
+    output[i++] = itob( date->tm_year % 10);
+
+    output[i++] = itob(date->tm_mon / 10);
+    output[i++] = itob(date->tm_mon % 10);
+
+    output[i++] = itob(date->tm_mday / 10);
+    output[i++] = itob(date->tm_mday % 10);
+
+    output[i++] = itob(date->tm_hour / 10);
+    output[i++] = itob(date->tm_hour % 10);
+
+    output[i++] = itob(date->tm_min / 10);
+    output[i++] = itob(date->tm_min % 10);
+
+    output[i++] = itob(date->tm_sec / 10);
+    output[i++] = itob(date->tm_sec % 10);
+    
+    output[i] = 'Z';  /* Zulu profiel */
+}
+
+
+/* Set Date validity from now until now + daysValid */
+static int SetValidity(byte* output, int daysValid)
+{
+    byte before[MAX_DATE_SIZE];
+    byte  after[MAX_DATE_SIZE];
+
+    int beforeSz;
+    int afterSz;
+    int seqSz;
+
+    time_t     ticks;
+    struct tm* now;
+    struct tm  local;
+
+    ticks = XTIME(0);
+    now   = XGMTIME(&ticks);
+
+    /* before now */
+    local = *now;
+    before[0] = ASN_GENERALIZED_TIME;
+    beforeSz  = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1;  /* gen tag */
+
+    /* adjust */
+    local.tm_year += 1900;
+    local.tm_mon  +=    1;
+
+    SetTime(&local, before + beforeSz);
+    beforeSz += ASN_GEN_TIME_SZ;
+    
+    /* after now + daysValid */
+    local = *now;
+    after[0] = ASN_GENERALIZED_TIME;
+    afterSz  = SetLength(ASN_GEN_TIME_SZ, after + 1) + 1;  /* gen tag */
+
+    /* add daysValid */
+    local.tm_mday += daysValid;
+    mktime(&local);
+
+    /* adjust */
+    local.tm_year += 1900;
+    local.tm_mon  +=    1;
+
+    SetTime(&local, after + afterSz);
+    afterSz += ASN_GEN_TIME_SZ;
+
+    /* headers and output */
+    seqSz = SetSequence(beforeSz + afterSz, output);
+    XMEMCPY(output + seqSz, before, beforeSz);
+    XMEMCPY(output + seqSz + beforeSz, after, afterSz);
+
+    return seqSz + beforeSz + afterSz;
+}
+
+
+/* ASN Encoded Name field */
+typedef struct EncodedName {
+    int  nameLen;                /* actual string value length */
+    int  totalLen;               /* total encodeding length */
+    int  type;                   /* type of name */
+    int  used;                   /* are we actually using this one */
+    byte encoded[NAME_SIZE * 2]; /* encoding */
+} EncodedName;
+
+
+/* Get Which Name from index */
+static const char* GetOneName(CertName* name, int index)
+{
+    switch (index) {
+    case 0:
+       return name->country;
+       break;
+    case 1:
+       return name->state;
+       break;
+    case 2:
+       return name->locality;
+       break;
+    case 3:
+       return name->sur;
+       break;
+    case 4:
+       return name->org;
+       break;
+    case 5:
+       return name->unit;
+       break;
+    case 6:
+       return name->commonName;
+       break;
+    case 7:
+       return name->email;
+       break;
+    default:
+       return 0;
+    }
+
+    return 0;
+}
+
+
+/* Get ASN Name from index */
+static byte GetNameId(int index)
+{
+    switch (index) {
+    case 0:
+       return ASN_COUNTRY_NAME;
+       break;
+    case 1:
+       return ASN_STATE_NAME;
+       break;
+    case 2:
+       return ASN_LOCALITY_NAME;
+       break;
+    case 3:
+       return ASN_SUR_NAME;
+       break;
+    case 4:
+       return ASN_ORG_NAME;
+       break;
+    case 5:
+       return ASN_ORGUNIT_NAME;
+       break;
+    case 6:
+       return ASN_COMMON_NAME;
+       break;
+    case 7:
+       /* email uses different id type */
+       return 0;
+       break;
+    default:
+       return 0;
+    }
+
+    return 0;
+}
+
+
+/* encode CertName into output, return total bytes written */
+static int SetName(byte* output, CertName* name)
+{
+    int         totalBytes = 0, i, idx;
+    EncodedName names[NAME_ENTRIES];
+
+    for (i = 0; i < NAME_ENTRIES; i++) {
+        const char* nameStr = GetOneName(name, i);
+        if (nameStr) {
+            /* bottom up */
+            byte firstLen[MAX_LENGTH_SZ];
+            byte secondLen[MAX_LENGTH_SZ];
+            byte sequence[MAX_SEQ_SZ];
+            byte set[MAX_SET_SZ];
+
+            int email = i == (NAME_ENTRIES - 1) ? 1 : 0;
+            int strLen  = XSTRLEN(nameStr);
+            int thisLen = strLen;
+            int firstSz, secondSz, seqSz, setSz;
+
+            if (strLen == 0) { /* no user data for this item */
+                names[i].used = 0;
+                continue;
+            }
+
+            secondSz = SetLength(strLen, secondLen);
+            thisLen += secondSz;
+            if (email) {
+                thisLen += EMAIL_JOINT_LEN;
+                thisLen ++;                               /* id type */
+                firstSz  = SetLength(EMAIL_JOINT_LEN, firstLen);
+            }
+            else {
+                thisLen++;                                 /* str type */
+                thisLen++;                                 /* id  type */
+                thisLen += JOINT_LEN;    
+                firstSz = SetLength(JOINT_LEN + 1, firstLen);
+            }
+            thisLen += firstSz;
+            thisLen++;                                /* object id */
+
+            seqSz = SetSequence(thisLen, sequence);
+            thisLen += seqSz;
+            setSz = SetSet(thisLen, set);
+            thisLen += setSz;
+
+            if (thisLen > sizeof(names[i].encoded))
+                return BUFFER_E;
+
+            /* store it */
+            idx = 0;
+            /* set */
+            XMEMCPY(names[i].encoded, set, setSz);
+            idx += setSz;
+            /* seq */
+            XMEMCPY(names[i].encoded + idx, sequence, seqSz);
+            idx += seqSz;
+            /* asn object id */
+            names[i].encoded[idx++] = ASN_OBJECT_ID;
+            /* first length */
+            XMEMCPY(names[i].encoded + idx, firstLen, firstSz);
+            idx += firstSz;
+            if (email) {
+                const byte EMAIL_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                           0x01, 0x09, 0x01, 0x16 };
+                /* email joint id */
+                XMEMCPY(names[i].encoded + idx, EMAIL_OID, sizeof(EMAIL_OID));
+                idx += sizeof(EMAIL_OID);
+            }
+            else {
+                /* joint id */
+                names[i].encoded[idx++] = 0x55;
+                names[i].encoded[idx++] = 0x04;
+                /* id type */
+                names[i].encoded[idx++] = GetNameId(i);
+                /* str type */
+                names[i].encoded[idx++] = 0x13;
+            }
+            /* second length */
+            XMEMCPY(names[i].encoded + idx, secondLen, secondSz);
+            idx += secondSz;
+            /* str value */
+            XMEMCPY(names[i].encoded + idx, nameStr, strLen);
+            idx += strLen;
+
+            totalBytes += idx;
+            names[i].totalLen = idx;
+            names[i].used = 1;
+        }
+        else
+            names[i].used = 0;
+    }
+
+    /* header */
+    idx = SetSequence(totalBytes, output);
+    totalBytes += idx;
+    if (totalBytes > ASN_NAME_MAX)
+        return BUFFER_E;
+
+    for (i = 0; i < NAME_ENTRIES; i++) {
+        if (names[i].used) {
+            XMEMCPY(output + idx, names[i].encoded, names[i].totalLen);
+            idx += names[i].totalLen;
+        }
+    }
+    return totalBytes;
+}
+
+
+/* encode info from cert into DER enocder format */
+static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, RNG* rng,
+                      const byte* ntruKey, word16 ntruSz)
+{
+    /* version */
+    der->versionSz = SetMyVersion(cert->version, der->version, TRUE);
+
+    /* serial number */
+    RNG_GenerateBlock(rng, cert->serial, SERIAL_SIZE);
+    cert->serial[0] = 0x01;   /* ensure positive */
+    der->serialSz  = SetSerial(cert->serial, der->serial);
+
+    /* signature algo */
+    der->sigAlgoSz = SetAlgoID(cert->sigType, der->sigAlgo, sigType);
+    if (der->sigAlgoSz == 0)
+        return ALGO_ID_E;
+
+    /* public key */
+    if (cert->keyType == RSA_KEY) {
+        der->publicKeySz = SetPublicKey(der->publicKey, rsaKey);
+        if (der->publicKeySz == 0)
+            return PUBLIC_KEY_E;
+    }
+    else {
+#ifdef HAVE_NTRU
+        word32 rc;
+        word16 encodedSz;
+
+        rc  = crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz,
+                                              ntruKey, &encodedSz, NULL);
+        if (rc != NTRU_OK)
+            return PUBLIC_KEY_E;
+        if (encodedSz > MAX_PUBLIC_KEY_SZ)
+            return PUBLIC_KEY_E;
+
+        rc  = crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz,
+                              ntruKey, &encodedSz, der->publicKey);
+        if (rc != NTRU_OK)
+            return PUBLIC_KEY_E;
+
+        der->publicKeySz = encodedSz;
+#endif
+    }
+
+    /* date validity */
+    der->validitySz = SetValidity(der->validity, cert->daysValid);
+    if (der->validitySz == 0)
+        return DATE_E;
+
+    /* subject name */
+    der->subjectSz = SetName(der->subject, &cert->subject);
+    if (der->subjectSz == 0)
+        return SUBJECT_E;
+
+    /* issuer name */
+    der->issuerSz = SetName(der->issuer, cert->selfSigned ?
+             &cert->subject : &cert->issuer);
+    if (der->issuerSz == 0)
+        return ISSUER_E;
+
+    der->total = der->versionSz + der->serialSz + der->sigAlgoSz +
+        der->publicKeySz + der->validitySz + der->subjectSz + der->issuerSz;
+
+    return 0;
+}
+
+
+/* write DER encoded cert to buffer, size already checked */
+static int WriteCertBody(DerCert* der, byte* buffer)
+{
+    int idx;
+
+    /* signed part header */
+    idx = SetSequence(der->total, buffer);
+    /* version */
+    XMEMCPY(buffer + idx, der->version, der->versionSz);
+    idx += der->versionSz;
+    /* serial */
+    XMEMCPY(buffer + idx, der->serial, der->serialSz);
+    idx += der->serialSz;
+    /* sig algo */
+    XMEMCPY(buffer + idx, der->sigAlgo, der->sigAlgoSz);
+    idx += der->sigAlgoSz;
+    /* issuer */
+    XMEMCPY(buffer + idx, der->issuer, der->issuerSz);
+    idx += der->issuerSz;
+    /* validity */
+    XMEMCPY(buffer + idx, der->validity, der->validitySz);
+    idx += der->validitySz;
+    /* subject */
+    XMEMCPY(buffer + idx, der->subject, der->subjectSz);
+    idx += der->subjectSz;
+    /* public key */
+    XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz);
+    idx += der->publicKeySz;
+
+    return idx;
+}
+
+
+/* Make MD5wRSA signature from buffer (sz), write to sig (sigSz) */
+static int MakeSignature(const byte* buffer, int sz, byte* sig, int sigSz,
+                         RsaKey* key, RNG* rng)
+{
+    byte    digest[SHA_DIGEST_SIZE];     /* max size */
+    byte    encSig[MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ];
+    int     encSigSz, digestSz, hashType;
+    Md5     md5;                         /* md5 for now */
+
+    InitMd5(&md5);
+    Md5Update(&md5, buffer, sz);
+    Md5Final(&md5, digest);
+    digestSz = MD5_DIGEST_SIZE;
+    hashType = MD5h;
+
+    /* signature */
+    encSigSz = EncodeSignature(encSig, digest, digestSz, hashType);
+    return RsaSSL_Sign(encSig, encSigSz, sig, sigSz, key, rng);
+}
+
+
+/* add signature to end of buffer, size of buffer assumed checked, return
+   new length */
+static int AddSignature(byte* buffer, int bodySz, const byte* sig, int sigSz)
+{
+    byte seq[MAX_SEQ_SZ];
+    int  idx = bodySz, seqSz;
+
+    /* algo */
+    idx += SetAlgoID(MD5wRSA, buffer + idx, sigType);
+    /* bit string */
+    buffer[idx++] = ASN_BIT_STRING;
+    /* length */
+    idx += SetLength(sigSz + 1, buffer + idx);
+    buffer[idx++] = 0;   /* trailing 0 */
+    /* signature */
+    XMEMCPY(buffer + idx, sig, sigSz);
+    idx += sigSz;
+
+    /* make room for overall header */
+    seqSz = SetSequence(idx, seq);
+    XMEMMOVE(buffer + seqSz, buffer, idx);
+    XMEMCPY(buffer, seq, seqSz);
+
+    return idx + seqSz;
+}
+
+
+/* Make an x509 Certificate v3 any key type from cert input, write to buffer */
+static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz,
+                   RsaKey* rsaKey, RNG* rng, const byte* ntruKey, word16 ntruSz)
+{
+    DerCert der;
+    int     ret;
+
+    cert->keyType = rsaKey ? RSA_KEY : NTRU_KEY;
+    ret = EncodeCert(cert, &der, rsaKey, rng, ntruKey, ntruSz);
+    if (ret != 0)
+        return ret;
+
+    if (der.total + MAX_SEQ_SZ * 2 > (int)derSz)
+        return BUFFER_E;
+
+    return cert->bodySz = WriteCertBody(&der, derBuffer);
+}
+
+
+/* Make an x509 Certificate v3 RSA from cert input, write to buffer */
+int MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey,RNG* rng)
+{
+    return MakeAnyCert(cert, derBuffer, derSz, rsaKey, rng, NULL, 0);
+}
+
+
+#ifdef HAVE_NTRU
+
+int  MakeNtruCert(Cert* cert, byte* derBuffer, word32 derSz,
+                  const byte* ntruKey, word16 keySz, RNG* rng)
+{
+    return MakeAnyCert(cert, derBuffer, derSz, NULL, rng, ntruKey, keySz);
+}
+
+#endif /* HAVE_NTRU */
+
+
+int SignCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng)
+{
+    byte    sig[MAX_ENCODED_SIG_SZ];
+    int     sigSz;
+    int     bodySz = cert->bodySz;
+
+    if (bodySz < 0)
+        return bodySz;
+
+    sigSz  = MakeSignature(buffer, bodySz, sig, sizeof(sig), key, rng);
+    if (sigSz < 0)
+        return sigSz; 
+
+    if (bodySz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz)
+        return BUFFER_E; 
+
+    return AddSignature(buffer, bodySz, sig, sigSz);
+}
+
+
+int MakeSelfCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng)
+{
+    int ret = MakeCert(cert, buffer, buffSz, key, rng);
+
+    if (ret < 0)
+        return ret;
+
+    return SignCert(cert, buffer, buffSz, key, rng);
+}
+
+
+/* forward from CyaSSL */
+int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz);
+
+#ifndef NO_FILESYSTEM
+
+int SetIssuer(Cert* cert, const char* issuerCertFile)
+{
+    DecodedCert decoded;
+    byte        der[8192];
+    int         derSz = CyaSSL_PemCertToDer(issuerCertFile, der, sizeof(der));
+    int         ret;
+    int         sz;
+
+    if (derSz < 0)
+        return derSz;
+
+    cert->selfSigned = 0;
+
+    InitDecodedCert(&decoded, der, 0);
+    ret = ParseCertRelative(&decoded, derSz, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0)
+        return ret;
+
+    if (decoded.subjectCN) {
+        sz = (decoded.subjectCNLen < NAME_SIZE) ? decoded.subjectCNLen :
+                                                  NAME_SIZE - 1;
+        strncpy(cert->issuer.commonName, decoded.subjectCN, NAME_SIZE);
+        cert->issuer.commonName[sz] = 0;
+    }
+    if (decoded.subjectC) {
+        sz = (decoded.subjectCLen < NAME_SIZE) ? decoded.subjectCLen :
+                                                 NAME_SIZE - 1;
+        strncpy(cert->issuer.country, decoded.subjectC, NAME_SIZE);
+        cert->issuer.country[sz] = 0;
+    }
+    if (decoded.subjectST) {
+        sz = (decoded.subjectSTLen < NAME_SIZE) ? decoded.subjectSTLen :
+                                                  NAME_SIZE - 1;
+        strncpy(cert->issuer.state, decoded.subjectST, NAME_SIZE);
+        cert->issuer.state[sz] = 0;
+    }
+    if (decoded.subjectL) {
+        sz = (decoded.subjectLLen < NAME_SIZE) ? decoded.subjectLLen :
+                                                 NAME_SIZE - 1;
+        strncpy(cert->issuer.locality, decoded.subjectL, NAME_SIZE);
+        cert->issuer.locality[sz] = 0;
+    }
+    if (decoded.subjectO) {
+        sz = (decoded.subjectOLen < NAME_SIZE) ? decoded.subjectOLen :
+                                                 NAME_SIZE - 1;
+        strncpy(cert->issuer.org, decoded.subjectO, NAME_SIZE);
+        cert->issuer.org[sz] = 0;
+    }
+    if (decoded.subjectOU) {
+        sz = (decoded.subjectOULen < NAME_SIZE) ? decoded.subjectOULen :
+                                                  NAME_SIZE - 1;
+        strncpy(cert->issuer.unit, decoded.subjectOU, NAME_SIZE);
+        cert->issuer.unit[sz] = 0;
+    }
+    if (decoded.subjectSN) {
+        sz = (decoded.subjectSNLen < NAME_SIZE) ? decoded.subjectSNLen :
+                                                  NAME_SIZE - 1;
+        strncpy(cert->issuer.sur, decoded.subjectSN, NAME_SIZE);
+        cert->issuer.sur[sz] = 0;
+    }
+    if (decoded.subjectEmail) {
+        sz = (decoded.subjectEmailLen < NAME_SIZE) ? decoded.subjectEmailLen :
+                                                     NAME_SIZE - 1;
+        strncpy(cert->issuer.email, decoded.subjectEmail, NAME_SIZE);
+        cert->issuer.email[sz] = 0;
+    }
+
+    FreeDecodedCert(&decoded);
+
+    return 0;
+}
+
+#endif /* NO_FILESYSTEM */
+#endif /* CYASSL_CERT_GEN */
diff -r 000000000000 -r 5045d2638c29 asn.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/asn.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,290 @@
+/* asn.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_ASN_H
+#define CTAO_CRYPT_ASN_H
+
+#include "types.h"
+#include "ctc_rsa.h"
+#include "ctc_dh.h"
+#include "ctc_dsa.h"
+#include "ctc_sha.h"
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* ASN Tags   */
+enum ASN_Tags {        
+    ASN_INTEGER           = 0x02,
+    ASN_BIT_STRING        = 0x03,
+    ASN_OCTET_STRING      = 0x04,
+    ASN_TAG_NULL          = 0x05,
+    ASN_OBJECT_ID         = 0x06,
+    ASN_SEQUENCE          = 0x10,
+    ASN_SET               = 0x11,
+    ASN_UTC_TIME          = 0x17,
+    ASN_GENERALIZED_TIME  = 0x18,
+    ASN_LONG_LENGTH       = 0x80
+};
+
+
+enum  ASN_Flags{
+    ASN_CONSTRUCTED       = 0x20,
+    ASN_CONTEXT_SPECIFIC  = 0x80
+};
+
+enum DN_Tags {
+    ASN_COMMON_NAME   = 0x03,   /* CN */
+    ASN_SUR_NAME      = 0x04,   /* SN */
+    ASN_COUNTRY_NAME  = 0x06,   /* C  */
+    ASN_LOCALITY_NAME = 0x07,   /* L  */
+    ASN_STATE_NAME    = 0x08,   /* ST */
+    ASN_ORG_NAME      = 0x0a,   /* O  */
+    ASN_ORGUNIT_NAME  = 0x0b    /* OU */
+};
+
+enum Misc_ASN { 
+    ASN_NAME_MAX        = 256,    
+    SHA_SIZE            =  20,
+    RSA_INTS            =   8,     /* RSA ints in private key */
+    MIN_DATE_SIZE       =  13,
+    MAX_DATE_SIZE       =  32,
+    ASN_GEN_TIME_SZ     =  15,     /* 7 numbers * 2 + Zulu tag */
+    MAX_ENCODED_SIG_SZ  = 512,
+    MAX_SIG_SZ          = 256,
+    MAX_ALGO_SZ         =  20,
+    MAX_SEQ_SZ          =   5,     /* enum(seq | con) + length(4) */  
+    MAX_SET_SZ          =   5,     /* enum(set | con) + length(4) */  
+    MAX_VERSION_SZ      =   5,     /* enum + id + version(byte) + (header(2))*/
+    MAX_ENCODED_DIG_SZ  =  25,     /* sha + enum(bit or octet) + legnth(4) */
+    MAX_RSA_INT_SZ      = 517,     /* RSA raw sz 4096 for bits + tag + len(4) */
+    MAX_NTRU_KEY_SZ     = 610,     /* NTRU 112 bit public key */
+    MAX_NTRU_ENC_SZ     = 628,     /* NTRU 112 bit DER public encoding */
+    MAX_RSA_E_SZ        =  16,     /* Max RSA public e size */
+    MAX_PUBLIC_KEY_SZ   = MAX_NTRU_ENC_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ * 2, 
+                                   /* use bigger NTRU size */
+    MAX_LENGTH_SZ       =   4 
+};
+
+
+enum Oid_Types {
+    hashType = 0,
+    sigType  = 1,
+    keyType  = 2
+};
+
+
+enum Sig_Sum  {
+    SHAwDSA = 517,
+    MD2wRSA = 646,
+    MD5wRSA = 648,
+    SHAwRSA = 649
+};
+
+enum Hash_Sum  {
+    MD2h  = 646,
+    MD5h  = 649,
+    SHAh  =  88
+};
+
+enum Key_Sum {
+    DSAk  = 515,
+    RSAk  = 645,
+    NTRUk = 364
+};
+
+
+/* Certificate file Type */
+enum CertType {
+    CERT_TYPE       = 0, 
+    PRIVATEKEY_TYPE,
+    CA_TYPE
+};
+
+
+enum VerifyType {
+    NO_VERIFY = 0,
+    VERIFY    = 1
+};
+
+
+typedef struct DecodedCert {
+    byte*   publicKey;
+    word32  pubKeySize;
+    int     pubKeyStored;
+    word32  certBegin;               /* offset to start of cert          */
+    word32  sigIndex;                /* offset to start of signature     */
+    word32  sigLength;               /* length of signature              */
+    word32  signatureOID;            /* sum of algorithm object id       */
+    word32  keyOID;                  /* sum of key algo  object id       */
+    byte    subjectHash[SHA_SIZE];   /* hash of all Names                */
+    byte    issuerHash[SHA_SIZE];    /* hash of all Names                */
+    byte*   signature;               /* not owned, points into raw cert  */
+    char*   subjectCN;               /* CommonName                       */
+    int     subjectCNLen;
+    char    issuer[ASN_NAME_MAX];    /* full name including common name  */
+    char    subject[ASN_NAME_MAX];   /* full name including common name  */
+    int     verify;                  /* Default to yes, but could be off */
+    byte*   source;                  /* byte buffer holder cert, NOT owner */
+    word32  srcIdx;                  /* current offset into buffer       */
+    void*   heap;                    /* for user memory overrides        */
+#ifdef CYASSL_CERT_GEN
+    /* easy access to sujbect info for other sign */
+    char*   subjectSN;
+    int     subjectSNLen;
+    char*   subjectC;
+    int     subjectCLen;
+    char*   subjectL;
+    int     subjectLLen;
+    char*   subjectST;
+    int     subjectSTLen;
+    char*   subjectO;
+    int     subjectOLen;
+    char*   subjectOU;
+    int     subjectOULen;
+    char*   subjectEmail;
+    int     subjectEmailLen;
+#endif /* CYASSL_CERT_GEN */
+} DecodedCert;
+
+
+typedef struct Signer Signer;
+
+/* CA Signers */
+struct Signer {
+    byte*   publicKey;
+    word32  pubKeySize;
+    word32  keyOID;                  /* key type */
+    char*   name;                    /* common name */
+    byte    hash[SHA_DIGEST_SIZE];   /* sha hash of names in certificate */
+    Signer* next;
+};
+
+
+void InitDecodedCert(DecodedCert*, byte*, void*);
+void FreeDecodedCert(DecodedCert*);
+int  ParseCert(DecodedCert*, word32, int type, int verify, Signer* signer);
+int  ParseCertRelative(DecodedCert*, word32, int type, int verify,
+                       Signer* signer);
+
+word32 EncodeSignature(byte* out, const byte* digest, word32 digSz,int hashOID);
+
+Signer* MakeSigner(void*);
+void    FreeSigners(Signer*, void*);
+
+
+int RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey*, word32);
+int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey*, word32);
+int ToTraditional(byte* buffer, word32 length);
+
+#ifndef NO_DH
+int DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32);
+int DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz);
+#endif
+
+#ifndef NO_DSA
+int DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey*, word32);
+int DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey*, word32);
+#endif
+
+#ifdef CYASSL_KEY_GEN
+int RsaKeyToDer(RsaKey*, byte* output, word32 inLen);
+#endif
+
+
+#if defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN)
+int DerToPem(const byte* der, word32 derSz, byte* output, word32 outputSz,
+             int type);
+#endif
+
+#ifdef CYASSL_CERT_GEN
+
+enum cert_enums {
+    SERIAL_SIZE     =  8,
+    NAME_SIZE       = 64,
+    NAME_ENTRIES    =  8,
+    JOINT_LEN       =  2,
+    EMAIL_JOINT_LEN =  9,
+    RSA_KEY         = 10,
+    NTRU_KEY        = 11
+};
+
+
+typedef struct CertName {
+    char country[NAME_SIZE];
+    char state[NAME_SIZE];
+    char locality[NAME_SIZE];
+    char sur[NAME_SIZE];
+    char org[NAME_SIZE];
+    char unit[NAME_SIZE];
+    char commonName[NAME_SIZE];
+    char email[NAME_SIZE];  /* !!!! email has to be last !!!! */
+} CertName;
+
+
+/* for user to fill for certificate generation */
+typedef struct Cert {
+    int      version;                   /* x509 version  */
+    byte     serial[SERIAL_SIZE];       /* serial number */
+    int      sigType;                   /* signature algo type */
+    CertName issuer;                    /* issuer info */
+    int      daysValid;                 /* validity days */
+    int      selfSigned;                /* self signed flag */
+    CertName subject;                   /* subject info */
+    /* internal use only */
+    int      bodySz;                    /* pre sign total size */
+    int      keyType;                   /* public key type of subject */
+} Cert;
+
+
+/* Initialize and Set Certficate defaults:
+   version    = 3 (0x2)
+   serial     = 0 (Will be randomly generated)
+   sigType    = MD5_WITH_RSA
+   issuer     = blank
+   daysValid  = 500
+   selfSigned = 1 (true) use subject as issuer
+   subject    = blank
+   keyType    = RSA_KEY (default)
+*/
+void InitCert(Cert*);
+int  MakeCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*, RNG*);
+int  SignCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*, RNG*);
+int  MakeSelfCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*, RNG*);
+int  SetIssuer(Cert*, const char*);
+#ifdef HAVE_NTRU
+int  MakeNtruCert(Cert*, byte* derBuffer, word32 derSz, const byte* ntruKey,
+                  word16 keySz, RNG*);
+#endif
+
+
+#endif /* CYASSL_CERT_GEN */
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_ASN_H */
+
diff -r 000000000000 -r 5045d2638c29 coding.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/coding.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,229 @@
+/* coding.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include "coding.h"
+
+
+enum {
+    BAD         = 0xFF,  /* invalid encoding */
+    PAD         = '=',
+    PEM_LINE_SZ = 64
+};
+
+
+static
+const byte base64Decode[] = { 62, BAD, BAD, BAD, 63,   /* + starts at 0x2B */
+                              52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+                              BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                              0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+                              10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+                              20, 21, 22, 23, 24, 25,
+                              BAD, BAD, BAD, BAD, BAD, BAD,
+                              26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+                              36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+                              46, 47, 48, 49, 50, 51
+                            };
+
+
+int Base64Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    word32 i = 0;
+    word32 j = 0;
+    word32 plainSz = inLen - ((inLen + (PEM_LINE_SZ - 1)) / PEM_LINE_SZ );
+
+    plainSz = (plainSz * 3 + 3) / 4;
+    if (plainSz > *outLen) return -1;
+
+    while (inLen > 3) {
+        byte b1, b2, b3;
+        byte e1 = in[j++];
+        byte e2 = in[j++];
+        byte e3 = in[j++];
+        byte e4 = in[j++];
+
+        int pad3 = 0;
+        int pad4 = 0;
+
+        if (e1 == 0)            /* end file 0's */
+            break;
+        if (e3 == PAD)
+            pad3 = 1;
+        if (e4 == PAD)
+            pad4 = 1;
+
+        e1 = base64Decode[e1 - 0x2B];
+        e2 = base64Decode[e2 - 0x2B];
+        e3 = (e3 == PAD) ? 0 : base64Decode[e3 - 0x2B];
+        e4 = (e4 == PAD) ? 0 : base64Decode[e4 - 0x2B];
+
+        b1 = (e1 << 2) | (e2 >> 4);
+        b2 = ((e2 & 0xF) << 4) | (e3 >> 2);
+        b3 = ((e3 & 0x3) << 6) | e4;
+
+        out[i++] = b1;
+        if (!pad3)
+            out[i++] = b2;
+        if (!pad4)
+            out[i++] = b3;
+        else
+            break;
+        
+        inLen -= 4;
+        if (in[j] == ' ' || in[j] == '\r' || in[j] == '\n') {
+            byte endLine = in[j++];
+            inLen--;
+            while (endLine == ' ') {   /* allow trailing whitespace */
+                endLine = in[j++];
+                inLen--;
+            }
+            if (endLine == '\r') {
+                endLine = in[j++];
+                inLen--;
+            }
+            if (endLine != '\n')
+                return -1;
+        }
+    }
+    *outLen = i;
+
+    return 0;
+}
+
+
+#if defined(OPENSSL_EXTRA) || defined (SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN)
+
+static
+const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+                              'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+                              'U', 'V', 'W', 'X', 'Y', 'Z',
+                              'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+                              'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+                              'u', 'v', 'w', 'x', 'y', 'z',
+                              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+                              '+', '/'
+                            };
+
+
+/* porting assistance from yaSSL by Raphael HUCK */
+int Base64Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    word32 i = 0,
+           j = 0,
+           n = 0;   /* new line counter */
+
+    word32 outSz = (inLen + 3 - 1) / 3 * 4;
+    outSz += (outSz + PEM_LINE_SZ - 1) / PEM_LINE_SZ;  /* new lines */
+
+    if (outSz > *outLen) return -1;
+    
+    while (inLen > 2) {
+        byte b1 = in[j++];
+        byte b2 = in[j++];
+        byte b3 = in[j++];
+
+        /* encoded idx */
+        byte e1 = b1 >> 2;
+        byte e2 = ((b1 & 0x3) << 4) | (b2 >> 4);
+        byte e3 = ((b2 & 0xF) << 2) | (b3 >> 6);
+        byte e4 = b3 & 0x3F;
+
+        /* store */
+        out[i++] = base64Encode[e1];
+        out[i++] = base64Encode[e2];
+        out[i++] = base64Encode[e3];
+        out[i++] = base64Encode[e4];
+
+        inLen -= 3;
+
+        if ((++n % (PEM_LINE_SZ / 4)) == 0 && inLen)
+            out[i++] = '\n';
+    }
+
+    /* last integral */
+    if (inLen) {
+        int twoBytes = (inLen == 2);
+
+        byte b1 = in[j++];
+        byte b2 = (twoBytes) ? in[j++] : 0;
+
+        byte e1 = b1 >> 2;
+        byte e2 = ((b1 & 0x3) << 4) | (b2 >> 4);
+        byte e3 =  (b2 & 0xF) << 2;
+
+        out[i++] = base64Encode[e1];
+        out[i++] = base64Encode[e2];
+        out[i++] = (twoBytes) ? base64Encode[e3] : PAD;
+        out[i++] = PAD;
+    } 
+
+    out[i++] = '\n';
+    if (i != outSz)
+        return -1;
+    *outLen = outSz;
+
+    return 0; 
+}
+
+
+static
+const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+                           BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                           10, 11, 12, 13, 14, 15 
+                         };  /* A starts at 0x41 not 0x3A */
+
+int Base16Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    word32 inIdx  = 0;
+    word32 outIdx = 0;
+
+    if (inLen % 2)
+        return -1;
+
+    if (*outLen < (inLen / 2))
+        return -1;
+
+    while (inLen) {
+        byte b  = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
+        byte b2 = in[inIdx++] - 0x30;
+
+        /* sanity checks */
+        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
+            return -1;
+        if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0]))
+            return -1;
+
+        b  = hexDecode[b];
+        b2 = hexDecode[b2];
+
+        if (b == BAD || b2 == BAD)
+            return -1;
+        
+        out[outIdx++] = (b << 4) | b2;
+        inLen -= 2;
+    }
+
+    *outLen = outIdx;
+    return 0;
+}
+
+
+#endif  /* OPENSSL_EXTRA */
diff -r 000000000000 -r 5045d2638c29 coding.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/coding.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,47 @@
+/* coding.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_CODING_H
+#define CTAO_CRYPT_CODING_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* decode needed by CyaSSL */
+int Base64Decode(const byte* in, word32 inLen, byte* out, word32* outLen);
+
+#if defined(OPENSSL_EXTRA) || defined(SESSION_CERTS) || defined(CYASSL_KEY_GEN)  || defined(CYASSL_CERT_GEN)
+    /* encode isn't */
+    int Base64Encode(const byte* in, word32 inLen, byte* out, word32* outLen);
+    int Base16Decode(const byte* in, word32 inLen, byte* out, word32* outLen);
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_CODING_H */
+
diff -r 000000000000 -r 5045d2638c29 ctc_aes.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctc_aes.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,84 @@
+/* ctc_aes.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef NO_AES
+
+#ifndef CTAO_CRYPT_AES_H
+#define CTAO_CRYPT_AES_H
+
+
+#include "types.h"
+
+#ifdef CYASSL_AESNI
+
+#include <wmmintrin.h>
+
+#if !defined (ALIGN16)
+    #if defined (__GNUC__)
+        #define ALIGN16 __attribute__ ( (aligned (16)))
+    #elif defined(_MSC_VER)
+        #define ALIGN16 __declspec (align (16))
+    #else
+        #define ALIGN16
+    #endif
+#endif
+
+#endif /* CYASSL_AESNI */
+
+#if !defined (ALIGN16)
+    #define ALIGN16
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum {
+    AES_ENCRYPTION = 0,
+    AES_DECRYPTION = 1,
+    AES_BLOCK_SIZE = 16
+};
+
+
+typedef struct Aes {
+    /* AESNI needs key first, rounds 2nd, not sure why yet */
+    ALIGN16 word32 key[60];
+    word32  rounds;
+
+    ALIGN16 word32 reg[AES_BLOCK_SIZE / sizeof(word32)];      /* for CBC mode */
+    ALIGN16 word32 tmp[AES_BLOCK_SIZE / sizeof(word32)];      /* same         */
+} Aes;
+
+
+int  AesSetKey(Aes* aes, const byte* key, word32 len, const byte* iv, int dir);
+void AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz);
+void AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_AES_H */
+#endif /* NO_AES */
+
diff -r 000000000000 -r 5045d2638c29 ctc_dh.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctc_dh.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,59 @@
+/* ctc_dh.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef NO_DH
+
+#ifndef CTAO_CRYPT_DH_H
+#define CTAO_CRYPT_DH_H
+
+#include "types.h"
+#include "integer.h"
+#include "random.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+/* Diffie-Hellman Key */
+typedef struct DhKey {
+    mp_int p, g;                            /* group parameters  */
+} DhKey;
+
+
+void InitDhKey(DhKey* key);
+void FreeDhKey(DhKey* key);
+
+int DhGenerateKeyPair(DhKey* key, RNG* rng, byte* priv, word32* privSz,
+                      byte* pub, word32* pubSz);
+int DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv,
+            word32 privSz, const byte* otherPub, word32 pubSz);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_DH_H */
+
+#endif /* NO_DH */
+
diff -r 000000000000 -r 5045d2638c29 ctc_dsa.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctc_dsa.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,61 @@
+/* ctc_dsa.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef NO_DSA
+
+#ifndef CTAO_CRYPT_DSA_H
+#define CTAO_CRYPT_DSA_H
+
+#include "types.h"
+#include "integer.h"
+#include "random.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum {
+    DSA_PUBLIC   = 0,
+    DSA_PRIVATE  = 1
+};
+
+/* DSA */
+typedef struct DsaKey {
+    mp_int p, q, g, y, x;
+    int type;                               /* public or private */
+} DsaKey;
+
+
+void InitDsaKey(DsaKey* key);
+void FreeDsaKey(DsaKey* key);
+
+int DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng);
+int DsaVerify(const byte* digest, const byte* sig, DsaKey* key, int* answer);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_DSA_H */
+#endif /* NO_DSA */
+
diff -r 000000000000 -r 5045d2638c29 ctc_hmac.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctc_hmac.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,85 @@
+/* ctc_hmac.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef NO_HMAC
+
+#ifndef CTAO_CRYPT_HMAC_H
+#define CTAO_CRYPT_HMAC_H
+
+#include "ctc_md5.h"
+#include "ctc_sha.h"
+
+#ifndef NO_SHA256
+    #include "sha256.h"
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+enum {
+    IPAD    = 0x36,
+    OPAD    = 0x5C,
+#ifndef NO_SHA256
+    INNER_HASH_SIZE = SHA256_DIGEST_SIZE,
+#else
+    INNER_HASH_SIZE = SHA_DIGEST_SIZE,
+    SHA256          = 2,                     /* hash type unique */
+#endif
+    HMAC_BLOCK_SIZE = MD5_BLOCK_SIZE
+};
+
+
+/* hash union */
+typedef union {
+    Md5 md5;
+    Sha sha;
+    #ifndef NO_SHA256
+        Sha256 sha256;
+    #endif
+} Hash;
+
+/* Hmac digest */
+typedef struct Hmac {
+    Hash    hash;
+    word32  ipad[HMAC_BLOCK_SIZE  / sizeof(word32)];  /* same block size all*/
+    word32  opad[HMAC_BLOCK_SIZE  / sizeof(word32)];
+    word32  innerHash[INNER_HASH_SIZE / sizeof(word32)]; /* max size */
+    byte    macType;                                     /* md5 sha or sha256 */
+    byte    innerHashKeyed;                              /* keyed flag */
+} Hmac;
+
+
+void HmacSetKey(Hmac*, int type, const byte* key, word32 keySz); /* does init */
+void HmacUpdate(Hmac*, const byte*, word32);
+void HmacFinal(Hmac*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_HMAC_H */
+
+#endif /* NO_HMAC */
+
diff -r 000000000000 -r 5045d2638c29 ctc_md4.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctc_md4.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,65 @@
+/* ctc_md4.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_MD4
+
+#ifndef CTAO_CRYPT_MD4_H
+#define CTAO_CRYPT_MD4_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* in bytes */
+enum {
+    MD4_BLOCK_SIZE  = 64,
+    MD4_DIGEST_SIZE = 16,
+    MD4_PAD_SIZE    = 56
+};
+
+
+/* MD4 digest */
+typedef struct Md4 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[MD4_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[MD4_BLOCK_SIZE  / sizeof(word32)];
+} Md4;
+
+
+void InitMd4(Md4*);
+void Md4Update(Md4*, const byte*, word32);
+void Md4Final(Md4*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_MD4_H */
+
+#endif /* NO_MD4 */
+
diff -r 000000000000 -r 5045d2638c29 ctc_md5.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctc_md5.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,62 @@
+/* ctc_md5.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_MD5_H
+#define CTAO_CRYPT_MD5_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* in bytes */
+enum {
+    MD5             =  0,      /* hash type unique */
+    MD5_BLOCK_SIZE  = 64,
+    MD5_DIGEST_SIZE = 16,
+    MD5_PAD_SIZE    = 56
+};
+
+
+/* MD5 digest */
+typedef struct Md5 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[MD5_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[MD5_BLOCK_SIZE  / sizeof(word32)];
+} Md5;
+
+
+void InitMd5(Md5*);
+void Md5Update(Md5*, const byte*, word32);
+void Md5Final(Md5*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_MD5_H */
+
diff -r 000000000000 -r 5045d2638c29 ctc_ripemd.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctc_ripemd.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,65 @@
+/* ctc_ripemd.h
+ *
+ * Copyright (C) 2006-2010 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef CYASSL_RIPEMD
+
+#ifndef CTAO_CRYPT_RIPEMD_H
+#define CTAO_CRYPT_RIPEME_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+/* in bytes */
+enum {
+    RIPEMD             =  3,    /* hash type unique */
+    RIPEMD_BLOCK_SIZE  = 64,
+    RIPEMD_DIGEST_SIZE = 20,
+    RIPEMD_PAD_SIZE    = 56
+};
+
+
+/* RipeMd 160 digest */
+typedef struct RipeMd {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[RIPEMD_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[RIPEMD_BLOCK_SIZE  / sizeof(word32)];
+} RipeMd;
+
+
+void InitRipeMd(RipeMd*);
+void RipeMdUpdate(RipeMd*, const byte*, word32);
+void RipeMdFinal(RipeMd*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_RIPEMD_H */
+#endif /* CYASSL_RIPEMD */
diff -r 000000000000 -r 5045d2638c29 ctc_rsa.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctc_rsa.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,74 @@
+/* ctc_rsa.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_RSA_H
+#define CTAO_CRYPT_RSA_H
+
+#include "types.h"
+#include "integer.h"
+#include "random.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum {
+    RSA_PUBLIC   = 0,
+    RSA_PRIVATE  = 1
+};
+
+/* RSA */
+typedef struct RsaKey {
+    mp_int n, e, d, p, q, dP, dQ, u;
+    int   type;                               /* public or private */
+    void* heap;                               /* for user memory overrides */
+} RsaKey;
+
+
+void InitRsaKey(RsaKey* key, void*);
+void FreeRsaKey(RsaKey* key);
+
+int  RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
+                      RsaKey* key, RNG* rng);
+int  RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key);
+int  RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
+                       RsaKey* key);
+int  RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
+                 RsaKey* key, RNG* rng);
+int  RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key);
+int  RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen,
+                   RsaKey* key);
+
+int  RsaEncryptSize(RsaKey* key);
+
+#ifdef CYASSL_KEY_GEN
+    int MakeRsaKey(RsaKey* key, int size, long e, RNG* rng);
+#endif
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_RSA_H */
+
diff -r 000000000000 -r 5045d2638c29 ctc_sha.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctc_sha.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,63 @@
+/* ctc_sha.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_SHA_H
+#define CTAO_CRYPT_SHA_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+/* in bytes */
+enum {
+    SHA              =  1,    /* hash type unique */
+    SHA_BLOCK_SIZE   = 64,
+    SHA_DIGEST_SIZE  = 20,
+    SHA_PAD_SIZE     = 56
+};
+
+
+/* Sha digest */
+typedef struct Sha {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[SHA_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[SHA_BLOCK_SIZE  / sizeof(word32)];
+} Sha;
+
+
+void InitSha(Sha*);
+void ShaUpdate(Sha*, const byte*, word32);
+void ShaFinal(Sha*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_SHA_H */
+
diff -r 000000000000 -r 5045d2638c29 cyassl_error.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl_error.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,111 @@
+/* cyassl_error.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#ifndef CYASSL_ERROR_H
+#define CYASSL_ERROR_H
+
+#include "error.h"   /* CTaoCrypt errors */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+enum CyaSSL_ErrorCodes {
+    PREFIX_ERROR           = -202,            /* bad index to key rounds  */
+    MEMORY_ERROR           = -203,            /* out of memory            */
+    VERIFY_FINISHED_ERROR  = -204,            /* verify problem on finished */
+    VERIFY_MAC_ERROR       = -205,            /* verify mac problem       */
+    PARSE_ERROR            = -206,            /* parse error on header    */
+    UNKNOWN_HANDSHAKE_TYPE = -207,            /* weird handshake type     */
+    SOCKET_ERROR_E         = -208,            /* error state on socket    */
+    SOCKET_NODATA          = -209,            /* expected data, not there */
+    INCOMPLETE_DATA        = -210,            /* don't have enough data to 
+                                                 complete task            */
+    UNKNOWN_RECORD_TYPE    = -211,            /* unknown type in record hdr */
+    DECRYPT_ERROR          = -212,            /* error during decryption  */
+    FATAL_ERROR            = -213,            /* revcd alert fatal error  */
+    ENCRYPT_ERROR          = -214,            /* error during encryption  */
+    FREAD_ERROR            = -215,            /* fread problem            */
+    NO_PEER_KEY            = -216,            /* need peer's key          */
+    NO_PRIVATE_KEY         = -217,            /* need the private key     */
+    RSA_PRIVATE_ERROR      = -218,            /* error during rsa priv op */
+    BUILD_MSG_ERROR        = -220,            /* build message failure    */
+
+    BAD_HELLO              = -221,            /* client hello malformed   */
+    DOMAIN_NAME_MISMATCH   = -222,            /* peer subject name mismatch */
+    WANT_READ              = -223,            /* want read, call again    */
+    NOT_READY_ERROR        = -224,            /* handshake layer not ready */
+    PMS_VERSION_ERROR      = -225,            /* pre m secret version error */
+    VERSION_ERROR          = -226,            /* record layer version error */
+    WANT_WRITE             = -227,            /* want write, call again   */
+    BUFFER_ERROR           = -228,            /* malformed buffer input   */
+    VERIFY_CERT_ERROR      = -229,            /* verify cert error        */
+    VERIFY_SIGN_ERROR      = -230,            /* verify sign error        */
+    CLIENT_ID_ERROR        = -231,            /* psk client identity error  */
+    SERVER_HINT_ERROR      = -232,            /* psk server hint error  */
+    PSK_KEY_ERROR          = -233,            /* psk key error  */
+    ZLIB_INIT_ERROR        = -234,            /* zlib init error  */
+    ZLIB_COMPRESS_ERROR    = -235,            /* zlib compression error  */
+    ZLIB_DECOMPRESS_ERROR  = -236,            /* zlib decompression error  */
+
+    GETTIME_ERROR          = -237,            /* gettimeofday failed ??? */
+    GETITIMER_ERROR        = -238,            /* getitimer failed ??? */
+    SIGACT_ERROR           = -239,            /* sigaction failed ??? */
+    SETITIMER_ERROR        = -240,            /* setitimer failed ??? */
+    LENGTH_ERROR           = -241,            /* record layer length error */
+    PEER_KEY_ERROR         = -242,            /* cant decode peer key */
+    ZERO_RETURN            = -243,            /* peer sent close notify */
+    SIDE_ERROR             = -244,            /* wrong client/server type */
+    NO_PEER_CERT           = -245,            /* peer didn't send key */
+    NTRU_KEY_ERROR         = -246,            /* NTRU key error  */
+    NTRU_DRBG_ERROR        = -247,            /* NTRU drbg error  */
+    NTRU_ENCRYPT_ERROR     = -248,            /* NTRU encrypt error  */
+    NTRU_DECRYPT_ERROR     = -249,            /* NTRU decrypt error  */
+    /* add strings to SetErrorString !!!!! */
+
+    /* begin negotiation parameter errors */
+    UNSUPPORTED_SUITE      = -260,            /* unsupported cipher suite */
+    MATCH_SUITE_ERROR      = -261             /* can't match cipher suite */
+    /* end   negotiation parameter errors only 10 for now */
+    /* add strings to SetErrorString !!!!! */
+};
+
+
+#ifdef CYASSL_CALLBACKS
+    enum {
+        MIN_PARAM_ERR = UNSUPPORTED_SUITE,
+        MAX_PARAM_ERR = MIN_PARAM_ERR - 10
+    };
+#endif
+
+
+void SetErrorString(int error, char* buffer);
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* CyaSSL_ERROR_H */
+
diff -r 000000000000 -r 5045d2638c29 cyassl_int.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl_int.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,4782 @@
+/* cyassl_int.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#include "cyassl_int.h"
+#include "cyassl_error.h"
+#include "asn.h"
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifdef HAVE_NTRU
+    #include "crypto_ntru.h"
+#endif
+
+#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS)
+    #include <stdio.h>
+#endif
+
+#ifdef __sun
+    #include <sys/filio.h>
+#endif
+
+#define TRUE  1
+#define FALSE 0
+
+
+int CyaSSL_negotiate(SSL*);
+
+
+#ifndef NO_CYASSL_CLIENT
+    static int DoHelloVerifyRequest(SSL* ssl, const byte* input, word32*);
+    static int DoServerHello(SSL* ssl, const byte* input, word32*);
+    static int DoCertificateRequest(SSL* ssl, const byte* input, word32*);
+    static int DoServerKeyExchange(SSL* ssl, const byte* input, word32*);
+#endif
+
+
+#ifndef NO_CYASSL_SERVER
+    static int DoClientHello(SSL* ssl, const byte* input, word32*, word32,
+                             word32);
+    static int DoCertificateVerify(SSL* ssl, byte*, word32*, word32);
+    static int DoClientKeyExchange(SSL* ssl, byte* input, word32*);
+#endif
+
+typedef enum {
+    doProcessInit = 0,
+#ifndef NO_CYASSL_SERVER
+    runProcessOldClientHello,
+#endif
+    getRecordLayerHeader,
+    getData,
+    runProcessingOneMessage
+} processReply;
+
+static void Hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz,
+                 int content, int verify);
+
+static void BuildCertHashes(SSL* ssl, Hashes* hashes);
+
+
+void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender);
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+int IsTLS(const SSL* ssl)
+{
+    if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR)
+        return 1;
+
+    return 0;
+}
+
+
+int IsAtLeastTLSv1_2(const SSL* ssl)
+{
+    if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_2_MINOR)
+        return 1;
+
+    return 0;
+}
+
+
+#ifdef HAVE_NTRU
+
+static byte GetEntropy(ENTROPY_CMD cmd, byte* out)
+{
+    /* TODO: add locking? */
+    static RNG rng;
+
+    if (cmd == INIT) {
+        int ret = InitRng(&rng);
+        if (ret == 0)
+            return 1;
+        else
+            return 0;
+    }
+
+    if (out == NULL)
+        return 0;
+
+    if (cmd == GET_BYTE_OF_ENTROPY) {
+        RNG_GenerateBlock(&rng, out, 1);
+        return 1;
+    }
+
+    if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY) {
+        *out = 1;
+        return 1;
+    }
+
+    return 0;
+}
+
+#endif /* HAVE_NTRU */
+
+static INLINE void c32to24(word32 in, word24 out)
+{
+    out[0] = (in >> 16) & 0xff;
+    out[1] = (in >>  8) & 0xff;
+    out[2] =  in & 0xff;
+}
+
+
+static INLINE void c32to48(word32 in, byte out[6])
+{
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = (in >> 24) & 0xff;
+    out[3] = (in >> 16) & 0xff;
+    out[4] = (in >>  8) & 0xff;
+    out[5] =  in & 0xff;
+}
+
+
+/* convert 16 bit integer to opaque */
+static void INLINE c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+
+/* convert 32 bit integer to opaque */
+static INLINE void c32toa(word32 u32, byte* c)
+{
+    c[0] = (u32 >> 24) & 0xff;
+    c[1] = (u32 >> 16) & 0xff;
+    c[2] = (u32 >>  8) & 0xff;
+    c[3] =  u32 & 0xff;
+}
+
+
+/* convert a 24 bit integer into a 32 bit one */
+static INLINE void c24to32(const word24 u24, word32* u32)
+{
+    *u32 = 0;
+    *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2];
+}
+
+
+/* convert opaque to 16 bit integer */
+static INLINE void ato16(const byte* c, word16* u16)
+{
+    *u16 = 0;
+    *u16 = (c[0] << 8) | (c[1]);
+}
+
+
+/* convert opaque to 32 bit integer */
+static INLINE void ato32(const byte* c, word32* u32)
+{
+    *u32 = 0;
+    *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
+}
+
+
+#ifdef HAVE_LIBZ
+
+    /* alloc user allocs to work with zlib */
+    void* myAlloc(void* opaque, unsigned int item, unsigned int size)
+    {
+        return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ);
+    }
+
+
+    void myFree(void* opaque, void* memory)
+    {
+        XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ);
+    }
+
+
+    /* init zlib comp/decomp streams, 0 on success */
+    static int InitStreams(SSL* ssl)
+    {
+        ssl->c_stream.zalloc = (alloc_func)myAlloc;
+        ssl->c_stream.zfree  = (free_func)myFree;
+        ssl->c_stream.opaque = (voidpf)ssl->heap;
+
+        if (deflateInit(&ssl->c_stream, 8) != Z_OK) return ZLIB_INIT_ERROR;
+
+        ssl->didStreamInit = 1;
+
+        ssl->d_stream.zalloc = (alloc_func)myAlloc;
+        ssl->d_stream.zfree  = (free_func)myFree;
+        ssl->d_stream.opaque = (voidpf)ssl->heap;
+
+        if (inflateInit(&ssl->d_stream) != Z_OK) return ZLIB_INIT_ERROR;
+
+        return 0;
+    }
+
+
+    static void FreeStreams(SSL* ssl)
+    {
+        if (ssl->didStreamInit) {
+            deflateEnd(&ssl->c_stream);
+            inflateEnd(&ssl->d_stream);
+        }
+    }
+
+
+    /* compress in to out, return out size or error */
+    static int Compress(SSL* ssl, byte* in, int inSz, byte* out, int outSz)
+    {
+        int    err;
+        int    currTotal = ssl->c_stream.total_out;
+
+        /* put size in front of compression */
+        c16toa((word16)inSz, out);
+        out   += 2;
+        outSz -= 2;
+
+        ssl->c_stream.next_in   = in;
+        ssl->c_stream.avail_in  = inSz;
+        ssl->c_stream.next_out  = out;
+        ssl->c_stream.avail_out = outSz;
+
+        err = deflate(&ssl->c_stream, Z_SYNC_FLUSH);
+        if (err != Z_OK && err != Z_STREAM_END) return ZLIB_COMPRESS_ERROR;
+
+        return ssl->c_stream.total_out - currTotal + sizeof(word16);
+    }
+        
+
+    /* decompress in to out, returnn out size or error */
+    static int DeCompress(SSL* ssl, byte* in, int inSz, byte* out, int outSz)
+    {
+        int    err;
+        int    currTotal = ssl->d_stream.total_out;
+        word16 len;
+
+        /* find size in front of compression */
+        ato16(in, &len);
+        in   += 2;
+        inSz -= 2;
+
+        ssl->d_stream.next_in   = in;
+        ssl->d_stream.avail_in  = inSz;
+        ssl->d_stream.next_out  = out;
+        ssl->d_stream.avail_out = outSz;
+
+        err = inflate(&ssl->d_stream, Z_SYNC_FLUSH);
+        if (err != Z_OK && err != Z_STREAM_END) return ZLIB_DECOMPRESS_ERROR;
+
+        return ssl->d_stream.total_out - currTotal;
+    }
+        
+#endif /* HAVE_LIBZ */
+
+
+void InitSSL_Method(SSL_METHOD* method, ProtocolVersion pv)
+{
+    method->version    = pv;
+    method->side       = CLIENT_END;
+    method->verifyPeer = 0;
+    method->verifyNone = 0;
+    method->failNoCert = 0;
+    method->downgrade  = 0;
+}
+
+
+void InitSSL_Ctx(SSL_CTX* ctx, SSL_METHOD* method)
+{
+    ctx->method = method;
+    ctx->certificate.buffer = 0;
+    ctx->privateKey.buffer  = 0;
+    ctx->haveDH             = 0;
+    ctx->haveNTRU           = 0;    /* start off */
+    ctx->heap               = ctx;  /* defaults to self */
+#ifndef NO_PSK
+    ctx->havePSK            = 0;
+    ctx->server_hint[0]     = 0;
+    ctx->client_psk_cb      = 0;
+    ctx->server_psk_cb      = 0;
+#endif /* NO_PSK */
+
+#ifdef OPENSSL_EXTRA
+    ctx->passwd_cb   = 0;
+    ctx->userdata    = 0;
+#endif /* OPENSSL_EXTRA */
+
+#ifndef CYASSL_USER_IO
+    ctx->CBIORecv = EmbedReceive;
+    ctx->CBIOSend = EmbedSend;
+#else
+    /* user will set */
+    ctx->CBIORecv = NULL;
+    ctx->CBIOSend = NULL;
+#endif
+    ctx->partialWrite   = 0;
+    ctx->verifyCallback = 0;
+
+    ctx->caList = 0;
+#ifdef HAVE_NTRU
+    if (method->side == CLIENT_END)
+        ctx->haveNTRU = 1;           /* always on cliet side */
+                                     /* server can turn on by loading key */
+#endif
+    /* remove DH later if server didn't set, add psk later */
+    InitSuites(&ctx->suites, method->version, TRUE, FALSE, ctx->haveNTRU);  
+    ctx->verifyPeer = 0;
+    ctx->verifyNone = 0;
+    ctx->failNoCert = 0;
+    ctx->sessionCacheOff      = 0;  /* initially on */
+    ctx->sessionCacheFlushOff = 0;  /* initially on */
+    ctx->sendVerify = 0;
+    ctx->quietShutdown = 0;
+
+}
+
+
+/* In case contexts are held in array and don't want to free actual ctx */
+void SSL_CtxResourceFree(SSL_CTX* ctx)
+{
+    XFREE(ctx->privateKey.buffer, ctx->heap, DYNAMIC_TYPE_KEY);
+    XFREE(ctx->certificate.buffer, ctx->heap, DYNAMIC_TYPE_CERT);
+    XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD);
+
+    FreeSigners(ctx->caList, ctx->heap);
+}
+
+
+void FreeSSL_Ctx(SSL_CTX* ctx)
+{
+    SSL_CtxResourceFree(ctx);
+    XFREE(ctx, ctx->heap, DYNAMIC_TYPE_CTX);
+}
+
+    
+
+void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK,
+                byte haveNTRU)
+{
+    word32 idx = 0;
+    int    tls = pv.major == 3 && pv.minor >= 1;
+
+    (void)tls;  /* shut up compiler */
+
+#ifdef CYASSL_DTLS
+    if (pv.major == DTLS_MAJOR && pv.minor == DTLS_MINOR)
+        tls = 1;
+#endif
+
+    suites->setSuites = 0;  /* user hasn't set yet */
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveNTRU) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveNTRU) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    if (tls && haveNTRU) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveNTRU) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveDH) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveDH) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    if (tls) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    if (tls) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    suites->suites[idx++] = 0; 
+    suites->suites[idx++] = SSL_RSA_WITH_RC4_128_SHA;
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    suites->suites[idx++] = 0; 
+    suites->suites[idx++] = SSL_RSA_WITH_RC4_128_MD5;
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    suites->suites[idx++] = 0; 
+    suites->suites[idx++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    if (tls) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_MD5;
+    }
+#endif
+    
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+    if (tls) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    if (tls) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_RABBIT_CBC_SHA;
+    }
+#endif
+
+    suites->suiteSz = idx;
+}
+
+
+int InitSSL(SSL* ssl, SSL_CTX* ctx)
+{
+    int  ret;
+    byte havePSK = 0;
+
+    ssl->ctx     = ctx; /* only for passing to calls, options could change */
+    ssl->version = ctx->method->version;
+    ssl->suites  = ctx->suites;
+
+#ifdef HAVE_LIBZ
+    ssl->didStreamInit = 0;
+#endif
+   
+    ssl->buffers.certificate.buffer   = 0;
+    ssl->buffers.key.buffer           = 0;
+    ssl->buffers.inputBuffer.length   = 0;
+    ssl->buffers.inputBuffer.idx      = 0;
+    ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer;
+    ssl->buffers.inputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.inputBuffer.dynamicFlag = 0;
+    ssl->buffers.outputBuffer.length  = 0;
+    ssl->buffers.outputBuffer.idx     = 0;
+    ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer;
+    ssl->buffers.outputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.outputBuffer.dynamicFlag = 0;
+    ssl->buffers.domainName.buffer    = 0;
+    ssl->buffers.serverDH_P.buffer    = 0;
+    ssl->buffers.serverDH_G.buffer    = 0;
+    ssl->buffers.serverDH_Pub.buffer  = 0;
+    ssl->buffers.serverDH_Priv.buffer = 0;
+    ssl->buffers.clearOutputBuffer.buffer  = 0;
+    ssl->buffers.clearOutputBuffer.length  = 0;
+    ssl->buffers.prevSent                  = 0;
+    ssl->buffers.plainSz                   = 0;
+
+    if ( (ret = InitRng(&ssl->rng)) )
+        return ret;
+
+    InitMd5(&ssl->hashMd5);
+    InitSha(&ssl->hashSha);
+    InitRsaKey(&ssl->peerRsaKey, ctx->heap);
+
+    ssl->peerRsaKeyPresent = 0;
+    ssl->options.side      = ctx->method->side;
+    ssl->options.downgrade = ctx->method->downgrade;
+    ssl->error = 0;
+    ssl->options.connReset = 0;
+    ssl->options.isClosed  = 0;
+    ssl->options.closeNotify  = 0;
+    ssl->options.sentNotify   = 0;
+    ssl->options.usingCompression = 0;
+    ssl->options.haveDH    = ctx->haveDH;
+    ssl->options.haveNTRU  = ctx->haveNTRU;
+    ssl->options.havePeerCert = 0; 
+    ssl->options.usingPSK_cipher = 0;
+    ssl->options.sendAlertState = 0;
+#ifndef NO_PSK
+    havePSK = ctx->havePSK;
+    ssl->options.havePSK   = ctx->havePSK;
+    ssl->options.client_psk_cb = ctx->client_psk_cb;
+    ssl->options.server_psk_cb = ctx->server_psk_cb;
+#endif /* NO_PSK */
+
+    ssl->options.serverState = NULL_STATE;
+    ssl->options.clientState = NULL_STATE;
+    ssl->options.connectState = CONNECT_BEGIN;
+    ssl->options.acceptState  = ACCEPT_BEGIN; 
+    ssl->options.handShakeState  = NULL_STATE; 
+    ssl->options.processReply = doProcessInit;
+
+#ifdef CYASSL_DTLS
+    ssl->keys.dtls_sequence_number       = 0;
+    ssl->keys.dtls_peer_sequence_number  = 0;
+    ssl->keys.dtls_handshake_number      = 0;
+    ssl->keys.dtls_epoch      = 0;
+    ssl->keys.dtls_peer_epoch = 0;
+#endif
+    ssl->keys.encryptionOn = 0;     /* initially off */
+    ssl->options.sessionCacheOff      = ctx->sessionCacheOff;
+    ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff;
+
+    ssl->options.verifyPeer = ctx->verifyPeer;
+    ssl->options.verifyNone = ctx->verifyNone;
+    ssl->options.failNoCert = ctx->failNoCert;
+    ssl->options.sendVerify = ctx->sendVerify;
+    
+    ssl->options.resuming = 0;
+    ssl->hmac = Hmac;         /* default to SSLv3 */
+    ssl->heap = ctx->heap;    /* defaults to self */
+    ssl->options.tls    = 0;
+    ssl->options.tls1_1 = 0;
+    ssl->options.dtls   = 0;
+    ssl->options.partialWrite  = ctx->partialWrite;
+    ssl->options.quietShutdown = ctx->quietShutdown;
+
+    /* SSL_CTX still owns certificate, key, and caList buffers */
+    ssl->buffers.certificate = ctx->certificate;
+    ssl->buffers.key = ctx->privateKey;
+    ssl->caList = ctx->caList;
+
+#ifdef OPENSSL_EXTRA
+    ssl->peerCert.issuer.sz    = 0;
+    ssl->peerCert.subject.sz   = 0;
+#endif
+    
+    /* make sure server has cert and key unless using PSK */
+    if (ssl->options.side == SERVER_END && !havePSK)
+        if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer)
+            return NO_PRIVATE_KEY;
+
+#ifndef NO_PSK
+    ssl->arrays.client_identity[0] = 0;
+    if (ctx->server_hint[0])   /* set in CTX */
+        XSTRNCPY(ssl->arrays.server_hint, ctx->server_hint, MAX_PSK_ID_LEN);
+    else
+        ssl->arrays.server_hint[0] = 0;
+#endif /* NO_PSK */
+
+#ifdef CYASSL_CALLBACKS
+    ssl->hsInfoOn = 0;
+    ssl->toInfoOn = 0;
+#endif
+
+    /* make sure server has DH parms, and add PSK if there, add NTRU too */
+    if (!ssl->ctx->suites.setSuites) {    /* trust user override */
+        if (ssl->options.side == SERVER_END) 
+            InitSuites(&ssl->suites, ssl->version,ssl->options.haveDH, havePSK,
+                       ssl->options.haveNTRU);
+        else 
+            InitSuites(&ssl->suites, ssl->version, TRUE, havePSK,
+                       ssl->options.haveNTRU);
+    }
+
+    ssl->rfd = -1;   /* set to invalid descriptor */
+    ssl->wfd = -1;
+    ssl->biord = 0;
+    ssl->biowr = 0;
+
+    ssl->IOCB_ReadCtx  = &ssl->rfd;   /* prevent invalid pointer acess if not */
+    ssl->IOCB_WriteCtx = &ssl->wfd;   /* correctly set */
+
+#ifdef SESSION_CERTS
+    ssl->session.chain.count = 0;
+#endif
+
+    ssl->cipher.ssl = ssl;
+
+    return 0;
+}
+
+
+int BIO_free(BIO*);  /* cyassl_int doesn't have */
+
+
+/* In case holding SSL object in array and don't want to free actual ssl */
+void SSL_ResourceFree(SSL* ssl)
+{
+    XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+    FreeRsaKey(&ssl->peerRsaKey);
+    if (ssl->buffers.inputBuffer.dynamicFlag)
+        ShrinkInputBuffer(ssl, FORCED_FREE);
+    if (ssl->buffers.outputBuffer.dynamicFlag)
+        ShrinkOutputBuffer(ssl);
+#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+    BIO_free(ssl->biord);
+    if (ssl->biord != ssl->biowr)        /* in case same as write */
+        BIO_free(ssl->biowr);
+#endif
+#ifdef HAVE_LIBZ
+    FreeStreams(ssl);
+#endif
+}
+
+
+void FreeSSL(SSL* ssl)
+{
+    SSL_ResourceFree(ssl);
+    XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL);
+}
+
+
+ProtocolVersion MakeSSLv3(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = SSLv3_MINOR;
+
+    return pv;
+}
+
+
+#ifdef CYASSL_DTLS
+
+ProtocolVersion MakeDTLSv1(void)
+{
+    ProtocolVersion pv;
+    pv.major = DTLS_MAJOR;
+    pv.minor = DTLS_MINOR;
+
+    return pv;
+}
+
+#endif /* CYASSL_DTLS */
+
+
+
+
+#ifdef USE_WINDOWS_API 
+
+    timer_d Timer(void)
+    {
+        static int           init = 0;
+        static LARGE_INTEGER freq;
+        LARGE_INTEGER        count;
+    
+        if (!init) {
+            QueryPerformanceFrequency(&freq);
+            init = 1;
+        }
+
+        QueryPerformanceCounter(&count);
+
+        return (double)count.QuadPart / freq.QuadPart;
+    }
+
+
+    word32 LowResTimer(void)
+    {
+        return (word32)Timer();
+    }
+
+
+#elif defined(THREADX)
+
+    #include "rtptime.h"
+
+    word32 LowResTimer(void)
+    {
+        return (word32)rtp_get_system_sec();
+    }
+
+
+#elif defined(MICRIUM)
+
+    word32 LowResTimer(void)
+    {
+        NET_SECURE_OS_TICK  clk;
+
+        #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+            clk = NetSecure_OS_TimeGet();
+        #endif
+        return (word32)clk;
+    }
+
+#elif defined(USER_TICKS)
+
+    word32 LowResTimer(void)
+    {
+        /*
+        write your own clock tick function if don't want time(0)
+        needs second accuracy but doesn't have to correlated to EPOCH
+        */
+    }
+
+#else /* !USE_WINDOWS_API && !THREADX && !MICRIUM && !USER_TICKS */
+
+    #include <time.h>
+
+    word32 LowResTimer(void)
+    {
+        return time(0); 
+    }
+
+
+#endif /* USE_WINDOWS_API */
+
+
+/* add output to md5 and sha handshake hashes, exclude record header */
+static void HashOutput(SSL* ssl, const byte* output, int sz, int ivSz)
+{
+    const byte* buffer = output + RECORD_HEADER_SZ + ivSz;
+    sz -= RECORD_HEADER_SZ;
+    
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        buffer += DTLS_RECORD_EXTRA;
+        sz     -= DTLS_RECORD_EXTRA;
+    }
+#endif
+
+    Md5Update(&ssl->hashMd5, buffer, sz);
+    ShaUpdate(&ssl->hashSha, buffer, sz);
+}
+
+
+/* add input to md5 and sha handshake hashes, include handshake header */
+static void HashInput(SSL* ssl, const byte* input, int sz)
+{
+    const byte* buffer = input - HANDSHAKE_HEADER_SZ;
+    sz += HANDSHAKE_HEADER_SZ;
+    
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        buffer -= DTLS_HANDSHAKE_EXTRA;
+        sz     += DTLS_HANDSHAKE_EXTRA;
+    }
+#endif
+
+    Md5Update(&ssl->hashMd5, buffer, sz);
+    ShaUpdate(&ssl->hashSha, buffer, sz);
+}
+
+
+/* add record layer header for message */
+static void AddRecordHeader(byte* output, word32 length, byte type, SSL* ssl)
+{
+    RecordLayerHeader* rl;
+  
+    /* record layer header */
+    rl = (RecordLayerHeader*)output;
+    rl->type    = type;
+    rl->version = ssl->version;           /* type and version same in each */
+
+    if (!ssl->options.dtls)
+        c16toa((word16)length, rl->length);
+    else {
+#ifdef CYASSL_DTLS
+        DtlsRecordLayerHeader* dtls;
+    
+        /* dtls record layer header extensions */
+        dtls = (DtlsRecordLayerHeader*)output;
+        c16toa(ssl->keys.dtls_epoch, dtls->epoch);
+        c32to48(ssl->keys.dtls_sequence_number++, dtls->sequence_number);
+        c16toa((word16)length, dtls->length);
+#endif
+    }
+}
+
+
+/* add handshake header for message */
+static void AddHandShakeHeader(byte* output, word32 length, byte type, SSL* ssl)
+{
+    HandShakeHeader* hs;
+ 
+    /* handshake header */
+    hs = (HandShakeHeader*)output;
+    hs->type = type;
+    c32to24(length, hs->length);         /* type and length same for each */
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        DtlsHandShakeHeader* dtls;
+    
+        /* dtls handshake header extensions */
+        dtls = (DtlsHandShakeHeader*)output;
+        c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq);
+        c32to24(0, dtls->fragment_offset);
+        c32to24(length, dtls->fragment_length);
+    }
+#endif
+}
+
+
+/* add both headers for handshake message */
+static void AddHeaders(byte* output, word32 length, byte type, SSL* ssl)
+{
+    if (!ssl->options.dtls) {
+        AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl);
+        AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl);
+    }
+    else  {
+        AddRecordHeader(output, length+DTLS_HANDSHAKE_HEADER_SZ, handshake,ssl);
+        AddHandShakeHeader(output + DTLS_RECORD_HEADER_SZ, length, type, ssl);
+    }
+}
+
+
+static int Receive(SSL* ssl, byte* buf, word32 sz, int flags)
+{
+    int recvd;
+
+retry:
+    recvd = ssl->ctx->CBIORecv((char *)buf, (int)sz, ssl->IOCB_ReadCtx);
+    if (recvd < 0)
+        switch (recvd) {
+            case IO_ERR_GENERAL:        /* general/unknown error */
+                return -1;
+
+            case IO_ERR_WANT_READ:      /* want read, would block */
+                return WANT_READ;
+
+            case IO_ERR_CONN_RST:       /* connection reset */
+                ssl->options.connReset = 1;
+                return -1;
+
+            case IO_ERR_ISR:            /* interrupt */
+                /* see if we got our timeout */
+                #ifdef CYASSL_CALLBACKS
+                    if (ssl->toInfoOn) {
+                        struct itimerval timeout;
+                        getitimer(ITIMER_REAL, &timeout);
+                        if (timeout.it_value.tv_sec == 0 && 
+                                                timeout.it_value.tv_usec == 0) {
+                            XSTRNCPY(ssl->timeoutInfo.timeoutName,
+                                    "recv() timeout", MAX_TIMEOUT_NAME_SZ);
+                            return 0;
+                        }
+                    }
+                #endif
+                goto retry;
+
+            case IO_ERR_CONN_CLOSE:     /* peer closed connection */
+                ssl->options.isClosed = 1;
+                return -1;
+        }
+
+    return recvd;
+}
+
+
+/* Switch dynamic output buffer back to static, buffer is assumed clear */
+void ShrinkOutputBuffer(SSL* ssl)
+{
+    CYASSL_MSG("Shrinking output buffer\n");
+    XFREE(ssl->buffers.outputBuffer.buffer, ssl->heap, DYNAMIC_TYPE_OUT_BUFFER);
+    ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer;
+    ssl->buffers.outputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.outputBuffer.dynamicFlag = 0;
+}
+
+
+/* Switch dynamic input buffer back to static, keep any remaining input */
+/* forced free means cleaning up */
+void ShrinkInputBuffer(SSL* ssl, int forcedFree)
+{
+    int usedLength = ssl->buffers.inputBuffer.length -
+                     ssl->buffers.inputBuffer.idx;
+    if (!forcedFree && usedLength > STATIC_BUFFER_LEN)
+        return;
+
+    CYASSL_MSG("Shrinking input buffer\n");
+
+    if (!forcedFree && usedLength)
+        XMEMCPY(ssl->buffers.inputBuffer.staticBuffer,
+               ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx,
+               usedLength);
+
+    XFREE(ssl->buffers.inputBuffer.buffer, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+    ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer;
+    ssl->buffers.inputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.inputBuffer.dynamicFlag = 0;
+    ssl->buffers.inputBuffer.idx = 0;
+    ssl->buffers.inputBuffer.length = usedLength;
+}
+
+
+int SendBuffered(SSL* ssl)
+{
+    while (ssl->buffers.outputBuffer.length > 0) {
+        int sent = ssl->ctx->CBIOSend((char*)ssl->buffers.outputBuffer.buffer +
+                                      ssl->buffers.outputBuffer.idx,
+                                      (int)ssl->buffers.outputBuffer.length,
+                                      ssl->IOCB_WriteCtx);
+        if (sent < 0) {
+            switch (sent) {
+
+                case IO_ERR_WANT_WRITE:        /* would block */
+                    return WANT_WRITE;
+
+                case IO_ERR_CONN_RST:          /* connection reset */
+                    ssl->options.connReset = 1;
+                    break;
+
+                case IO_ERR_ISR:               /* interrupt */
+                    /* see if we got our timeout */
+                    #ifdef CYASSL_CALLBACKS
+                        if (ssl->toInfoOn) {
+                            struct itimerval timeout;
+                            getitimer(ITIMER_REAL, &timeout);
+                            if (timeout.it_value.tv_sec == 0 && 
+                                                timeout.it_value.tv_usec == 0) {
+                                XSTRNCPY(ssl->timeoutInfo.timeoutName,
+                                        "send() timeout", MAX_TIMEOUT_NAME_SZ);
+                                return WANT_WRITE;
+                            }
+                        }
+                    #endif
+                    continue;
+
+                case IO_ERR_CONN_CLOSE: /* epipe / conn closed, same as reset */
+                    ssl->options.connReset = 1;
+                    break;
+            }
+
+            return SOCKET_ERROR_E;
+        }
+
+        ssl->buffers.outputBuffer.idx += sent;
+        ssl->buffers.outputBuffer.length -= sent;
+    }
+      
+    ssl->buffers.outputBuffer.idx = 0;
+
+    if (ssl->buffers.outputBuffer.dynamicFlag)
+        ShrinkOutputBuffer(ssl);
+
+    return 0;
+}
+
+
+/* Grow the output buffer, should only be to send cert, should be blank */
+static INLINE int GrowOutputBuffer(SSL* ssl, int size)
+{
+    byte* tmp = (byte*) XMALLOC(size + ssl->buffers.outputBuffer.length,
+                                ssl->heap, DYNAMIC_TYPE_OUT_BUFFER);
+    CYASSL_MSG("growing output buffer\n");
+   
+    if (!tmp) return -1;
+
+    if (ssl->buffers.outputBuffer.length)
+        XMEMCPY(tmp, ssl->buffers.outputBuffer.buffer,
+               ssl->buffers.outputBuffer.length);
+
+    if (ssl->buffers.outputBuffer.dynamicFlag)
+        XFREE(ssl->buffers.outputBuffer.buffer, ssl->heap,
+              DYNAMIC_TYPE_OUT_BUFFER);
+    ssl->buffers.outputBuffer.dynamicFlag = 1;
+    ssl->buffers.outputBuffer.buffer = tmp;
+    ssl->buffers.outputBuffer.bufferSize = size +
+                                           ssl->buffers.outputBuffer.length; 
+    return 0;
+}
+
+
+/* Grow the input buffer, should only be to read cert or big app data */
+static INLINE int GrowInputBuffer(SSL* ssl, int size, int usedLength)
+{
+    byte* tmp = (byte*) XMALLOC(size + usedLength, ssl->heap,
+                                DYNAMIC_TYPE_IN_BUFFER);
+    CYASSL_MSG("growing input buffer\n");
+   
+    if (!tmp) return -1;
+
+    if (usedLength)
+        XMEMCPY(tmp, ssl->buffers.inputBuffer.buffer +
+                    ssl->buffers.inputBuffer.idx, usedLength);
+
+    if (ssl->buffers.inputBuffer.dynamicFlag)
+        XFREE(ssl->buffers.inputBuffer.buffer,ssl->heap,DYNAMIC_TYPE_IN_BUFFER);
+
+    ssl->buffers.inputBuffer.dynamicFlag = 1;
+    ssl->buffers.inputBuffer.buffer = tmp;
+    ssl->buffers.inputBuffer.bufferSize = size + usedLength;
+    ssl->buffers.inputBuffer.idx    = 0;
+    ssl->buffers.inputBuffer.length = usedLength;
+
+    return 0;
+}
+
+
+/* check avalaible size into outbut buffer */
+static INLINE int CheckAvalaibleSize(SSL *ssl, int size)
+{
+    if ((word32)size > ssl->buffers.outputBuffer.bufferSize)
+        if (GrowOutputBuffer(ssl, size) < 0)
+            return MEMORY_E;
+
+    if (ssl->buffers.outputBuffer.bufferSize - ssl->buffers.outputBuffer.length
+                                             < (word32)size) {
+        if (SendBuffered(ssl) == SOCKET_ERROR_E)
+            return SOCKET_ERROR_E;
+        if (ssl->buffers.outputBuffer.bufferSize -
+                                ssl->buffers.outputBuffer.length < (word32)size)
+            return WANT_WRITE;
+    }
+    return 0;
+}
+
+/* do all verify and sanity checks on record header */
+static int GetRecordHeader(SSL* ssl, const byte* input, word32* inOutIdx,
+                           RecordLayerHeader* rh, word16 *size)
+{
+    if (!ssl->options.dtls) {
+        XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ);
+        *inOutIdx += RECORD_HEADER_SZ;
+        ato16(rh->length, size);
+    }
+    else {
+#ifdef CYASSL_DTLS
+        /* type and version in same sport */
+        XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ);
+        *inOutIdx += ENUM_LEN + VERSION_SZ;
+        *inOutIdx += 4;  /* skip epoch and first 2 seq bytes for now */
+        ato32(input + *inOutIdx, &ssl->keys.dtls_peer_sequence_number);
+        *inOutIdx += 4;  /* advance past rest of seq */
+        ato16(input + *inOutIdx, size);
+        *inOutIdx += LENGTH_SZ;
+#endif
+    }
+
+    /* catch version mismatch */
+    if (rh->version.major != ssl->version.major || 
+        rh->version.minor != ssl->version.minor) {
+        
+        if (ssl->options.side == SERVER_END && ssl->options.downgrade == 1 &&
+            ssl->options.acceptState == ACCEPT_BEGIN)
+            ;                                  /* haven't negotiated yet */
+        else
+            return VERSION_ERROR;              /* only use requested version */
+    }
+
+    /* record layer length check */
+    if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA))
+        return LENGTH_ERROR;
+
+    /* verify record type here as well */
+    switch ((enum ContentType)rh->type) {
+        case handshake:
+        case change_cipher_spec:
+        case application_data:
+        case alert:
+            break;
+        default:
+            return UNKNOWN_RECORD_TYPE;
+    }
+
+    return 0;
+}
+
+
+static int GetHandShakeHeader(SSL* ssl, const byte* input, word32* inOutIdx,
+                              byte *type, word32 *size)
+{
+    const byte *ptr = input + *inOutIdx;
+    *inOutIdx += HANDSHAKE_HEADER_SZ;
+    
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        *inOutIdx += DTLS_HANDSHAKE_EXTRA;
+#endif
+
+    *type = ptr[0];
+    c24to32(&ptr[1], size);
+
+    return 0;
+}
+
+
+/* fill with MD5 pad size since biggest required */
+static const byte PAD1[PAD_MD5] = 
+                              { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
+                              };
+static const byte PAD2[PAD_MD5] =
+                              { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
+                              };
+
+/* calculate MD5 hash for finished */
+static void BuildMD5(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+    byte md5_result[MD5_DIGEST_SIZE];
+
+    /* make md5 inner */    
+    Md5Update(&ssl->hashMd5, sender, SIZEOF_SENDER);
+    Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD1, PAD_MD5);
+    Md5Final(&ssl->hashMd5, md5_result);
+
+    /* make md5 outer */
+    Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD2, PAD_MD5);
+    Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE);
+
+    Md5Final(&ssl->hashMd5, hashes->md5);
+}
+
+
+/* calculate SHA hash for finished */
+static void BuildSHA(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+    byte sha_result[SHA_DIGEST_SIZE];
+
+    /* make sha inner */
+    ShaUpdate(&ssl->hashSha, sender, SIZEOF_SENDER);
+    ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA);
+    ShaFinal(&ssl->hashSha, sha_result);
+
+    /* make sha outer */
+    ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA);
+    ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE);
+
+    ShaFinal(&ssl->hashSha, hashes->sha);
+}
+
+
+static void BuildFinished(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+    /* store current states, building requires get_digest which resets state */
+    Md5 md5 = ssl->hashMd5;
+    Sha sha = ssl->hashSha;
+
+    if (ssl->options.tls)
+        BuildTlsFinished(ssl, hashes, sender);
+    else {
+        BuildMD5(ssl, hashes, sender);
+        BuildSHA(ssl, hashes, sender);
+    }
+    
+    /* restore */
+    ssl->hashMd5 = md5;
+    ssl->hashSha = sha;
+}
+
+
+static int DoCertificate(SSL* ssl, byte* input, word32* inOutIdx)
+{
+    word32 listSz, i = *inOutIdx;
+    int    ret = 0;
+    int    firstTime = 1;  /* peer's is at front */
+    char   domain[ASN_NAME_MAX];
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo);
+    #endif
+    c24to32(&input[i], &listSz);
+    i += CERT_HEADER_SZ;
+    
+    while (listSz && ret == 0) {
+        /* cert size */
+        buffer      myCert;
+        word32      certSz;
+        DecodedCert dCert;
+        word32      idx = 0;
+
+        c24to32(&input[i], &certSz);
+        i += CERT_HEADER_SZ;
+        
+        myCert.length = certSz;
+        myCert.buffer = input + i;
+        i += certSz;
+
+        listSz -= certSz + CERT_HEADER_SZ;
+
+#ifdef SESSION_CERTS
+        if (ssl->session.chain.count < MAX_CHAIN_DEPTH &&
+                                       myCert.length < MAX_X509_SIZE) {
+            ssl->session.chain.certs[ssl->session.chain.count].length =
+                 myCert.length;
+            XMEMCPY(ssl->session.chain.certs[ssl->session.chain.count].buffer,
+                   myCert.buffer, myCert.length);
+            ssl->session.chain.count++;
+        } else {
+            CYASSL_MSG("Couldn't store chain cert for session");
+        }
+#endif
+
+        InitDecodedCert(&dCert, myCert.buffer, ssl->heap);
+        ret = ParseCertRelative(&dCert, myCert.length, CERT_TYPE,
+                                !ssl->options.verifyNone, ssl->caList);
+
+        if (!firstTime) {
+            FreeDecodedCert(&dCert);
+            continue;
+        }
+
+        /* get rest of peer info in case user wants to continue */
+        if (ret != 0) {
+            if (!(ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E ||
+                                              ret == ASN_SIG_CONFIRM_E)) {
+                FreeDecodedCert(&dCert);
+                continue;
+            }
+        }
+        
+        /* first one has peer's key */
+        firstTime = 0;
+
+        ssl->options.havePeerCert = 1;
+        /* set X509 format */
+#ifdef OPENSSL_EXTRA
+        ssl->peerCert.issuer.sz    = (int)XSTRLEN(dCert.issuer) + 1;
+        XSTRNCPY(ssl->peerCert.issuer.name, dCert.issuer, ASN_NAME_MAX);
+        ssl->peerCert.subject.sz   = (int)XSTRLEN(dCert.subject) + 1;
+        XSTRNCPY(ssl->peerCert.subject.name, dCert.subject, ASN_NAME_MAX);
+#endif    
+
+        XMEMCPY(domain, dCert.subjectCN, dCert.subjectCNLen);
+        domain[dCert.subjectCNLen] = '\0';
+
+        if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer)
+            if (XSTRNCMP((char*)ssl->buffers.domainName.buffer,
+                        dCert.subjectCN,
+                        ssl->buffers.domainName.length - 1)) {
+                ret = DOMAIN_NAME_MISMATCH;   /* try to get peer key still */
+            }
+
+        /* decode peer key */
+        if (dCert.keyOID == RSAk) {
+            if (RsaPublicKeyDecode(dCert.publicKey, &idx,
+                               &ssl->peerRsaKey, dCert.pubKeySize) != 0) {
+                ret = PEER_KEY_ERROR;
+                FreeDecodedCert(&dCert);
+                continue;
+            }
+            ssl->peerRsaKeyPresent = 1;
+        }
+#ifdef HAVE_NTRU
+        else if (dCert.keyOID == NTRUk) {
+            if (dCert.pubKeySize > sizeof(ssl->peerNtruKey)) {
+                ret = PEER_KEY_ERROR;
+                FreeDecodedCert(&dCert);
+                continue;
+            }
+            XMEMCPY(ssl->peerNtruKey, dCert.publicKey, dCert.pubKeySize);
+            ssl->peerNtruKeyLen = (word16)dCert.pubKeySize;
+            ssl->peerNtruKeyPresent = 1;
+        }
+#endif
+
+        FreeDecodedCert(&dCert);
+    }
+
+    if (ret == 0 && ssl->options.side == CLIENT_END)
+        ssl->options.serverState = SERVER_CERT_COMPLETE;
+
+    if (ret != 0) {
+        if (!ssl->options.verifyNone) {
+            int why = bad_certificate;
+            if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E)
+                why = certificate_expired;
+            if (ssl->ctx->verifyCallback) {
+                int            ok;
+                X509_STORE_CTX store;
+
+                store.error = ret;
+                store.error_depth = 1;
+                store.domain = domain;
+#ifdef OPENSSL_EXTRA
+                store.current_cert = &ssl->peerCert;
+#else
+                store.current_cert = NULL;
+#endif
+                ok = ssl->ctx->verifyCallback(0, &store);
+                if (ok)
+                    ret = 0;
+            }
+            if (ret != 0) {
+                SendAlert(ssl, alert_fatal, why);   /* try to send */
+                ssl->options.isClosed = 1;
+            }
+        }
+        ssl->error = ret;
+    }
+
+    *inOutIdx = i;
+    return ret;
+}
+
+
+int DoFinished(SSL* ssl, const byte* input, word32* inOutIdx, int sniff)
+{
+    byte   verifyMAC[SHA_DIGEST_SIZE];
+    int    finishedSz = ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ;
+    int    headerSz = HANDSHAKE_HEADER_SZ;
+    word32 macSz = finishedSz + HANDSHAKE_HEADER_SZ,
+           idx = *inOutIdx,
+           padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - finishedSz -
+                   ssl->specs.hash_size;
+    const byte* mac;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            headerSz += DTLS_HANDSHAKE_EXTRA;
+            macSz    += DTLS_HANDSHAKE_EXTRA;
+            padSz    -= DTLS_HANDSHAKE_EXTRA;
+        }
+    #endif
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
+    #endif
+    if (sniff == NO_SNIFF) {
+        if (XMEMCMP(input + idx, &ssl->verifyHashes, finishedSz))
+            return VERIFY_FINISHED_ERROR;
+    }
+
+    ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz,
+         handshake, 1);
+    idx += finishedSz;
+
+    /* read mac and fill */
+    mac = input + idx;
+    idx += ssl->specs.hash_size;
+
+    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+        padSz -= ssl->specs.block_size;
+
+    idx += padSz;
+
+    /* verify mac */
+    if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size))
+        return VERIFY_MAC_ERROR;
+
+    if (ssl->options.side == CLIENT_END) {
+        ssl->options.serverState = SERVER_FINISHED_COMPLETE;
+        if (!ssl->options.resuming)
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+    }
+    else {
+        ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
+        if (ssl->options.resuming)
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+    }
+
+    *inOutIdx = idx;
+    return 0;
+}
+
+
+static int DoHandShakeMsg(SSL* ssl, byte* input, word32* inOutIdx,
+                          word32 totalSz)
+{
+    byte type;
+    word32 size;
+    int ret = 0;
+
+    CYASSL_ENTER("DoHandShakeMsg()");
+
+    if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size) != 0)
+        return PARSE_ERROR;
+
+    if (*inOutIdx + size > totalSz)
+        return INCOMPLETE_DATA;
+    
+    HashInput(ssl, input + *inOutIdx, size);
+#ifdef CYASSL_CALLBACKS
+    /* add name later, add on record and handshake header  part back on */
+    if (ssl->toInfoOn) {
+        int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        AddPacketInfo(0, &ssl->timeoutInfo, input + *inOutIdx - add,
+                      size + add, ssl->heap);
+        AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
+    }
+#endif
+
+    switch (type) {
+
+#ifndef NO_CYASSL_CLIENT
+    case hello_verify_request:
+        CYASSL_MSG("processing hello verify request");
+        ret = DoHelloVerifyRequest(ssl, input,inOutIdx);
+        break;
+            
+    case server_hello:
+        CYASSL_MSG("processing server hello");
+        ret = DoServerHello(ssl, input, inOutIdx);
+        break;
+
+    case certificate_request:
+        CYASSL_MSG("processing certificate request");
+        ret = DoCertificateRequest(ssl, input, inOutIdx);
+        break;
+
+    case server_key_exchange:
+        CYASSL_MSG("processing server key exchange");
+        ret = DoServerKeyExchange(ssl, input, inOutIdx);
+        break;
+#endif
+
+    case certificate:
+        CYASSL_MSG("processing certificate");
+        ret =  DoCertificate(ssl, input, inOutIdx);
+        break;
+
+    case server_hello_done:
+        CYASSL_MSG("processing server hello done");
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn) 
+                AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("ServerHelloDone", &ssl->timeoutInfo);
+        #endif
+        ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
+        break;
+
+    case finished:
+        CYASSL_MSG("processing finished");
+        ret = DoFinished(ssl, input, inOutIdx, NO_SNIFF);
+        break;
+
+#ifndef NO_CYASSL_SERVER
+    case client_hello:
+        CYASSL_MSG("processing client hello");
+        ret = DoClientHello(ssl, input, inOutIdx, totalSz, size);
+        break;
+
+    case client_key_exchange:
+        CYASSL_MSG("processing client key exchange");
+        ret = DoClientKeyExchange(ssl, input, inOutIdx);
+        break;
+
+    case certificate_verify:
+        CYASSL_MSG("processing certificate verify");
+        ret = DoCertificateVerify(ssl, input, inOutIdx, totalSz);
+        break;
+
+#endif
+
+    default:
+        ret = UNKNOWN_HANDSHAKE_TYPE;
+    }
+
+    CYASSL_LEAVE("DoHandShakeMsg()", ret);
+    return ret;
+}
+
+
+static INLINE void Encrypt(SSL* ssl, byte* out, const byte* input, word32 sz)
+{
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+            case rc4:
+                Arc4Process(&ssl->encrypt.arc4, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case triple_des:
+                Des3_CbcEncrypt(&ssl->encrypt.des3, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AES
+            case aes:
+#ifdef CYASSL_AESNI
+                if ((word)input % 16) {
+                    byte buffer[MAX_RECORD_SIZE + MAX_COMP_EXTRA+MAX_MSG_EXTRA];
+                    XMEMCPY(buffer, input, sz);
+                    AesCbcEncrypt(&ssl->encrypt.aes, buffer, buffer, sz);
+                    XMEMCPY(out, buffer, sz);
+                    break;
+                }
+#endif
+                AesCbcEncrypt(&ssl->encrypt.aes, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_HC128
+            case hc128:
+                Hc128_Process(&ssl->encrypt.hc128, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case rabbit:
+                RabbitProcess(&ssl->encrypt.rabbit, out, input, sz);
+                break;
+        #endif
+    }
+}
+
+
+static INLINE void Decrypt(SSL* ssl, byte* plain, const byte* input, word32 sz)
+{
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+            case rc4:
+                Arc4Process(&ssl->decrypt.arc4, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case triple_des:
+                Des3_CbcDecrypt(&ssl->decrypt.des3, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AES
+            case aes:
+                AesCbcDecrypt(&ssl->decrypt.aes, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_HC128
+            case hc128:
+                Hc128_Process(&ssl->decrypt.hc128, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case rabbit:
+                RabbitProcess(&ssl->decrypt.rabbit, plain, input, sz);
+                break;
+        #endif
+    }
+}
+
+
+/* decrypt input message in place */
+static int DecryptMessage(SSL* ssl, byte* input, word32 sz, word32* idx)
+{
+    Decrypt(ssl, input, input, sz);
+    ssl->keys.encryptSz = sz;
+    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+        *idx += ssl->specs.block_size;  /* go past TLSv1.1 IV */
+
+    return 0;
+}
+
+
+static INLINE word32 GetSEQIncrement(SSL* ssl, int verify)
+{
+    if (verify)
+        return ssl->keys.peer_sequence_number++; 
+    else
+        return ssl->keys.sequence_number++; 
+}
+
+
+int DoApplicationData(SSL* ssl, byte* input, word32* inOutIdx)
+{
+    word32 msgSz   = ssl->keys.encryptSz;
+    word32 pad     = 0, 
+           padByte = 0,
+           idx     = *inOutIdx,
+           digestSz = ssl->specs.hash_size;
+    int    dataSz;
+    int    ivExtra = 0;
+    byte*  rawData = input + idx;  /* keep current  for hmac */
+#ifdef HAVE_LIBZ
+    byte   decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+#endif
+
+    byte        verify[SHA_DIGEST_SIZE];
+    const byte* mac;
+
+    if (ssl->specs.cipher_type == block) {
+        if (ssl->options.tls1_1)
+            ivExtra = ssl->specs.block_size;
+        pad = *(input + idx + msgSz - ivExtra - 1);
+        padByte = 1;
+    }
+
+    dataSz = msgSz - ivExtra - digestSz - pad - padByte;
+    if (dataSz < 0)
+        return BUFFER_ERROR;
+
+    /* read data */
+    if (dataSz) {
+        int    rawSz   = dataSz;       /* keep raw size for hmac */
+
+        ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1);
+
+#ifdef HAVE_LIBZ
+        byte  decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+        
+        if (ssl->options.usingCompression) {
+            dataSz = DeCompress(ssl, rawData, dataSz, decomp, sizeof(decomp));
+            if (dataSz < 0) return dataSz;
+        }
+#endif
+
+        if (ssl->options.usingCompression)
+            idx += rawSz;
+        else
+            idx += dataSz;
+
+        ssl->buffers.clearOutputBuffer.buffer = rawData;
+        ssl->buffers.clearOutputBuffer.length = dataSz;
+    }
+
+    /* read mac and fill */
+    mac = input + idx;
+    idx += digestSz;
+   
+    idx += pad;
+    if (padByte)
+        idx++;
+
+#ifdef HAVE_LIBZ
+    if (ssl->options.usingCompression)
+        XMEMMOVE(rawData, decomp, dataSz);
+#endif
+
+    /* verify */
+    if (dataSz) {
+        if (XMEMCMP(mac, verify, digestSz))
+            return VERIFY_MAC_ERROR;
+    }
+    else 
+        GetSEQIncrement(ssl, 1);  /* even though no data, increment verify */
+
+    *inOutIdx = idx;
+    return 0;
+}
+
+
+/* process alert, return level */
+static int DoAlert(SSL* ssl, byte* input, word32* inOutIdx, int* type)
+{
+    byte level;
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("Alert", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            /* add record header back on to info + 2 byte level, data */
+            AddPacketInfo("Alert", &ssl->timeoutInfo, input + *inOutIdx -
+                          RECORD_HEADER_SZ, 2 + RECORD_HEADER_SZ, ssl->heap);
+    #endif
+    level = input[(*inOutIdx)++];
+    *type  = (int)input[(*inOutIdx)++];
+
+    if (*type == close_notify)
+        ssl->options.closeNotify = 1;
+
+    if (ssl->keys.encryptionOn) {
+        int         aSz = ALERT_SIZE;
+        const byte* mac;
+        byte        verify[SHA_DIGEST_SIZE];
+        int         padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size;
+        
+        ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1);
+
+        /* read mac and fill */
+        mac = input + *inOutIdx;
+        *inOutIdx += (ssl->specs.hash_size + padSz);
+
+        /* verify */
+        if (XMEMCMP(mac, verify, ssl->specs.hash_size))
+            return VERIFY_MAC_ERROR;
+    }
+
+    return level;
+}
+
+static int GetInputData(SSL *ssl, size_t size)
+{
+    int in;
+    int inSz;
+    int maxLength;
+    int usedLength;
+
+    
+    /* check max input length */
+    usedLength = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx;
+    maxLength  = ssl->buffers.inputBuffer.bufferSize - usedLength;
+    inSz       = (int)(size - usedLength);      /* from last partial read */
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        inSz = 1500;       /* read ahead up to MTU */
+#endif
+    
+    if (inSz > maxLength) {
+        if (GrowInputBuffer(ssl, size, usedLength) < 0)
+            return MEMORY_E;
+    }
+           
+    if (inSz <= 0)
+        return BUFFER_ERROR;
+    
+    /* Put buffer data at start if not there */
+    if (usedLength > 0 && ssl->buffers.inputBuffer.idx != 0)
+        XMEMMOVE(ssl->buffers.inputBuffer.buffer,
+                ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx,
+                usedLength);
+    
+    /* remove processed data */
+    ssl->buffers.inputBuffer.idx    = 0;
+    ssl->buffers.inputBuffer.length = usedLength;
+  
+    /* read data from network */
+    do {
+        in = Receive(ssl, 
+                     ssl->buffers.inputBuffer.buffer +
+                     ssl->buffers.inputBuffer.length, 
+                     inSz, 0);
+        if (in == -1)
+            return SOCKET_ERROR_E;
+   
+        if (in == WANT_READ)
+            return WANT_READ;
+        
+        ssl->buffers.inputBuffer.length += in;
+        inSz -= in;
+
+    } while (ssl->buffers.inputBuffer.length < size);
+
+    return 0;
+}
+
+/* process input requests, return 0 is done, 1 is call again to complete, and
+   negative number is error */
+int ProcessReply(SSL* ssl)
+{
+    int    ret, type, readSz;
+    word32 startIdx = 0;
+    byte   b0, b1;
+#ifdef CYASSL_DTLS
+    int    used;
+#endif
+
+    for (;;) {
+        switch ((processReply)ssl->options.processReply) {
+
+        /* in the CYASSL_SERVER case, get the first byte for detecting 
+         * old client hello */
+        case doProcessInit:
+            
+            readSz = RECORD_HEADER_SZ;
+            
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls)
+                    readSz = DTLS_RECORD_HEADER_SZ;
+            #endif
+
+            /* get header or return error */
+            if (!ssl->options.dtls) {
+                if ((ret = GetInputData(ssl, readSz)) < 0)
+                    return ret;
+            } else {
+            #ifdef CYASSL_DTLS
+                /* read ahead may already have header */
+                used = ssl->buffers.inputBuffer.length -
+                       ssl->buffers.inputBuffer.idx;
+                if (used < readSz)
+                    if ((ret = GetInputData(ssl, readSz)) < 0)
+                        return ret;
+            #endif
+            }
+
+#ifndef NO_CYASSL_SERVER
+
+            /* see if sending SSLv2 client hello */
+            if ( ssl->options.side == SERVER_END &&
+                 ssl->options.clientState == NULL_STATE &&
+                 ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx]
+                         != handshake) {
+                ssl->options.processReply = runProcessOldClientHello;
+
+                /* how many bytes need ProcessOldClientHello */
+                b0 =
+                ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++];
+                b1 =
+                ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++];
+                ssl->curSize = ((b0 & 0x7f) << 8) | b1;
+            }
+            else {
+                ssl->options.processReply = getRecordLayerHeader;
+                continue;
+            }
+
+        /* in the CYASSL_SERVER case, run the old client hello */
+        case runProcessOldClientHello:     
+
+            /* get sz bytes or return error */
+            if (!ssl->options.dtls) {
+                if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                    return ret;
+            } else {
+            #ifdef CYASSL_DTLS
+                /* read ahead may already have */
+                used = ssl->buffers.inputBuffer.length -
+                       ssl->buffers.inputBuffer.idx;
+                if (used < ssl->curSize)
+                    if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                        return ret;
+            #endif  /* CYASSL_DTLS */
+            }
+
+            ret = ProcessOldClientHello(ssl, ssl->buffers.inputBuffer.buffer,
+                                        &ssl->buffers.inputBuffer.idx,
+                                        ssl->buffers.inputBuffer.length -
+                                        ssl->buffers.inputBuffer.idx,
+                                        ssl->curSize);
+            if (ret < 0)
+                return ret;
+
+            else if (ssl->buffers.inputBuffer.idx ==
+                     ssl->buffers.inputBuffer.length) {
+                ssl->options.processReply = doProcessInit;
+                return 0;
+            }
+
+#endif  /* NO_CYASSL_SERVER */
+
+        /* get the record layer header */
+        case getRecordLayerHeader:
+
+            ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer,
+                                       &ssl->buffers.inputBuffer.idx,
+                                       &ssl->curRL, &ssl->curSize);
+            if (ret != 0)
+                return ret;
+
+            ssl->options.processReply = getData;
+
+        /* retrieve record layer data */
+        case getData:
+
+            /* get sz bytes or return error */
+            if (!ssl->options.dtls) {
+                if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                    return ret;
+            } else {
+#ifdef CYASSL_DTLS
+                /* read ahead may already have */
+                used = ssl->buffers.inputBuffer.length -
+                       ssl->buffers.inputBuffer.idx;
+                if (used < ssl->curSize)
+                    if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                        return ret;
+#endif
+            }
+            
+            ssl->options.processReply = runProcessingOneMessage;
+            startIdx = ssl->buffers.inputBuffer.idx;  /* in case > 1 msg per */
+
+        /* the record layer is here */
+        case runProcessingOneMessage:
+
+            if (ssl->keys.encryptionOn)
+                if (DecryptMessage(ssl, ssl->buffers.inputBuffer.buffer + 
+                                        ssl->buffers.inputBuffer.idx,
+                                        ssl->curSize,
+                                        &ssl->buffers.inputBuffer.idx) < 0)
+                    return DECRYPT_ERROR;
+
+            CYASSL_MSG("received record layer msg");
+
+            switch (ssl->curRL.type) {
+                case handshake :
+                    /* debugging in DoHandShakeMsg */
+                    if ((ret = DoHandShakeMsg(ssl, 
+                                              ssl->buffers.inputBuffer.buffer,
+                                              &ssl->buffers.inputBuffer.idx,
+                                              ssl->buffers.inputBuffer.length))
+                                                                           != 0)
+                        return ret;
+                    break;
+
+                case change_cipher_spec:
+                    CYASSL_MSG("got CHANGE CIPHER SPEC");
+                    #ifdef CYASSL_CALLBACKS
+                        if (ssl->hsInfoOn)
+                            AddPacketName("ChangeCipher", &ssl->handShakeInfo);
+                        /* add record header back on info */
+                        if (ssl->toInfoOn) {
+                            AddPacketInfo("ChangeCipher", &ssl->timeoutInfo,
+                                ssl->buffers.inputBuffer.buffer +
+                                ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ,
+                                1 + RECORD_HEADER_SZ, ssl->heap);
+                            AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
+                        }
+                    #endif
+                    ssl->buffers.inputBuffer.idx++;
+                    ssl->keys.encryptionOn = 1;
+
+                    #ifdef CYASSL_DTLS
+                        if (ssl->options.dtls)
+                            ssl->keys.dtls_peer_epoch++;
+                    #endif
+
+                    #ifdef HAVE_LIBZ
+                        if (ssl->options.usingCompression)
+                            if ( (ret = InitStreams(ssl)) != 0)
+                                return ret;
+                    #endif
+                    if (ssl->options.resuming && ssl->options.side ==
+                                                                    CLIENT_END)
+                        BuildFinished(ssl, &ssl->verifyHashes, server);
+                    else if (!ssl->options.resuming && ssl->options.side ==
+                                                                    SERVER_END)
+                        BuildFinished(ssl, &ssl->verifyHashes, client);
+                    break;
+
+                case application_data:
+                    CYASSL_MSG("got app DATA");
+                    if ((ret = DoApplicationData(ssl,
+                                                ssl->buffers.inputBuffer.buffer,
+                                               &ssl->buffers.inputBuffer.idx))
+                                                                         != 0) {
+                        CYASSL_ERROR(ret);
+                        return ret;
+                    }
+                    break;
+
+                case alert:
+                    CYASSL_MSG("got ALERT!");
+                    if (DoAlert(ssl, ssl->buffers.inputBuffer.buffer,
+                           &ssl->buffers.inputBuffer.idx, &type) == alert_fatal)
+                        return FATAL_ERROR;
+
+                    /* catch warnings that are handled as errors */
+                    if (type == close_notify)
+                        return ssl->error = ZERO_RETURN;
+                           
+                    if (type == decrypt_error)
+                        return FATAL_ERROR;
+                    break;
+            
+                default:
+                    CYASSL_ERROR(UNKNOWN_RECORD_TYPE);
+                    return UNKNOWN_RECORD_TYPE;
+            }
+
+            ssl->options.processReply = doProcessInit;
+
+            /* input exhausted? */
+            if (ssl->buffers.inputBuffer.idx == ssl->buffers.inputBuffer.length)
+                return 0;
+            /* more messages per record */
+            else if ((ssl->buffers.inputBuffer.idx - startIdx) < ssl->curSize) {
+                #ifdef CYASSL_DTLS
+                    /* read-ahead but dtls doesn't bundle messages per record */
+                    if (ssl->options.dtls) {
+                        ssl->options.processReply = doProcessInit;
+                        continue;
+                    }
+                #endif
+                ssl->options.processReply = runProcessingOneMessage;
+                continue;
+            }
+            /* more records */
+            else {
+                ssl->options.processReply = doProcessInit;
+                continue;
+            }
+        }
+    }
+}
+
+
+int SendChangeCipher(SSL* ssl)
+{
+    byte              *output;
+    int                sendSz = RECORD_HEADER_SZ + ENUM_LEN;
+    int                idx    = RECORD_HEADER_SZ;
+    int                ret;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            sendSz += DTLS_RECORD_EXTRA;
+            idx    += DTLS_RECORD_EXTRA;
+        }
+    #endif
+
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer + 
+             ssl->buffers.outputBuffer.idx;
+
+    AddRecordHeader(output, 1, change_cipher_spec, ssl);
+
+    output[idx] = 1;             /* turn it on */
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ChangeCipher", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, output, sendSz,
+                           ssl->heap);
+    #endif
+    ssl->buffers.outputBuffer.length += sendSz;
+    return SendBuffered(ssl);
+}
+
+
+static INLINE const byte* GetMacSecret(SSL* ssl, int verify)
+{
+    if ( (ssl->options.side == CLIENT_END && !verify) ||
+         (ssl->options.side == SERVER_END &&  verify) )
+        return ssl->keys.client_write_MAC_secret;
+    else
+        return ssl->keys.server_write_MAC_secret;
+}
+
+
+static void Hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz,
+                 int content, int verify)
+{
+    byte   result[SHA_DIGEST_SIZE];                    /* max possible sizes */
+    word32 digestSz = ssl->specs.hash_size;            /* actual sizes */
+    word32 padSz    = ssl->specs.pad_size;
+
+    Md5 md5;
+    Sha sha;
+
+    /* data */
+    byte seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 };
+    byte conLen[ENUM_LEN + LENGTH_SZ];     /* content & length */
+    const byte* macSecret = GetMacSecret(ssl, verify);
+    
+    conLen[0] = content;
+    c16toa((word16)sz, &conLen[ENUM_LEN]);
+    c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
+
+    if (ssl->specs.mac_algorithm == md5_mac) {
+        InitMd5(&md5);
+        /* inner */
+        Md5Update(&md5, macSecret, digestSz);
+        Md5Update(&md5, PAD1, padSz);
+        Md5Update(&md5, seq, SEQ_SZ);
+        Md5Update(&md5, conLen, sizeof(conLen));
+        /* buffer */
+        Md5Update(&md5, buffer, sz);
+        Md5Final(&md5, result);
+        /* outer */
+        Md5Update(&md5, macSecret, digestSz);
+        Md5Update(&md5, PAD2, padSz);
+        Md5Update(&md5, result, digestSz);
+        Md5Final(&md5, digest);        
+    }
+    else {
+        InitSha(&sha);
+        /* inner */
+        ShaUpdate(&sha, macSecret, digestSz);
+        ShaUpdate(&sha, PAD1, padSz);
+        ShaUpdate(&sha, seq, SEQ_SZ);
+        ShaUpdate(&sha, conLen, sizeof(conLen));
+        /* buffer */
+        ShaUpdate(&sha, buffer, sz);
+        ShaFinal(&sha, result);
+        /* outer */
+        ShaUpdate(&sha, macSecret, digestSz);
+        ShaUpdate(&sha, PAD2, padSz);
+        ShaUpdate(&sha, result, digestSz);
+        ShaFinal(&sha, digest);        
+    }
+}
+
+
+static void BuildMD5_CertVerify(SSL* ssl, byte* digest)
+{
+    byte md5_result[MD5_DIGEST_SIZE];
+
+    /* make md5 inner */
+    Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD1, PAD_MD5);
+    Md5Final(&ssl->hashMd5, md5_result);
+
+    /* make md5 outer */
+    Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD2, PAD_MD5);
+    Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE);
+
+    Md5Final(&ssl->hashMd5, digest);
+}
+
+
+static void BuildSHA_CertVerify(SSL* ssl, byte* digest)
+{
+    byte sha_result[SHA_DIGEST_SIZE];
+    
+    /* make sha inner */
+    ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA);
+    ShaFinal(&ssl->hashSha, sha_result);
+
+    /* make sha outer */
+    ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA);
+    ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE);
+
+    ShaFinal(&ssl->hashSha, digest);
+}
+
+
+static void BuildCertHashes(SSL* ssl, Hashes* hashes)
+{
+    /* store current states, building requires get_digest which resets state */
+    Md5 md5 = ssl->hashMd5;
+    Sha sha = ssl->hashSha;
+
+    if (ssl->options.tls) {
+        Md5Final(&ssl->hashMd5, hashes->md5);
+        ShaFinal(&ssl->hashSha, hashes->sha);
+    }
+    else {
+        BuildMD5_CertVerify(ssl, hashes->md5);
+        BuildSHA_CertVerify(ssl, hashes->sha);
+    }
+    
+    /* restore */
+    ssl->hashMd5 = md5;
+    ssl->hashSha = sha;
+}
+
+
+/* Build SSL Message, encrypted */
+static int BuildMessage(SSL* ssl, byte* output, const byte* input, int inSz,
+                        int type)
+{
+    word32 digestSz = ssl->specs.hash_size;
+    word32 sz = RECORD_HEADER_SZ + inSz + digestSz;                
+    word32 pad  = 0, i;
+    word32 idx  = RECORD_HEADER_SZ;
+    word32 ivSz = 0;      /* TLSv1.1  IV */
+    word32 headerSz = RECORD_HEADER_SZ;
+    word16 size;
+    byte               iv[AES_BLOCK_SIZE];                  /* max size */
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        sz       += DTLS_RECORD_EXTRA;
+        idx      += DTLS_RECORD_EXTRA; 
+        headerSz += DTLS_RECORD_EXTRA;
+    }
+#endif
+
+    if (ssl->specs.cipher_type == block) {
+        word32 blockSz = ssl->specs.block_size;
+        if (ssl->options.tls1_1) {
+            ivSz = blockSz;
+            sz  += ivSz;
+            RNG_GenerateBlock(&ssl->rng, iv, ivSz);
+        }
+        sz += 1;       /* pad byte */
+        pad = (sz - headerSz) % blockSz;
+        pad = blockSz - pad;
+        sz += pad;
+    }
+
+    size = sz - headerSz;    /* include mac and digest */
+    AddRecordHeader(output, size, type, ssl);    
+
+    /* write to output */
+    if (ivSz) {
+        XMEMCPY(output + idx, iv, ivSz);
+        idx += ivSz;
+    }
+    XMEMCPY(output + idx, input, inSz);
+    idx += inSz;
+
+    if (type == handshake)
+        HashOutput(ssl, output, headerSz + inSz, ivSz);
+    ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0);
+    idx += digestSz;
+
+    if (ssl->specs.cipher_type == block)
+        for (i = 0; i <= pad; i++) output[idx++] = pad; /* pad byte gets */
+                                                        /* pad value too */
+    Encrypt(ssl, output + headerSz, output + headerSz, size);
+
+    return sz;
+}
+
+
+int SendFinished(SSL* ssl)
+{
+    int              sendSz,
+                     finishedSz = ssl->options.tls ? TLS_FINISHED_SZ :
+                                                     FINISHED_SZ;
+    byte             input[FINISHED_SZ + DTLS_HANDSHAKE_HEADER_SZ];  /* max */
+    byte            *output;
+    Hashes*          hashes;
+    int              ret;
+    int              headerSz = HANDSHAKE_HEADER_SZ;
+
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            headerSz += DTLS_HANDSHAKE_EXTRA;
+            ssl->keys.dtls_epoch++;
+            ssl->keys.dtls_sequence_number = 0;  /* reset after epoch change */
+        }
+    #endif
+    
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer + 
+             ssl->buffers.outputBuffer.idx;
+
+    AddHandShakeHeader(input, finishedSz, finished, ssl);
+
+    /* make finished hashes */
+    hashes = (Hashes*)&input[headerSz];
+    BuildFinished(ssl, hashes, ssl->options.side == CLIENT_END ? client :
+                  server);
+
+    if ( (sendSz = BuildMessage(ssl, output, input, headerSz +
+                                finishedSz, handshake)) == -1)
+        return BUILD_MSG_ERROR;
+
+    if (!ssl->options.resuming) {
+        AddSession(ssl);    /* just try */
+        if (ssl->options.side == CLIENT_END)
+            BuildFinished(ssl, &ssl->verifyHashes, server);
+        else
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+    }
+    else {
+        if (ssl->options.side == CLIENT_END)
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+        else
+            BuildFinished(ssl, &ssl->verifyHashes, client);
+    }
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz,
+                          ssl->heap);
+    #endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    return SendBuffered(ssl);
+}
+
+
+int SendCertificate(SSL* ssl)
+{
+    int    sendSz, length, ret = 0;
+    word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    word32 certSz, listSz;
+    byte*  output = 0;
+
+    if (ssl->options.usingPSK_cipher) return 0;  /* not needed */
+
+    if (ssl->options.sendVerify == SEND_BLANK_CERT) {
+        certSz = 0;
+        length = CERT_HEADER_SZ;
+        listSz = 0;
+    }
+    else {
+        certSz = ssl->buffers.certificate.length;
+        /* list + cert size */
+        length = certSz + 2 * CERT_HEADER_SZ;
+        listSz = certSz + CERT_HEADER_SZ;
+    }
+    sendSz = length + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            i      += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+        }
+    #endif
+
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.idx;
+
+    AddHeaders(output, length, certificate, ssl);
+
+    /* list total */
+    c32to24(listSz, output + i);
+    i += CERT_HEADER_SZ;
+
+    /* member */
+    if (certSz) {
+        c32to24(certSz, output + i);
+        i += CERT_HEADER_SZ;
+        XMEMCPY(output + i, ssl->buffers.certificate.buffer, certSz);
+        i += certSz;
+    }
+    HashOutput(ssl, output, sendSz, 0);
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
+                           ssl->heap);
+    #endif
+
+    if (ssl->options.side == SERVER_END)
+        ssl->options.serverState = SERVER_CERT_COMPLETE;
+
+    ssl->buffers.outputBuffer.length += sendSz;
+    return SendBuffered(ssl);
+}
+
+
+int SendCertificateRequest(SSL* ssl)
+{
+    byte   *output;
+    int    ret;
+    int    sendSz;
+    word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    
+    int  typeTotal = 1;  /* only rsa for now */
+    int  reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ;  /* add auth later */
+
+    if (ssl->options.usingPSK_cipher) return 0;  /* not needed */
+
+    sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            i      += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+        }
+    #endif
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.idx;
+
+    AddHeaders(output, reqSz, certificate_request, ssl);
+
+    /* write to output */
+    output[i++] = typeTotal;  /* # of types */
+    output[i++] = rsa_sign;
+
+    c16toa(0, &output[i]);  /* auth's */
+    i += REQ_HEADER_SZ;
+
+    HashOutput(ssl, output, sendSz, 0);
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output,
+                          sendSz, ssl->heap);
+    #endif
+    ssl->buffers.outputBuffer.length += sendSz;
+    return SendBuffered(ssl);
+}
+
+
+int SendData(SSL* ssl, const void* buffer, int sz)
+{
+    int sent = 0,  /* plainText size */
+        sendSz,
+        ret;
+
+    if (ssl->error == WANT_WRITE)
+        ssl->error = 0;
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        int err;
+        if ( (err = CyaSSL_negotiate(ssl)) != 0) 
+            return  err;
+    }
+
+    /* last time system socket output buffer was full, try again to send */
+    if (ssl->buffers.outputBuffer.length > 0) {
+        if ( (ssl->error = SendBuffered(ssl)) < 0) {
+            CYASSL_ERROR(ssl->error);
+            if (ssl->error == SOCKET_ERROR_E && ssl->options.connReset)
+                return 0;     /* peer reset */
+            return ssl->error;
+        }
+        else {
+            /* advance sent to previous sent + plain size just sent */
+            sent = ssl->buffers.prevSent + ssl->buffers.plainSz;
+            CYASSL_MSG("sent write buffered data");
+        }
+    }
+
+    for (;;) {
+        int   len = min(sz - sent, OUTPUT_RECORD_SIZE);
+        byte* out;
+        byte* sendBuffer = (byte*)buffer + sent;  /* may switch on comp */
+        int   buffSz = len;                       /* may switch on comp */
+#ifdef HAVE_LIBZ
+        byte  comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+#endif
+
+        if (sent == sz) break;
+
+#ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            len    = min(len, MAX_UDP_SIZE);
+            buffSz = len;
+        }
+#endif
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, len + COMP_EXTRA +
+                                      MAX_MSG_EXTRA)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        out = ssl->buffers.outputBuffer.buffer +
+              ssl->buffers.outputBuffer.idx;
+
+#ifdef HAVE_LIBZ
+        if (ssl->options.usingCompression) {
+            buffSz = Compress(ssl, sendBuffer, buffSz, comp, sizeof(comp));
+            if (buffSz < 0) {
+                return buffSz;
+            }
+            sendBuffer = comp;
+        }
+#endif
+        sendSz = BuildMessage(ssl, out, sendBuffer, buffSz,
+                              application_data);
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        if ( (ret = SendBuffered(ssl)) < 0) {
+            CYASSL_ERROR(ret);
+            /* store for next call if WANT_WRITE or user embedSend() that
+               doesn't present like WANT_WRITE */
+            ssl->buffers.plainSz  = len;
+            ssl->buffers.prevSent = sent;
+            if (ret == SOCKET_ERROR_E && ssl->options.connReset)
+                return 0;  /* peer reset */
+            return ssl->error = ret;
+        }
+
+        sent += len;
+
+        /* only one message per attempt */
+        if (ssl->options.partialWrite == 1)
+            break;
+    }
+ 
+    return sent;
+}
+
+/* process input data */
+int ReceiveData(SSL* ssl, byte* output, int sz)
+{
+    int size;
+
+    CYASSL_ENTER("ReceiveData()");
+
+    if (ssl->error == WANT_READ)
+        ssl->error = 0;
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        int err;
+        if ( (err = CyaSSL_negotiate(ssl)) != 0)
+            return  err;
+    }
+
+    while (ssl->buffers.clearOutputBuffer.length == 0)
+        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+            CYASSL_ERROR(ssl->error);
+            if (ssl->error == ZERO_RETURN) {
+                ssl->options.isClosed = 1;
+                return 0;         /* no more data coming */
+            }
+            if (ssl->error == SOCKET_ERROR_E)
+                if (ssl->options.connReset || ssl->options.isClosed)
+                    return 0;     /* peer reset or closed */
+            return ssl->error;
+        }
+
+    if (sz < (int)ssl->buffers.clearOutputBuffer.length)
+        size = sz;
+    else
+        size = ssl->buffers.clearOutputBuffer.length;
+
+    XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size);
+    ssl->buffers.clearOutputBuffer.length -= size;
+    ssl->buffers.clearOutputBuffer.buffer += size;
+   
+    if (ssl->buffers.clearOutputBuffer.length == 0 && 
+                                           ssl->buffers.inputBuffer.dynamicFlag)
+       ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+
+    CYASSL_LEAVE("ReceiveData()", size);
+    return size;
+}
+
+
+/* send alert message */
+int SendAlert(SSL* ssl, int severity, int type)
+{
+    byte input[ALERT_SIZE];
+    byte *output;
+    int  sendSz;
+    int  ret;
+
+    /* if sendalert is called again for nonbloking */
+    if (ssl->options.sendAlertState != 0) {
+        ret = SendBuffered(ssl);
+        if (ret == 0)
+            ssl->options.sendAlertState = 0;
+        return ret;
+    }
+
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, ALERT_SIZE + MAX_MSG_EXTRA)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.idx;
+
+    input[0] = severity;
+    input[1] = type;
+
+    if (ssl->keys.encryptionOn)
+        sendSz = BuildMessage(ssl, output, input, sizeof(input), alert);
+    else {
+        RecordLayerHeader *const rl = (RecordLayerHeader*)output;
+        rl->type    = alert;
+        rl->version = ssl->version;
+        c16toa(ALERT_SIZE, rl->length);      
+
+        XMEMCPY(output + RECORD_HEADER_SZ, input, sizeof(input));
+        sendSz = RECORD_HEADER_SZ + sizeof(input);
+    }
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("Alert", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Alert", &ssl->timeoutInfo, output, sendSz,ssl->heap);
+    #endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+    ssl->options.sendAlertState = 1;
+
+    return SendBuffered(ssl);
+}
+
+
+
+void SetErrorString(int error, char* buffer)
+{
+    const int max = MAX_ERROR_SZ;  /* shorthand */
+
+#ifdef NO_ERROR_STRINGS
+
+    XSTRNCPY(buffer, "no support for error strings built in", max);
+
+#else
+
+    /* pass to CTaoCrypt */
+    if (error < MAX_CODE_E && error > MIN_CODE_E) {
+        CTaoCryptErrorString(error, buffer);
+        return;
+    }
+
+    switch (error) {
+
+    case UNSUPPORTED_SUITE :
+        XSTRNCPY(buffer, "unsupported cipher suite", max);
+        break;
+
+    case PREFIX_ERROR :
+        XSTRNCPY(buffer, "bad index to key rounds", max);
+        break;
+
+    case MEMORY_ERROR :
+        XSTRNCPY(buffer, "out of memory", max);
+        break;
+
+    case VERIFY_FINISHED_ERROR :
+        XSTRNCPY(buffer, "verify problem on finished", max);
+        break;
+
+    case VERIFY_MAC_ERROR :
+        XSTRNCPY(buffer, "verify mac problem", max);
+        break;
+
+    case PARSE_ERROR :
+        XSTRNCPY(buffer, "parse error on header", max);
+        break;
+
+    case SIDE_ERROR :
+        XSTRNCPY(buffer, "wrong client/server type", max);
+        break;
+
+    case NO_PEER_CERT :
+        XSTRNCPY(buffer, "peer didn't send cert", max);
+        break;
+
+    case UNKNOWN_HANDSHAKE_TYPE :
+        XSTRNCPY(buffer, "weird handshake type", max);
+        break;
+
+    case SOCKET_ERROR_E :
+        XSTRNCPY(buffer, "error state on socket", max);
+        break;
+
+    case SOCKET_NODATA :
+        XSTRNCPY(buffer, "expected data, not there", max);
+        break;
+
+    case INCOMPLETE_DATA :
+        XSTRNCPY(buffer, "don't have enough data to complete task", max);
+        break;
+
+    case UNKNOWN_RECORD_TYPE :
+        XSTRNCPY(buffer, "unknown type in record hdr", max);
+        break;
+
+    case DECRYPT_ERROR :
+        XSTRNCPY(buffer, "error during decryption", max);
+        break;
+
+    case FATAL_ERROR :
+        XSTRNCPY(buffer, "revcd alert fatal error", max);
+        break;
+
+    case ENCRYPT_ERROR :
+        XSTRNCPY(buffer, "error during encryption", max);
+        break;
+
+    case FREAD_ERROR :
+        XSTRNCPY(buffer, "fread problem", max);
+        break;
+
+    case NO_PEER_KEY :
+        XSTRNCPY(buffer, "need peer's key", max);
+        break;
+
+    case NO_PRIVATE_KEY :
+        XSTRNCPY(buffer, "need the private key", max);
+        break;
+
+    case RSA_PRIVATE_ERROR :
+        XSTRNCPY(buffer, "error during rsa priv op", max);
+        break;
+
+    case MATCH_SUITE_ERROR :
+        XSTRNCPY(buffer, "can't match cipher suite", max);
+        break;
+
+    case BUILD_MSG_ERROR :
+        XSTRNCPY(buffer, "build message failure", max);
+        break;
+
+    case BAD_HELLO :
+        XSTRNCPY(buffer, "client hello malformed", max);
+        break;
+
+    case DOMAIN_NAME_MISMATCH :
+        XSTRNCPY(buffer, "peer subject name mismatch", max);
+        break;
+
+    case WANT_READ :
+        XSTRNCPY(buffer, "non-blocking socket wants data to be read", max);
+        break;
+
+    case NOT_READY_ERROR :
+        XSTRNCPY(buffer, "handshake layer not ready yet, complete first", max);
+        break;
+
+    case PMS_VERSION_ERROR :
+        XSTRNCPY(buffer, "premaster secret version mismatch error", max);
+        break;
+
+    case VERSION_ERROR :
+        XSTRNCPY(buffer, "record layer version error", max);
+        break;
+
+    case WANT_WRITE :
+        XSTRNCPY(buffer, "non-blocking socket write buffer full", max);
+        break;
+
+    case BUFFER_ERROR :
+        XSTRNCPY(buffer, "malformed buffer input error", max);
+        break;
+
+    case VERIFY_CERT_ERROR :
+        XSTRNCPY(buffer, "verify problem on certificate", max);
+        break;
+
+    case VERIFY_SIGN_ERROR :
+        XSTRNCPY(buffer, "verify problem based on signature", max);
+        break;
+
+    case CLIENT_ID_ERROR :
+        XSTRNCPY(buffer, "psk client identity error", max);
+        break;
+
+    case SERVER_HINT_ERROR:
+        XSTRNCPY(buffer, "psk server hint error", max);
+        break;
+
+    case PSK_KEY_ERROR:
+        XSTRNCPY(buffer, "psk key callback error", max);
+        break;
+
+    case NTRU_KEY_ERROR:
+        XSTRNCPY(buffer, "NTRU key error", max);
+        break;
+
+    case NTRU_DRBG_ERROR:
+        XSTRNCPY(buffer, "NTRU drbg error", max);
+        break;
+
+    case NTRU_ENCRYPT_ERROR:
+        XSTRNCPY(buffer, "NTRU encrypt error", max);
+        break;
+
+    case NTRU_DECRYPT_ERROR:
+        XSTRNCPY(buffer, "NTRU decrypt error", max);
+        break;
+
+    case ZLIB_INIT_ERROR:
+        XSTRNCPY(buffer, "zlib init error", max);
+        break;
+
+    case ZLIB_COMPRESS_ERROR:
+        XSTRNCPY(buffer, "zlib compress error", max);
+        break;
+
+    case ZLIB_DECOMPRESS_ERROR:
+        XSTRNCPY(buffer, "zlib decompress error", max);
+        break;
+
+    case GETTIME_ERROR:
+        XSTRNCPY(buffer, "gettimeofday() error", max);
+        break;
+
+    case GETITIMER_ERROR:
+        XSTRNCPY(buffer, "getitimer() error", max);
+        break;
+
+    case SIGACT_ERROR:
+        XSTRNCPY(buffer, "sigaction() error", max);
+        break;
+
+    case SETITIMER_ERROR:
+        XSTRNCPY(buffer, "setitimer() error", max);
+        break;
+
+    case LENGTH_ERROR:
+        XSTRNCPY(buffer, "record layer length error", max);
+        break;
+
+    case PEER_KEY_ERROR:
+        XSTRNCPY(buffer, "cant decode peer key", max);
+        break;
+
+    case ZERO_RETURN:
+        XSTRNCPY(buffer, "peer sent close notify alert", max);
+        break;
+
+    default :
+        XSTRNCPY(buffer, "unknown error number", max);
+    }
+
+#endif /* NO_ERROR_STRINGS */
+}
+
+
+
+/* be sure to add to cipher_name_idx too !!!! */
+const char* const cipher_names[] = 
+{
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    "RC4-SHA",
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    "RC4-MD5",
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    "DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    "AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    "AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    "DHE-RSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    "DHE-RSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    "PSK-AES128-CBC-SHA",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    "PSK-AES256-CBC-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    "HC128-MD5",
+#endif
+    
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+    "HC128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    "RABBIT-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    "NTRU-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    "NTRU-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    "NTRU-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    "NTRU-AES256-SHA",
+#endif
+};
+
+
+
+/* cipher suite number that matches above name table */
+int cipher_name_idx[] =
+{
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    SSL_RSA_WITH_RC4_128_SHA,
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    SSL_RSA_WITH_RC4_128_MD5,
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    SSL_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    TLS_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    TLS_RSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    TLS_PSK_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    TLS_PSK_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    TLS_RSA_WITH_HC_128_CBC_MD5,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+    TLS_RSA_WITH_HC_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    TLS_RSA_WITH_RABBIT_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    TLS_NTRU_RSA_WITH_RC4_128_SHA,
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    TLS_NTRU_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    TLS_NTRU_RSA_WITH_AES_256_CBC_SHA,    
+#endif
+};
+
+
+/* return true if set, else false */
+/* only supports full name from cipher_name[] delimited by : */
+int SetCipherList(SSL_CTX* ctx, const char* list)
+{
+    int  ret = 0, i;
+    char name[MAX_SUITE_NAME];
+
+    char  needle[] = ":";
+    char* haystack = (char*)list;
+    char* prev;
+
+    const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]);
+    int idx = 0;
+
+    if (!list)
+        return 0;
+    
+    if (*list == 0) return 1;   /* CyaSSL default */
+
+    if (XSTRNCMP(haystack, "ALL", 3) == 0) return 1;  /* CyaSSL defualt */
+
+    for(;;) {
+        size_t len;
+        prev = haystack;
+        haystack = XSTRSTR(haystack, needle);
+
+        if (!haystack)    /* last cipher */
+            len = min(sizeof(name), XSTRLEN(prev));
+        else
+            len = min(sizeof(name), (size_t)(haystack - prev));
+
+        XSTRNCPY(name, prev, len);
+        name[(len == sizeof(name)) ? len - 1 : len] = 0;
+
+        for (i = 0; i < suiteSz; i++)
+            if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) {
+
+                ctx->suites.suites[idx++] = 0x00;  /* first byte always zero */
+                ctx->suites.suites[idx++] = cipher_name_idx[i];
+
+                if (!ret) ret = 1;   /* found at least one */
+                break;
+            }
+        if (!haystack) break;
+        haystack++;
+    }
+
+    if (ret) {
+        ctx->suites.setSuites = 1;
+        ctx->suites.suiteSz   = idx;
+    }
+
+    return ret;
+}
+
+
+#ifdef CYASSL_CALLBACKS
+
+    /* Initialisze HandShakeInfo */
+    void InitHandShakeInfo(HandShakeInfo* info)
+    {
+        int i;
+
+        info->cipherName[0] = 0;
+        for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++)
+            info->packetNames[i][0] = 0;
+        info->numberPackets = 0;
+        info->negotiationError = 0;
+    }
+
+    /* Set Final HandShakeInfo parameters */
+    void FinishHandShakeInfo(HandShakeInfo* info, const SSL* ssl)
+    {
+        int i;
+        int sz = sizeof(cipher_name_idx)/sizeof(int); 
+
+        for (i = 0; i < sz; i++)
+            if (ssl->options.cipherSuite == (byte)cipher_name_idx[i]) {
+                XSTRNCPY(info->cipherName, cipher_names[i], MAX_CIPHERNAME_SZ);
+                break;
+            }
+
+        /* error max and min are negative numbers */
+        if (ssl->error <= MIN_PARAM_ERR && ssl->error >= MAX_PARAM_ERR)
+            info->negotiationError = ssl->error;
+    }
+
+   
+    /* Add name to info packet names, increase packet name count */
+    void AddPacketName(const char* name, HandShakeInfo* info)
+    {
+        if (info->numberPackets < MAX_PACKETS_HANDSHAKE) {
+            XSTRNCPY(info->packetNames[info->numberPackets++], name,
+                    MAX_PACKETNAME_SZ);
+        }
+    } 
+
+
+    /* Initialisze TimeoutInfo */
+    void InitTimeoutInfo(TimeoutInfo* info)
+    {
+        int i;
+
+        info->timeoutName[0] = 0;
+        info->flags          = 0;
+
+        for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) {
+            info->packets[i].packetName[0]     = 0;
+            info->packets[i].timestamp.tv_sec  = 0;
+            info->packets[i].timestamp.tv_usec = 0;
+            info->packets[i].bufferValue       = 0;
+            info->packets[i].valueSz           = 0;
+        }
+        info->numberPackets        = 0;
+        info->timeoutValue.tv_sec  = 0;
+        info->timeoutValue.tv_usec = 0;
+    }
+
+
+    /* Free TimeoutInfo */
+    void FreeTimeoutInfo(TimeoutInfo* info, void* heap)
+    {
+        int i;
+        for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++)
+            if (info->packets[i].bufferValue) {
+                XFREE(info->packets[i].bufferValue, heap, DYNAMIC_TYPE_INFO);
+                info->packets[i].bufferValue = 0;
+            }
+
+    }
+
+
+    /* Add PacketInfo to TimeoutInfo */
+    void AddPacketInfo(const char* name, TimeoutInfo* info, const byte* data,
+                       int sz, void* heap)
+    {
+        if (info->numberPackets < (MAX_PACKETS_HANDSHAKE - 1)) {
+            Timeval currTime;
+
+            /* may add name after */
+            if (name)
+                XSTRNCPY(info->packets[info->numberPackets].packetName, name,
+                        MAX_PACKETNAME_SZ);
+
+            /* add data, put in buffer if bigger than static buffer */
+            info->packets[info->numberPackets].valueSz = sz;
+            if (sz < MAX_VALUE_SZ)
+                XMEMCPY(info->packets[info->numberPackets].value, data, sz);
+            else {
+                info->packets[info->numberPackets].bufferValue =
+                           XMALLOC(sz, heap, DYNAMIC_TYPE_INFO);
+                if (!info->packets[info->numberPackets].bufferValue)
+                    /* let next alloc catch, just don't fill, not fatal here  */
+                    info->packets[info->numberPackets].valueSz = 0;
+                else
+                    XMEMCPY(info->packets[info->numberPackets].bufferValue,
+                           data, sz);
+            }
+            gettimeofday(&currTime, 0);
+            info->packets[info->numberPackets].timestamp.tv_sec  =
+                                                             currTime.tv_sec;
+            info->packets[info->numberPackets].timestamp.tv_usec =
+                                                             currTime.tv_usec;
+            info->numberPackets++;
+        }
+    }
+
+
+    /* Add packet name to previsouly added packet info */
+    void AddLateName(const char* name, TimeoutInfo* info)
+    {
+        /* make sure we have a valid previous one */
+        if (info->numberPackets > 0 && info->numberPackets <
+                                                        MAX_PACKETS_HANDSHAKE) {
+            XSTRNCPY(info->packets[info->numberPackets - 1].packetName, name,
+                    MAX_PACKETNAME_SZ);
+        }
+    }
+
+    /* Add record header to previsouly added packet info */
+    void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info)
+    {
+        /* make sure we have a valid previous one */
+        if (info->numberPackets > 0 && info->numberPackets <
+                                                        MAX_PACKETS_HANDSHAKE) {
+            if (info->packets[info->numberPackets - 1].bufferValue)
+                XMEMCPY(info->packets[info->numberPackets - 1].bufferValue, rl,
+                       RECORD_HEADER_SZ);
+            else
+                XMEMCPY(info->packets[info->numberPackets - 1].value, rl,
+                       RECORD_HEADER_SZ);
+        }
+    }
+
+#endif /* CYASSL_CALLBACKS */
+
+
+
+/* client only parts */
+#ifndef NO_CYASSL_CLIENT
+
+    int SendClientHello(SSL* ssl)
+    {
+        byte              *output;
+        word32             length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                sendSz;
+        int                idSz = ssl->options.resuming ? ID_LEN : 0;
+        int                ret;
+
+        length = sizeof(ProtocolVersion) + RAN_LEN
+               + idSz + ENUM_LEN                      
+               + ssl->suites.suiteSz + SUITE_LEN
+               + COMP_LEN  + ENUM_LEN;
+
+        sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+#ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            length += ENUM_LEN;   /* cookie */
+            sendSz  = length + DTLS_HANDSHAKE_HEADER_SZ + DTLS_RECORD_HEADER_SZ;
+            idx    += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+        }
+#endif
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.idx;
+
+        AddHeaders(output, length, client_hello, ssl);
+
+            /* client hello, first version */
+        XMEMCPY(output + idx, &ssl->version, sizeof(ProtocolVersion));
+        idx += sizeof(ProtocolVersion);
+        ssl->chVersion = ssl->version;  /* store in case changed */
+
+            /* then random */
+        if (ssl->options.connectState == CONNECT_BEGIN) {
+            RNG_GenerateBlock(&ssl->rng, output + idx, RAN_LEN);
+            
+                /* store random */
+            XMEMCPY(ssl->arrays.clientRandom, output + idx, RAN_LEN);
+        } else {
+#ifdef CYASSL_DTLS
+                /* send same random on hello again */
+            XMEMCPY(output + idx, ssl->arrays.clientRandom, RAN_LEN);
+#endif
+        }
+        idx += RAN_LEN;
+
+            /* then session id */
+        output[idx++] = idSz;
+        if (idSz) {
+            XMEMCPY(output + idx, ssl->session.sessionID, ID_LEN);
+            idx += ID_LEN;
+        }
+        
+            /* then DTLS cookie */
+#ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            output[idx++] = 0;
+        }
+#endif
+            /* then cipher suites */
+        c16toa(ssl->suites.suiteSz, output + idx);
+        idx += 2;
+        XMEMCPY(output + idx, &ssl->suites.suites, ssl->suites.suiteSz);
+        idx += ssl->suites.suiteSz;
+
+            /* last, compression */
+        output[idx++] = COMP_LEN;
+        if (ssl->options.usingCompression)
+            output[idx++] = ZLIB_COMPRESSION;
+        else
+            output[idx++] = NO_COMPRESSION;
+            
+        HashOutput(ssl, output, sendSz, 0);
+
+        ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz,
+                          ssl->heap);
+#endif
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        return SendBuffered(ssl);
+    }
+
+
+    static int DoHelloVerifyRequest(SSL* ssl, const byte* input,
+                                    word32* inOutIdx)
+    {
+        ProtocolVersion pv;
+        byte            cookieSz;
+        
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest",
+                                         &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo);
+#endif
+        XMEMCPY(&pv, input + *inOutIdx, sizeof(pv));
+        *inOutIdx += sizeof(pv);
+        
+        cookieSz = input[(*inOutIdx)++];
+        
+        if (cookieSz)
+            *inOutIdx += cookieSz;   /* skip for now */
+        
+        ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+        return 0;
+    }
+
+
+    static int DoServerHello(SSL* ssl, const byte* input, word32* inOutIdx)
+    {
+        byte b;
+        byte compression;
+        ProtocolVersion pv;
+        word32 i = *inOutIdx;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo);
+#endif
+        XMEMCPY(&pv, input + i, sizeof(pv));
+        i += sizeof(pv);
+        XMEMCPY(ssl->arrays.serverRandom, input + i, RAN_LEN);
+        i += RAN_LEN;
+        b = input[i++];
+        if (b) {
+            XMEMCPY(ssl->arrays.sessionID, input + i, b);
+            i += b;
+        }
+        ssl->options.cipherSuite = input[++i];  
+        compression = input[++i];
+        ++i;   /* 2nd byte */
+
+        if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression)
+            ssl->options.usingCompression = 0;  /* turn off if server refused */
+        
+        ssl->options.serverState = SERVER_HELLO_COMPLETE;
+
+        *inOutIdx = i;
+
+        if (ssl->options.resuming) {
+            if (XMEMCMP(ssl->arrays.sessionID, ssl->session.sessionID, ID_LEN)
+                                                                        == 0) {
+                if (SetCipherSpecs(ssl) == 0) {
+                    XMEMCPY(ssl->arrays.masterSecret, ssl->session.masterSecret,
+                           SECRET_LEN);
+                    if (ssl->options.tls)
+                        DeriveTlsKeys(ssl);
+                    else
+                        DeriveKeys(ssl);
+                    ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
+                    return 0;
+                }
+                else
+                    return UNSUPPORTED_SUITE;
+            }
+            else
+                ssl->options.resuming = 0; /* server denied resumption try */
+        }
+
+        return SetCipherSpecs(ssl);
+    }
+
+
+    /* just read in and ignore for now TODO: */
+    static int DoCertificateRequest(SSL* ssl, const byte* input, word32*
+                                    inOutIdx)
+    {
+        word16 len;
+       
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateRequest", &ssl->timeoutInfo);
+        #endif
+        len = input[(*inOutIdx)++];
+
+        /* types, read in here */
+        *inOutIdx += len;
+        ato16(&input[*inOutIdx], &len);
+        *inOutIdx += LENGTH_SZ;
+
+        /* authorities */
+        while (len) {
+            word16 dnSz;
+       
+            ato16(&input[*inOutIdx], &dnSz);
+            *inOutIdx += (REQUEST_HEADER + dnSz);
+            len -= dnSz + REQUEST_HEADER;
+        }
+
+        /* don't send client cert or cert verify if user hasn't provided
+           cert and private key */
+        if (ssl->buffers.certificate.buffer && ssl->buffers.key.buffer)
+            ssl->options.sendVerify = SEND_CERT;
+        else if (IsAtLeastTLSv1_2(ssl))
+            ssl->options.sendVerify = SEND_BLANK_CERT;
+
+        return 0;
+    }
+
+
+    static int DoServerKeyExchange(SSL* ssl, const byte* input, word32*
+                                   inOutIdx)
+    {
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddLateName("ServerKeyExchange", &ssl->timeoutInfo);
+    #endif
+
+    #ifndef NO_PSK
+        if (ssl->specs.kea == psk_kea) {
+            word16 length;
+           
+            ato16(&input[*inOutIdx], &length);
+            *inOutIdx += LENGTH_SZ;
+            XMEMCPY(ssl->arrays.server_hint, &input[*inOutIdx],
+                   min(length, MAX_PSK_ID_LEN));
+            if (length < MAX_PSK_ID_LEN)
+                ssl->arrays.server_hint[length] = 0;
+            else
+                ssl->arrays.server_hint[MAX_PSK_ID_LEN - 1] = 0;
+            *inOutIdx += length;
+
+            return 0;
+        }
+    #endif
+    #ifdef OPENSSL_EXTRA
+        if (ssl->specs.kea == diffie_hellman_kea)
+        {
+        word16 length, verifySz, messageTotal = 6;  /* pSz + gSz + pubSz */
+        byte   messageVerify[MAX_DH_SZ];
+        byte*  signature;
+        byte   hash[FINISHED_SZ];
+        Md5    md5;
+        Sha    sha;
+
+        /* p */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+        messageTotal += length;
+
+        ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                         DYNAMIC_TYPE_DH);
+        if (ssl->buffers.serverDH_P.buffer)
+            ssl->buffers.serverDH_P.length = length;
+        else
+            return MEMORY_ERROR;
+        XMEMCPY(ssl->buffers.serverDH_P.buffer, &input[*inOutIdx], length);
+        *inOutIdx += length;
+
+        /* g */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+        messageTotal += length;
+
+        ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                         DYNAMIC_TYPE_DH);
+        if (ssl->buffers.serverDH_G.buffer)
+            ssl->buffers.serverDH_G.length = length;
+        else
+            return MEMORY_ERROR;
+        XMEMCPY(ssl->buffers.serverDH_G.buffer, &input[*inOutIdx], length);
+        *inOutIdx += length;
+
+        /* pub */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+        messageTotal += length;
+
+        ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                           DYNAMIC_TYPE_DH);
+        if (ssl->buffers.serverDH_Pub.buffer)
+            ssl->buffers.serverDH_Pub.length = length;
+        else
+            return MEMORY_ERROR;
+        XMEMCPY(ssl->buffers.serverDH_Pub.buffer, &input[*inOutIdx], length);
+        *inOutIdx += length;
+
+        /* save message for hash verify */
+        if (messageTotal > sizeof(messageVerify))
+            return BUFFER_ERROR;
+        XMEMCPY(messageVerify, &input[*inOutIdx - messageTotal], messageTotal);
+        verifySz = messageTotal;
+
+        /* signature */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+
+        signature = (byte*)&input[*inOutIdx];
+        *inOutIdx += length;
+
+        /* verify signature */
+
+        /* md5 */
+        InitMd5(&md5);
+        Md5Update(&md5, ssl->arrays.clientRandom, RAN_LEN);
+        Md5Update(&md5, ssl->arrays.serverRandom, RAN_LEN);
+        Md5Update(&md5, messageVerify, verifySz);
+        Md5Final(&md5, hash);
+
+        /* sha */
+        InitSha(&sha);
+        ShaUpdate(&sha, ssl->arrays.clientRandom, RAN_LEN);
+        ShaUpdate(&sha, ssl->arrays.serverRandom, RAN_LEN);
+        ShaUpdate(&sha, messageVerify, verifySz);
+        ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]);
+
+        /* rsa for now */
+        {
+            int   ret;
+            byte* out;
+
+            if (!ssl->peerRsaKeyPresent)
+                return NO_PEER_KEY;
+
+            ret = RsaSSL_VerifyInline(signature, length,&out, &ssl->peerRsaKey);
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                word32 sigSz;
+                byte*  digest;
+                int    hashType;
+                int    digestSz;
+
+                /* sha1 for now */
+                digest   = &hash[MD5_DIGEST_SIZE];
+                hashType = SHAh;
+                digestSz = SHA_DIGEST_SIZE;
+
+                sigSz = EncodeSignature(encodedSig, digest, digestSz, hashType);
+
+                if (sigSz != ret || XMEMCMP(out, encodedSig, sigSz) != 0)
+                    return VERIFY_SIGN_ERROR;
+            }
+            else { 
+                if (ret != sizeof(hash) || XMEMCMP(out, hash, sizeof(hash)))
+                    return VERIFY_SIGN_ERROR;
+            }
+        }
+
+        ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+
+        return 0;
+        }  /* dh_kea */
+    #endif /* OPENSSL_EXTRA */
+        return -1;  /* not supported by build */
+    }
+
+
+    int SendClientKeyExchange(SSL* ssl)
+    {
+        byte   encSecret[MAX_NTRU_ENCRYPT_SZ];
+        word32 encSz = 0;
+        word32 idx = 0;
+        int    ret = 0;
+
+        if (ssl->specs.kea == rsa_kea) {
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.preMasterSecret,
+                              SECRET_LEN);
+            ssl->arrays.preMasterSecret[0] = ssl->chVersion.major;
+            ssl->arrays.preMasterSecret[1] = ssl->chVersion.minor;
+            ssl->arrays.preMasterSz = SECRET_LEN;
+
+            if (ssl->peerRsaKeyPresent == 0)
+                return NO_PEER_KEY;
+
+            ret = RsaPublicEncrypt(ssl->arrays.preMasterSecret, SECRET_LEN,
+                             encSecret, sizeof(encSecret), &ssl->peerRsaKey,
+                             &ssl->rng);
+            if (ret > 0) {
+                encSz = ret;
+                ret = 0;   /* set success to 0 */
+            }
+        #ifdef OPENSSL_EXTRA
+        } else if (ssl->specs.kea == diffie_hellman_kea) {
+            buffer  serverP   = ssl->buffers.serverDH_P;
+            buffer  serverG   = ssl->buffers.serverDH_G;
+            buffer  serverPub = ssl->buffers.serverDH_Pub;
+            byte    priv[ENCRYPT_LEN];
+            word32  privSz;
+            DhKey   key;
+
+            if (serverP.buffer == 0 || serverG.buffer == 0 ||
+                                       serverPub.buffer == 0)
+                return NO_PEER_KEY;
+
+            InitDhKey(&key);
+            ret = DhSetKey(&key, serverP.buffer, serverP.length,
+                           serverG.buffer, serverG.length);
+            if (ret == 0)
+                /* for DH, encSecret is Yc, agree is pre-master */
+                ret = DhGenerateKeyPair(&key, &ssl->rng, priv, &privSz,
+                                        encSecret, &encSz);
+            if (ret == 0)
+                ret = DhAgree(&key, ssl->arrays.preMasterSecret,
+                              &ssl->arrays.preMasterSz, priv, privSz,
+                              serverPub.buffer, serverPub.length);
+            FreeDhKey(&key);
+        #endif /* OPENSSL_EXTRA */
+        #ifndef NO_PSK
+        } else if (ssl->specs.kea == psk_kea) {
+            byte* pms = ssl->arrays.preMasterSecret;
+
+            ssl->arrays.psk_keySz = ssl->options.client_psk_cb(ssl,
+                ssl->arrays.server_hint, ssl->arrays.client_identity,
+                MAX_PSK_ID_LEN, ssl->arrays.psk_key, MAX_PSK_KEY_LEN);
+            if (ssl->arrays.psk_keySz == 0 || 
+                ssl->arrays.psk_keySz > MAX_PSK_KEY_LEN)
+                return PSK_KEY_ERROR;
+            encSz = (word32)XSTRLEN(ssl->arrays.client_identity);
+            if (encSz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR;
+            XMEMCPY(encSecret, ssl->arrays.client_identity, encSz);
+
+            /* make psk pre master secret */
+            /* length of key + length 0s + length of key + key */
+            c16toa((word16)ssl->arrays.psk_keySz, pms);
+            pms += 2;
+            XMEMSET(pms, 0, ssl->arrays.psk_keySz);
+            pms += ssl->arrays.psk_keySz;
+            c16toa((word16)ssl->arrays.psk_keySz, pms);
+            pms += 2;
+            XMEMCPY(pms, ssl->arrays.psk_key, ssl->arrays.psk_keySz);
+            ssl->arrays.preMasterSz = ssl->arrays.psk_keySz * 2 + 4;
+        #endif /* NO_PSK */
+        #ifdef HAVE_NTRU
+        } else if (ssl->specs.kea == ntru_kea) {
+            word32 rc;
+            word16 cipherLen = sizeof(encSecret);
+            DRBG_HANDLE drbg;
+            static uint8_t const cyasslStr[] = {
+                'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U'
+            };
+
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.preMasterSecret,
+                              SECRET_LEN);
+            ssl->arrays.preMasterSz = SECRET_LEN;
+
+            if (ssl->peerNtruKeyPresent == 0)
+                return NO_PEER_KEY;
+
+            rc = crypto_drbg_instantiate(MAX_NTRU_BITS, cyasslStr,
+                                          sizeof(cyasslStr), GetEntropy, &drbg);
+            if (rc != DRBG_OK)
+                return NTRU_DRBG_ERROR; 
+
+            rc = crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen,ssl->peerNtruKey,
+                                     ssl->arrays.preMasterSz,
+                                     ssl->arrays.preMasterSecret,
+                                     &cipherLen, encSecret);
+            crypto_drbg_uninstantiate(drbg);
+            if (rc != NTRU_OK)
+                return NTRU_ENCRYPT_ERROR;
+
+            encSz = cipherLen;
+            ret = 0;
+        #endif /* HAVE_NTRU */
+        } else
+            return -1; /* unsupported kea */
+
+        if (ret == 0) {
+            byte              *output;
+            int                sendSz;
+            word32             tlsSz = 0;
+            
+            if (ssl->options.tls || ssl->specs.kea == diffie_hellman_kea)
+                tlsSz = 2;
+
+            sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+            idx    = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls) {
+                    sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+                    idx    += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+                }
+            #endif
+
+            /* check for avalaible size */
+            if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+                return ret;
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer + 
+                     ssl->buffers.outputBuffer.idx;
+
+            AddHeaders(output, encSz + tlsSz, client_key_exchange, ssl);
+
+            if (tlsSz) {
+                c16toa((word16)encSz, &output[idx]);
+                idx += 2;
+            }
+            XMEMCPY(output + idx, encSecret, encSz);
+            idx += encSz;
+
+            HashOutput(ssl, output, sendSz, 0);
+
+            #ifdef CYASSL_CALLBACKS
+                if (ssl->hsInfoOn)
+                    AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
+                if (ssl->toInfoOn)
+                    AddPacketInfo("ClientKeyExchange", &ssl->timeoutInfo,
+                                  output, sendSz, ssl->heap);
+            #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+
+            ret = SendBuffered(ssl);
+        }
+    
+        if (ret == 0 || ret == WANT_WRITE) {
+            int tmpRet = MakeMasterSecret(ssl);
+            if (tmpRet != 0)
+                ret = tmpRet;   /* save WANT_WRITE unless more serious */
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+        }
+
+        return ret;
+    }
+
+    int SendCertificateVerify(SSL* ssl)
+    {
+        byte              *output;
+        int                sendSz = 0, length, ret;
+        word32             idx = 0;
+        RsaKey             key;
+
+        if (ssl->options.sendVerify == SEND_BLANK_CERT)
+            return 0;  /* sent blank cert, can't verify */
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, MAX_CERT_VERIFY_SZ)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.idx;
+
+        BuildCertHashes(ssl, &ssl->certHashes);
+
+        /* TODO: when add DSS support check here  */
+        InitRsaKey(&key, ssl->heap);
+        ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key,
+                                  ssl->buffers.key.length); 
+        if (ret == 0) {
+            byte*  verify = (byte*)&output[RECORD_HEADER_SZ +
+                                           HANDSHAKE_HEADER_SZ];
+            byte*  signBuffer = ssl->certHashes.md5;
+            word32 signSz = sizeof(Hashes);
+
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls)
+                    verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            #endif
+            length = RsaEncryptSize(&key);
+            c16toa((word16)length, verify);   /* prepend verify header */
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte  encodedSig[MAX_ENCODED_SIG_SZ];
+                byte* digest;
+                int   hashType;
+                int   digestSz;
+
+                /* sha1 for now */
+                digest   = ssl->certHashes.sha;
+                hashType = SHAh;
+                digestSz = SHA_DIGEST_SIZE;
+
+                signSz = EncodeSignature(encodedSig, digest, digestSz,hashType);
+                signBuffer = encodedSig;
+            }
+
+            ret = RsaSSL_Sign(signBuffer, signSz, verify +
+                  VERIFY_HEADER, ENCRYPT_LEN, &key, &ssl->rng);
+
+            if (ret > 0) {
+                ret = 0;  /* reset */
+
+                AddHeaders(output, length + VERIFY_HEADER, certificate_verify,
+                           ssl);
+
+                sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length +
+                                            VERIFY_HEADER;
+                #ifdef CYASSL_DTLS
+                    if (ssl->options.dtls)
+                        sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                #endif
+                HashOutput(ssl, output, sendSz, 0);
+            }
+        }
+
+        FreeRsaKey(&key);
+
+        if (ret == 0) {
+            #ifdef CYASSL_CALLBACKS
+                if (ssl->hsInfoOn)
+                    AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+                if (ssl->toInfoOn)
+                    AddPacketInfo("CertificateVerify", &ssl->timeoutInfo,
+                                  output, sendSz, ssl->heap);
+            #endif
+            ssl->buffers.outputBuffer.length += sendSz;
+            return SendBuffered(ssl);
+        }
+        else
+            return ret;
+    }
+
+
+
+#endif /* NO_CYASSL_CLIENT */
+
+
+#ifndef NO_CYASSL_SERVER
+
+    int SendServerHello(SSL* ssl)
+    {
+        byte              *output;
+        word32             length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                sendSz;
+        int                ret;
+
+        length = sizeof(ProtocolVersion) + RAN_LEN
+               + ID_LEN + ENUM_LEN                 
+               + SUITE_LEN 
+               + ENUM_LEN;
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, MAX_HELLO_SZ)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer + 
+                 ssl->buffers.outputBuffer.idx;
+
+        sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+        AddHeaders(output, length, server_hello, ssl);
+
+        #ifdef CYASSL_DTLS
+            if (ssl->options.dtls) {
+                idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            }
+        #endif
+        /* now write to output */
+            /* first version */
+        XMEMCPY(output + idx, &ssl->version, sizeof(ProtocolVersion));
+        idx += sizeof(ProtocolVersion);
+
+            /* then random */
+        if (!ssl->options.resuming)         
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN);
+        XMEMCPY(output + idx, ssl->arrays.serverRandom, RAN_LEN);
+        idx += RAN_LEN;
+
+#ifdef SHOW_SECRETS
+        {
+            int j;
+            printf("server random: ");
+            for (j = 0; j < RAN_LEN; j++)
+                printf("%02x", ssl->arrays.serverRandom[j]);
+            printf("\n");
+        }
+#endif
+            /* then session id */
+        output[idx++] = ID_LEN;
+        if (!ssl->options.resuming)
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.sessionID, ID_LEN);
+        XMEMCPY(output + idx, ssl->arrays.sessionID, ID_LEN);
+        idx += ID_LEN;
+
+            /* then cipher suite */
+        output[idx++] = 0x00; 
+        output[idx++] = ssl->options.cipherSuite;
+
+            /* last, compression */
+        if (ssl->options.usingCompression)
+            output[idx++] = ZLIB_COMPRESSION;
+        else
+            output[idx++] = NO_COMPRESSION;
+            
+        ssl->buffers.outputBuffer.length += sendSz;
+        HashOutput(ssl, output, sendSz, 0);
+
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ServerHello", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz,
+                              ssl->heap);
+        #endif
+
+        ssl->options.serverState = SERVER_HELLO_COMPLETE;
+
+        return SendBuffered(ssl);
+    }
+
+    int SendServerKeyExchange(SSL* ssl)
+    {
+        int ret = 0;
+
+        if (ssl->specs.kea != psk_kea) return 0;
+
+        #ifndef NO_PSK
+        {
+            byte    *output;
+            word32   length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+            int      sendSz;
+            if (ssl->arrays.server_hint[0] == 0) return 0; /* don't send */
+
+            /* include size part */
+            length = (word32)XSTRLEN(ssl->arrays.server_hint);
+            if (length > MAX_PSK_ID_LEN) return SERVER_HINT_ERROR;
+            length += + HINT_LEN_SZ;
+            sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+            #ifdef CYASSL_DTLS 
+                if (ssl->options.dtls) {
+                    sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                    idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                }
+            #endif
+            /* check for avalaible size */
+            if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+               return ret;
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer + 
+                     ssl->buffers.outputBuffer.idx;
+
+            AddHeaders(output, length, server_key_exchange, ssl);
+
+            /* key data */
+            c16toa((word16)(length - HINT_LEN_SZ), output + idx);
+            idx += HINT_LEN_SZ;
+            XMEMCPY(output + idx, ssl->arrays.server_hint, length - HINT_LEN_SZ);
+
+            HashOutput(ssl, output, sendSz, 0);
+
+            #ifdef CYASSL_CALLBACKS
+                if (ssl->hsInfoOn)
+                    AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+                if (ssl->toInfoOn)
+                    AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo,
+                                  output, sendSz, ssl->heap);
+            #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+            ret = SendBuffered(ssl);
+            ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+        }
+        #endif /*NO_PSK */
+
+        return ret;
+    }
+
+
+    static int MatchSuite(SSL* ssl, Suites* peerSuites)
+    {
+        word16 i, j;
+
+        /* & 0x1 equivalent % 2 */
+        if (peerSuites->suiteSz == 0 || peerSuites->suiteSz & 0x1)
+            return MATCH_SUITE_ERROR;
+
+        /* start with best, if a match we are good, Ciphers are at odd index
+           since all SSL and TLS ciphers have 0x00 first byte               */
+        for (i = 1; i < ssl->suites.suiteSz; i += 2)
+            for (j = 1; j < peerSuites->suiteSz; j += 2)
+                if (ssl->suites.suites[i] == peerSuites->suites[j]) {
+                    ssl->options.cipherSuite = ssl->suites.suites[i];
+                    return SetCipherSpecs(ssl);
+                }
+
+        return MATCH_SUITE_ERROR;
+    }
+
+
+    /* process alert, return level */
+    int ProcessOldClientHello(SSL* ssl, const byte* input, word32* inOutIdx,
+                              word32 inSz, word16 sz)
+    {
+        word32          idx = *inOutIdx;
+        word16          sessionSz;
+        word16          randomSz;
+        word16          i, j;
+        ProtocolVersion pv;
+        Suites          clSuites;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("ClientHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddLateName("ClientHello", &ssl->timeoutInfo);
+#endif
+
+        /* manually hash input since different format */
+        Md5Update(&ssl->hashMd5, input + idx, sz);
+        ShaUpdate(&ssl->hashSha, input + idx, sz);
+
+        /* does this value mean client_hello? */
+        idx++;
+
+        /* version */
+        pv.major = input[idx++];
+        pv.minor = input[idx++];
+        ssl->chVersion = pv;  /* store */
+
+        if (ssl->version.minor > 0 && pv.minor == 0) {
+            if (!ssl->options.downgrade)
+                return VERSION_ERROR;
+            /* turn off tls */
+            ssl->options.tls    = 0;
+            ssl->options.tls1_1 = 0;
+            ssl->version.minor  = 0;
+            InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, FALSE,
+                       ssl->options.haveNTRU);
+        }
+
+        /* suite size */
+        ato16(&input[idx], &clSuites.suiteSz);
+        idx += 2;
+
+        if (clSuites.suiteSz > MAX_SUITE_SZ)
+            return BUFFER_ERROR;
+
+        /* session size */
+        ato16(&input[idx], &sessionSz);
+        idx += 2;
+
+        if (sessionSz > ID_LEN)
+            return BUFFER_ERROR;
+    
+        /* random size */
+        ato16(&input[idx], &randomSz);
+        idx += 2;
+
+        if (randomSz > RAN_LEN)
+            return BUFFER_ERROR;
+
+        /* suites */
+        for (i = 0, j = 0; i < clSuites.suiteSz; i += 3) {    
+            byte first = input[idx++];
+            if (!first) { /* implicit: skip sslv2 type */
+                XMEMCPY(&clSuites.suites[j], &input[idx], 2);
+                j += 2;
+            }
+            idx += 2;
+        }
+        clSuites.suiteSz = j;
+
+        /* session id */
+        if (sessionSz) {
+            XMEMCPY(ssl->arrays.sessionID, input + idx, sessionSz);
+            idx += sessionSz;
+            ssl->options.resuming = 1;
+        }
+
+        /* random */
+        if (randomSz < RAN_LEN)
+            XMEMSET(ssl->arrays.clientRandom, 0, RAN_LEN - randomSz);
+        XMEMCPY(&ssl->arrays.clientRandom[RAN_LEN - randomSz], input + idx,
+               randomSz);
+        idx += randomSz;
+
+        if (ssl->options.usingCompression)
+            ssl->options.usingCompression = 0;  /* turn off */
+
+        ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+        *inOutIdx = idx;
+
+        /* DoClientHello uses same resume code */
+        while (ssl->options.resuming) {  /* let's try */
+            SSL_SESSION* session = GetSession(ssl, ssl->arrays.masterSecret);
+            if (!session) {
+                ssl->options.resuming = 0;
+                break;   /* session lookup failed */
+            }
+            if (MatchSuite(ssl, &clSuites) < 0)
+                return UNSUPPORTED_SUITE;
+
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN);
+            if (ssl->options.tls)
+                DeriveTlsKeys(ssl);
+            else
+                DeriveKeys(ssl);
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+
+            return 0;
+        }
+
+        return MatchSuite(ssl, &clSuites);
+    }
+
+
+    static int DoClientHello(SSL* ssl, const byte* input, word32* inOutIdx,
+                             word32 totalSz, word32 helloSz)
+    {
+        byte b;
+        ProtocolVersion pv;
+        Suites          clSuites;
+        word32 i = *inOutIdx;
+        word32 begin = i;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo);
+#endif
+        /* make sure can read up to session */
+        if (i + sizeof(pv) + RAN_LEN + ENUM_LEN > totalSz)
+            return INCOMPLETE_DATA;
+
+        XMEMCPY(&pv, input + i, sizeof(pv));
+        ssl->chVersion = pv;   /* store */
+        i += sizeof(pv);
+        if (ssl->version.minor > 0 && pv.minor == 0) {
+            if (!ssl->options.downgrade)
+                return VERSION_ERROR;
+            /* turn off tls */
+            ssl->options.tls    = 0;
+            ssl->options.tls1_1 = 0;
+            ssl->version.minor  = 0;
+            InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, FALSE,
+                       ssl->options.haveNTRU);
+        }
+        /* random */
+        XMEMCPY(ssl->arrays.clientRandom, input + i, RAN_LEN);
+        i += RAN_LEN;
+
+#ifdef SHOW_SECRETS
+        {
+            int j;
+            printf("client random: ");
+            for (j = 0; j < RAN_LEN; j++)
+                printf("%02x", ssl->arrays.clientRandom[j]);
+            printf("\n");
+        }
+#endif
+        /* session id */
+        b = input[i++];
+        if (b) {
+            if (i + ID_LEN > totalSz)
+                return INCOMPLETE_DATA;
+            XMEMCPY(ssl->arrays.sessionID, input + i, ID_LEN);
+            i += b;
+            ssl->options.resuming= 1; /* client wants to resume */
+        }
+        
+        #ifdef CYASSL_DTLS
+            /* cookie */
+            if (ssl->options.dtls) {
+                b = input[i++];
+                if (b) {
+                    if (b > MAX_COOKIE_LEN)
+                        return BUFFER_ERROR;
+                    if (i + b > totalSz)
+                        return INCOMPLETE_DATA;
+                    XMEMCPY(ssl->arrays.cookie, input + i, b);
+                    i += b;
+                }
+            }
+        #endif
+
+        if (i + LENGTH_SZ > totalSz)
+            return INCOMPLETE_DATA;
+        /* suites */
+        ato16(&input[i], &clSuites.suiteSz);
+        i += 2;
+
+        /* suites and comp len */
+        if (i + clSuites.suiteSz + ENUM_LEN > totalSz)
+            return INCOMPLETE_DATA;
+        if (clSuites.suiteSz > MAX_SUITE_SZ)
+            return BUFFER_ERROR;
+        XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz);
+        i += clSuites.suiteSz;
+
+        b = input[i++];  /* comp len */
+        if (i + b > totalSz)
+            return INCOMPLETE_DATA;
+
+        if (ssl->options.usingCompression) {
+            int match = 0;
+            while (b--) {
+                byte comp = input[i++];
+                if (comp == ZLIB_COMPRESSION)
+                    match = 1;
+            }
+            if (!match)
+                ssl->options.usingCompression = 0;  /* turn off */
+        }
+        else
+            i += b;  /* ignore, since we're not on */
+
+        ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+
+        *inOutIdx = i;
+        if ( (i - begin) < helloSz)
+            *inOutIdx = begin + helloSz;  /* skip extensions */
+        
+        /* ProcessOld uses same resume code */
+        while (ssl->options.resuming) {  /* let's try */
+            SSL_SESSION* session = GetSession(ssl, ssl->arrays.masterSecret);
+            if (!session) {
+                ssl->options.resuming = 0;
+                break;   /* session lookup failed */
+            }
+            if (MatchSuite(ssl, &clSuites) < 0)
+                return UNSUPPORTED_SUITE;
+
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN);
+            if (ssl->options.tls)
+                DeriveTlsKeys(ssl);
+            else
+                DeriveKeys(ssl);
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+
+            return 0;
+        }
+        return MatchSuite(ssl, &clSuites);
+    }
+
+
+    static int DoCertificateVerify(SSL* ssl, byte* input, word32* inOutsz,
+                                   word32 totalSz)
+    {
+        word16      sz = 0;
+        word32      i = *inOutsz;
+        int         ret = VERIFY_CERT_ERROR;   /* start in error state */
+        byte*       sig;
+        byte*       out;
+        int         outLen;
+
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateVerify", &ssl->timeoutInfo);
+        #endif
+        if ( (i + VERIFY_HEADER) > totalSz)
+            return INCOMPLETE_DATA;
+
+        ato16(&input[i], &sz);
+        i += VERIFY_HEADER;
+
+        if ( (i + sz) > totalSz)
+            return INCOMPLETE_DATA;
+
+        if (sz > ENCRYPT_LEN)
+            return BUFFER_ERROR;
+
+        sig = &input[i];
+        *inOutsz = i + sz;
+        /* TODO: when add DSS support check here  */
+        if (ssl->peerRsaKeyPresent != 0) {
+            outLen = RsaSSL_VerifyInline(sig, sz, &out, &ssl->peerRsaKey);
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                word32 sigSz;
+                byte*  digest;
+                int    hashType;
+                int    digestSz;
+
+                /* sha1 for now */
+                digest   = ssl->certHashes.sha;
+                hashType = SHAh;
+                digestSz = SHA_DIGEST_SIZE;
+
+                sigSz = EncodeSignature(encodedSig, digest, digestSz, hashType);
+
+                if (outLen == sigSz && XMEMCMP(out, encodedSig, sigSz) == 0)
+                    ret = 0;
+            }
+            else {
+                if (outLen == sizeof(ssl->certHashes) && XMEMCMP(out,
+                             ssl->certHashes.md5, sizeof(ssl->certHashes)) == 0)
+                    ret = 0;
+            }
+        }
+        return ret;
+    }
+
+
+    int SendServerHelloDone(SSL* ssl)
+    {
+        byte              *output;
+        int                sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                ret;
+
+        #ifdef CYASSL_DTLS
+            if (ssl->options.dtls)
+                sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+        #endif
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.idx;
+
+        AddHeaders(output, 0, server_hello_done, ssl);
+
+        HashOutput(ssl, output, sendSz, 0);
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("ServerHelloDone", &ssl->timeoutInfo, output, sendSz,
+                          ssl->heap);
+#endif
+        ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        return SendBuffered(ssl);
+    }
+
+
+    int SendHelloVerifyRequest(SSL* ssl)
+    {
+        byte* output;
+        int   length = VERSION_SZ + ENUM_LEN;
+        int   idx    = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ;
+        int   sendSz = length + idx;
+        int   ret;
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.idx;
+
+        AddHeaders(output, length, hello_verify_request, ssl);
+
+        XMEMCPY(output + idx, &ssl->chVersion, VERSION_SZ);
+        idx += VERSION_SZ;
+        output[idx++] = 0;     /* no cookie for now */
+
+        HashOutput(ssl, output, sendSz, 0);
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("HelloVerifyRequest", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("HelloVerifyRequest", &ssl->timeoutInfo, output,
+                          sendSz, ssl->heap);
+#endif
+        ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        return SendBuffered(ssl);
+    }
+
+
+    static int DoClientKeyExchange(SSL* ssl, byte* input,
+                                   word32* inOutIdx)
+    {
+        int    ret = 0;
+        word32 length = 0;
+        byte*  out;
+
+        if (ssl->options.verifyPeer && ssl->options.failNoCert)
+            if (!ssl->options.havePeerCert) {
+                CYASSL_MSG("client didn't present peer cert");
+                return NO_PEER_CERT;
+            }
+
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("ClientKeyExchange", &ssl->timeoutInfo);
+        #endif
+        if (ssl->specs.kea == rsa_kea) {
+            word32 idx = 0;
+            RsaKey key;
+            byte*  tmp = 0;
+
+            InitRsaKey(&key, ssl->heap);
+
+            if (ssl->buffers.key.buffer)
+                ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key,
+                                          ssl->buffers.key.length);
+            else
+                return NO_PRIVATE_KEY;
+
+            if (ret == 0) {
+                length = RsaEncryptSize(&key);
+                ssl->arrays.preMasterSz = SECRET_LEN;
+
+                if (ssl->options.tls)
+                    (*inOutIdx) += 2;
+                tmp = input + *inOutIdx;
+                *inOutIdx += length;
+
+                if (RsaPrivateDecryptInline(tmp, length, &out, &key) ==
+                                                             SECRET_LEN) {
+                    XMEMCPY(ssl->arrays.preMasterSecret, out, SECRET_LEN);
+                    if (ssl->arrays.preMasterSecret[0] != ssl->chVersion.major
+                     ||
+                        ssl->arrays.preMasterSecret[1] != ssl->chVersion.minor)
+
+                        ret = PMS_VERSION_ERROR;
+                    else
+                        ret = MakeMasterSecret(ssl);
+                }
+                else
+                    ret = RSA_PRIVATE_ERROR;
+            }
+
+            FreeRsaKey(&key);
+#ifndef NO_PSK
+        } else if (ssl->specs.kea == psk_kea) {
+            byte* pms = ssl->arrays.preMasterSecret;
+            word16 ci_sz;
+
+            ato16(&input[*inOutIdx], &ci_sz);
+            *inOutIdx += LENGTH_SZ;
+            if (ci_sz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR;
+
+            XMEMCPY(ssl->arrays.client_identity, &input[*inOutIdx], ci_sz);
+            *inOutIdx += ci_sz;
+            ssl->arrays.client_identity[ci_sz] = 0;
+
+            ssl->arrays.psk_keySz = ssl->options.server_psk_cb(ssl,
+                ssl->arrays.client_identity, ssl->arrays.psk_key,
+                MAX_PSK_KEY_LEN);
+            if (ssl->arrays.psk_keySz == 0 || 
+                ssl->arrays.psk_keySz > MAX_PSK_KEY_LEN) return PSK_KEY_ERROR;
+            
+            /* make psk pre master secret */
+            /* length of key + length 0s + length of key + key */
+            c16toa((word16)ssl->arrays.psk_keySz, pms);
+            pms += 2;
+            XMEMSET(pms, 0, ssl->arrays.psk_keySz);
+            pms += ssl->arrays.psk_keySz;
+            c16toa((word16)ssl->arrays.psk_keySz, pms);
+            pms += 2;
+            XMEMCPY(pms, ssl->arrays.psk_key, ssl->arrays.psk_keySz);
+            ssl->arrays.preMasterSz = ssl->arrays.psk_keySz * 2 + 4;
+
+            ret = MakeMasterSecret(ssl);
+#endif /* NO_PSK */
+#ifdef HAVE_NTRU
+        } else if (ssl->specs.kea == ntru_kea) {
+            word32 rc;
+            word16 cipherLen;
+            word16 plainLen = sizeof(ssl->arrays.preMasterSecret);
+            byte*  tmp;
+
+            if (!ssl->buffers.key.buffer)
+                return NO_PRIVATE_KEY;
+
+            ato16(&input[*inOutIdx], &cipherLen);
+            *inOutIdx += LENGTH_SZ;
+            if (cipherLen > MAX_NTRU_ENCRYPT_SZ)
+                return NTRU_KEY_ERROR;
+
+            tmp = input + *inOutIdx;
+            rc = crypto_ntru_decrypt((word16)ssl->buffers.key.length,
+                        ssl->buffers.key.buffer, cipherLen, tmp, &plainLen,
+                        ssl->arrays.preMasterSecret);
+
+            if (rc != NTRU_OK || plainLen != SECRET_LEN)
+                return NTRU_DECRYPT_ERROR;
+            *inOutIdx += cipherLen;
+
+            ssl->arrays.preMasterSz = plainLen;
+            ret = MakeMasterSecret(ssl);
+#endif /* HAVE_NTRU */
+        }
+
+        if (ret == 0) {
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+            if (ssl->options.verifyPeer)
+                BuildCertHashes(ssl, &ssl->certHashes);
+        }
+
+        return ret;
+    }
+
+#endif /* NO_CYASSL_SERVER */
+
+
+#ifdef SINGLE_THREADED
+
+int InitMutex(CyaSSL_Mutex* m)
+{
+    return 0;
+}
+
+
+int FreeMutex(CyaSSL_Mutex* m)
+{
+    return 0;
+}
+
+
+int LockMutex(CyaSSL_Mutex* m)
+{
+    return 0;
+}
+
+
+int UnLockMutex(CyaSSL_Mutex* m)
+{
+    return 0;
+}
+
+#else /* MULTI_THREAD */
+
+    #ifdef USE_WINDOWS_API
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            InitializeCriticalSection(m);
+            return 0;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            DeleteCriticalSection(m);
+            return 0;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            EnterCriticalSection(m);
+            return 0;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            LeaveCriticalSection(m);
+            return 0;
+        }
+
+    #elif defined(CYASSL_PTHREADS)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_init(m, 0) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_destroy(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_lock(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_unlock(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+    #elif defined(THREADX)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_create(m, "CyaSSL Mutex", TX_NO_INHERIT) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_delete(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_get(m, TX_WAIT_FOREVER) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_put(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+    #elif defined(MICRIUM)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_MutexCreate(m) == 0)
+                    return 0;
+                else
+                    return -1;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_FreeMutex(m) == 0)
+                    return 0;
+                else
+                    return -1;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_LockMutex(m) == 0)
+                    return 0;
+                else
+                    return -1;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_UnLockMutex(m) == 0)
+                    return 0;
+                else
+                    return -1;
+            #else
+                return 0;
+            #endif
+
+        }
+
+    #endif /* USE_WINDOWS_API */
+#endif /* SINGLE_THREADED */
+
+
+#ifdef DEBUG_CYASSL
+
+    static int logging = 0;
+
+
+    int CyaSSL_Debugging_ON(void)
+    {
+        logging = 1;
+        return 0;
+    }
+
+
+    void CyaSSL_Debugging_OFF(void)
+    {
+        logging = 0;
+    }
+
+
+#ifdef THREADX
+    int dc_log_printf(char*, ...);
+#endif
+
+    void CYASSL_MSG(const char* msg)
+    {
+        if (logging) {
+#ifdef THREADX
+            dc_log_printf("%s\n", msg);
+#elif defined(MICRIUM)
+        #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+            NetSecure_TraceOut((CPU_CHAR *)msg);
+        #endif
+#else
+            fprintf(stderr, "%s\n", msg);
+#endif
+        }
+    }
+
+
+    void CYASSL_ENTER(const char* msg)
+    {
+        if (logging) {
+            char buffer[80];
+            sprintf(buffer, "CyaSSL Entering %s", msg);
+            CYASSL_MSG(buffer);
+        }
+    }
+
+
+    void CYASSL_LEAVE(const char* msg, int ret)
+    {
+        if (logging) {
+            char buffer[80];
+            sprintf(buffer, "CyaSSL Leaving %s, return %d", msg, ret);
+            CYASSL_MSG(buffer);
+        }
+    }
+
+
+    void CYASSL_ERROR(int error)
+    {
+        if (logging) {
+            char buffer[80];
+            sprintf(buffer, "CyaSSL error occured, error = %d", error);
+            CYASSL_MSG(buffer);
+        }
+    }
+
+
+#else   /* DEBUG_CYASSL */
+
+    int CyaSSL_Debugging_ON(void)
+    {
+        return -1;    /* not compiled in */
+    }
+
+
+    void CyaSSL_Debugging_OFF(void)
+    {
+        /* already off */
+    }
+
+#endif  /* DEBUG_CYASSL */
diff -r 000000000000 -r 5045d2638c29 cyassl_int.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl_int.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,1141 @@
+/* cyassl_int.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#ifndef CYASSL_INT_H
+#define CYASSL_INT_H
+
+
+#include "types.h"
+#include "random.h"
+#include "des3.h"
+#include "hc128.h"
+#include "rabbit.h"
+#include "asn.h"
+#include "ctc_md5.h"
+#include "ctc_aes.h"
+
+#ifdef CYASSL_CALLBACKS
+    #include "cyassl_callbacks.h"
+    #include <signal.h>
+#endif
+
+#ifdef USE_WINDOWS_API 
+    #include <windows.h>
+#elif defined(THREADX)
+    #ifndef SINGLE_THREADED
+        #include "tx_api.h"
+    #endif
+#elif defined(MICRIUM)
+    /* do nothing, just don't pick Unix */
+#else
+    #ifndef SINGLE_THREADED
+        #define CYASSL_PTHREADS
+        #include <pthread.h>
+    #endif
+    #if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+        #include <unistd.h>      /* for close of BIO */
+    #endif
+#endif
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifdef _MSC_VER
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */
+    #pragma warning(disable: 4996)
+#endif
+
+#ifdef NO_AES
+    #if !defined (ALIGN16)
+        #define ALIGN16
+    #endif
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#ifdef USE_WINDOWS_API 
+    typedef unsigned int SOCKET_T;
+#else
+    typedef int SOCKET_T;
+#endif
+
+
+typedef byte word24[3];
+
+/* Define or comment out the cipher suites you'd like to be compiled in
+   make sure to use at least one BUILD_SSL_xxx or BUILD_TLS_xxx is defined
+
+   When adding cipher suites, add name to cipher_names, idx to cipher_name_idx
+*/
+#ifndef NO_RC4
+    #define BUILD_SSL_RSA_WITH_RC4_128_SHA
+    #define BUILD_SSL_RSA_WITH_RC4_128_MD5
+    #if !defined(NO_TLS) && defined(HAVE_NTRU)
+        #define BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    #endif
+#endif
+
+#ifndef NO_DES3
+    #define BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    #if !defined(NO_TLS) && defined(HAVE_NTRU)
+        #define BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    #endif
+#endif
+
+#if !defined(NO_AES) && !defined(NO_TLS)
+    #define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    #define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    #if !defined (NO_PSK)
+        #define BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+        #define BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    #endif
+    #if defined(HAVE_NTRU)
+        #define BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+        #define BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    #endif
+#endif
+
+#if !defined(NO_HC128) && !defined(NO_TLS)
+    #define BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    #define BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+#endif
+
+#if !defined(NO_RABBIT) && !defined(NO_TLS)
+    #define BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+#endif
+
+#if !defined(NO_DH) && !defined(NO_AES) && !defined(NO_TLS) && defined(OPENSSL_EXTRA)
+    #define BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    #define BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+#endif
+
+
+
+#if defined(BUILD_SSL_RSA_WITH_RC4_128_SHA) || \
+    defined(BUILD_SSL_RSA_WITH_RC4_128_MD5)
+    #define BUILD_ARC4
+#endif
+
+#if defined(BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA)
+    #define BUILD_DES3
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_AES_128_CBC_SHA) || \
+    defined(BUILD_TLS_RSA_WITH_AES_256_CBC_SHA)
+    #define BUILD_AES
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_HC_128_CBC_SHA) || \
+    defined(BUILD_TLS_RSA_WITH_HC_128_CBC_MD5)
+    #define BUILD_HC128
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA)
+    #define BUILD_RABBIT
+#endif
+
+#ifdef NO_DES3
+    #define DES_BLOCK_SIZE 8
+#endif
+
+#ifdef NO_AES
+    #define AES_BLOCK_SIZE 16
+#endif
+
+
+/* actual cipher values, 2nd byte */
+enum {
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA  = 0x39,
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA  = 0x33,
+    TLS_RSA_WITH_AES_256_CBC_SHA      = 0x35,
+    TLS_RSA_WITH_AES_128_CBC_SHA      = 0x2F,
+    TLS_PSK_WITH_AES_256_CBC_SHA      = 0x8d,
+    TLS_PSK_WITH_AES_128_CBC_SHA      = 0x8c,
+    SSL_RSA_WITH_RC4_128_SHA          = 0x05,
+    SSL_RSA_WITH_RC4_128_MD5          = 0x04,
+    SSL_RSA_WITH_3DES_EDE_CBC_SHA     = 0x0A,
+
+    /* CyaSSL extension - eSTRAM */
+    TLS_RSA_WITH_HC_128_CBC_MD5       = 0xFB,
+    TLS_RSA_WITH_HC_128_CBC_SHA       = 0xFC,
+    TLS_RSA_WITH_RABBIT_CBC_SHA       = 0xFD,
+
+    /* CyaSSL extension - NTRU */
+    TLS_NTRU_RSA_WITH_RC4_128_SHA      = 0x65,
+    TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA = 0x66,
+    TLS_NTRU_RSA_WITH_AES_128_CBC_SHA  = 0x67,
+    TLS_NTRU_RSA_WITH_AES_256_CBC_SHA  = 0x68
+};
+
+
+enum Misc {
+    SERVER_END = 0,
+    CLIENT_END,
+
+    SEND_CERT       = 1,
+    SEND_BLANK_CERT = 2,
+
+    DTLS_MAJOR      = 0xfe,     /* DTLS major version number */
+    DTLS_MINOR      = 0xff,     /* DTLS minor version number */
+    SSLv3_MAJOR     = 3,        /* SSLv3 and TLSv1+  major version number */
+    SSLv3_MINOR     = 0,        /* TLSv1   minor version number */
+    TLSv1_MINOR     = 1,        /* TLSv1   minor version number */
+    TLSv1_1_MINOR   = 2,        /* TLSv1_1 minor version number */
+    TLSv1_2_MINOR   = 3,        /* TLSv1_2 minor version number */
+    NO_COMPRESSION  =  0,
+    ZLIB_COMPRESSION = 221,     /* CyaSSL zlib compression */
+    SECRET_LEN      = 48,       /* pre RSA and all master */
+    ENCRYPT_LEN     = 256,      /* allow 2048 bit static buffer */
+    SIZEOF_SENDER   =  4,       /* clnt or srvr           */
+    FINISHED_SZ     = MD5_DIGEST_SIZE + SHA_DIGEST_SIZE,
+    MAX_RECORD_SIZE = 16384,    /* 2^14, max size by standard */
+    MAX_UDP_SIZE    = 1400,     /* don't exceed MTU */
+    MAX_MSG_EXTRA   = 68,       /* max added to msg, mac + pad */
+    MAX_COMP_EXTRA  = 1024,     /* max compression extra */
+    MAX_MTU         = 1500,     /* max expected MTU */
+    MAX_DH_SZ       = 612,      /* 2240 p, pub, g + 2 byte size for each */
+    MAX_STR_VERSION = 8,        /* string rep of protocol version */
+
+    PAD_MD5        = 48,       /* pad length for finished */
+    PAD_SHA        = 40,       /* pad length for finished */
+    PEM_LINE_LEN   = 80,       /* PEM line max + fudge */
+    LENGTH_SZ      =  2,       /* length field for HMAC, data only */
+    VERSION_SZ     =  2,       /* length of proctocol version */
+    SEQ_SZ         =  8,       /* 64 bit sequence number  */
+    BYTE3_LEN      =  3,       /* up to 24 bit byte lengths */
+    ALERT_SIZE     =  2,       /* level + description     */
+    REQUEST_HEADER =  2,       /* always use 2 bytes      */
+    VERIFY_HEADER  =  2,       /* always use 2 bytes      */
+
+    MAX_SUITE_SZ = 128,         /* only 64 suites for now! */
+    RAN_LEN      = 32,         /* random length           */
+    SEED_LEN     = RAN_LEN * 2, /* tls prf seed length    */
+    ID_LEN       = 32,         /* session id length       */
+    MAX_COOKIE_LEN = 32,       /* max dtls cookie size    */
+    SUITE_LEN    =  2,         /* cipher suite sz length  */
+    ENUM_LEN     =  1,         /* always a byte           */
+    COMP_LEN     =  1,         /* compression length      */
+    
+    HANDSHAKE_HEADER_SZ = 4,   /* type + length(3)        */
+    RECORD_HEADER_SZ    = 5,   /* type + version + len(2) */
+    CERT_HEADER_SZ      = 3,   /* always 3 bytes          */
+    REQ_HEADER_SZ       = 2,   /* cert request header sz  */
+    HINT_LEN_SZ         = 2,   /* length of hint size field */
+
+    DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */
+    DTLS_RECORD_HEADER_SZ    = 13, /* normal + epoch(2) + seq_num(6) */
+    DTLS_HANDSHAKE_EXTRA     = 8,  /* diff from normal */
+    DTLS_RECORD_EXTRA        = 8,  /* diff from normal */
+
+    FINISHED_LABEL_SZ   = 15,  /* TLS finished label size */
+    TLS_FINISHED_SZ     = 12,  /* TLS has a shorter size  */
+    MASTER_LABEL_SZ     = 13,  /* TLS master secret label sz */
+    KEY_LABEL_SZ        = 13,  /* TLS key block expansion sz */
+    MAX_PRF_HALF        = 128, /* Maximum half secret len */
+    MAX_PRF_LABSEED     = 80,  /* Maximum label + seed len */
+    MAX_PRF_DIG         = 148, /* Maximum digest len      */
+    MAX_REQUEST_SZ      = 256, /* Maximum cert req len (no auth yet */
+    SESSION_FLUSH_COUNT = 256, /* Flush session cache unless user turns off */ 
+
+    RC4_KEY_SIZE        = 16,  /* always 128bit           */
+    DES_KEY_SIZE        =  8,  /* des                     */
+    DES3_KEY_SIZE       = 24,  /* 3 des ede               */
+    DES_IV_SIZE         = DES_BLOCK_SIZE,
+    AES_256_KEY_SIZE    = 32,  /* for 256 bit             */
+    AES_192_KEY_SIZE    = 24,  /* for 192 bit             */
+    AES_IV_SIZE         = 16,  /* always block size       */
+    AES_128_KEY_SIZE    = 16,  /* for 128 bit             */
+
+    HC_128_KEY_SIZE     = 16,  /* 128 bits                */
+    HC_128_IV_SIZE      = 16,  /* also 128 bits           */
+
+    RABBIT_KEY_SIZE     = 16,  /* 128 bits                */
+    RABBIT_IV_SIZE      =  8,  /* 64 bits for iv          */
+
+    EVP_SALT_SIZE       =  8,  /* evp salt size 64 bits   */
+
+    MAX_HELLO_SZ       = 128,  /* max client or server hello */
+    MAX_CERT_VERIFY_SZ = 1024, /* max   */
+    CLIENT_HELLO_FIRST =  35,  /* Protocol + RAN_LEN + sizeof(id_len) */
+    MAX_SUITE_NAME     =  48,  /* maximum length of cipher suite string */
+    DEFAULT_TIMEOUT    = 500,  /* default resumption timeout in seconds */
+
+    MAX_PSK_ID_LEN     = 128,  /* max psk identity/hint supported */
+    MAX_PSK_KEY_LEN    =  64,  /* max psk key supported */
+
+    MAX_CHAIN_DEPTH    =   4,  /* max cert chain peer depth */
+    MAX_X509_SIZE      = 2048, /* max static x509 buffer size */
+    FILE_BUFFER_SIZE   = 1024, /* default static file buffer size for input,
+                                  will use dynamic buffer if not big enough */
+
+    MAX_NTRU_PUB_KEY_SZ = 1027, /* NTRU max for now */
+    MAX_NTRU_ENCRYPT_SZ = 1027, /* NTRU max for now */
+    MAX_NTRU_BITS       =  256, /* max symmetric bit strength */
+    NO_SNIFF           =   0,  /* not sniffing */
+    SNIFF              =   1,  /* currently sniffing */
+
+    NO_COPY            =   0,  /* should we copy static buffer for write */
+    COPY               =   1   /* should we copy static buffer for write */
+};
+
+
+/* states */
+enum states {
+    NULL_STATE = 0,
+
+    SERVER_HELLOVERIFYREQUEST_COMPLETE,
+    SERVER_HELLO_COMPLETE,
+    SERVER_CERT_COMPLETE,
+    SERVER_KEYEXCHANGE_COMPLETE,
+    SERVER_HELLODONE_COMPLETE,
+    SERVER_FINISHED_COMPLETE,
+
+    CLIENT_HELLO_COMPLETE,
+    CLIENT_KEYEXCHANGE_COMPLETE,
+    CLIENT_FINISHED_COMPLETE,
+
+    HANDSHAKE_DONE
+};
+
+
+#ifndef SSL_TYPES_DEFINED
+    typedef struct SSL_METHOD  SSL_METHOD;
+    typedef struct SSL_CTX     SSL_CTX;
+    typedef struct SSL_SESSION SSL_SESSION;
+    typedef struct SSL_CIPHER  SSL_CIPHER;
+    typedef struct SSL         SSL;
+    typedef struct X509        X509;
+    typedef struct X509_CHAIN  X509_CHAIN;
+    typedef struct BIO         BIO;
+    typedef struct BIO_METHOD  BIO_METHOD;
+
+    #undef X509_NAME
+    typedef struct X509_NAME   X509_NAME;
+
+    typedef struct X509_STORE_CTX {
+        int   error;
+        int   error_depth;
+        X509* current_cert;          /* stunnel dereference */
+        char* domain;                /* subject CN domain name */
+    } X509_STORE_CTX;
+
+
+    typedef int (*pem_password_cb)(char*, int, int, void*);
+    typedef int (*CallbackIORecv)(char *buf, int sz, void *ctx);
+    typedef int (*CallbackIOSend)(char *buf, int sz, void *ctx);
+    typedef int (*VerifyCallback)(int, X509_STORE_CTX*);
+    
+    /* make sure C++ programs have C linkage for callbacks */
+    void CyaSSL_SetIORecv(SSL_CTX*, CallbackIORecv);
+    void CyaSSL_SetIOSend(SSL_CTX*, CallbackIOSend);
+
+    void CyaSSL_SetIOReadCtx(SSL* ssl, void *ctx);
+    void CyaSSL_SetIOWriteCtx(SSL* ssl, void *ctx);
+#endif /* SSL_TYPES_DEFINED */
+
+
+/* SSL Version */
+typedef struct ProtocolVersion {
+    byte major;
+    byte minor;
+} ProtocolVersion;
+
+
+ProtocolVersion MakeSSLv3(void);
+ProtocolVersion MakeTLSv1(void);
+ProtocolVersion MakeTLSv1_1(void);
+ProtocolVersion MakeTLSv1_2(void);
+
+#ifdef CYASSL_DTLS
+    ProtocolVersion MakeDTLSv1(void);
+#endif
+
+
+enum BIO_TYPE {
+    BIO_BUFFER = 1,
+    BIO_SOCKET = 2,
+    BIO_SSL    = 3
+};
+
+
+/* OpenSSL BIO_METHOD type */
+struct BIO_METHOD {
+    byte type;               /* method type */
+};
+
+
+/* OpenSSL BIO type */
+struct BIO {
+    byte type;          /* method type */
+    byte close;         /* close flag */
+    byte eof;           /* eof flag */
+    SSL* ssl;           /* possible associated ssl */
+    int  fd;            /* possible file descriptor */
+    BIO* prev;          /* previous in chain */
+    BIO* next;          /* next in chain */
+};
+
+
+/* OpenSSL method type */
+struct SSL_METHOD {
+    ProtocolVersion version;
+    int             side;         /* connection side, server or client */
+    int             verifyPeer;   /* request or send certificate       */
+    int             verifyNone;   /* whether to verify certificate     */
+    int             failNoCert;   /* fail if no certificate            */
+    int             downgrade;    /* whether to downgrade version, default no */
+};
+
+
+/* defautls to client */
+void InitSSL_Method(SSL_METHOD*, ProtocolVersion);
+
+/* for sniffer */
+int DoFinished(SSL* ssl, const byte* input, word32* inOutIdx, int sniff);
+int DoApplicationData(SSL* ssl, byte* input, word32* inOutIdx);
+
+
+/* CyaSSL buffer type */
+typedef struct buffer {
+    word32 length;
+    byte*  buffer;
+} buffer;
+
+
+enum {
+    FORCED_FREE = 1,
+    NO_FORCED_FREE = 0
+};
+
+
+/* only use compression extra if using compression */
+#ifdef HAVE_LIBZ
+    #define COMP_EXTRA MAX_COMP_EXTRA
+#else
+    #define COMP_EXTRA 0
+#endif
+
+/* only the sniffer needs space in the buffer for an extra MTU record */
+#ifdef CYASSL_SNIFFER
+    #define MTU_EXTRA MAX_MTU
+#else
+    #define MTU_EXTRA 0
+#endif
+
+/* give user option to use 16K static buffers, sniffer needs them too */
+#if defined(LARGE_STATIC_BUFFERS) || defined(CYASSL_SNIFFER)
+    #define RECORD_SIZE MAX_RECORD_SIZE
+#else
+    #define RECORD_SIZE 128
+#endif
+
+
+/* user option to turn off 16K output option */
+/* if using small static buffers (default) and SSL_write tries to write data
+   larger than the record we have, dynamically get it, unless user says only
+   write in static buffer chuncks  */
+#ifndef STATIC_CHUNKS_ONLY
+    #define OUTPUT_RECORD_SIZE MAX_RECORD_SIZE
+#else
+    #define OUTPUT_RECORD_SIZE RECORD_SIZE
+#endif
+
+/* CyaSSL input buffer
+
+   RFC 2246:
+
+   length
+       The length (in bytes) of the following TLSPlaintext.fragment.
+       The length should not exceed 2^14.
+*/
+#define STATIC_BUFFER_LEN RECORD_HEADER_SZ + RECORD_SIZE + COMP_EXTRA + \
+        MTU_EXTRA + MAX_MSG_EXTRA
+
+typedef struct {
+    word32 length;       /* total buffer length used */
+    word32 idx;          /* idx to part of length already consumed */
+    byte*  buffer;       /* place holder for static or dynamic buffer */
+    ALIGN16 byte staticBuffer[STATIC_BUFFER_LEN];
+    word32 bufferSize;   /* current buffer size */
+    byte   dynamicFlag;  /* dynamic memory currently in use */
+} bufferStatic;
+
+/* Cipher Suites holder */
+typedef struct Suites {
+    int    setSuites;               /* user set suites from default */
+    byte   suites[MAX_SUITE_SZ];  
+    word16 suiteSz;                 /* suite length in bytes        */
+} Suites;
+
+
+void InitSuites(Suites*, ProtocolVersion, byte, byte, byte);
+int  SetCipherList(SSL_CTX* ctx, const char* list);
+
+#ifndef PSK_TYPES_DEFINED
+    typedef unsigned int (*psk_client_callback)(SSL*, const char*, char*,
+                          unsigned int, unsigned char*, unsigned int);
+    typedef unsigned int (*psk_server_callback)(SSL*, const char*,
+                          unsigned char*, unsigned int);
+#endif /* PSK_TYPES_DEFINED */
+
+
+#ifndef CYASSL_USER_IO
+    /* default IO callbacks */
+    int EmbedReceive(char *buf, int sz, void *ctx);
+    int EmbedSend(char *buf, int sz, void *ctx);
+#endif
+
+#ifdef CYASSL_DTLS
+    int IsUDP(void*);
+#endif
+
+
+/* OpenSSL Cipher type just points back to SSL */
+struct SSL_CIPHER {
+    SSL* ssl;
+};
+
+
+/* OpenSSL context type */
+struct SSL_CTX {
+    SSL_METHOD* method;
+    buffer      certificate;
+    buffer      privateKey;
+    Signer*     caList;           /* SSL_CTX owns this, SSL will reference */
+    Suites      suites;
+    void*       heap;             /* for user memory overrides */
+    byte        verifyPeer;
+    byte        verifyNone;
+    byte        failNoCert;
+    byte        sessionCacheOff;
+    byte        sessionCacheFlushOff;
+    byte        sendVerify;       /* for client side */
+    byte        haveDH;           /* server DH parms set by user */
+    byte        haveNTRU;         /* server private NTRU key loaded */
+    byte        partialWrite;     /* only one msg per write call */
+    byte        quietShutdown;    /* don't send close notify */
+    CallbackIORecv CBIORecv;
+    CallbackIOSend CBIOSend;
+    VerifyCallback verifyCallback;      /* cert verification callback */
+#ifndef NO_PSK
+    byte        havePSK;                /* psk key set by user */
+    psk_client_callback client_psk_cb;  /* client callback */
+    psk_server_callback server_psk_cb;  /* server callback */
+    char        server_hint[MAX_PSK_ID_LEN];
+#endif /* NO_PSK */
+#ifdef OPENSSL_EXTRA
+    pem_password_cb passwd_cb;
+    void*            userdata;
+#endif /* OPENSSL_EXTRA */
+};
+
+
+void InitSSL_Ctx(SSL_CTX*, SSL_METHOD*);
+void FreeSSL_Ctx(SSL_CTX*);
+void SSL_CtxResourceFree(SSL_CTX*);
+
+int DeriveTlsKeys(SSL* ssl);
+int ProcessOldClientHello(SSL* ssl, const byte* input, word32* inOutIdx,
+                          word32 inSz, word16 sz);
+
+/* All cipher suite related info */
+typedef struct CipherSpecs {
+    byte bulk_cipher_algorithm;
+    byte cipher_type;               /* block or stream */
+    byte mac_algorithm;
+    byte kea;                       /* key exchange algo */
+    byte sig_algo;
+    byte hash_size;
+    byte pad_size;
+    word16 key_size;
+    word16 iv_size;
+    word16 block_size;
+} CipherSpecs;
+
+
+
+/* Supported Ciphers from page 43  */
+enum BulkCipherAlgorithm { 
+    cipher_null,
+    rc4,
+    rc2,
+    des,
+    triple_des,             /* leading 3 (3des) not valid identifier */
+    des40,
+    idea,
+    aes,
+    hc128,                  /* CyaSSL extensions */
+    rabbit
+};
+
+
+/* Supported Message Authentication Codes from page 43 */
+enum MACAlgorithm { 
+    no_mac,
+    md5_mac,
+    sha_mac,
+    rmd_mac,
+    sha256_mac
+};
+
+
+/* Supported Key Exchange Protocols */
+enum KeyExchangeAlgorithm { 
+    no_kea = 0,
+    rsa_kea, 
+    diffie_hellman_kea, 
+    fortezza_kea,
+    psk_kea,
+    ntru_kea
+};
+
+
+/* Supported Authentication Schemes */
+enum SignatureAlgorithm {
+    anonymous_sa_algo = 0,
+    rsa_sa_algo,
+    dsa_sa_algo
+};
+
+
+/* Valid client certificate request types from page 27 */
+enum ClientCertificateType {    
+    rsa_sign            = 1, 
+    dss_sign            = 2,
+    rsa_fixed_dh        = 3,
+    dss_fixed_dh        = 4,
+    rsa_ephemeral_dh    = 5,
+    dss_ephemeral_dh    = 6,
+    fortezza_kea_cert   = 20
+};
+
+
+enum CipherType { stream, block };
+
+
+/* keys and secrets */
+typedef struct Keys {
+    byte client_write_MAC_secret[SHA_DIGEST_SIZE];   /* max sizes */
+    byte server_write_MAC_secret[SHA_DIGEST_SIZE]; 
+    byte client_write_key[AES_256_KEY_SIZE];         /* max sizes */
+    byte server_write_key[AES_256_KEY_SIZE]; 
+    byte client_write_IV[AES_IV_SIZE];               /* max sizes */
+    byte server_write_IV[AES_IV_SIZE];
+
+    word32 peer_sequence_number;
+    word32 sequence_number;
+    
+#ifdef CYASSL_DTLS
+    word32 dtls_sequence_number;
+    word32 dtls_peer_sequence_number;
+    word16 dtls_handshake_number;
+    word16 dtls_epoch;
+    word16 dtls_peer_epoch;
+#endif
+
+    word32 encryptSz;             /* last size of encrypted data   */
+    byte   encryptionOn;          /* true after change cipher spec */
+} Keys;
+
+
+/* cipher for now */
+typedef union {
+#ifdef BUILD_ARC4
+    Arc4   arc4;
+#endif
+#ifdef BUILD_DES3
+    Des3   des3;
+#endif
+#ifdef BUILD_AES
+    Aes    aes;
+#endif
+#ifdef BUILD_HC128
+    HC128  hc128;
+#endif
+#ifdef BUILD_RABBIT
+    Rabbit rabbit;
+#endif
+} Ciphers;
+
+
+/* hashes type */
+typedef struct Hashes {
+    byte md5[MD5_DIGEST_SIZE];
+    byte sha[SHA_DIGEST_SIZE];
+} Hashes;
+
+
+/* Static x509 buffer */
+typedef struct x509_buffer {
+    int  length;                  /* actual size */
+    byte buffer[MAX_X509_SIZE];   /* max static cert size */
+} x509_buffer;
+
+
+/* CyaSSL X509_CHAIN, for no dynamic memory SESSION_CACHE */
+struct X509_CHAIN {
+    int         count;                    /* total number in chain */
+    x509_buffer certs[MAX_CHAIN_DEPTH];   /* only allow max depth 4 for now */
+};
+
+
+/* openSSL session type */
+struct SSL_SESSION {
+    byte         sessionID[ID_LEN];
+    byte         masterSecret[SECRET_LEN];
+    word32       bornOn;                        /* create time in seconds   */
+    word32       timeout;                       /* timeout in seconds       */
+#ifdef SESSION_CERTS
+    X509_CHAIN      chain;                      /* peer cert chain, static  */
+    ProtocolVersion version;
+    byte            cipherSuite;
+#endif
+};
+
+
+SSL_SESSION* GetSession(SSL*, byte*);
+int          SetSession(SSL*, SSL_SESSION*);
+
+typedef void (*hmacfp) (SSL*, byte*, const byte*, word32, int, int);
+
+
+/* client connect state for nonblocking restart */
+enum ConnectState {
+    CONNECT_BEGIN = 0,
+    CLIENT_HELLO_SENT,
+    HELLO_AGAIN,               /* HELLO_AGAIN s for DTLS case */
+    HELLO_AGAIN_REPLY,
+    FIRST_REPLY_DONE,
+    FIRST_REPLY_FIRST,
+    FIRST_REPLY_SECOND,
+    FIRST_REPLY_THIRD,
+    FIRST_REPLY_FOURTH,
+    FINISHED_DONE,
+    SECOND_REPLY_DONE
+};
+
+
+/* server accpet state for nonblocking restart */
+enum AcceptState {
+    ACCEPT_BEGIN = 0,
+    ACCEPT_CLIENT_HELLO_DONE,
+    HELLO_VERIFY_SENT,
+    ACCEPT_FIRST_REPLY_DONE,
+    SERVER_HELLO_SENT,
+    CERT_SENT,
+    KEY_EXCHANGE_SENT,
+    CERT_REQ_SENT,
+    SERVER_HELLO_DONE,
+    ACCEPT_SECOND_REPLY_DONE,
+    CHANGE_CIPHER_SENT,
+    ACCEPT_FINISHED_DONE,
+    ACCEPT_THIRD_REPLY_DONE
+};
+
+
+typedef struct Buffers {
+    buffer          certificate;            /* SSL_CTX owns */
+    buffer          key;                    /* SSL_CTX owns */
+    buffer          domainName;             /* for client check */
+    buffer          serverDH_P;
+    buffer          serverDH_G;
+    buffer          serverDH_Pub;
+    buffer          serverDH_Priv;
+    bufferStatic    inputBuffer;
+    bufferStatic    outputBuffer;
+    buffer          clearOutputBuffer;
+    int             prevSent;              /* previous plain text bytes sent
+                                              when got WANT_WRITE            */
+    int             plainSz;               /* plain text bytes in buffer to send
+                                              when got WANT_WRITE            */
+} Buffers;
+
+
+typedef struct Options {
+    byte            sessionCacheOff;
+    byte            sessionCacheFlushOff;
+    byte            cipherSuite;
+    byte            serverState;
+    byte            clientState;
+    byte            handShakeState;
+    byte            side;               /* client or server end */
+    byte            verifyPeer;
+    byte            verifyNone;
+    byte            failNoCert;
+    byte            downgrade;          /* allow downgrade of versions */
+    byte            sendVerify;         /* false = 0, true = 1, sendBlank = 2 */
+    byte            resuming;
+    byte            tls;                /* using TLS ? */
+    byte            tls1_1;             /* using TLSv1.1+ ? */
+    byte            dtls;               /* using datagrams ? */
+    byte            connReset;          /* has the peer reset */
+    byte            isClosed;           /* if we consider conn closed */
+    byte            closeNotify;        /* we've recieved a close notify */
+    byte            sentNotify;         /* we've sent a close notify */
+    byte            connectState;       /* nonblocking resume */
+    byte            acceptState;        /* nonblocking resume */
+    byte            usingCompression;   /* are we using compression */
+    byte            haveDH;             /* server DH parms set by user */
+    byte            haveNTRU;           /* server NTRU private key loaded */
+    byte            havePeerCert;       /* do we have peer's cert */
+    byte            usingPSK_cipher;    /* whether we're using psk as cipher */
+    byte            sendAlertState;     /* nonblocking resume */ 
+    byte            processReply;       /* nonblocking resume */
+    byte            partialWrite;       /* only one msg per write call */
+    byte            quietShutdown;      /* don't send close notify */
+#ifndef NO_PSK
+    byte            havePSK;            /* psk key set by user */
+    psk_client_callback client_psk_cb;
+    psk_server_callback server_psk_cb;
+#endif /* NO_PSK */
+} Options;
+
+
+typedef struct Arrays {
+    byte            clientRandom[RAN_LEN];
+    byte            serverRandom[RAN_LEN];
+    byte            sessionID[ID_LEN];
+    byte            preMasterSecret[ENCRYPT_LEN];
+    byte            masterSecret[SECRET_LEN];
+#ifdef CYASSL_DTLS
+    byte            cookie[MAX_COOKIE_LEN];
+#endif
+#ifndef NO_PSK
+    char            client_identity[MAX_PSK_ID_LEN];
+    char            server_hint[MAX_PSK_ID_LEN];
+    byte            psk_key[MAX_PSK_KEY_LEN];
+    word32          psk_keySz;          /* acutal size */
+#endif
+    word32          preMasterSz;        /* differs for DH, actual size */
+} Arrays;
+
+
+#undef X509_NAME
+
+struct X509_NAME {
+    char  name[ASN_NAME_MAX];
+    int   sz;
+};
+
+
+struct X509 {
+    X509_NAME issuer;
+    X509_NAME subject;
+};
+
+
+/* record layer header for PlainText, Compressed, and CipherText */
+typedef struct RecordLayerHeader {
+    byte            type;
+    ProtocolVersion version;
+    byte            length[2];
+} RecordLayerHeader;
+
+
+/* record layer header for DTLS PlainText, Compressed, and CipherText */
+typedef struct DtlsRecordLayerHeader {
+    byte            type;
+    ProtocolVersion version;
+    byte            epoch[2];             /* increment on cipher state change */
+    byte            sequence_number[6];   /* per record */
+    byte            length[2];
+} DtlsRecordLayerHeader;
+
+
+/* OpenSSL ssl type */
+struct SSL {
+    SSL_CTX*        ctx;
+    int             error;
+    ProtocolVersion version;            /* negotiated version */
+    ProtocolVersion chVersion;          /* client hello version */
+    Suites          suites;
+    Ciphers         encrypt;
+    Ciphers         decrypt;
+    CipherSpecs     specs;
+    Keys            keys;
+    int             rfd;                /* read  file descriptor */
+    int             wfd;                /* write file descriptor */
+    BIO*            biord;              /* socket bio read  to free/close */
+    BIO*            biowr;              /* socket bio write to free/close */
+    void*           IOCB_ReadCtx;
+    void*           IOCB_WriteCtx;
+    RNG             rng;
+    Md5             hashMd5;            /* md5 hash of handshake msgs */
+    Sha             hashSha;            /* sha hash of handshake msgs */
+    Hashes          verifyHashes;
+    Hashes          certHashes;         /* for cert verify */
+    Signer*         caList;             /* SSL_CTX owns */
+    Buffers         buffers;
+    Options         options;
+    Arrays          arrays;
+    SSL_SESSION     session;
+    RsaKey          peerRsaKey;
+    byte            peerRsaKeyPresent;
+#ifdef HAVE_NTRU
+    word16          peerNtruKeyLen;
+    byte            peerNtruKey[MAX_NTRU_PUB_KEY_SZ];
+    byte            peerNtruKeyPresent;
+#endif
+    hmacfp          hmac;
+    void*           heap;               /* for user overrides */
+    RecordLayerHeader curRL;
+    word16            curSize;
+    SSL_CIPHER      cipher;
+#ifdef HAVE_LIBZ
+    z_stream        c_stream;           /* compression   stream */
+    z_stream        d_stream;           /* decompression stream */
+    byte            didStreamInit;      /* for stream init and end */
+#endif
+#ifdef CYASSL_CALLBACKS
+    HandShakeInfo   handShakeInfo;      /* info saved during handshake */
+    TimeoutInfo     timeoutInfo;        /* info saved during handshake */
+    byte            hsInfoOn;           /* track handshake info        */
+    byte            toInfoOn;           /* track timeout   info        */
+#endif
+#ifdef OPENSSL_EXTRA
+    X509            peerCert;           /* X509 peer cert */
+#endif
+};
+
+
+int  InitSSL(SSL*, SSL_CTX*);
+void FreeSSL(SSL*);
+void SSL_ResourceFree(SSL*);
+
+
+enum {
+    IV_SZ   = 32,          /* max iv sz */
+    NAME_SZ = 80,          /* max one line */
+};
+
+
+typedef struct EncryptedInfo {
+    char   name[NAME_SZ];
+    byte   iv[IV_SZ];
+    word32 ivSz;
+    byte   set;
+} EncryptedInfo;
+
+
+#ifdef CYASSL_CALLBACKS
+    void InitHandShakeInfo(HandShakeInfo*);
+    void FinishHandShakeInfo(HandShakeInfo*, const SSL*);
+    void AddPacketName(const char*, HandShakeInfo*);
+
+    void InitTimeoutInfo(TimeoutInfo*);
+    void FreeTimeoutInfo(TimeoutInfo*, void*);
+    void AddPacketInfo(const char*, TimeoutInfo*, const byte*, int, void*);
+    void AddLateName(const char*, TimeoutInfo*);
+    void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info);
+#endif
+
+
+/* Record Layer Header identifier from page 12 */
+enum ContentType {
+    no_type            = 0,
+    change_cipher_spec = 20, 
+    alert              = 21, 
+    handshake          = 22, 
+    application_data   = 23 
+};
+
+
+/* handshake header, same for each message type, pgs 20/21 */
+typedef struct HandShakeHeader {
+    byte            type;
+    word24          length;
+} HandShakeHeader;
+
+
+/* DTLS handshake header, same for each message type */
+typedef struct DtlsHandShakeHeader {
+    byte            type;
+    word24          length;
+    byte            message_seq[2];    /* start at 0, restransmit gets same # */
+    word24          fragment_offset;   /* bytes in previous fragments */
+    word24          fragment_length;   /* length of this fragment */
+} DtlsHandShakeHeader;
+
+
+enum HandShakeType {
+    no_shake            = -1,
+    hello_request       = 0, 
+    client_hello        = 1, 
+    server_hello        = 2,
+    hello_verify_request = 3,       /* DTLS addition */
+    certificate         = 11, 
+    server_key_exchange = 12,
+    certificate_request = 13, 
+    server_hello_done   = 14,
+    certificate_verify  = 15, 
+    client_key_exchange = 16,
+    finished            = 20
+};
+
+
+/* Valid Alert types from page 16/17 */
+enum AlertDescription {
+    close_notify            = 0,
+    unexpected_message      = 10,
+    bad_record_mac          = 20,
+    decompression_failure   = 30,
+    handshake_failure       = 40,
+    no_certificate          = 41,
+    bad_certificate         = 42,
+    unsupported_certificate = 43,
+    certificate_revoked     = 44,
+    certificate_expired     = 45,
+    certificate_unknown     = 46,
+    illegal_parameter       = 47,
+    decrypt_error           = 51
+};
+
+
+/* I/O Callback default errors */
+enum IOerrors {
+    IO_ERR_GENERAL    = -1,     /* general unexpected err, not in below group */
+    IO_ERR_WANT_READ  = -2,     /* need to call read  again */
+    IO_ERR_WANT_WRITE = -2,     /* need to call write again */
+    IO_ERR_CONN_RST   = -3,     /* connection reset */
+    IO_ERR_ISR        = -4,     /* interrupt */
+    IO_ERR_CONN_CLOSE = -5      /* connection closed or epipe */
+};
+
+
+enum AlertLevel { 
+    alert_warning = 1, 
+    alert_fatal = 2
+};
+
+
+static const byte client[SIZEOF_SENDER] = { 0x43, 0x4C, 0x4E, 0x54 };
+static const byte server[SIZEOF_SENDER] = { 0x53, 0x52, 0x56, 0x52 };
+
+static const byte tls_client[FINISHED_LABEL_SZ + 1] = "client finished";
+static const byte tls_server[FINISHED_LABEL_SZ + 1] = "server finished";
+
+
+/* internal functions */
+int SendChangeCipher(SSL*);
+int SendData(SSL*, const void*, int);
+int SendCertificate(SSL*);
+int SendCertificateRequest(SSL*);
+int SendServerKeyExchange(SSL*);
+int SendBuffered(SSL*);
+int ReceiveData(SSL*, byte*, int);
+int SendFinished(SSL*);
+int SendAlert(SSL*, int, int);
+int ProcessReply(SSL*);
+
+int SetCipherSpecs(SSL*);
+int MakeMasterSecret(SSL*);
+
+int  AddSession(SSL*);
+int  DeriveKeys(SSL* ssl);
+int  StoreKeys(SSL* ssl, const byte* keyData);
+
+int IsTLS(const SSL* ssl);
+int IsAtLeastTLSv1_2(const SSL* ssl);
+
+void ShrinkInputBuffer(SSL* ssl, int forcedFree);
+void ShrinkOutputBuffer(SSL* ssl);
+
+#ifndef NO_CYASSL_CLIENT
+    int SendClientHello(SSL*);
+    int SendClientKeyExchange(SSL*);
+    int SendCertificateVerify(SSL*);
+#endif /* NO_CYASSL_CLIENT */
+
+#ifndef NO_CYASSL_SERVER
+    int SendServerHello(SSL*);
+    int SendServerHelloDone(SSL*);
+    #ifdef CYASSL_DTLS
+        int SendHelloVerifyRequest(SSL*);
+    #endif
+#endif /* NO_CYASSL_SERVER */
+
+
+#ifndef NO_TLS
+    
+
+#endif /* NO_TLS */
+
+
+
+typedef double timer_d;
+
+timer_d Timer(void);
+word32  LowResTimer(void);
+
+
+#ifdef SINGLE_THREADED
+    typedef int CyaSSL_Mutex;
+#else /* MULTI_THREADED */
+    #ifdef USE_WINDOWS_API 
+        typedef CRITICAL_SECTION CyaSSL_Mutex;
+    #elif defined(CYASSL_PTHREADS)
+        typedef pthread_mutex_t CyaSSL_Mutex;
+    #elif defined(THREADX)
+        typedef TX_MUTEX CyaSSL_Mutex;
+    #elif defined(MICRIUM)
+        typedef OS_MUTEX CyaSSL_Mutex;
+    #else
+        #error Need a mutex type in multithreaded mode
+    #endif /* USE_WINDOWS_API */
+#endif /* SINGLE_THREADED */
+
+int InitMutex(CyaSSL_Mutex*);
+int FreeMutex(CyaSSL_Mutex*);
+int LockMutex(CyaSSL_Mutex*);
+int UnLockMutex(CyaSSL_Mutex*);
+
+
+#ifdef DEBUG_CYASSL
+
+    void CYASSL_ENTER(const char* msg);
+    void CYASSL_LEAVE(const char* msg, int ret);
+
+    void CYASSL_ERROR(int);
+    void CYASSL_MSG(const char* msg);
+
+#else /* DEBUG_CYASSL   */
+
+    #define CYASSL_ENTER(m)
+    #define CYASSL_LEAVE(m, r)
+
+    #define CYASSL_ERROR(e) 
+    #define CYASSL_MSG(m)
+
+#endif /* DEBUG_CYASSL  */
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* CyaSSL_INT_H */
+
diff -r 000000000000 -r 5045d2638c29 cyassl_io.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl_io.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,192 @@
+/* cyassl_io.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef _WIN32_WCE
+    /* On WinCE winsock2.h must be included before windows.h for socket stuff */
+    #include <winsock2.h>
+#endif
+
+#include "cyassl_int.h"
+
+/* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove
+   automatic setting of defualt I/O functions EmbedSend() and EmbedReceive()
+   but they'll still nedd SetCallback xxx() at end of file 
+*/
+#ifndef CYASSL_USER_IO
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifndef USE_WINDOWS_API 
+    #include <sys/types.h>
+    #include <errno.h>
+    #include <unistd.h>
+    #include <fcntl.h>
+    #if !(defined(DEVKITPRO) || defined(THREADX))
+        #include <sys/socket.h>
+        #include <arpa/inet.h>
+        #include <netinet/in.h>
+        #include <netdb.h>
+        #include <sys/ioctl.h>
+    #endif
+    #ifdef THREADX
+        #include <socket.h>
+    #endif
+#endif /* USE_WINDOWS_API */
+
+#ifdef __sun
+    #include <sys/filio.h>
+#endif
+
+#ifdef USE_WINDOWS_API 
+    /* no epipe yet */
+    #ifndef WSAEPIPE
+        #define WSAEPIPE       -12345
+    #endif
+    #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
+    #define SOCKET_EAGAIN      WSAEWOULDBLOCK
+    #define SOCKET_ECONNRESET  WSAECONNRESET
+    #define SOCKET_EINTR       WSAEINTR
+    #define SOCKET_EPIPE       WSAEPIPE
+#else
+    #define SOCKET_EWOULDBLOCK EWOULDBLOCK
+    #define SOCKET_EAGAIN      EAGAIN
+    #define SOCKET_ECONNRESET  ECONNRESET
+    #define SOCKET_EINTR       EINTR
+    #define SOCKET_EPIPE       EPIPE
+#endif /* USE_WINDOWS_API */
+
+
+#ifdef DEVKITPRO
+    /* from network.h */
+    int net_send(int, const void*, int, unsigned int);
+    int net_recv(int, void*, int, unsigned int);
+    #define SEND_FUNCTION net_send
+    #define RECV_FUNCTION net_recv
+#else
+    #define SEND_FUNCTION send
+    #define RECV_FUNCTION recv
+#endif
+
+
+static INLINE int LastError(void)
+{
+#ifdef USE_WINDOWS_API 
+    return WSAGetLastError();
+#else
+    return errno;
+#endif
+}
+
+/* The receive embedded callback
+ *  return : nb bytes read, or error
+ */
+int EmbedReceive(char *buf, int sz, void *ctx)
+{
+    int recvd;
+    int err;
+    int socket = *(int*)ctx;
+
+    recvd = RECV_FUNCTION(socket, (char *)buf, sz, 0);
+
+    if (recvd == -1) {
+        err = LastError();
+        if (err == SOCKET_EWOULDBLOCK ||
+            err == SOCKET_EAGAIN)
+            return IO_ERR_WANT_READ;
+
+        else if (err == SOCKET_ECONNRESET)
+            return IO_ERR_CONN_RST;
+
+        else if (err == SOCKET_EINTR)
+            return IO_ERR_ISR;
+
+        else
+            return IO_ERR_GENERAL;
+    }
+    else if (recvd == 0)
+        return IO_ERR_CONN_CLOSE;
+
+    return recvd;
+}
+
+/* The send embedded callback
+ *  return : nb bytes sent, or error
+ */
+int EmbedSend(char *buf, int sz, void *ctx)
+{
+    int socket = *(int*)ctx;
+    int sent;
+    int len = sz;
+
+    sent = SEND_FUNCTION(socket, &buf[sz - len], len, 0);
+
+    if (sent == -1) {
+        if (LastError() == SOCKET_EWOULDBLOCK || 
+            LastError() == SOCKET_EAGAIN)
+            return IO_ERR_WANT_WRITE;
+
+        else if (LastError() == SOCKET_ECONNRESET)
+            return IO_ERR_CONN_RST;
+
+        else if (LastError() == SOCKET_EINTR)
+            return IO_ERR_ISR;
+
+        else if (LastError() == SOCKET_EPIPE)
+            return IO_ERR_CONN_CLOSE;
+
+        else
+            return IO_ERR_GENERAL;
+    }
+ 
+    return sent;
+}
+
+
+#endif /* CYASSL_USER_IO */
+
+
+
+void CyaSSL_SetIORecv(SSL_CTX *ctx, CallbackIORecv CBIORecv)
+{
+    ctx->CBIORecv = CBIORecv;
+}
+
+
+void CyaSSL_SetIOSend(SSL_CTX *ctx, CallbackIOSend CBIOSend)
+{
+    ctx->CBIOSend = CBIOSend;
+}
+
+
+void CyaSSL_SetIOReadCtx(SSL* ssl, void *rctx)
+{
+    ssl->IOCB_ReadCtx = rctx;
+}
+
+
+void CyaSSL_SetIOWriteCtx(SSL* ssl, void *wctx)
+{
+    ssl->IOCB_WriteCtx = wctx;
+}
+
diff -r 000000000000 -r 5045d2638c29 des3.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/des3.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,493 @@
+/* des3.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_DES3
+
+#include "des3.h"
+#ifdef NO_INLINE
+    #include "misc.h"
+#else
+    #include "misc.c"
+#endif
+
+
+/* permuted choice table (key) */
+static const byte pc1[] = {
+       57, 49, 41, 33, 25, 17,  9,
+        1, 58, 50, 42, 34, 26, 18,
+       10,  2, 59, 51, 43, 35, 27,
+       19, 11,  3, 60, 52, 44, 36,
+
+       63, 55, 47, 39, 31, 23, 15,
+        7, 62, 54, 46, 38, 30, 22,
+       14,  6, 61, 53, 45, 37, 29,
+       21, 13,  5, 28, 20, 12,  4
+};
+
+/* number left rotations of pc1 */
+static const byte totrot[] = {
+       1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
+};
+
+/* permuted choice key (table) */
+static const byte pc2[] = {
+       14, 17, 11, 24,  1,  5,
+        3, 28, 15,  6, 21, 10,
+       23, 19, 12,  4, 26,  8,
+       16,  7, 27, 20, 13,  2,
+       41, 52, 31, 37, 47, 55,
+       30, 40, 51, 45, 33, 48,
+       44, 49, 39, 56, 34, 53,
+       46, 42, 50, 36, 29, 32
+};
+
+/* End of DES-defined tables */
+
+/* bit 0 is left-most in byte */
+static const int bytebit[] = {
+       0200,0100,040,020,010,04,02,01
+};
+
+const word32 Spbox[8][64] = {
+{
+0x01010400,0x00000000,0x00010000,0x01010404,
+0x01010004,0x00010404,0x00000004,0x00010000,
+0x00000400,0x01010400,0x01010404,0x00000400,
+0x01000404,0x01010004,0x01000000,0x00000004,
+0x00000404,0x01000400,0x01000400,0x00010400,
+0x00010400,0x01010000,0x01010000,0x01000404,
+0x00010004,0x01000004,0x01000004,0x00010004,
+0x00000000,0x00000404,0x00010404,0x01000000,
+0x00010000,0x01010404,0x00000004,0x01010000,
+0x01010400,0x01000000,0x01000000,0x00000400,
+0x01010004,0x00010000,0x00010400,0x01000004,
+0x00000400,0x00000004,0x01000404,0x00010404,
+0x01010404,0x00010004,0x01010000,0x01000404,
+0x01000004,0x00000404,0x00010404,0x01010400,
+0x00000404,0x01000400,0x01000400,0x00000000,
+0x00010004,0x00010400,0x00000000,0x01010004},
+{
+0x80108020,0x80008000,0x00008000,0x00108020,
+0x00100000,0x00000020,0x80100020,0x80008020,
+0x80000020,0x80108020,0x80108000,0x80000000,
+0x80008000,0x00100000,0x00000020,0x80100020,
+0x00108000,0x00100020,0x80008020,0x00000000,
+0x80000000,0x00008000,0x00108020,0x80100000,
+0x00100020,0x80000020,0x00000000,0x00108000,
+0x00008020,0x80108000,0x80100000,0x00008020,
+0x00000000,0x00108020,0x80100020,0x00100000,
+0x80008020,0x80100000,0x80108000,0x00008000,
+0x80100000,0x80008000,0x00000020,0x80108020,
+0x00108020,0x00000020,0x00008000,0x80000000,
+0x00008020,0x80108000,0x00100000,0x80000020,
+0x00100020,0x80008020,0x80000020,0x00100020,
+0x00108000,0x00000000,0x80008000,0x00008020,
+0x80000000,0x80100020,0x80108020,0x00108000},
+{
+0x00000208,0x08020200,0x00000000,0x08020008,
+0x08000200,0x00000000,0x00020208,0x08000200,
+0x00020008,0x08000008,0x08000008,0x00020000,
+0x08020208,0x00020008,0x08020000,0x00000208,
+0x08000000,0x00000008,0x08020200,0x00000200,
+0x00020200,0x08020000,0x08020008,0x00020208,
+0x08000208,0x00020200,0x00020000,0x08000208,
+0x00000008,0x08020208,0x00000200,0x08000000,
+0x08020200,0x08000000,0x00020008,0x00000208,
+0x00020000,0x08020200,0x08000200,0x00000000,
+0x00000200,0x00020008,0x08020208,0x08000200,
+0x08000008,0x00000200,0x00000000,0x08020008,
+0x08000208,0x00020000,0x08000000,0x08020208,
+0x00000008,0x00020208,0x00020200,0x08000008,
+0x08020000,0x08000208,0x00000208,0x08020000,
+0x00020208,0x00000008,0x08020008,0x00020200},
+{
+0x00802001,0x00002081,0x00002081,0x00000080,
+0x00802080,0x00800081,0x00800001,0x00002001,
+0x00000000,0x00802000,0x00802000,0x00802081,
+0x00000081,0x00000000,0x00800080,0x00800001,
+0x00000001,0x00002000,0x00800000,0x00802001,
+0x00000080,0x00800000,0x00002001,0x00002080,
+0x00800081,0x00000001,0x00002080,0x00800080,
+0x00002000,0x00802080,0x00802081,0x00000081,
+0x00800080,0x00800001,0x00802000,0x00802081,
+0x00000081,0x00000000,0x00000000,0x00802000,
+0x00002080,0x00800080,0x00800081,0x00000001,
+0x00802001,0x00002081,0x00002081,0x00000080,
+0x00802081,0x00000081,0x00000001,0x00002000,
+0x00800001,0x00002001,0x00802080,0x00800081,
+0x00002001,0x00002080,0x00800000,0x00802001,
+0x00000080,0x00800000,0x00002000,0x00802080},
+{
+0x00000100,0x02080100,0x02080000,0x42000100,
+0x00080000,0x00000100,0x40000000,0x02080000,
+0x40080100,0x00080000,0x02000100,0x40080100,
+0x42000100,0x42080000,0x00080100,0x40000000,
+0x02000000,0x40080000,0x40080000,0x00000000,
+0x40000100,0x42080100,0x42080100,0x02000100,
+0x42080000,0x40000100,0x00000000,0x42000000,
+0x02080100,0x02000000,0x42000000,0x00080100,
+0x00080000,0x42000100,0x00000100,0x02000000,
+0x40000000,0x02080000,0x42000100,0x40080100,
+0x02000100,0x40000000,0x42080000,0x02080100,
+0x40080100,0x00000100,0x02000000,0x42080000,
+0x42080100,0x00080100,0x42000000,0x42080100,
+0x02080000,0x00000000,0x40080000,0x42000000,
+0x00080100,0x02000100,0x40000100,0x00080000,
+0x00000000,0x40080000,0x02080100,0x40000100},
+{
+0x20000010,0x20400000,0x00004000,0x20404010,
+0x20400000,0x00000010,0x20404010,0x00400000,
+0x20004000,0x00404010,0x00400000,0x20000010,
+0x00400010,0x20004000,0x20000000,0x00004010,
+0x00000000,0x00400010,0x20004010,0x00004000,
+0x00404000,0x20004010,0x00000010,0x20400010,
+0x20400010,0x00000000,0x00404010,0x20404000,
+0x00004010,0x00404000,0x20404000,0x20000000,
+0x20004000,0x00000010,0x20400010,0x00404000,
+0x20404010,0x00400000,0x00004010,0x20000010,
+0x00400000,0x20004000,0x20000000,0x00004010,
+0x20000010,0x20404010,0x00404000,0x20400000,
+0x00404010,0x20404000,0x00000000,0x20400010,
+0x00000010,0x00004000,0x20400000,0x00404010,
+0x00004000,0x00400010,0x20004010,0x00000000,
+0x20404000,0x20000000,0x00400010,0x20004010},
+{
+0x00200000,0x04200002,0x04000802,0x00000000,
+0x00000800,0x04000802,0x00200802,0x04200800,
+0x04200802,0x00200000,0x00000000,0x04000002,
+0x00000002,0x04000000,0x04200002,0x00000802,
+0x04000800,0x00200802,0x00200002,0x04000800,
+0x04000002,0x04200000,0x04200800,0x00200002,
+0x04200000,0x00000800,0x00000802,0x04200802,
+0x00200800,0x00000002,0x04000000,0x00200800,
+0x04000000,0x00200800,0x00200000,0x04000802,
+0x04000802,0x04200002,0x04200002,0x00000002,
+0x00200002,0x04000000,0x04000800,0x00200000,
+0x04200800,0x00000802,0x00200802,0x04200800,
+0x00000802,0x04000002,0x04200802,0x04200000,
+0x00200800,0x00000000,0x00000002,0x04200802,
+0x00000000,0x00200802,0x04200000,0x00000800,
+0x04000002,0x04000800,0x00000800,0x00200002},
+{
+0x10001040,0x00001000,0x00040000,0x10041040,
+0x10000000,0x10001040,0x00000040,0x10000000,
+0x00040040,0x10040000,0x10041040,0x00041000,
+0x10041000,0x00041040,0x00001000,0x00000040,
+0x10040000,0x10000040,0x10001000,0x00001040,
+0x00041000,0x00040040,0x10040040,0x10041000,
+0x00001040,0x00000000,0x00000000,0x10040040,
+0x10000040,0x10001000,0x00041040,0x00040000,
+0x00041040,0x00040000,0x10041000,0x00001000,
+0x00000040,0x10040040,0x00001000,0x00041040,
+0x10001000,0x00000040,0x10000040,0x10040000,
+0x10040040,0x10000000,0x00040000,0x10001040,
+0x00000000,0x10041040,0x00040040,0x10000040,
+0x10040000,0x10001000,0x10001040,0x00000000,
+0x10041040,0x00041000,0x00041000,0x00001040,
+0x00001040,0x00040040,0x10000000,0x10041000}
+};
+
+
+static INLINE void IPERM(word32* left, word32* right)
+{
+    word32 work;
+
+    *right = rotlFixed(*right, 4U);
+    work = (*left ^ *right) & 0xf0f0f0f0;
+    *left ^= work;
+
+    *right = rotrFixed(*right^work, 20U);
+    work = (*left ^ *right) & 0xffff0000;
+    *left ^= work;
+
+    *right = rotrFixed(*right^work, 18U);
+    work = (*left ^ *right) & 0x33333333;
+    *left ^= work;
+
+    *right = rotrFixed(*right^work, 6U);
+    work = (*left ^ *right) & 0x00ff00ff;
+    *left ^= work;
+
+    *right = rotlFixed(*right^work, 9U);
+    work = (*left ^ *right) & 0xaaaaaaaa;
+    *left = rotlFixed(*left^work, 1U);
+    *right ^= work;
+}
+
+
+static INLINE void FPERM(word32* left, word32* right)
+{
+    word32 work;
+
+    *right = rotrFixed(*right, 1U);
+    work = (*left ^ *right) & 0xaaaaaaaa;
+    *right ^= work;
+
+    *left = rotrFixed(*left^work, 9U);
+    work = (*left ^ *right) & 0x00ff00ff;
+    *right ^= work;
+
+    *left = rotlFixed(*left^work, 6U);
+    work = (*left ^ *right) & 0x33333333;
+    *right ^= work;
+
+    *left = rotlFixed(*left^work, 18U);
+    work = (*left ^ *right) & 0xffff0000;
+    *right ^= work;
+
+    *left = rotlFixed(*left^work, 20U);
+    work = (*left ^ *right) & 0xf0f0f0f0;
+    *right ^= work;
+
+    *left = rotrFixed(*left^work, 4U);
+}
+
+
+static void DesSetKey(const byte* key, int dir, word32* out)
+{
+    byte buffer[56+56+8];
+    byte *const pc1m = buffer;                 /* place to modify pc1 into */
+    byte *const pcr = pc1m + 56;               /* place to rotate pc1 into */
+    byte *const ks = pcr + 56;
+    register int i,j,l;
+    int m;
+
+    for (j = 0; j < 56; j++) {          /* convert pc1 to bits of key */
+        l = pc1[j] - 1;                 /* integer bit location  */
+        m = l & 07;                     /* find bit              */
+        pc1m[j] = (key[l >> 3] &        /* find which key byte l is in */
+            bytebit[m])                 /* and which bit of that byte */
+            ? 1 : 0;                    /* and store 1-bit result */
+    }
+    for (i = 0; i < 16; i++) {          /* key chunk for each iteration */
+        XMEMSET(ks, 0, 8);               /* Clear key schedule */
+        for (j = 0; j < 56; j++)        /* rotate pc1 the right amount */
+            pcr[j] = pc1m[(l = j + totrot[i]) < (j < 28 ? 28 : 56) ? l: l-28];
+        /* rotate left and right halves independently */
+        for (j = 0; j < 48; j++){   /* select bits individually */
+            /* check bit that goes to ks[j] */
+            if (pcr[pc2[j] - 1]){
+                /* mask it in if it's there */
+                l= j % 6;
+                ks[j/6] |= bytebit[l] >> 2;
+            }
+        }
+        /* Now convert to odd/even interleaved form for use in F */
+        out[2*i] = ((word32)ks[0] << 24)
+            | ((word32)ks[2] << 16)
+            | ((word32)ks[4] << 8)
+            | ((word32)ks[6]);
+        out[2*i + 1] = ((word32)ks[1] << 24)
+            | ((word32)ks[3] << 16)
+            | ((word32)ks[5] << 8)
+            | ((word32)ks[7]);
+    }
+    
+    /* reverse key schedule order */
+    if (dir == DES_DECRYPTION)
+        for (i = 0; i < 16; i += 2) {
+            word32 swap = out[i];
+            out[i] = out[DES_KS_SIZE - 2 - i];
+            out[DES_KS_SIZE - 2 - i] = swap;
+
+            swap = out[i + 1];
+            out[i + 1] = out[DES_KS_SIZE - 1 - i];
+            out[DES_KS_SIZE - 1 - i] = swap;
+        }
+   
+}
+
+
+static INLINE int Reverse(int dir)
+{
+    return !dir;
+}
+
+
+void Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+{
+    DesSetKey(key, dir, des->key);
+    
+    XMEMCPY(des->reg, iv, DES_BLOCK_SIZE);
+}
+
+
+void Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+{
+    DesSetKey(key + (dir == DES_ENCRYPTION ? 0 : 16), dir, des->key[0]);
+    DesSetKey(key + 8, Reverse(dir), des->key[1]);
+    DesSetKey(key + (dir == DES_DECRYPTION ? 0 : 16), dir, des->key[2]);
+    
+    XMEMCPY(des->reg, iv, DES_BLOCK_SIZE);
+}
+
+
+void DesRawProcessBlock(word32* lIn, word32* rIn, const word32* kptr)
+{
+    word32 l = *lIn, r = *rIn, i;
+
+    for (i=0; i<8; i++)
+    {
+        word32 work = rotrFixed(r, 4U) ^ kptr[4*i+0];
+        l ^= Spbox[6][(work) & 0x3f]
+          ^  Spbox[4][(work >> 8) & 0x3f]
+          ^  Spbox[2][(work >> 16) & 0x3f]
+          ^  Spbox[0][(work >> 24) & 0x3f];
+        work = r ^ kptr[4*i+1];
+        l ^= Spbox[7][(work) & 0x3f]
+          ^  Spbox[5][(work >> 8) & 0x3f]
+          ^  Spbox[3][(work >> 16) & 0x3f]
+          ^  Spbox[1][(work >> 24) & 0x3f];
+
+        work = rotrFixed(l, 4U) ^ kptr[4*i+2];
+        r ^= Spbox[6][(work) & 0x3f]
+          ^  Spbox[4][(work >> 8) & 0x3f]
+          ^  Spbox[2][(work >> 16) & 0x3f]
+          ^  Spbox[0][(work >> 24) & 0x3f];
+        work = l ^ kptr[4*i+3];
+        r ^= Spbox[7][(work) & 0x3f]
+          ^  Spbox[5][(work >> 8) & 0x3f]
+          ^  Spbox[3][(work >> 16) & 0x3f]
+          ^  Spbox[1][(work >> 24) & 0x3f];
+    }
+
+    *lIn = l; *rIn = r;
+}
+
+
+static void DesProcessBlock(Des* des, const byte* in, byte* out)
+{
+    word32 l, r;
+
+    XMEMCPY(&l, in, sizeof(l));
+    XMEMCPY(&r, in + sizeof(l), sizeof(r));
+    #ifdef LITTLE_ENDIAN_ORDER
+        l = ByteReverseWord32(l);
+        r = ByteReverseWord32(r);
+    #endif
+    IPERM(&l,&r);
+    
+    DesRawProcessBlock(&l, &r, des->key);   
+
+    FPERM(&l,&r);
+    #ifdef LITTLE_ENDIAN_ORDER
+        l = ByteReverseWord32(l);
+        r = ByteReverseWord32(r);
+    #endif
+    XMEMCPY(out, &r, sizeof(r));
+    XMEMCPY(out + sizeof(r), &l, sizeof(l));
+}
+
+
+static void Des3ProcessBlock(Des3* des, const byte* in, byte* out)
+{
+    word32 l, r;
+
+    XMEMCPY(&l, in, sizeof(l));
+    XMEMCPY(&r, in + sizeof(l), sizeof(r));
+    #ifdef LITTLE_ENDIAN_ORDER
+        l = ByteReverseWord32(l);
+        r = ByteReverseWord32(r);
+    #endif
+    IPERM(&l,&r);
+    
+    DesRawProcessBlock(&l, &r, des->key[0]);   
+    DesRawProcessBlock(&r, &l, des->key[1]);   
+    DesRawProcessBlock(&l, &r, des->key[2]);   
+
+    FPERM(&l,&r);
+    #ifdef LITTLE_ENDIAN_ORDER
+        l = ByteReverseWord32(l);
+        r = ByteReverseWord32(r);
+    #endif
+    XMEMCPY(out, &r, sizeof(r));
+    XMEMCPY(out + sizeof(r), &l, sizeof(l));
+}
+
+
+void Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / DES_BLOCK_SIZE;
+
+    while (blocks--) {
+        xorbuf((byte*)des->reg, in, DES_BLOCK_SIZE);
+        DesProcessBlock(des, (byte*)des->reg, (byte*)des->reg);
+        XMEMCPY(out, des->reg, DES_BLOCK_SIZE);
+
+        out += DES_BLOCK_SIZE;
+        in  += DES_BLOCK_SIZE; 
+    }
+}
+
+
+void Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / DES_BLOCK_SIZE;
+    byte   hold[16];
+
+    while (blocks--) {
+        XMEMCPY(des->tmp, in, DES_BLOCK_SIZE);
+        DesProcessBlock(des, (byte*)des->tmp, out);
+        xorbuf(out, (byte*)des->reg, DES_BLOCK_SIZE);
+
+        XMEMCPY(hold, des->reg, DES_BLOCK_SIZE);
+        XMEMCPY(des->reg, des->tmp, DES_BLOCK_SIZE);
+        XMEMCPY(des->tmp, hold, DES_BLOCK_SIZE);
+
+        out += DES_BLOCK_SIZE;
+        in  += DES_BLOCK_SIZE; 
+    }
+}
+
+
+void Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / DES_BLOCK_SIZE;
+
+    while (blocks--) {
+        xorbuf((byte*)des->reg, in, DES_BLOCK_SIZE);
+        Des3ProcessBlock(des, (byte*)des->reg, (byte*)des->reg);
+        XMEMCPY(out, des->reg, DES_BLOCK_SIZE);
+
+        out += DES_BLOCK_SIZE;
+        in  += DES_BLOCK_SIZE; 
+    }
+}
+
+
+void Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / DES_BLOCK_SIZE;
+
+    while (blocks--) {
+        XMEMCPY(des->tmp, in, DES_BLOCK_SIZE);
+        Des3ProcessBlock(des, (byte*)des->tmp, out);
+        xorbuf(out, (byte*)des->reg, DES_BLOCK_SIZE);
+        XMEMCPY(des->reg, des->tmp, DES_BLOCK_SIZE);
+
+        out += DES_BLOCK_SIZE;
+        in  += DES_BLOCK_SIZE; 
+    }
+}
+
+
+#endif /* NO_DES3 */
diff -r 000000000000 -r 5045d2638c29 des3.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/des3.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,75 @@
+/* des3.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef NO_DES3
+
+#ifndef CTAO_CRYPT_DES3_H
+#define CTAO_CRYPT_DES3_H
+
+
+#include "types.h"
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+enum {
+    DES_BLOCK_SIZE  = 8,
+    DES_KS_SIZE     = 32,
+
+    DES_ENCRYPTION  = 0,
+    DES_DECRYPTION  = 1,
+};
+
+
+/* DES encryption and decryption */
+typedef struct Des {
+    word32 key[DES_KS_SIZE];
+    word32 reg[DES_BLOCK_SIZE / sizeof(word32)];      /* for CBC mode */
+    word32 tmp[DES_BLOCK_SIZE / sizeof(word32)];      /* same         */
+} Des;
+
+
+/* DES3 encryption and decryption */
+typedef struct Des3 {
+    word32 key[3][DES_KS_SIZE];
+    word32 reg[DES_BLOCK_SIZE / sizeof(word32)];      /* for CBC mode */
+    word32 tmp[DES_BLOCK_SIZE / sizeof(word32)];      /* same         */
+} Des3;
+
+
+void Des_SetKey(Des* des, const byte* key, const byte* iv, int dir);
+void Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz);
+void Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz);
+
+void Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir);
+void Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz);
+void Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_DES3 */
+#endif /* CTAO_CRYPT_DES3_H */
+
diff -r 000000000000 -r 5045d2638c29 error.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/error.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,100 @@
+/* error.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_ERROR_H
+#define CTAO_CRYPT_ERROR_H
+
+#include "types.h"
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* error codes */
+enum {
+    MAX_ERROR_SZ       =  80,   /* max size of error string */
+    MAX_CODE_E         = -100,  /* errors -101 - -199 */
+    OPEN_RAN_E         = -101,  /* opening random device error */
+    READ_RAN_E         = -102,  /* reading random device error */
+    WINCRYPT_E         = -103,  /* windows crypt init error */
+    CRYPTGEN_E         = -104,  /* windows crypt generation error */
+    RAN_BLOCK_E        = -105,  /* reading random device would block */
+
+    MP_INIT_E          = -110,  /* mp_init error state */
+    MP_READ_E          = -111,  /* mp_read error state */
+    MP_EXPTMOD_E       = -112,  /* mp_exptmod error state */
+    MP_TO_E            = -113,  /* mp_to_xxx error state, can't convert */
+    MP_SUB_E           = -114,  /* mp_sub error state, can't subtract */
+    MP_ADD_E           = -115,  /* mp_add error state, can't add */
+    MP_MUL_E           = -116,  /* mp_mul error state, can't multiply */
+    MP_MULMOD_E        = -117,  /* mp_mulmod error state, can't multiply mod */
+    MP_MOD_E           = -118,  /* mp_mod error state, can't mod */
+    MP_INVMOD_E        = -119,  /* mp_invmod error state, can't inv mod */
+    MP_CMP_E           = -120,  /* mp_cmp error state */
+
+    MEMORY_E           = -125,  /* out of memory error */
+
+    RSA_WRONG_TYPE_E   = -130,  /* RSA wrong block type for RSA function */
+    RSA_BUFFER_E       = -131,  /* RSA buffer error, output too small or 
+                                   input too large */
+    BUFFER_E           = -132,  /* output buffer too small or input too large */
+    ALGO_ID_E          = -133,  /* setting algo id error */
+    PUBLIC_KEY_E       = -134,  /* setting public key error */
+    DATE_E             = -135,  /* setting date validity error */
+    SUBJECT_E          = -136,  /* setting subject name error */
+    ISSUER_E           = -137,  /* setting issuer  name error */
+
+    ASN_PARSE_E        = -140,  /* ASN parsing error, invalid input */
+    ASN_VERSION_E      = -141,  /* ASN version error, invalid number */
+    ASN_GETINT_E       = -142,  /* ASN get big int error, invalid data */
+    ASN_RSA_KEY_E      = -143,  /* ASN key init error, invalid input */
+    ASN_OBJECT_ID_E    = -144,  /* ASN object id error, invalid id */
+    ASN_TAG_NULL_E     = -145,  /* ASN tag error, not null */
+    ASN_EXPECT_0_E     = -146,  /* ASN expect error, not zero */
+    ASN_BITSTR_E       = -147,  /* ASN bit string error, wrong id */
+    ASN_UNKNOWN_OID_E  = -148,  /* ASN oid error, unknown sum id */
+    ASN_DATE_SZ_E      = -149,  /* ASN date error, bad size */
+    ASN_BEFORE_DATE_E  = -150,  /* ASN date error, current date before */
+    ASN_AFTER_DATE_E   = -151,  /* ASN date error, current date after */
+    ASN_SIG_OID_E      = -152,  /* ASN signature error, mismatched oid */
+    ASN_TIME_E         = -153,  /* ASN time error, unkown time type */
+    ASN_INPUT_E        = -154,  /* ASN input error, not enough data */
+    ASN_SIG_CONFIRM_E  = -155,  /* ASN sig error, confirm failure */
+    ASN_SIG_HASH_E     = -156,  /* ASN sig error, unsupported hash type */
+    ASN_SIG_KEY_E      = -157,  /* ASN sig error, unsupported key  type */
+    ASN_DH_KEY_E       = -158,  /* ASN key init error, invalid input */
+    ASN_NTRU_KEY_E     = -159,  /* ASN ntru key decode error, invalid input */
+    MIN_CODE_E         = -200   /* errors -101 - -199 */
+};
+
+
+void CTaoCryptErrorString(int error, char* buffer);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_ERROR_H */
+
diff -r 000000000000 -r 5045d2638c29 hc128.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hc128.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,57 @@
+/* hc128.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_HC128
+
+#ifndef CTAO_CRYPT_HC128_H
+#define CTAO_CRYPT_HC128_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+/* HC-128 stream cipher */
+typedef struct HC128 {
+    word32 T[1024];             /* P[i] = T[i];  Q[i] = T[1024 + i ]; */
+    word32 X[16];
+    word32 Y[16];
+    word32 counter1024;         /* counter1024 = i mod 1024 at the ith step */
+    word32 key[8];
+    word32 iv[8];
+} HC128;
+
+
+void Hc128_Process(HC128*, byte*, const byte*, word32);
+void Hc128_SetKey(HC128*, const byte* key, const byte* iv);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_HC128_H */
+
+#endif /* NO_HC128 */
diff -r 000000000000 -r 5045d2638c29 hmac.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hmac.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,158 @@
+/* hmac.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_HMAC
+
+#include "ctc_hmac.h"
+
+
+
+static int InitHmac(Hmac* hmac, int type)
+{
+    hmac->innerHashKeyed = 0;
+    hmac->macType = type;
+
+    if (!(type == MD5 || type == SHA || type == SHA256))
+        return -1;
+
+    if (type == MD5)
+        InitMd5(&hmac->hash.md5);
+    else if (type == SHA)
+        InitSha(&hmac->hash.sha);
+#ifndef NO_SHA256
+    else if (type == SHA256)
+        InitSha256(&hmac->hash.sha256);
+#endif
+
+    return 0;
+}
+
+
+void HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
+{
+    byte*  ip = (byte*) hmac->ipad;
+    byte*  op = (byte*) hmac->opad;
+    word32 i;
+
+    InitHmac(hmac, type);
+
+    if (length <= HMAC_BLOCK_SIZE)
+        XMEMCPY(ip, key, length);
+    else {
+        if (hmac->macType == MD5) {
+            Md5Update(&hmac->hash.md5, key, length);
+            Md5Final(&hmac->hash.md5, ip);
+            length = MD5_DIGEST_SIZE;
+        }
+        else if (hmac->macType == SHA) {
+            ShaUpdate(&hmac->hash.sha, key, length);
+            ShaFinal(&hmac->hash.sha, ip);
+            length = SHA_DIGEST_SIZE;
+        }
+#ifndef NO_SHA256
+        else if (hmac->macType == SHA256) {
+            Sha256Update(&hmac->hash.sha256, key, length);
+            Sha256Final(&hmac->hash.sha256, ip);
+            length = SHA256_DIGEST_SIZE;
+        }
+#endif
+    }
+    XMEMSET(ip + length, 0, HMAC_BLOCK_SIZE - length);
+
+    for(i = 0; i < HMAC_BLOCK_SIZE; i++) {
+        op[i] = ip[i] ^ OPAD;
+        ip[i] ^= IPAD;
+    }
+}
+
+
+static void HmacKeyInnerHash(Hmac* hmac)
+{
+    if (hmac->macType == MD5)
+        Md5Update(&hmac->hash.md5, (byte*) hmac->ipad, HMAC_BLOCK_SIZE);
+    else if (hmac->macType == SHA)
+        ShaUpdate(&hmac->hash.sha, (byte*) hmac->ipad, HMAC_BLOCK_SIZE);
+#ifndef NO_SHA256
+    else if (hmac->macType == SHA256)
+        Sha256Update(&hmac->hash.sha256, (byte*) hmac->ipad, HMAC_BLOCK_SIZE);
+#endif
+
+    hmac->innerHashKeyed = 1;
+}
+
+
+void HmacUpdate(Hmac* hmac, const byte* msg, word32 length)
+{
+    if (!hmac->innerHashKeyed)
+        HmacKeyInnerHash(hmac);
+
+    if (hmac->macType == MD5)
+        Md5Update(&hmac->hash.md5, msg, length);
+    else if (hmac->macType == SHA)
+        ShaUpdate(&hmac->hash.sha, msg, length);
+#ifndef NO_SHA256
+    else if (hmac->macType == SHA256)
+        Sha256Update(&hmac->hash.sha256, msg, length);
+#endif
+
+}
+
+
+void HmacFinal(Hmac* hmac, byte* hash)
+{
+    if (!hmac->innerHashKeyed)
+        HmacKeyInnerHash(hmac);
+
+    if (hmac->macType == MD5) {
+        Md5Final(&hmac->hash.md5, (byte*) hmac->innerHash);
+
+        Md5Update(&hmac->hash.md5, (byte*) hmac->opad, HMAC_BLOCK_SIZE);
+        Md5Update(&hmac->hash.md5, (byte*) hmac->innerHash, MD5_DIGEST_SIZE);
+
+        Md5Final(&hmac->hash.md5, hash);
+    }
+    else if (hmac->macType ==SHA) {
+        ShaFinal(&hmac->hash.sha, (byte*) hmac->innerHash);
+
+        ShaUpdate(&hmac->hash.sha, (byte*) hmac->opad, HMAC_BLOCK_SIZE);
+        ShaUpdate(&hmac->hash.sha, (byte*) hmac->innerHash, SHA_DIGEST_SIZE);
+
+        ShaFinal(&hmac->hash.sha, hash);
+    }
+#ifndef NO_SHA256
+    else if (hmac->macType ==SHA256) {
+        Sha256Final(&hmac->hash.sha256, (byte*) hmac->innerHash);
+
+        Sha256Update(&hmac->hash.sha256, (byte*) hmac->opad, HMAC_BLOCK_SIZE);
+        Sha256Update(&hmac->hash.sha256, (byte*) hmac->innerHash,
+                     SHA256_DIGEST_SIZE);
+
+        Sha256Final(&hmac->hash.sha256, hash);
+    }
+#endif
+
+    hmac->innerHashKeyed = 0;
+}
+
+
+#endif /* NO_HMAC */
+
diff -r 000000000000 -r 5045d2638c29 integer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/integer.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,4280 @@
+/* integer.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/*
+ * Based on public domain LibTomMath 0.38 by Tom St Denis, tomstdenis@iahu.ca,
+ * http://math.libtomcrypt.com
+ */
+
+
+#ifndef USE_FAST_MATH
+
+#include "integer.h"
+
+
+/* handle up to 6 inits */
+int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e,
+                  mp_int* f)
+{
+    int res = MP_OKAY;
+
+    if (a && ((res = mp_init(a)) != MP_OKAY))
+        return res;
+
+    if (b && ((res = mp_init(b)) != MP_OKAY)) {
+        mp_clear(a);
+        return res;
+    }
+
+    if (c && ((res = mp_init(c)) != MP_OKAY)) {
+        mp_clear(a); mp_clear(b);
+        return res;
+    }
+
+    if (d && ((res = mp_init(d)) != MP_OKAY)) {
+        mp_clear(a); mp_clear(b); mp_clear(c);
+        return res;
+    }
+
+    if (e && ((res = mp_init(e)) != MP_OKAY)) {
+        mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d);
+        return res;
+    }
+
+    if (f && ((res = mp_init(f)) != MP_OKAY)) {
+        mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d); mp_clear(e);
+        return res;
+    }
+
+    return res;
+}
+
+
+/* init a new mp_int */
+int mp_init (mp_int * a)
+{
+  int i;
+
+  /* allocate memory required and clear it */
+  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC, 0,
+                                      DYNAMIC_TYPE_BIGINT);
+  if (a->dp == NULL) {
+    return MP_MEM;
+  }
+
+  /* set the digits to zero */
+  for (i = 0; i < MP_PREC; i++) {
+      a->dp[i] = 0;
+  }
+
+  /* set the used to zero, allocated digits to the default precision
+   * and sign to positive */
+  a->used  = 0;
+  a->alloc = MP_PREC;
+  a->sign  = MP_ZPOS;
+
+  return MP_OKAY;
+}
+
+
+/* clear one (frees)  */
+void
+mp_clear (mp_int * a)
+{
+  int i;
+
+  /* only do anything if a hasn't been freed previously */
+  if (a->dp != NULL) {
+    /* first zero the digits */
+    for (i = 0; i < a->used; i++) {
+        a->dp[i] = 0;
+    }
+
+    /* free ram */
+    XFREE(a->dp, 0, DYNAMIC_TYPE_BIGINT);
+
+    /* reset members to make debugging easier */
+    a->dp    = NULL;
+    a->alloc = a->used = 0;
+    a->sign  = MP_ZPOS;
+  }
+}
+
+
+/* get the size for an unsigned equivalent */
+int mp_unsigned_bin_size (mp_int * a)
+{
+  int     size = mp_count_bits (a);
+  return (size / 8 + ((size & 7) != 0 ? 1 : 0));
+}
+
+
+/* returns the number of bits in an int */
+int
+mp_count_bits (mp_int * a)
+{
+  int     r;
+  mp_digit q;
+
+  /* shortcut */
+  if (a->used == 0) {
+    return 0;
+  }
+
+  /* get number of digits and add that */
+  r = (a->used - 1) * DIGIT_BIT;
+  
+  /* take the last digit and count the bits in it */
+  q = a->dp[a->used - 1];
+  while (q > ((mp_digit) 0)) {
+    ++r;
+    q >>= ((mp_digit) 1);
+  }
+  return r;
+}
+
+
+/* store in unsigned [big endian] format */
+int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
+{
+  int     x, res;
+  mp_int  t;
+
+  if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+    return res;
+  }
+
+  x = 0;
+  while (mp_iszero (&t) == 0) {
+#ifndef MP_8BIT
+      b[x++] = (unsigned char) (t.dp[0] & 255);
+#else
+      b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
+#endif
+    if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
+      mp_clear (&t);
+      return res;
+    }
+  }
+  bn_reverse (b, x);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* creates "a" then copies b into it */
+int mp_init_copy (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  if ((res = mp_init (a)) != MP_OKAY) {
+    return res;
+  }
+  return mp_copy (b, a);
+}
+
+
+/* copy, b = a */
+int
+mp_copy (mp_int * a, mp_int * b)
+{
+  int     res, n;
+
+  /* if dst == src do nothing */
+  if (a == b) {
+    return MP_OKAY;
+  }
+
+  /* grow dest */
+  if (b->alloc < a->used) {
+     if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* zero b and copy the parameters over */
+  {
+    register mp_digit *tmpa, *tmpb;
+
+    /* pointer aliases */
+
+    /* source */
+    tmpa = a->dp;
+
+    /* destination */
+    tmpb = b->dp;
+
+    /* copy all the digits */
+    for (n = 0; n < a->used; n++) {
+      *tmpb++ = *tmpa++;
+    }
+
+    /* clear high digits */
+    for (; n < b->used; n++) {
+      *tmpb++ = 0;
+    }
+  }
+
+  /* copy used count and sign */
+  b->used = a->used;
+  b->sign = a->sign;
+  return MP_OKAY;
+}
+
+
+/* grow as required */
+int mp_grow (mp_int * a, int size)
+{
+  int     i;
+  mp_digit *tmp;
+
+  /* if the alloc size is smaller alloc more ram */
+  if (a->alloc < size) {
+    /* ensure there are always at least MP_PREC digits extra on top */
+    size += (MP_PREC * 2) - (size % MP_PREC);
+
+    /* reallocate the array a->dp
+     *
+     * We store the return in a temporary variable
+     * in case the operation failed we don't want
+     * to overwrite the dp member of a.
+     */
+    tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size, 0,
+                                       DYNAMIC_TYPE_BIGINT);
+    if (tmp == NULL) {
+      /* reallocation failed but "a" is still valid [can be freed] */
+      return MP_MEM;
+    }
+
+    /* reallocation succeeded so set a->dp */
+    a->dp = tmp;
+
+    /* zero excess digits */
+    i        = a->alloc;
+    a->alloc = size;
+    for (; i < a->alloc; i++) {
+      a->dp[i] = 0;
+    }
+  }
+  return MP_OKAY;
+}
+
+
+/* reverse an array, used for radix code */
+void
+bn_reverse (unsigned char *s, int len)
+{
+  int     ix, iy;
+  unsigned char t;
+
+  ix = 0;
+  iy = len - 1;
+  while (ix < iy) {
+    t     = s[ix];
+    s[ix] = s[iy];
+    s[iy] = t;
+    ++ix;
+    --iy;
+  }
+}
+
+
+/* shift right by a certain bit count (store quotient in c, optional
+   remainder in d) */
+int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
+{
+  mp_digit D, r, rr;
+  int     x, res;
+  mp_int  t;
+
+
+  /* if the shift count is <= 0 then we do no work */
+  if (b <= 0) {
+    res = mp_copy (a, c);
+    if (d != NULL) {
+      mp_zero (d);
+    }
+    return res;
+  }
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  /* get the remainder */
+  if (d != NULL) {
+    if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
+      mp_clear (&t);
+      return res;
+    }
+  }
+
+  /* copy */
+  if ((res = mp_copy (a, c)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    mp_rshd (c, b / DIGIT_BIT);
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  D = (mp_digit) (b % DIGIT_BIT);
+  if (D != 0) {
+    register mp_digit *tmpc, mask, shift;
+
+    /* mask */
+    mask = (((mp_digit)1) << D) - 1;
+
+    /* shift for lsb */
+    shift = DIGIT_BIT - D;
+
+    /* alias */
+    tmpc = c->dp + (c->used - 1);
+
+    /* carry */
+    r = 0;
+    for (x = c->used - 1; x >= 0; x--) {
+      /* get the lower  bits of this word in a temp */
+      rr = *tmpc & mask;
+
+      /* shift the current word and mix in the carry bits from the previous
+         word */
+      *tmpc = (*tmpc >> D) | (r << shift);
+      --tmpc;
+
+      /* set the carry to the carry bits of the current word found above */
+      r = rr;
+    }
+  }
+  mp_clamp (c);
+  if (d != NULL) {
+    mp_exch (&t, d);
+  }
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* set to zero */
+void mp_zero (mp_int * a)
+{
+  int       n;
+  mp_digit *tmp;
+
+  a->sign = MP_ZPOS;
+  a->used = 0;
+
+  tmp = a->dp;
+  for (n = 0; n < a->alloc; n++) {
+     *tmp++ = 0;
+  }
+}
+
+
+/* trim unused digits 
+ *
+ * This is used to ensure that leading zero digits are
+ * trimed and the leading "used" digit will be non-zero
+ * Typically very fast.  Also fixes the sign if there
+ * are no more leading digits
+ */
+void
+mp_clamp (mp_int * a)
+{
+  /* decrease used while the most significant digit is
+   * zero.
+   */
+  while (a->used > 0 && a->dp[a->used - 1] == 0) {
+    --(a->used);
+  }
+
+  /* reset the sign flag if used == 0 */
+  if (a->used == 0) {
+    a->sign = MP_ZPOS;
+  }
+}
+
+
+/* swap the elements of two integers, for cases where you can't simply swap the 
+ * mp_int pointers around
+ */
+void
+mp_exch (mp_int * a, mp_int * b)
+{
+  mp_int  t;
+
+  t  = *a;
+  *a = *b;
+  *b = t;
+}
+
+
+/* shift right a certain amount of digits */
+void mp_rshd (mp_int * a, int b)
+{
+  int     x;
+
+  /* if b <= 0 then ignore it */
+  if (b <= 0) {
+    return;
+  }
+
+  /* if b > used then simply zero it and return */
+  if (a->used <= b) {
+    mp_zero (a);
+    return;
+  }
+
+  {
+    register mp_digit *bottom, *top;
+
+    /* shift the digits down */
+
+    /* bottom */
+    bottom = a->dp;
+
+    /* top [offset into digits] */
+    top = a->dp + b;
+
+    /* this is implemented as a sliding window where 
+     * the window is b-digits long and digits from 
+     * the top of the window are copied to the bottom
+     *
+     * e.g.
+
+     b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
+                 /\                   |      ---->
+                  \-------------------/      ---->
+     */
+    for (x = 0; x < (a->used - b); x++) {
+      *bottom++ = *top++;
+    }
+
+    /* zero the top digits */
+    for (; x < a->used; x++) {
+      *bottom++ = 0;
+    }
+  }
+  
+  /* remove excess digits */
+  a->used -= b;
+}
+
+
+/* calc a value mod 2**b */
+int
+mp_mod_2d (mp_int * a, int b, mp_int * c)
+{
+  int     x, res;
+
+  /* if b is <= 0 then zero the int */
+  if (b <= 0) {
+    mp_zero (c);
+    return MP_OKAY;
+  }
+
+  /* if the modulus is larger than the value than return */
+  if (b >= (int) (a->used * DIGIT_BIT)) {
+    res = mp_copy (a, c);
+    return res;
+  }
+
+  /* copy */
+  if ((res = mp_copy (a, c)) != MP_OKAY) {
+    return res;
+  }
+
+  /* zero digits above the last digit of the modulus */
+  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+    c->dp[x] = 0;
+  }
+  /* clear the digit that is not completely outside/inside the modulus */
+  c->dp[b / DIGIT_BIT] &= (mp_digit) ((((mp_digit) 1) <<
+              (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* reads a unsigned char array, assumes the msb is stored first [big endian] */
+int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
+{
+  int     res;
+
+  /* make sure there are at least two digits */
+  if (a->alloc < 2) {
+     if ((res = mp_grow(a, 2)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* zero the int */
+  mp_zero (a);
+
+  /* read the bytes in */
+  while (c-- > 0) {
+    if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
+      return res;
+    }
+
+#ifndef MP_8BIT
+      a->dp[0] |= *b++;
+      a->used += 1;
+#else
+      a->dp[0] = (*b & MP_MASK);
+      a->dp[1] |= ((*b++ >> 7U) & 1);
+      a->used += 2;
+#endif
+  }
+  mp_clamp (a);
+  return MP_OKAY;
+}
+
+
+/* shift left by a certain bit count */
+int mp_mul_2d (mp_int * a, int b, mp_int * c)
+{
+  mp_digit d;
+  int      res;
+
+  /* copy */
+  if (a != c) {
+     if ((res = mp_copy (a, c)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
+     if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  d = (mp_digit) (b % DIGIT_BIT);
+  if (d != 0) {
+    register mp_digit *tmpc, shift, mask, r, rr;
+    register int x;
+
+    /* bitmask for carries */
+    mask = (((mp_digit)1) << d) - 1;
+
+    /* shift for msbs */
+    shift = DIGIT_BIT - d;
+
+    /* alias */
+    tmpc = c->dp;
+
+    /* carry */
+    r    = 0;
+    for (x = 0; x < c->used; x++) {
+      /* get the higher bits of the current word */
+      rr = (*tmpc >> shift) & mask;
+
+      /* shift the current word and OR in the carry */
+      *tmpc = ((*tmpc << d) | r) & MP_MASK;
+      ++tmpc;
+
+      /* set the carry to the carry bits of the current word */
+      r = rr;
+    }
+    
+    /* set final carry */
+    if (r != 0) {
+       c->dp[(c->used)++] = r;
+    }
+  }
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* shift left a certain amount of digits */
+int mp_lshd (mp_int * a, int b)
+{
+  int     x, res;
+
+  /* if its less than zero return */
+  if (b <= 0) {
+    return MP_OKAY;
+  }
+
+  /* grow to fit the new digits */
+  if (a->alloc < a->used + b) {
+     if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  {
+    register mp_digit *top, *bottom;
+
+    /* increment the used by the shift amount then copy upwards */
+    a->used += b;
+
+    /* top */
+    top = a->dp + a->used - 1;
+
+    /* base */
+    bottom = a->dp + a->used - 1 - b;
+
+    /* much like mp_rshd this is implemented using a sliding window
+     * except the window goes the otherway around.  Copying from
+     * the bottom to the top.  see bn_mp_rshd.c for more info.
+     */
+    for (x = a->used - 1; x >= b; x--) {
+      *top-- = *bottom--;
+    }
+
+    /* zero the lower digits */
+    top = a->dp;
+    for (x = 0; x < b; x++) {
+      *top++ = 0;
+    }
+  }
+  return MP_OKAY;
+}
+
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions.  Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted alot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
+{
+  int dr;
+
+  /* modulus P must be positive */
+  if (P->sign == MP_NEG) {
+     return MP_VAL;
+  }
+
+  /* if exponent X is negative we have to recurse */
+  if (X->sign == MP_NEG) {
+#ifdef BN_MP_INVMOD_C
+     mp_int tmpG, tmpX;
+     int err;
+
+     /* first compute 1/G mod P */
+     if ((err = mp_init(&tmpG)) != MP_OKAY) {
+        return err;
+     }
+     if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        return err;
+     }
+
+     /* now get |X| */
+     if ((err = mp_init(&tmpX)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        return err;
+     }
+     if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        mp_clear(&tmpX);
+        return err;
+     }
+
+     /* and now compute (1/G)**|X| instead of G**X [X < 0] */
+     err = mp_exptmod(&tmpG, &tmpX, P, Y);
+     mp_clear(&tmpG);
+     mp_clear(&tmpX);
+     return err;
+#else 
+     /* no invmod */
+     return MP_VAL;
+#endif
+  }
+
+/* modified diminished radix reduction */
+#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && \
+  defined(BN_S_MP_EXPTMOD_C)
+  if (mp_reduce_is_2k_l(P) == MP_YES) {
+     return s_mp_exptmod(G, X, P, Y, 1);
+  }
+#endif
+
+#ifdef BN_MP_DR_IS_MODULUS_C
+  /* is it a DR modulus? */
+  dr = mp_dr_is_modulus(P);
+#else
+  /* default to no */
+  dr = 0;
+#endif
+
+#ifdef BN_MP_REDUCE_IS_2K_C
+  /* if not, is it a unrestricted DR modulus? */
+  if (dr == 0) {
+     dr = mp_reduce_is_2k(P) << 1;
+  }
+#endif
+    
+  /* if the modulus is odd or dr != 0 use the montgomery method */
+#ifdef BN_MP_EXPTMOD_FAST_C
+  if (mp_isodd (P) == 1 || dr !=  0) {
+    return mp_exptmod_fast (G, X, P, Y, dr);
+  } else {
+#endif
+#ifdef BN_S_MP_EXPTMOD_C
+    /* otherwise use the generic Barrett reduction technique */
+    return s_mp_exptmod (G, X, P, Y, 0);
+#else
+    /* no exptmod for evens */
+    return MP_VAL;
+#endif
+#ifdef BN_MP_EXPTMOD_FAST_C
+  }
+#endif
+}
+
+
+/* b = |a| 
+ *
+ * Simple function copies the input and fixes the sign to positive
+ */
+int
+mp_abs (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  /* copy a to b */
+  if (a != b) {
+     if ((res = mp_copy (a, b)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  /* force the sign of b to positive */
+  b->sign = MP_ZPOS;
+
+  return MP_OKAY;
+}
+
+
+/* hac 14.61, pp608 */
+int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  /* b cannot be negative */
+  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+    return MP_VAL;
+  }
+
+#ifdef BN_FAST_MP_INVMOD_C
+  /* if the modulus is odd we can use a faster routine instead */
+  if (mp_isodd (b) == 1) {
+    return fast_mp_invmod (a, b, c);
+  }
+#endif
+
+#ifdef BN_MP_INVMOD_SLOW_C
+  return mp_invmod_slow(a, b, c);
+#endif
+}
+
+
+/* computes the modular inverse via binary extended euclidean algorithm, 
+ * that is c = 1/a mod b 
+ *
+ * Based on slow invmod except this is optimized for the case where b is 
+ * odd as per HAC Note 14.64 on pp. 610
+ */
+int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int  x, y, u, v, B, D;
+  int     res, neg;
+
+  /* 2. [modified] b must be odd   */
+  if (mp_iseven (b) == 1) {
+    return MP_VAL;
+  }
+
+  /* init all our temps */
+  if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D)) != MP_OKAY) {
+     return res;
+  }
+
+  /* x == modulus, y == value to invert */
+  if ((res = mp_copy (b, &x)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+
+  /* we need y = |a| */
+  if ((res = mp_mod (a, b, &y)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+
+  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+  if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  mp_set (&D, 1);
+
+top:
+  /* 4.  while u is even do */
+  while (mp_iseven (&u) == 1) {
+    /* 4.1 u = u/2 */
+    if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 4.2 if B is odd then */
+    if (mp_isodd (&B) == 1) {
+      if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+        goto LBL_ERR;
+      }
+    }
+    /* B = B/2 */
+    if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 5.  while v is even do */
+  while (mp_iseven (&v) == 1) {
+    /* 5.1 v = v/2 */
+    if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 5.2 if D is odd then */
+    if (mp_isodd (&D) == 1) {
+      /* D = (D-x)/2 */
+      if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+        goto LBL_ERR;
+      }
+    }
+    /* D = D/2 */
+    if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 6.  if u >= v then */
+  if (mp_cmp (&u, &v) != MP_LT) {
+    /* u = u - v, B = B - D */
+    if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  } else {
+    /* v - v - u, D = D - B */
+    if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* if not zero goto step 4 */
+  if (mp_iszero (&u) == 0) {
+    goto top;
+  }
+
+  /* now a = C, b = D, gcd == g*v */
+
+  /* if v != 1 then there is no inverse */
+  if (mp_cmp_d (&v, 1) != MP_EQ) {
+    res = MP_VAL;
+    goto LBL_ERR;
+  }
+
+  /* b is now the inverse */
+  neg = a->sign;
+  while (D.sign == MP_NEG) {
+    if ((res = mp_add (&D, b, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+  mp_exch (&D, c);
+  c->sign = neg;
+  res = MP_OKAY;
+
+LBL_ERR:mp_clear(&x);
+        mp_clear(&y);
+        mp_clear(&u);
+        mp_clear(&v);
+        mp_clear(&B);
+        mp_clear(&D);
+  return res;
+}
+
+
+/* hac 14.61, pp608 */
+int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int  x, y, u, v, A, B, C, D;
+  int     res;
+
+  /* b cannot be negative */
+  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+    return MP_VAL;
+  }
+
+  /* init temps */
+  if ((res = mp_init_multi(&x, &y, &u, &v, 
+                           &A, &B)) != MP_OKAY) {
+     return res;
+  }
+
+  /* init rest of tmps temps */
+  if ((res = mp_init_multi(&C, &D, 0, 0, 0, 0)) != MP_OKAY) {
+     return res;
+  }
+
+  /* x = a, y = b */
+  if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
+      goto LBL_ERR;
+  }
+  if ((res = mp_copy (b, &y)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+
+  /* 2. [modified] if x,y are both even then return an error! */
+  if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
+    res = MP_VAL;
+    goto LBL_ERR;
+  }
+
+  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+  if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  mp_set (&A, 1);
+  mp_set (&D, 1);
+
+top:
+  /* 4.  while u is even do */
+  while (mp_iseven (&u) == 1) {
+    /* 4.1 u = u/2 */
+    if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 4.2 if A or B is odd then */
+    if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
+      /* A = (A+y)/2, B = (B-x)/2 */
+      if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+      if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+    }
+    /* A = A/2, B = B/2 */
+    if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 5.  while v is even do */
+  while (mp_iseven (&v) == 1) {
+    /* 5.1 v = v/2 */
+    if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 5.2 if C or D is odd then */
+    if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
+      /* C = (C+y)/2, D = (D-x)/2 */
+      if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+      if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+    }
+    /* C = C/2, D = D/2 */
+    if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 6.  if u >= v then */
+  if (mp_cmp (&u, &v) != MP_LT) {
+    /* u = u - v, A = A - C, B = B - D */
+    if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  } else {
+    /* v - v - u, C = C - A, D = D - B */
+    if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* if not zero goto step 4 */
+  if (mp_iszero (&u) == 0)
+    goto top;
+
+  /* now a = C, b = D, gcd == g*v */
+
+  /* if v != 1 then there is no inverse */
+  if (mp_cmp_d (&v, 1) != MP_EQ) {
+    res = MP_VAL;
+    goto LBL_ERR;
+  }
+
+  /* if its too low */
+  while (mp_cmp_d(&C, 0) == MP_LT) {
+      if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+  }
+  
+  /* too big */
+  while (mp_cmp_mag(&C, b) != MP_LT) {
+      if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+  }
+  
+  /* C is now the inverse */
+  mp_exch (&C, c);
+  res = MP_OKAY;
+LBL_ERR:mp_clear(&x);
+        mp_clear(&y);
+        mp_clear(&u);
+        mp_clear(&v);
+        mp_clear(&A);
+        mp_clear(&B);
+        mp_clear(&C);
+        mp_clear(&D);
+  return res;
+}
+
+
+/* compare maginitude of two ints (unsigned) */
+int mp_cmp_mag (mp_int * a, mp_int * b)
+{
+  int     n;
+  mp_digit *tmpa, *tmpb;
+
+  /* compare based on # of non-zero digits */
+  if (a->used > b->used) {
+    return MP_GT;
+  }
+  
+  if (a->used < b->used) {
+    return MP_LT;
+  }
+
+  /* alias for a */
+  tmpa = a->dp + (a->used - 1);
+
+  /* alias for b */
+  tmpb = b->dp + (a->used - 1);
+
+  /* compare based on digits  */
+  for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
+    if (*tmpa > *tmpb) {
+      return MP_GT;
+    }
+
+    if (*tmpa < *tmpb) {
+      return MP_LT;
+    }
+  }
+  return MP_EQ;
+}
+
+
+/* compare two ints (signed)*/
+int
+mp_cmp (mp_int * a, mp_int * b)
+{
+  /* compare based on sign */
+  if (a->sign != b->sign) {
+     if (a->sign == MP_NEG) {
+        return MP_LT;
+     } else {
+        return MP_GT;
+     }
+  }
+  
+  /* compare digits */
+  if (a->sign == MP_NEG) {
+     /* if negative compare opposite direction */
+     return mp_cmp_mag(b, a);
+  } else {
+     return mp_cmp_mag(a, b);
+  }
+}
+
+
+/* compare a digit */
+int mp_cmp_d(mp_int * a, mp_digit b)
+{
+  /* compare based on sign */
+  if (a->sign == MP_NEG) {
+    return MP_LT;
+  }
+
+  /* compare based on magnitude */
+  if (a->used > 1) {
+    return MP_GT;
+  }
+
+  /* compare the only digit of a to b */
+  if (a->dp[0] > b) {
+    return MP_GT;
+  } else if (a->dp[0] < b) {
+    return MP_LT;
+  } else {
+    return MP_EQ;
+  }
+}
+
+
+/* set to a digit */
+void mp_set (mp_int * a, mp_digit b)
+{
+  mp_zero (a);
+  a->dp[0] = b & MP_MASK;
+  a->used  = (a->dp[0] != 0) ? 1 : 0;
+}
+
+
+/* c = a mod b, 0 <= c < b */
+int
+mp_mod (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int  t;
+  int     res;
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+
+  if (t.sign != b->sign) {
+    res = mp_add (b, &t, c);
+  } else {
+    res = MP_OKAY;
+    mp_exch (&t, c);
+  }
+
+  mp_clear (&t);
+  return res;
+}
+
+
+/* slower bit-bang division... also smaller */
+int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+   mp_int ta, tb, tq, q;
+   int    res, n, n2;
+
+  /* is divisor zero ? */
+  if (mp_iszero (b) == 1) {
+    return MP_VAL;
+  }
+
+  /* if a < b then q=0, r = a */
+  if (mp_cmp_mag (a, b) == MP_LT) {
+    if (d != NULL) {
+      res = mp_copy (a, d);
+    } else {
+      res = MP_OKAY;
+    }
+    if (c != NULL) {
+      mp_zero (c);
+    }
+    return res;
+  }
+	
+  /* init our temps */
+  if ((res = mp_init_multi(&ta, &tb, &tq, &q, 0, 0) != MP_OKAY)) {
+     return res;
+  }
+
+
+  mp_set(&tq, 1);
+  n = mp_count_bits(a) - mp_count_bits(b);
+  if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
+      ((res = mp_abs(b, &tb)) != MP_OKAY) || 
+      ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
+      ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
+      goto LBL_ERR;
+  }
+
+  while (n-- >= 0) {
+     if (mp_cmp(&tb, &ta) != MP_GT) {
+        if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
+            ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
+           goto LBL_ERR;
+        }
+     }
+     if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
+         ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
+           goto LBL_ERR;
+     }
+  }
+
+  /* now q == quotient and ta == remainder */
+  n  = a->sign;
+  n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
+  if (c != NULL) {
+     mp_exch(c, &q);
+     c->sign  = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
+  }
+  if (d != NULL) {
+     mp_exch(d, &ta);
+     d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
+  }
+LBL_ERR:
+   mp_clear(&ta);
+   mp_clear(&tb);
+   mp_clear(&tq);
+   mp_clear(&q);
+   return res;
+}
+
+
+/* b = a/2 */
+int mp_div_2(mp_int * a, mp_int * b)
+{
+  int     x, res, oldused;
+
+  /* copy */
+  if (b->alloc < a->used) {
+    if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  oldused = b->used;
+  b->used = a->used;
+  {
+    register mp_digit r, rr, *tmpa, *tmpb;
+
+    /* source alias */
+    tmpa = a->dp + b->used - 1;
+
+    /* dest alias */
+    tmpb = b->dp + b->used - 1;
+
+    /* carry */
+    r = 0;
+    for (x = b->used - 1; x >= 0; x--) {
+      /* get the carry for the next iteration */
+      rr = *tmpa & 1;
+
+      /* shift the current digit, add in carry and store */
+      *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
+
+      /* forward carry to next iteration */
+      r = rr;
+    }
+
+    /* zero excess digits */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+  mp_clamp (b);
+  return MP_OKAY;
+}
+
+
+/* high level addition (handles signs) */
+int mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     sa, sb, res;
+
+  /* get sign of both inputs */
+  sa = a->sign;
+  sb = b->sign;
+
+  /* handle two cases, not four */
+  if (sa == sb) {
+    /* both positive or both negative */
+    /* add their magnitudes, copy the sign */
+    c->sign = sa;
+    res = s_mp_add (a, b, c);
+  } else {
+    /* one positive, the other negative */
+    /* subtract the one with the greater magnitude from */
+    /* the one of the lesser magnitude.  The result gets */
+    /* the sign of the one with the greater magnitude. */
+    if (mp_cmp_mag (a, b) == MP_LT) {
+      c->sign = sb;
+      res = s_mp_sub (b, a, c);
+    } else {
+      c->sign = sa;
+      res = s_mp_sub (a, b, c);
+    }
+  }
+  return res;
+}
+
+
+/* low level addition, based on HAC pp.594, Algorithm 14.7 */
+int
+s_mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int *x;
+  int     olduse, res, min, max;
+
+  /* find sizes, we let |a| <= |b| which means we have to sort
+   * them.  "x" will point to the input with the most digits
+   */
+  if (a->used > b->used) {
+    min = b->used;
+    max = a->used;
+    x = a;
+  } else {
+    min = a->used;
+    max = b->used;
+    x = b;
+  }
+
+  /* init result */
+  if (c->alloc < max + 1) {
+    if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* get old used digit count and set new one */
+  olduse = c->used;
+  c->used = max + 1;
+
+  {
+    register mp_digit u, *tmpa, *tmpb, *tmpc;
+    register int i;
+
+    /* alias for digit pointers */
+
+    /* first input */
+    tmpa = a->dp;
+
+    /* second input */
+    tmpb = b->dp;
+
+    /* destination */
+    tmpc = c->dp;
+
+    /* zero the carry */
+    u = 0;
+    for (i = 0; i < min; i++) {
+      /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
+      *tmpc = *tmpa++ + *tmpb++ + u;
+
+      /* U = carry bit of T[i] */
+      u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+      /* take away carry bit from T[i] */
+      *tmpc++ &= MP_MASK;
+    }
+
+    /* now copy higher words if any, that is in A+B 
+     * if A or B has more digits add those in 
+     */
+    if (min != max) {
+      for (; i < max; i++) {
+        /* T[i] = X[i] + U */
+        *tmpc = x->dp[i] + u;
+
+        /* U = carry bit of T[i] */
+        u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+        /* take away carry bit from T[i] */
+        *tmpc++ &= MP_MASK;
+      }
+    }
+
+    /* add carry */
+    *tmpc++ = u;
+
+    /* clear digits above oldused */
+    for (i = c->used; i < olduse; i++) {
+      *tmpc++ = 0;
+    }
+  }
+
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
+int
+s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     olduse, res, min, max;
+
+  /* find sizes */
+  min = b->used;
+  max = a->used;
+
+  /* init result */
+  if (c->alloc < max) {
+    if ((res = mp_grow (c, max)) != MP_OKAY) {
+      return res;
+    }
+  }
+  olduse = c->used;
+  c->used = max;
+
+  {
+    register mp_digit u, *tmpa, *tmpb, *tmpc;
+    register int i;
+
+    /* alias for digit pointers */
+    tmpa = a->dp;
+    tmpb = b->dp;
+    tmpc = c->dp;
+
+    /* set carry to zero */
+    u = 0;
+    for (i = 0; i < min; i++) {
+      /* T[i] = A[i] - B[i] - U */
+      *tmpc = *tmpa++ - *tmpb++ - u;
+
+      /* U = carry bit of T[i]
+       * Note this saves performing an AND operation since
+       * if a carry does occur it will propagate all the way to the
+       * MSB.  As a result a single shift is enough to get the carry
+       */
+      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+      /* Clear carry from T[i] */
+      *tmpc++ &= MP_MASK;
+    }
+
+    /* now copy higher words if any, e.g. if A has more digits than B  */
+    for (; i < max; i++) {
+      /* T[i] = A[i] - U */
+      *tmpc = *tmpa++ - u;
+
+      /* U = carry bit of T[i] */
+      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+      /* Clear carry from T[i] */
+      *tmpc++ &= MP_MASK;
+    }
+
+    /* clear digits above used (since we may not have grown result above) */
+    for (i = c->used; i < olduse; i++) {
+      *tmpc++ = 0;
+    }
+  }
+
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* high level subtraction (handles signs) */
+int
+mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     sa, sb, res;
+
+  sa = a->sign;
+  sb = b->sign;
+
+  if (sa != sb) {
+    /* subtract a negative from a positive, OR */
+    /* subtract a positive from a negative. */
+    /* In either case, ADD their magnitudes, */
+    /* and use the sign of the first number. */
+    c->sign = sa;
+    res = s_mp_add (a, b, c);
+  } else {
+    /* subtract a positive from a positive, OR */
+    /* subtract a negative from a negative. */
+    /* First, take the difference between their */
+    /* magnitudes, then... */
+    if (mp_cmp_mag (a, b) != MP_LT) {
+      /* Copy the sign from the first */
+      c->sign = sa;
+      /* The first has a larger or equal magnitude */
+      res = s_mp_sub (a, b, c);
+    } else {
+      /* The result has the *opposite* sign from */
+      /* the first number. */
+      c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+      /* The second has a larger magnitude */
+      res = s_mp_sub (b, a, c);
+    }
+  }
+  return res;
+}
+
+
+/* determines if reduce_2k_l can be used */
+int mp_reduce_is_2k_l(mp_int *a)
+{
+   int ix, iy;
+   
+   if (a->used == 0) {
+      return MP_NO;
+   } else if (a->used == 1) {
+      return MP_YES;
+   } else if (a->used > 1) {
+      /* if more than half of the digits are -1 we're sold */
+      for (iy = ix = 0; ix < a->used; ix++) {
+          if (a->dp[ix] == MP_MASK) {
+              ++iy;
+          }
+      }
+      return (iy >= (a->used/2)) ? MP_YES : MP_NO;
+      
+   }
+   return MP_NO;
+}
+
+
+/* determines if mp_reduce_2k can be used */
+int mp_reduce_is_2k(mp_int *a)
+{
+   int ix, iy, iw;
+   mp_digit iz;
+   
+   if (a->used == 0) {
+      return MP_NO;
+   } else if (a->used == 1) {
+      return MP_YES;
+   } else if (a->used > 1) {
+      iy = mp_count_bits(a);
+      iz = 1;
+      iw = 1;
+    
+      /* Test every bit from the second digit up, must be 1 */
+      for (ix = DIGIT_BIT; ix < iy; ix++) {
+          if ((a->dp[iw] & iz) == 0) {
+             return MP_NO;
+          }
+          iz <<= 1;
+          if (iz > (mp_digit)MP_MASK) {
+             ++iw;
+             iz = 1;
+          }
+      }
+   }
+   return MP_YES;
+}
+
+
+/* determines if a number is a valid DR modulus */
+int mp_dr_is_modulus(mp_int *a)
+{
+   int ix;
+
+   /* must be at least two digits */
+   if (a->used < 2) {
+      return 0;
+   }
+
+   /* must be of the form b**k - a [a <= b] so all
+    * but the first digit must be equal to -1 (mod b).
+    */
+   for (ix = 1; ix < a->used; ix++) {
+       if (a->dp[ix] != MP_MASK) {
+          return 0;
+       }
+   }
+   return 1;
+}
+
+
+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+ *
+ * Uses a left-to-right k-ary sliding window to compute the modular
+ * exponentiation.
+ * The value of k changes based on the size of the exponent.
+ *
+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+ */
+
+#ifdef MP_LOW_MEM
+   #define TAB_SIZE 32
+#else
+   #define TAB_SIZE 256
+#endif
+
+int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y,
+                     int redmode)
+{
+  mp_int  M[TAB_SIZE], res;
+  mp_digit buf, mp;
+  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+  /* use a pointer to the reduction algorithm.  This allows us to use
+   * one of many reduction algorithms without modding the guts of
+   * the code with if statements everywhere.
+   */
+  int     (*redux)(mp_int*,mp_int*,mp_digit);
+
+  /* find window size */
+  x = mp_count_bits (X);
+  if (x <= 7) {
+    winsize = 2;
+  } else if (x <= 36) {
+    winsize = 3;
+  } else if (x <= 140) {
+    winsize = 4;
+  } else if (x <= 450) {
+    winsize = 5;
+  } else if (x <= 1303) {
+    winsize = 6;
+  } else if (x <= 3529) {
+    winsize = 7;
+  } else {
+    winsize = 8;
+  }
+
+#ifdef MP_LOW_MEM
+  if (winsize > 5) {
+     winsize = 5;
+  }
+#endif
+
+  /* init M array */
+  /* init first cell */
+  if ((err = mp_init(&M[1])) != MP_OKAY) {
+     return err;
+  }
+
+  /* now init the second half of the array */
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    if ((err = mp_init(&M[x])) != MP_OKAY) {
+      for (y = 1<<(winsize-1); y < x; y++) {
+        mp_clear (&M[y]);
+      }
+      mp_clear(&M[1]);
+      return err;
+    }
+  }
+
+  /* determine and setup reduction code */
+  if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_SETUP_C     
+     /* now setup montgomery  */
+     if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
+        goto LBL_M;
+     }
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+
+     /* automatically pick the comba one if available (saves quite a few
+        calls/ifs) */
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+     if (((P->used * 2 + 1) < MP_WARRAY) &&
+          P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+        redux = fast_mp_montgomery_reduce;
+     } else 
+#endif
+     {
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+        /* use slower baseline Montgomery method */
+        redux = mp_montgomery_reduce;
+#else
+        err = MP_VAL;
+        goto LBL_M;
+#endif
+     }
+  } else if (redmode == 1) {
+#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
+     /* setup DR reduction for moduli of the form B**k - b */
+     mp_dr_setup(P, &mp);
+     redux = mp_dr_reduce;
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+  } else {
+#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
+     /* setup DR reduction for moduli of the form 2**k - b */
+     if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
+        goto LBL_M;
+     }
+     redux = mp_reduce_2k;
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+  }
+
+  /* setup result */
+  if ((err = mp_init (&res)) != MP_OKAY) {
+    goto LBL_M;
+  }
+
+  /* create M table
+   *
+
+   *
+   * The first half of the table is not computed though accept for M[0] and M[1]
+   */
+
+  if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+     /* now we need R mod m */
+     if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
+       goto LBL_RES;
+     }
+#else 
+     err = MP_VAL;
+     goto LBL_RES;
+#endif
+
+     /* now set M[1] to G * R mod m */
+     if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
+       goto LBL_RES;
+     }
+  } else {
+     mp_set(&res, 1);
+     if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
+        goto LBL_RES;
+     }
+  }
+
+  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times*/
+  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+    goto LBL_RES;
+  }
+
+  for (x = 0; x < (winsize - 1); x++) {
+    if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
+      goto LBL_RES;
+    }
+    if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
+      goto LBL_RES;
+    }
+  }
+
+  /* create upper table */
+  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+      goto LBL_RES;
+    }
+    if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
+      goto LBL_RES;
+    }
+  }
+
+  /* set initial mode and bit cnt */
+  mode   = 0;
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+  bitcpy = 0;
+  bitbuf = 0;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits so break */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int)DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
+    buf <<= (mp_digit)1;
+
+    /* if the bit is zero and mode == 0 then we ignore it
+     * These represent the leading zero bits before the first 1 bit
+     * in the exponent.  Technically this opt is not required but it
+     * does lower the # of trivial squaring/reductions used
+     */
+    if (mode == 0 && y == 0) {
+      continue;
+    }
+
+    /* if the bit is zero and mode == 1 then we square */
+    if (mode == 1 && y == 0) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      continue;
+    }
+
+    /* else we add it to the window */
+    bitbuf |= (y << (winsize - ++bitcpy));
+    mode    = 2;
+
+    if (bitcpy == winsize) {
+      /* ok window is filled so square as required and multiply  */
+      /* square first */
+      for (x = 0; x < winsize; x++) {
+        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, mp)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+
+      /* then multiply */
+      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* empty window and reset */
+      bitcpy = 0;
+      bitbuf = 0;
+      mode   = 1;
+    }
+  }
+
+  /* if bits remain then square/multiply */
+  if (mode == 2 && bitcpy > 0) {
+    /* square then multiply if the bit is set */
+    for (x = 0; x < bitcpy; x++) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* get next bit of the window */
+      bitbuf <<= 1;
+      if ((bitbuf & (1 << winsize)) != 0) {
+        /* then multiply */
+        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, mp)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+    }
+  }
+
+  if (redmode == 0) {
+     /* fixup result if Montgomery reduction is used
+      * recall that any value in a Montgomery system is
+      * actually multiplied by R mod n.  So we have
+      * to reduce one more time to cancel out the factor
+      * of R.
+      */
+     if ((err = redux(&res, P, mp)) != MP_OKAY) {
+       goto LBL_RES;
+     }
+  }
+
+  /* swap res with Y */
+  mp_exch (&res, Y);
+  err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_M:
+  mp_clear(&M[1]);
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    mp_clear (&M[x]);
+  }
+  return err;
+}
+
+
+/* setups the montgomery reduction stuff */
+int
+mp_montgomery_setup (mp_int * n, mp_digit * rho)
+{
+  mp_digit x, b;
+
+/* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
+ *                    =>  2*X*A - X*X*A*A = 1
+ *                    =>  2*(1) - (1)     = 1
+ */
+  b = n->dp[0];
+
+  if ((b & 1) == 0) {
+    return MP_VAL;
+  }
+
+  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
+#if !defined(MP_8BIT)
+  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
+#endif
+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
+  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
+#endif
+
+  /* rho = -1/m mod b */
+  /* TAO, switched mp_word casts to mp_digit to shut up compiler */
+  *rho = (((mp_digit)1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK;
+
+  return MP_OKAY;
+}
+
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction
+ *
+ * This is an optimized implementation of montgomery_reduce
+ * which uses the comba method to quickly calculate the columns of the
+ * reduction.
+ *
+ * Based on Algorithm 14.32 on pp.601 of HAC.
+*/
+int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+  int     ix, res, olduse;
+  mp_word W[MP_WARRAY];
+
+  /* get old used count */
+  olduse = x->used;
+
+  /* grow a as required */
+  if (x->alloc < n->used + 1) {
+    if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* first we have to get the digits of the input into
+   * an array of double precision words W[...]
+   */
+  {
+    register mp_word *_W;
+    register mp_digit *tmpx;
+
+    /* alias for the W[] array */
+    _W   = W;
+
+    /* alias for the digits of  x*/
+    tmpx = x->dp;
+
+    /* copy the digits of a into W[0..a->used-1] */
+    for (ix = 0; ix < x->used; ix++) {
+      *_W++ = *tmpx++;
+    }
+
+    /* zero the high words of W[a->used..m->used*2] */
+    for (; ix < n->used * 2 + 1; ix++) {
+      *_W++ = 0;
+    }
+  }
+
+  /* now we proceed to zero successive digits
+   * from the least significant upwards
+   */
+  for (ix = 0; ix < n->used; ix++) {
+    /* mu = ai * m' mod b
+     *
+     * We avoid a double precision multiplication (which isn't required)
+     * by casting the value down to a mp_digit.  Note this requires
+     * that W[ix-1] have  the carry cleared (see after the inner loop)
+     */
+    register mp_digit mu;
+    mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
+
+    /* a = a + mu * m * b**i
+     *
+     * This is computed in place and on the fly.  The multiplication
+     * by b**i is handled by offseting which columns the results
+     * are added to.
+     *
+     * Note the comba method normally doesn't handle carries in the
+     * inner loop In this case we fix the carry from the previous
+     * column since the Montgomery reduction requires digits of the
+     * result (so far) [see above] to work.  This is
+     * handled by fixing up one carry after the inner loop.  The
+     * carry fixups are done in order so after these loops the
+     * first m->used words of W[] have the carries fixed
+     */
+    {
+      register int iy;
+      register mp_digit *tmpn;
+      register mp_word *_W;
+
+      /* alias for the digits of the modulus */
+      tmpn = n->dp;
+
+      /* Alias for the columns set by an offset of ix */
+      _W = W + ix;
+
+      /* inner loop */
+      for (iy = 0; iy < n->used; iy++) {
+          *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
+      }
+    }
+
+    /* now fix carry for next digit, W[ix+1] */
+    W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
+  }
+
+  /* now we have to propagate the carries and
+   * shift the words downward [all those least
+   * significant digits we zeroed].
+   */
+  {
+    register mp_digit *tmpx;
+    register mp_word *_W, *_W1;
+
+    /* nox fix rest of carries */
+
+    /* alias for current word */
+    _W1 = W + ix;
+
+    /* alias for next word, where the carry goes */
+    _W = W + ++ix;
+
+    for (; ix <= n->used * 2 + 1; ix++) {
+      *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
+    }
+
+    /* copy out, A = A/b**n
+     *
+     * The result is A/b**n but instead of converting from an
+     * array of mp_word to mp_digit than calling mp_rshd
+     * we just copy them in the right order
+     */
+
+    /* alias for destination word */
+    tmpx = x->dp;
+
+    /* alias for shifted double precision result */
+    _W = W + n->used;
+
+    for (ix = 0; ix < n->used + 1; ix++) {
+      *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
+    }
+
+    /* zero oldused digits, if the input a was larger than
+     * m->used+1 we'll have to clear the digits
+     */
+    for (; ix < olduse; ix++) {
+      *tmpx++ = 0;
+    }
+  }
+
+  /* set the max used and clamp */
+  x->used = n->used + 1;
+  mp_clamp (x);
+
+  /* if A >= m then A = A - m */
+  if (mp_cmp_mag (x, n) != MP_LT) {
+    return s_mp_sub (x, n, x);
+  }
+  return MP_OKAY;
+}
+
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction */
+int
+mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+  int     ix, res, digs;
+  mp_digit mu;
+
+  /* can the fast reduction [comba] method be used?
+   *
+   * Note that unlike in mul you're safely allowed *less*
+   * than the available columns [255 per default] since carries
+   * are fixed up in the inner loop.
+   */
+  digs = n->used * 2 + 1;
+  if ((digs < MP_WARRAY) &&
+      n->used <
+      (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+    return fast_mp_montgomery_reduce (x, n, rho);
+  }
+
+  /* grow the input as required */
+  if (x->alloc < digs) {
+    if ((res = mp_grow (x, digs)) != MP_OKAY) {
+      return res;
+    }
+  }
+  x->used = digs;
+
+  for (ix = 0; ix < n->used; ix++) {
+    /* mu = ai * rho mod b
+     *
+     * The value of rho must be precalculated via
+     * montgomery_setup() such that
+     * it equals -1/n0 mod b this allows the
+     * following inner loop to reduce the
+     * input one digit at a time
+     */
+    mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK);
+
+    /* a = a + mu * m * b**i */
+    {
+      register int iy;
+      register mp_digit *tmpn, *tmpx, u;
+      register mp_word r;
+
+      /* alias for digits of the modulus */
+      tmpn = n->dp;
+
+      /* alias for the digits of x [the input] */
+      tmpx = x->dp + ix;
+
+      /* set the carry to zero */
+      u = 0;
+
+      /* Multiply and add in place */
+      for (iy = 0; iy < n->used; iy++) {
+        /* compute product and sum */
+        r       = ((mp_word)mu) * ((mp_word)*tmpn++) +
+                  ((mp_word) u) + ((mp_word) * tmpx);
+
+        /* get carry */
+        u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+        /* fix digit */
+        *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK));
+      }
+      /* At this point the ix'th digit of x should be zero */
+
+
+      /* propagate carries upwards as required*/
+      while (u) {
+        *tmpx   += u;
+        u        = *tmpx >> DIGIT_BIT;
+        *tmpx++ &= MP_MASK;
+      }
+    }
+  }
+
+  /* at this point the n.used'th least
+   * significant digits of x are all zero
+   * which means we can shift x to the
+   * right by n.used digits and the
+   * residue is unchanged.
+   */
+
+  /* x = x/b**n.used */
+  mp_clamp(x);
+  mp_rshd (x, n->used);
+
+  /* if x >= n then x = x - n */
+  if (mp_cmp_mag (x, n) != MP_LT) {
+    return s_mp_sub (x, n, x);
+  }
+
+  return MP_OKAY;
+}
+
+
+/* determines the setup value */
+void mp_dr_setup(mp_int *a, mp_digit *d)
+{
+   /* the casts are required if DIGIT_BIT is one less than
+    * the number of bits in a mp_digit [e.g. DIGIT_BIT==31]
+    */
+   *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - 
+        ((mp_word)a->dp[0]));
+}
+
+
+/* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
+ *
+ * Based on algorithm from the paper
+ *
+ * "Generating Efficient Primes for Discrete Log Cryptosystems"
+ *                 Chae Hoon Lim, Pil Joong Lee,
+ *          POSTECH Information Research Laboratories
+ *
+ * The modulus must be of a special format [see manual]
+ *
+ * Has been modified to use algorithm 7.10 from the LTM book instead
+ *
+ * Input x must be in the range 0 <= x <= (n-1)**2
+ */
+int
+mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k)
+{
+  int      err, i, m;
+  mp_word  r;
+  mp_digit mu, *tmpx1, *tmpx2;
+
+  /* m = digits in modulus */
+  m = n->used;
+
+  /* ensure that "x" has at least 2m digits */
+  if (x->alloc < m + m) {
+    if ((err = mp_grow (x, m + m)) != MP_OKAY) {
+      return err;
+    }
+  }
+
+/* top of loop, this is where the code resumes if
+ * another reduction pass is required.
+ */
+top:
+  /* aliases for digits */
+  /* alias for lower half of x */
+  tmpx1 = x->dp;
+
+  /* alias for upper half of x, or x/B**m */
+  tmpx2 = x->dp + m;
+
+  /* set carry to zero */
+  mu = 0;
+
+  /* compute (x mod B**m) + k * [x/B**m] inline and inplace */
+  for (i = 0; i < m; i++) {
+      r         = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu;
+      *tmpx1++  = (mp_digit)(r & MP_MASK);
+      mu        = (mp_digit)(r >> ((mp_word)DIGIT_BIT));
+  }
+
+  /* set final carry */
+  *tmpx1++ = mu;
+
+  /* zero words above m */
+  for (i = m + 1; i < x->used; i++) {
+      *tmpx1++ = 0;
+  }
+
+  /* clamp, sub and return */
+  mp_clamp (x);
+
+  /* if x >= n then subtract and reduce again
+   * Each successive "recursion" makes the input smaller and smaller.
+   */
+  if (mp_cmp_mag (x, n) != MP_LT) {
+    s_mp_sub(x, n, x);
+    goto top;
+  }
+  return MP_OKAY;
+}
+
+
+/* reduces a modulo n where n is of the form 2**p - d */
+int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d)
+{
+   mp_int q;
+   int    p, res;
+   
+   if ((res = mp_init(&q)) != MP_OKAY) {
+      return res;
+   }
+   
+   p = mp_count_bits(n);    
+top:
+   /* q = a/2**p, a = a mod 2**p */
+   if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+   
+   if (d != 1) {
+      /* q = q * d */
+      if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) { 
+         goto ERR;
+      }
+   }
+   
+   /* a = a + q */
+   if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+   
+   if (mp_cmp_mag(a, n) != MP_LT) {
+      s_mp_sub(a, n, a);
+      goto top;
+   }
+   
+ERR:
+   mp_clear(&q);
+   return res;
+}
+
+
+/* determines the setup value */
+int mp_reduce_2k_setup(mp_int *a, mp_digit *d)
+{
+   int res, p;
+   mp_int tmp;
+   
+   if ((res = mp_init(&tmp)) != MP_OKAY) {
+      return res;
+   }
+   
+   p = mp_count_bits(a);
+   if ((res = mp_2expt(&tmp, p)) != MP_OKAY) {
+      mp_clear(&tmp);
+      return res;
+   }
+   
+   if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) {
+      mp_clear(&tmp);
+      return res;
+   }
+   
+   *d = tmp.dp[0];
+   mp_clear(&tmp);
+   return MP_OKAY;
+}
+
+
+/* computes a = 2**b 
+ *
+ * Simple algorithm which zeroes the int, grows it then just sets one bit
+ * as required.
+ */
+int
+mp_2expt (mp_int * a, int b)
+{
+  int     res;
+
+  /* zero a as per default */
+  mp_zero (a);
+
+  /* grow a to accomodate the single bit */
+  if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
+    return res;
+  }
+
+  /* set the used count of where the bit will go */
+  a->used = b / DIGIT_BIT + 1;
+
+  /* put the single bit in its place */
+  a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
+
+  return MP_OKAY;
+}
+
+
+/* multiply by a digit */
+int
+mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
+{
+  mp_digit u, *tmpa, *tmpc;
+  mp_word  r;
+  int      ix, res, olduse;
+
+  /* make sure c is big enough to hold a*b */
+  if (c->alloc < a->used + 1) {
+    if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* get the original destinations used count */
+  olduse = c->used;
+
+  /* set the sign */
+  c->sign = a->sign;
+
+  /* alias for a->dp [source] */
+  tmpa = a->dp;
+
+  /* alias for c->dp [dest] */
+  tmpc = c->dp;
+
+  /* zero carry */
+  u = 0;
+
+  /* compute columns */
+  for (ix = 0; ix < a->used; ix++) {
+    /* compute product and carry sum for this term */
+    r       = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
+
+    /* mask off higher bits to get a single digit */
+    *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+    /* send carry into next iteration */
+    u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+  }
+
+  /* store final carry [if any] and increment ix offset  */
+  *tmpc++ = u;
+  ++ix;
+
+  /* now zero digits above the top */
+  while (ix++ < olduse) {
+     *tmpc++ = 0;
+  }
+
+  /* set used count */
+  c->used = a->used + 1;
+  mp_clamp(c);
+
+  return MP_OKAY;
+}
+
+
+/* d = a * b (mod c) */
+int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+  int     res;
+  mp_int  t;
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+  res = mp_mod (&t, c, d);
+  mp_clear (&t);
+  return res;
+}
+
+
+/* computes b = a*a */
+int
+mp_sqr (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  {
+#ifdef BN_FAST_S_MP_SQR_C
+    /* can we use the fast comba multiplier? */
+    if ((a->used * 2 + 1) < MP_WARRAY && 
+         a->used < 
+         (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
+      res = fast_s_mp_sqr (a, b);
+    } else
+#endif
+#ifdef BN_S_MP_SQR_C
+      res = s_mp_sqr (a, b);
+#else
+      res = MP_VAL;
+#endif
+  }
+  b->sign = MP_ZPOS;
+  return res;
+}
+
+
+/* high level multiplication (handles sign) */
+int mp_mul (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     res, neg;
+  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+
+  {
+    /* can we use the fast multiplier?
+     *
+     * The fast multiplier can be used if the output will 
+     * have less than MP_WARRAY digits and the number of 
+     * digits won't affect carry propagation
+     */
+    int     digs = a->used + b->used + 1;
+
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
+    if ((digs < MP_WARRAY) &&
+        MIN(a->used, b->used) <= 
+        (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+      res = fast_s_mp_mul_digs (a, b, c, digs);
+    } else 
+#endif
+#ifdef BN_S_MP_MUL_DIGS_C
+      res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
+#else
+      res = MP_VAL;
+#endif
+
+  }
+  c->sign = (c->used > 0) ? neg : MP_ZPOS;
+  return res;
+}
+
+
+/* b = a*2 */
+int mp_mul_2(mp_int * a, mp_int * b)
+{
+  int     x, res, oldused;
+
+  /* grow to accomodate result */
+  if (b->alloc < a->used + 1) {
+    if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  oldused = b->used;
+  b->used = a->used;
+
+  {
+    register mp_digit r, rr, *tmpa, *tmpb;
+
+    /* alias for source */
+    tmpa = a->dp;
+    
+    /* alias for dest */
+    tmpb = b->dp;
+
+    /* carry */
+    r = 0;
+    for (x = 0; x < a->used; x++) {
+    
+      /* get what will be the *next* carry bit from the 
+       * MSB of the current digit 
+       */
+      rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
+      
+      /* now shift up this digit, add in the carry [from the previous] */
+      *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
+      
+      /* copy the carry that would be from the source 
+       * digit into the next iteration 
+       */
+      r = rr;
+    }
+
+    /* new leading digit? */
+    if (r != 0) {
+      /* add a MSB which is always 1 at this point */
+      *tmpb = 1;
+      ++(b->used);
+    }
+
+    /* now zero any excess digits on the destination 
+     * that we didn't write to 
+     */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+  return MP_OKAY;
+}
+
+
+/* divide by three (based on routine from MPI and the GMP manual) */
+int
+mp_div_3 (mp_int * a, mp_int *c, mp_digit * d)
+{
+  mp_int   q;
+  mp_word  w, t;
+  mp_digit b;
+  int      res, ix;
+  
+  /* b = 2**DIGIT_BIT / 3 */
+  b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3);
+
+  if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
+     return res;
+  }
+  
+  q.used = a->used;
+  q.sign = a->sign;
+  w = 0;
+  for (ix = a->used - 1; ix >= 0; ix--) {
+     w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
+
+     if (w >= 3) {
+        /* multiply w by [1/3] */
+        t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT);
+
+        /* now subtract 3 * [w/3] from w, to get the remainder */
+        w -= t+t+t;
+
+        /* fixup the remainder as required since
+         * the optimization is not exact.
+         */
+        while (w >= 3) {
+           t += 1;
+           w -= 3;
+        }
+      } else {
+        t = 0;
+      }
+      q.dp[ix] = (mp_digit)t;
+  }
+
+  /* [optional] store the remainder */
+  if (d != NULL) {
+     *d = (mp_digit)w;
+  }
+
+  /* [optional] store the quotient */
+  if (c != NULL) {
+     mp_clamp(&q);
+     mp_exch(&q, c);
+  }
+  mp_clear(&q);
+  
+  return res;
+}
+
+
+/* init an mp_init for a given size */
+int mp_init_size (mp_int * a, int size)
+{
+  int x;
+
+  /* pad size so there are always extra digits */
+  size += (MP_PREC * 2) - (size % MP_PREC);	
+  
+  /* alloc mem */
+  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size, 0,
+                                      DYNAMIC_TYPE_BIGINT);
+  if (a->dp == NULL) {
+    return MP_MEM;
+  }
+
+  /* set the members */
+  a->used  = 0;
+  a->alloc = size;
+  a->sign  = MP_ZPOS;
+
+  /* zero the digits */
+  for (x = 0; x < size; x++) {
+      a->dp[x] = 0;
+  }
+
+  return MP_OKAY;
+}
+
+
+/* the jist of squaring...
+ * you do like mult except the offset of the tmpx [one that 
+ * starts closer to zero] can't equal the offset of tmpy.  
+ * So basically you set up iy like before then you min it with
+ * (ty-tx) so that it never happens.  You double all those 
+ * you add in the inner loop
+
+After that loop you do the squares and add them in.
+*/
+
+int fast_s_mp_sqr (mp_int * a, mp_int * b)
+{
+  int       olduse, res, pa, ix, iz;
+  mp_digit   W[MP_WARRAY], *tmpx;
+  mp_word   W1;
+
+  /* grow the destination as required */
+  pa = a->used + a->used;
+  if (b->alloc < pa) {
+    if ((res = mp_grow (b, pa)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* number of output digits to produce */
+  W1 = 0;
+  for (ix = 0; ix < pa; ix++) { 
+      int      tx, ty, iy;
+      mp_word  _W;
+      mp_digit *tmpy;
+
+      /* clear counter */
+      _W = 0;
+
+      /* get offsets into the two bignums */
+      ty = MIN(a->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = a->dp + tx;
+      tmpy = a->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(a->used-tx, ty+1);
+
+      /* now for squaring tx can never equal ty 
+       * we halve the distance since they approach at a rate of 2x
+       * and we have to round because odd cases need to be executed
+       */
+      iy = MIN(iy, (ty-tx+1)>>1);
+
+      /* execute loop */
+      for (iz = 0; iz < iy; iz++) {
+         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+      }
+
+      /* double the inner product and add carry */
+      _W = _W + _W + W1;
+
+      /* even columns have the square term in them */
+      if ((ix&1) == 0) {
+         _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
+      }
+
+      /* store it */
+      W[ix] = (mp_digit)(_W & MP_MASK);
+
+      /* make next carry */
+      W1 = _W >> ((mp_word)DIGIT_BIT);
+  }
+
+  /* setup dest */
+  olduse  = b->used;
+  b->used = a->used+a->used;
+
+  {
+    mp_digit *tmpb;
+    tmpb = b->dp;
+    for (ix = 0; ix < pa; ix++) {
+      *tmpb++ = W[ix] & MP_MASK;
+    }
+
+    /* clear unused digits [that existed in the old copy of c] */
+    for (; ix < olduse; ix++) {
+      *tmpb++ = 0;
+    }
+  }
+  mp_clamp (b);
+  return MP_OKAY;
+}
+
+
+/* Fast (comba) multiplier
+ *
+ * This is the fast column-array [comba] multiplier.  It is 
+ * designed to compute the columns of the product first 
+ * then handle the carries afterwards.  This has the effect 
+ * of making the nested loops that compute the columns very
+ * simple and schedulable on super-scalar processors.
+ *
+ * This has been modified to produce a variable number of 
+ * digits of output so if say only a half-product is required 
+ * you don't have to compute the upper half (a feature 
+ * required for fast Barrett reduction).
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ *
+ */
+int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  int     olduse, res, pa, ix, iz;
+  mp_digit W[MP_WARRAY];
+  register mp_word  _W;
+
+  /* grow the destination as required */
+  if (c->alloc < digs) {
+    if ((res = mp_grow (c, digs)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* number of output digits to produce */
+  pa = MIN(digs, a->used + b->used);
+
+  /* clear the carry */
+  _W = 0;
+  for (ix = 0; ix < pa; ix++) { 
+      int      tx, ty;
+      int      iy;
+      mp_digit *tmpx, *tmpy;
+
+      /* get offsets into the two bignums */
+      ty = MIN(b->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = a->dp + tx;
+      tmpy = b->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially 
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(a->used-tx, ty+1);
+
+      /* execute loop */
+      for (iz = 0; iz < iy; ++iz) {
+         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+
+      }
+
+      /* store term */
+      W[ix] = ((mp_digit)_W) & MP_MASK;
+
+      /* make next carry */
+      _W = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+  /* setup dest */
+  olduse  = c->used;
+  c->used = pa;
+
+  {
+    register mp_digit *tmpc;
+    tmpc = c->dp;
+    for (ix = 0; ix < pa+1; ix++) {
+      /* now extract the previous digit [below the carry] */
+      *tmpc++ = W[ix];
+    }
+
+    /* clear unused digits [that existed in the old copy of c] */
+    for (; ix < olduse; ix++) {
+      *tmpc++ = 0;
+    }
+  }
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
+int s_mp_sqr (mp_int * a, mp_int * b)
+{
+  mp_int  t;
+  int     res, ix, iy, pa;
+  mp_word r;
+  mp_digit u, tmpx, *tmpt;
+
+  pa = a->used;
+  if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
+    return res;
+  }
+
+  /* default used is maximum possible size */
+  t.used = 2*pa + 1;
+
+  for (ix = 0; ix < pa; ix++) {
+    /* first calculate the digit at 2*ix */
+    /* calculate double precision result */
+    r = ((mp_word) t.dp[2*ix]) +
+        ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
+
+    /* store lower part in result */
+    t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
+
+    /* get the carry */
+    u           = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+    /* left hand side of A[ix] * A[iy] */
+    tmpx        = a->dp[ix];
+
+    /* alias for where to store the results */
+    tmpt        = t.dp + (2*ix + 1);
+    
+    for (iy = ix + 1; iy < pa; iy++) {
+      /* first calculate the product */
+      r       = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
+
+      /* now calculate the double precision result, note we use
+       * addition instead of *2 since it's easier to optimize
+       */
+      r       = ((mp_word) *tmpt) + r + r + ((mp_word) u);
+
+      /* store lower part */
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+      /* get carry */
+      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+    }
+    /* propagate upwards */
+    while (u != ((mp_digit) 0)) {
+      r       = ((mp_word) *tmpt) + ((mp_word) u);
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+    }
+  }
+
+  mp_clamp (&t);
+  mp_exch (&t, b);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* multiplies |a| * |b| and only computes upto digs digits of result
+ * HAC pp. 595, Algorithm 14.12  Modified so you can control how 
+ * many digits of output are created.
+ */
+int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  mp_int  t;
+  int     res, pa, pb, ix, iy;
+  mp_digit u;
+  mp_word r;
+  mp_digit tmpx, *tmpt, *tmpy;
+
+  /* can we use the fast multiplier? */
+  if (((digs) < MP_WARRAY) &&
+      MIN (a->used, b->used) < 
+          (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+    return fast_s_mp_mul_digs (a, b, c, digs);
+  }
+
+  if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
+    return res;
+  }
+  t.used = digs;
+
+  /* compute the digits of the product directly */
+  pa = a->used;
+  for (ix = 0; ix < pa; ix++) {
+    /* set the carry to zero */
+    u = 0;
+
+    /* limit ourselves to making digs digits of output */
+    pb = MIN (b->used, digs - ix);
+
+    /* setup some aliases */
+    /* copy of the digit from a used within the nested loop */
+    tmpx = a->dp[ix];
+    
+    /* an alias for the destination shifted ix places */
+    tmpt = t.dp + ix;
+    
+    /* an alias for the digits of b */
+    tmpy = b->dp;
+
+    /* compute the columns of the output and propagate the carry */
+    for (iy = 0; iy < pb; iy++) {
+      /* compute the column as a mp_word */
+      r       = ((mp_word)*tmpt) +
+                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+                ((mp_word) u);
+
+      /* the new column is the lower part of the result */
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+      /* get the carry word from the result */
+      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+    }
+    /* set carry if it is placed below digs */
+    if (ix + iy < digs) {
+      *tmpt = u;
+    }
+  }
+
+  mp_clamp (&t);
+  mp_exch (&t, c);
+
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/*
+ * shifts with subtractions when the result is greater than b.
+ *
+ * The method is slightly modified to shift B unconditionally upto just under
+ * the leading bit of b.  This saves alot of multiple precision shifting.
+ */
+int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
+{
+  int     x, bits, res;
+
+  /* how many bits of last digit does b use */
+  bits = mp_count_bits (b) % DIGIT_BIT;
+
+  if (b->used > 1) {
+     if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
+        return res;
+     }
+  } else {
+     mp_set(a, 1);
+     bits = 1;
+  }
+
+
+  /* now compute C = A * B mod b */
+  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
+    if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
+      return res;
+    }
+    if (mp_cmp_mag (a, b) != MP_LT) {
+      if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
+        return res;
+      }
+    }
+  }
+
+  return MP_OKAY;
+}
+
+
+#ifdef MP_LOW_MEM
+   #define TAB_SIZE 32
+#else
+   #define TAB_SIZE 256
+#endif
+
+int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+  mp_int  M[TAB_SIZE], res, mu;
+  mp_digit buf;
+  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+  int (*redux)(mp_int*,mp_int*,mp_int*);
+
+  /* find window size */
+  x = mp_count_bits (X);
+  if (x <= 7) {
+    winsize = 2;
+  } else if (x <= 36) {
+    winsize = 3;
+  } else if (x <= 140) {
+    winsize = 4;
+  } else if (x <= 450) {
+    winsize = 5;
+  } else if (x <= 1303) {
+    winsize = 6;
+  } else if (x <= 3529) {
+    winsize = 7;
+  } else {
+    winsize = 8;
+  }
+
+#ifdef MP_LOW_MEM
+    if (winsize > 5) {
+       winsize = 5;
+    }
+#endif
+
+  /* init M array */
+  /* init first cell */
+  if ((err = mp_init(&M[1])) != MP_OKAY) {
+     return err; 
+  }
+
+  /* now init the second half of the array */
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    if ((err = mp_init(&M[x])) != MP_OKAY) {
+      for (y = 1<<(winsize-1); y < x; y++) {
+        mp_clear (&M[y]);
+      }
+      mp_clear(&M[1]);
+      return err;
+    }
+  }
+
+  /* create mu, used for Barrett reduction */
+  if ((err = mp_init (&mu)) != MP_OKAY) {
+    goto LBL_M;
+  }
+  
+  if (redmode == 0) {
+     if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
+        goto LBL_MU;
+     }
+     redux = mp_reduce;
+  } else {
+     if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
+        goto LBL_MU;
+     }
+     redux = mp_reduce_2k_l;
+  }    
+
+  /* create M table
+   *
+   * The M table contains powers of the base, 
+   * e.g. M[x] = G**x mod P
+   *
+   * The first half of the table is not 
+   * computed though accept for M[0] and M[1]
+   */
+  if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
+    goto LBL_MU;
+  }
+
+  /* compute the value at M[1<<(winsize-1)] by squaring 
+   * M[1] (winsize-1) times 
+   */
+  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+    goto LBL_MU;
+  }
+
+  for (x = 0; x < (winsize - 1); x++) {
+    /* square it */
+    if ((err = mp_sqr (&M[1 << (winsize - 1)], 
+                       &M[1 << (winsize - 1)])) != MP_OKAY) {
+      goto LBL_MU;
+    }
+
+    /* reduce modulo P */
+    if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
+      goto LBL_MU;
+    }
+  }
+
+  /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
+   * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
+   */
+  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+      goto LBL_MU;
+    }
+    if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
+      goto LBL_MU;
+    }
+  }
+
+  /* setup result */
+  if ((err = mp_init (&res)) != MP_OKAY) {
+    goto LBL_MU;
+  }
+  mp_set (&res, 1);
+
+  /* set initial mode and bit cnt */
+  mode   = 0;
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+  bitcpy = 0;
+  bitbuf = 0;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset the bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int) DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
+    buf <<= (mp_digit)1;
+
+    /* if the bit is zero and mode == 0 then we ignore it
+     * These represent the leading zero bits before the first 1 bit
+     * in the exponent.  Technically this opt is not required but it
+     * does lower the # of trivial squaring/reductions used
+     */
+    if (mode == 0 && y == 0) {
+      continue;
+    }
+
+    /* if the bit is zero and mode == 1 then we square */
+    if (mode == 1 && y == 0) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      continue;
+    }
+
+    /* else we add it to the window */
+    bitbuf |= (y << (winsize - ++bitcpy));
+    mode    = 2;
+
+    if (bitcpy == winsize) {
+      /* ok window is filled so square as required and multiply  */
+      /* square first */
+      for (x = 0; x < winsize; x++) {
+        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+
+      /* then multiply */
+      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* empty window and reset */
+      bitcpy = 0;
+      bitbuf = 0;
+      mode   = 1;
+    }
+  }
+
+  /* if bits remain then square/multiply */
+  if (mode == 2 && bitcpy > 0) {
+    /* square then multiply if the bit is set */
+    for (x = 0; x < bitcpy; x++) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      bitbuf <<= 1;
+      if ((bitbuf & (1 << winsize)) != 0) {
+        /* then multiply */
+        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+    }
+  }
+
+  mp_exch (&res, Y);
+  err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_MU:mp_clear (&mu);
+LBL_M:
+  mp_clear(&M[1]);
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    mp_clear (&M[x]);
+  }
+  return err;
+}
+
+
+/* pre-calculate the value required for Barrett reduction
+ * For a given modulus "b" it calulates the value required in "a"
+ */
+int mp_reduce_setup (mp_int * a, mp_int * b)
+{
+  int     res;
+  
+  if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
+    return res;
+  }
+  return mp_div (a, b, a, NULL);
+}
+
+
+/* reduces x mod m, assumes 0 < x < m**2, mu is 
+ * precomputed via mp_reduce_setup.
+ * From HAC pp.604 Algorithm 14.42
+ */
+int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
+{
+  mp_int  q;
+  int     res, um = m->used;
+
+  /* q = x */
+  if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
+    return res;
+  }
+
+  /* q1 = x / b**(k-1)  */
+  mp_rshd (&q, um - 1);         
+
+  /* according to HAC this optimization is ok */
+  if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
+    if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+  } else {
+#ifdef BN_S_MP_MUL_HIGH_DIGS_C
+    if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+    if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+#else 
+    { 
+      res = MP_VAL;
+      goto CLEANUP;
+    }
+#endif
+  }
+
+  /* q3 = q2 / b**(k+1) */
+  mp_rshd (&q, um + 1);         
+
+  /* x = x mod b**(k+1), quick (no division) */
+  if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
+    goto CLEANUP;
+  }
+
+  /* q = q * m mod b**(k+1), quick (no division) */
+  if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
+    goto CLEANUP;
+  }
+
+  /* x = x - q */
+  if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
+    goto CLEANUP;
+  }
+
+  /* If x < 0, add b**(k+1) to it */
+  if (mp_cmp_d (x, 0) == MP_LT) {
+    mp_set (&q, 1);
+    if ((res = mp_lshd (&q, um + 1)) != MP_OKAY)
+      goto CLEANUP;
+    if ((res = mp_add (x, &q, x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  /* Back off if it's too big */
+  while (mp_cmp (x, m) != MP_LT) {
+    if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+  }
+  
+CLEANUP:
+  mp_clear (&q);
+
+  return res;
+}
+
+
+/* reduces a modulo n where n is of the form 2**p - d 
+   This differs from reduce_2k since "d" can be larger
+   than a single digit.
+*/
+int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
+{
+   mp_int q;
+   int    p, res;
+   
+   if ((res = mp_init(&q)) != MP_OKAY) {
+      return res;
+   }
+   
+   p = mp_count_bits(n);    
+top:
+   /* q = a/2**p, a = a mod 2**p */
+   if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+   
+   /* q = q * d */
+   if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { 
+      goto ERR;
+   }
+   
+   /* a = a + q */
+   if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+   
+   if (mp_cmp_mag(a, n) != MP_LT) {
+      s_mp_sub(a, n, a);
+      goto top;
+   }
+   
+ERR:
+   mp_clear(&q);
+   return res;
+}
+
+
+/* determines the setup value */
+int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
+{
+   int    res;
+   mp_int tmp;
+   
+   if ((res = mp_init(&tmp)) != MP_OKAY) {
+      return res;
+   }
+   
+   if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
+      goto ERR;
+   }
+   
+   if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
+      goto ERR;
+   }
+   
+ERR:
+   mp_clear(&tmp);
+   return res;
+}
+
+
+/* multiplies |a| * |b| and does not compute the lower digs digits
+ * [meant to get the higher part of the product]
+ */
+int
+s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  mp_int  t;
+  int     res, pa, pb, ix, iy;
+  mp_digit u;
+  mp_word r;
+  mp_digit tmpx, *tmpt, *tmpy;
+
+  /* can we use the fast multiplier? */
+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+  if (((a->used + b->used + 1) < MP_WARRAY)
+      && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+    return fast_s_mp_mul_high_digs (a, b, c, digs);
+  }
+#endif
+
+  if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
+    return res;
+  }
+  t.used = a->used + b->used + 1;
+
+  pa = a->used;
+  pb = b->used;
+  for (ix = 0; ix < pa; ix++) {
+    /* clear the carry */
+    u = 0;
+
+    /* left hand side of A[ix] * B[iy] */
+    tmpx = a->dp[ix];
+
+    /* alias to the address of where the digits will be stored */
+    tmpt = &(t.dp[digs]);
+
+    /* alias for where to read the right hand side from */
+    tmpy = b->dp + (digs - ix);
+
+    for (iy = digs - ix; iy < pb; iy++) {
+      /* calculate the double precision result */
+      r       = ((mp_word)*tmpt) +
+                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+                ((mp_word) u);
+
+      /* get the lower part */
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+      /* carry the carry */
+      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+    }
+    *tmpt = u;
+  }
+  mp_clamp (&t);
+  mp_exch (&t, c);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* this is a modified version of fast_s_mul_digs that only produces
+ * output digits *above* digs.  See the comments for fast_s_mul_digs
+ * to see how it works.
+ *
+ * This is used in the Barrett reduction since for one of the multiplications
+ * only the higher digits were needed.  This essentially halves the work.
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ */
+int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  int     olduse, res, pa, ix, iz;
+  mp_digit W[MP_WARRAY];
+  mp_word  _W;
+
+  /* grow the destination as required */
+  pa = a->used + b->used;
+  if (c->alloc < pa) {
+    if ((res = mp_grow (c, pa)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* number of output digits to produce */
+  pa = a->used + b->used;
+  _W = 0;
+  for (ix = digs; ix < pa; ix++) { 
+      int      tx, ty, iy;
+      mp_digit *tmpx, *tmpy;
+
+      /* get offsets into the two bignums */
+      ty = MIN(b->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = a->dp + tx;
+      tmpy = b->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially its 
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(a->used-tx, ty+1);
+
+      /* execute loop */
+      for (iz = 0; iz < iy; iz++) {
+         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+      }
+
+      /* store term */
+      W[ix] = ((mp_digit)_W) & MP_MASK;
+
+      /* make next carry */
+      _W = _W >> ((mp_word)DIGIT_BIT);
+  }
+  
+  /* setup dest */
+  olduse  = c->used;
+  c->used = pa;
+
+  {
+    register mp_digit *tmpc;
+
+    tmpc = c->dp + digs;
+    for (ix = digs; ix <= pa; ix++) {
+      /* now extract the previous digit [below the carry] */
+      *tmpc++ = W[ix];
+    }
+
+    /* clear unused digits [that existed in the old copy of c] */
+    for (; ix < olduse; ix++) {
+      *tmpc++ = 0;
+    }
+  }
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+#ifdef CYASSL_KEY_GEN
+
+int mp_cnt_lsb(mp_int *a);
+
+/* c = a * a (mod b) */
+int mp_sqrmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     res;
+  mp_int  t;
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_sqr (a, &t)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+  res = mp_mod (&t, b, c);
+  mp_clear (&t);
+  return res;
+}
+
+
+/* single digit addition */
+int mp_add_d (mp_int * a, mp_digit b, mp_int * c)
+{
+  int     res, ix, oldused;
+  mp_digit *tmpa, *tmpc, mu;
+
+  /* grow c as required */
+  if (c->alloc < a->used + 1) {
+     if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* if a is negative and |a| >= b, call c = |a| - b */
+  if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) {
+     /* temporarily fix sign of a */
+     a->sign = MP_ZPOS;
+
+     /* c = |a| - b */
+     res = mp_sub_d(a, b, c);
+
+     /* fix sign  */
+     a->sign = c->sign = MP_NEG;
+
+     /* clamp */
+     mp_clamp(c);
+
+     return res;
+  }
+
+  /* old number of used digits in c */
+  oldused = c->used;
+
+  /* sign always positive */
+  c->sign = MP_ZPOS;
+
+  /* source alias */
+  tmpa    = a->dp;
+
+  /* destination alias */
+  tmpc    = c->dp;
+
+  /* if a is positive */
+  if (a->sign == MP_ZPOS) {
+     /* add digit, after this we're propagating
+      * the carry.
+      */
+     *tmpc   = *tmpa++ + b;
+     mu      = *tmpc >> DIGIT_BIT;
+     *tmpc++ &= MP_MASK;
+
+     /* now handle rest of the digits */
+     for (ix = 1; ix < a->used; ix++) {
+        *tmpc   = *tmpa++ + mu;
+        mu      = *tmpc >> DIGIT_BIT;
+        *tmpc++ &= MP_MASK;
+     }
+     /* set final carry */
+     ix++;
+     *tmpc++  = mu;
+
+     /* setup size */
+     c->used = a->used + 1;
+  } else {
+     /* a was negative and |a| < b */
+     c->used  = 1;
+
+     /* the result is a single digit */
+     if (a->used == 1) {
+        *tmpc++  =  b - a->dp[0];
+     } else {
+        *tmpc++  =  b;
+     }
+
+     /* setup count so the clearing of oldused
+      * can fall through correctly
+      */
+     ix       = 1;
+  }
+
+  /* now zero to oldused */
+  while (ix++ < oldused) {
+     *tmpc++ = 0;
+  }
+  mp_clamp(c);
+
+  return MP_OKAY;
+}
+
+
+/* single digit subtraction */
+int mp_sub_d (mp_int * a, mp_digit b, mp_int * c)
+{
+  mp_digit *tmpa, *tmpc, mu;
+  int       res, ix, oldused;
+
+  /* grow c as required */
+  if (c->alloc < a->used + 1) {
+     if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* if a is negative just do an unsigned
+   * addition [with fudged signs]
+   */
+  if (a->sign == MP_NEG) {
+     a->sign = MP_ZPOS;
+     res     = mp_add_d(a, b, c);
+     a->sign = c->sign = MP_NEG;
+
+     /* clamp */
+     mp_clamp(c);
+
+     return res;
+  }
+
+  /* setup regs */
+  oldused = c->used;
+  tmpa    = a->dp;
+  tmpc    = c->dp;
+
+  /* if a <= b simply fix the single digit */
+  if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) {
+     if (a->used == 1) {
+        *tmpc++ = b - *tmpa;
+     } else {
+        *tmpc++ = b;
+     }
+     ix      = 1;
+
+     /* negative/1digit */
+     c->sign = MP_NEG;
+     c->used = 1;
+  } else {
+     /* positive/size */
+     c->sign = MP_ZPOS;
+     c->used = a->used;
+
+     /* subtract first digit */
+     *tmpc    = *tmpa++ - b;
+     mu       = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+     *tmpc++ &= MP_MASK;
+
+     /* handle rest of the digits */
+     for (ix = 1; ix < a->used; ix++) {
+        *tmpc    = *tmpa++ - mu;
+        mu       = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+        *tmpc++ &= MP_MASK;
+     }
+  }
+
+  /* zero excess digits */
+  while (ix++ < oldused) {
+     *tmpc++ = 0;
+  }
+  mp_clamp(c);
+  return MP_OKAY;
+}
+
+
+static int s_is_power_of_two(mp_digit b, int *p)
+{
+   int x;
+
+   /* fast return if no power of two */
+   if ((b==0) || (b & (b-1))) {
+      return 0;
+   }
+
+   for (x = 0; x < DIGIT_BIT; x++) {
+      if (b == (((mp_digit)1)<<x)) {
+         *p = x;
+         return 1;
+      }
+   }
+   return 0;
+}
+
+/* single digit division (based on routine from MPI) */
+int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d)
+{
+  mp_int  q;
+  mp_word w;
+  mp_digit t;
+  int     res, ix;
+
+  /* cannot divide by zero */
+  if (b == 0) {
+     return MP_VAL;
+  }
+
+  /* quick outs */
+  if (b == 1 || mp_iszero(a) == 1) {
+     if (d != NULL) {
+        *d = 0;
+     }
+     if (c != NULL) {
+        return mp_copy(a, c);
+     }
+     return MP_OKAY;
+  }
+
+  /* power of two ? */
+  if (s_is_power_of_two(b, &ix) == 1) {
+     if (d != NULL) {
+        *d = a->dp[0] & ((((mp_digit)1)<<ix) - 1);
+     }
+     if (c != NULL) {
+        return mp_div_2d(a, ix, c, NULL);
+     }
+     return MP_OKAY;
+  }
+
+#ifdef BN_MP_DIV_3_C
+  /* three? */
+  if (b == 3) {
+     return mp_div_3(a, c, d);
+  }
+#endif
+
+  /* no easy answer [c'est la vie].  Just division */
+  if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
+     return res;
+  }
+  
+  q.used = a->used;
+  q.sign = a->sign;
+  w = 0;
+  for (ix = a->used - 1; ix >= 0; ix--) {
+     w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
+     
+     if (w >= b) {
+        t = (mp_digit)(w / b);
+        w -= ((mp_word)t) * ((mp_word)b);
+      } else {
+        t = 0;
+      }
+      q.dp[ix] = (mp_digit)t;
+  }
+  
+  if (d != NULL) {
+     *d = (mp_digit)w;
+  }
+  
+  if (c != NULL) {
+     mp_clamp(&q);
+     mp_exch(&q, c);
+  }
+  mp_clear(&q);
+  
+  return res;
+}
+
+
+int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c)
+{
+  return mp_div_d(a, b, NULL, c);
+}
+
+
+const mp_digit ltm_prime_tab[] = {
+  0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+  0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
+  0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
+  0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F,
+#ifndef MP_8BIT
+  0x0083,
+  0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
+  0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
+  0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
+  0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
+
+  0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
+  0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
+  0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
+  0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
+  0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
+  0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
+  0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
+  0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
+
+  0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
+  0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
+  0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
+  0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
+  0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
+  0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
+  0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
+  0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
+
+  0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
+  0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
+  0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
+  0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
+  0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
+  0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
+  0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
+  0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
+#endif
+};
+
+
+/* Miller-Rabin test of "a" to the base of "b" as described in 
+ * HAC pp. 139 Algorithm 4.24
+ *
+ * Sets result to 0 if definitely composite or 1 if probably prime.
+ * Randomly the chance of error is no more than 1/4 and often 
+ * very much lower.
+ */
+int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result)
+{
+  mp_int  n1, y, r;
+  int     s, j, err;
+
+  /* default */
+  *result = MP_NO;
+
+  /* ensure b > 1 */
+  if (mp_cmp_d(b, 1) != MP_GT) {
+     return MP_VAL;
+  }     
+
+  /* get n1 = a - 1 */
+  if ((err = mp_init_copy (&n1, a)) != MP_OKAY) {
+    return err;
+  }
+  if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) {
+    goto LBL_N1;
+  }
+
+  /* set 2**s * r = n1 */
+  if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) {
+    goto LBL_N1;
+  }
+
+  /* count the number of least significant bits
+   * which are zero
+   */
+  s = mp_cnt_lsb(&r);
+
+  /* now divide n - 1 by 2**s */
+  if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) {
+    goto LBL_R;
+  }
+
+  /* compute y = b**r mod a */
+  if ((err = mp_init (&y)) != MP_OKAY) {
+    goto LBL_R;
+  }
+  if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) {
+    goto LBL_Y;
+  }
+
+  /* if y != 1 and y != n1 do */
+  if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) {
+    j = 1;
+    /* while j <= s-1 and y != n1 */
+    while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) {
+      if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) {
+         goto LBL_Y;
+      }
+
+      /* if y == 1 then composite */
+      if (mp_cmp_d (&y, 1) == MP_EQ) {
+         goto LBL_Y;
+      }
+
+      ++j;
+    }
+
+    /* if y != n1 then composite */
+    if (mp_cmp (&y, &n1) != MP_EQ) {
+      goto LBL_Y;
+    }
+  }
+
+  /* probably prime now */
+  *result = MP_YES;
+LBL_Y:mp_clear (&y);
+LBL_R:mp_clear (&r);
+LBL_N1:mp_clear (&n1);
+  return err;
+}
+
+
+/* determines if an integers is divisible by one 
+ * of the first PRIME_SIZE primes or not
+ *
+ * sets result to 0 if not, 1 if yes
+ */
+int mp_prime_is_divisible (mp_int * a, int *result)
+{
+  int     err, ix;
+  mp_digit res;
+
+  /* default to not */
+  *result = MP_NO;
+
+  for (ix = 0; ix < PRIME_SIZE; ix++) {
+    /* what is a mod LBL_prime_tab[ix] */
+    if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) {
+      return err;
+    }
+
+    /* is the residue zero? */
+    if (res == 0) {
+      *result = MP_YES;
+      return MP_OKAY;
+    }
+  }
+
+  return MP_OKAY;
+}
+
+
+/*
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+int mp_prime_is_prime (mp_int * a, int t, int *result)
+{
+  mp_int  b;
+  int     ix, err, res;
+
+  /* default to no */
+  *result = MP_NO;
+
+  /* valid value of t? */
+  if (t <= 0 || t > PRIME_SIZE) {
+    return MP_VAL;
+  }
+
+  /* is the input equal to one of the primes in the table? */
+  for (ix = 0; ix < PRIME_SIZE; ix++) {
+      if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) {
+         *result = 1;
+         return MP_OKAY;
+      }
+  }
+
+  /* first perform trial division */
+  if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) {
+    return err;
+  }
+
+  /* return if it was trivially divisible */
+  if (res == MP_YES) {
+    return MP_OKAY;
+  }
+
+  /* now perform the miller-rabin rounds */
+  if ((err = mp_init (&b)) != MP_OKAY) {
+    return err;
+  }
+
+  for (ix = 0; ix < t; ix++) {
+    /* set the prime */
+    mp_set (&b, ltm_prime_tab[ix]);
+
+    if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) {
+      goto LBL_B;
+    }
+
+    if (res == MP_NO) {
+      goto LBL_B;
+    }
+  }
+
+  /* passed the test */
+  *result = MP_YES;
+LBL_B:mp_clear (&b);
+  return err;
+}
+
+
+/* computes least common multiple as |a*b|/(a, b) */
+int mp_lcm (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     res;
+  mp_int  t1, t2;
+
+
+  if ((res = mp_init_multi (&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+    return res;
+  }
+
+  /* t1 = get the GCD of the two inputs */
+  if ((res = mp_gcd (a, b, &t1)) != MP_OKAY) {
+    goto LBL_T;
+  }
+
+  /* divide the smallest by the GCD */
+  if (mp_cmp_mag(a, b) == MP_LT) {
+     /* store quotient in t2 such that t2 * b is the LCM */
+     if ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) {
+        goto LBL_T;
+     }
+     res = mp_mul(b, &t2, c);
+  } else {
+     /* store quotient in t2 such that t2 * a is the LCM */
+     if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) {
+        goto LBL_T;
+     }
+     res = mp_mul(a, &t2, c);
+  }
+
+  /* fix the sign to positive */
+  c->sign = MP_ZPOS;
+
+LBL_T:
+  mp_clear(&t1);
+  mp_clear(&t2);
+  return res;
+}
+
+
+static const int lnz[16] = { 
+   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(mp_int *a)
+{
+    int x;
+    mp_digit q, qq;
+
+    /* easy out */
+    if (mp_iszero(a) == 1) {
+        return 0;
+    }
+
+    /* scan lower digits until non-zero */
+    for (x = 0; x < a->used && a->dp[x] == 0; x++);
+    q = a->dp[x];
+    x *= DIGIT_BIT;
+
+    /* now scan this digit until a 1 is found */
+    if ((q & 1) == 0) {
+        do {
+            qq  = q & 15;
+            x  += lnz[qq];
+            q >>= 4;
+        } while (qq == 0);
+    }
+    return x;
+}
+
+
+/* Greatest Common Divisor using the binary method */
+int mp_gcd (mp_int * a, mp_int * b, mp_int * c)
+{
+    mp_int  u, v;
+    int     k, u_lsb, v_lsb, res;
+
+    /* either zero than gcd is the largest */
+    if (mp_iszero (a) == MP_YES) {
+        return mp_abs (b, c);
+    }
+    if (mp_iszero (b) == MP_YES) {
+        return mp_abs (a, c);
+    }
+
+    /* get copies of a and b we can modify */
+    if ((res = mp_init_copy (&u, a)) != MP_OKAY) {
+        return res;
+    }
+
+    if ((res = mp_init_copy (&v, b)) != MP_OKAY) {
+        goto LBL_U;
+    }
+
+    /* must be positive for the remainder of the algorithm */
+    u.sign = v.sign = MP_ZPOS;
+
+    /* B1.  Find the common power of two for u and v */
+    u_lsb = mp_cnt_lsb(&u);
+    v_lsb = mp_cnt_lsb(&v);
+    k     = MIN(u_lsb, v_lsb);
+
+    if (k > 0) {
+        /* divide the power of two out */
+        if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        }
+
+        if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        }
+    }
+
+    /* divide any remaining factors of two out */
+    if (u_lsb != k) {
+        if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        }
+    }
+
+    if (v_lsb != k) {
+        if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        }
+    }
+
+    while (mp_iszero(&v) == 0) {
+        /* make sure v is the largest */
+        if (mp_cmp_mag(&u, &v) == MP_GT) {
+            /* swap u and v to make sure v is >= u */
+            mp_exch(&u, &v);
+        }
+     
+        /* subtract smallest from largest */
+        if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) {
+            goto LBL_V;
+        }
+     
+        /* Divide out all factors of two */
+        if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        } 
+    } 
+
+    /* multiply by 2**k which we divided out at the beginning */
+    if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) {
+        goto LBL_V;
+    }
+    c->sign = MP_ZPOS;
+    res = MP_OKAY;
+LBL_V:mp_clear (&u);
+LBL_U:mp_clear (&v);
+    return res;
+}
+
+
+/* set a 32-bit const */
+int mp_set_int (mp_int * a, unsigned long b)
+{
+  int     x, res;
+
+  mp_zero (a);
+  
+  /* set four bits at a time */
+  for (x = 0; x < 8; x++) {
+    /* shift the number up four bits */
+    if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) {
+      return res;
+    }
+
+    /* OR in the top four bits of the source */
+    a->dp[0] |= (b >> 28) & 15;
+
+    /* shift the source up to the next four bits */
+    b <<= 4;
+
+    /* ensure that digits are not clamped off */
+    a->used += 1;
+  }
+  mp_clamp (a);
+  return MP_OKAY;
+}
+
+
+#endif /* CYASSL_KEY_GEN */
+
+#endif /* USE_FAST_MATH */
+
diff -r 000000000000 -r 5045d2638c29 integer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/integer.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,325 @@
+/* integer.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+/*
+ * Based on public domain LibTomMath 0.38 by Tom St Denis, tomstdenis@iahu.ca,
+ * http://math.libtomcrypt.com
+ */
+
+
+#ifndef CTAO_CRYPT_INTEGER_H
+#define CTAO_CRYPT_INTEGER_H
+
+/* may optionally use fast math instead, not yet supported on all platforms and
+   may not be faster on all
+*/
+#include "types.h"
+#ifdef USE_FAST_MATH
+    #include "tfm.h"
+#else
+
+#ifndef CHAR_BIT
+    #include <limits.h>
+#endif
+
+#include "types.h"       /* will set MP_xxBIT if not default */
+#include "mpi_class.h"
+
+#ifndef MIN
+   #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+   #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+
+/* C++ compilers don't like assigning void * to mp_digit * */
+#define  OPT_CAST(x)  (x *)
+
+#else
+
+/* C on the other hand doesn't care */
+#define  OPT_CAST(x)
+
+#endif
+
+
+/* detect 64-bit mode if possible */
+#if defined(__x86_64__) 
+   #if !(defined(MP_64BIT) && defined(MP_16BIT) && defined(MP_8BIT))
+      #define MP_64BIT
+   #endif
+#endif
+
+/* some default configurations.
+ *
+ * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
+ * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
+ *
+ * At the very least a mp_digit must be able to hold 7 bits
+ * [any size beyond that is ok provided it doesn't overflow the data type]
+ */
+#ifdef MP_8BIT
+   typedef unsigned char      mp_digit;
+   typedef unsigned short     mp_word;
+#elif defined(MP_16BIT)
+   typedef unsigned short     mp_digit;
+   typedef unsigned long      mp_word;
+#elif defined(MP_64BIT)
+   /* for GCC only on supported platforms */
+#ifndef CRYPT
+   typedef unsigned long long ulong64;
+   typedef signed long long   long64;
+#endif
+
+   typedef unsigned long      mp_digit;
+   typedef unsigned long      mp_word __attribute__ ((mode(TI)));
+
+   #define DIGIT_BIT          60
+#else
+   /* this is the default case, 28-bit digits */
+   
+   /* this is to make porting into LibTomCrypt easier :-) */
+#ifndef CRYPT
+   #if defined(_MSC_VER) || defined(__BORLANDC__) 
+      typedef unsigned __int64   ulong64;
+      typedef signed __int64     long64;
+   #else
+      typedef unsigned long long ulong64;
+      typedef signed long long   long64;
+   #endif
+#endif
+
+   typedef unsigned long      mp_digit;
+   typedef ulong64            mp_word;
+
+#ifdef MP_31BIT   
+   /* this is an extension that uses 31-bit digits */
+   #define DIGIT_BIT          31
+#else
+   /* default case is 28-bit digits, defines MP_28BIT as a handy test macro */
+   #define DIGIT_BIT          28
+   #define MP_28BIT
+#endif   
+#endif
+
+
+/* otherwise the bits per digit is calculated automatically from the size of
+   a mp_digit */
+#ifndef DIGIT_BIT
+   #define DIGIT_BIT ((int)((CHAR_BIT * sizeof(mp_digit) - 1)))
+      /* bits per digit */
+#endif
+
+#define MP_DIGIT_BIT     DIGIT_BIT
+#define MP_MASK          ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
+#define MP_DIGIT_MAX     MP_MASK
+
+/* equalities */
+#define MP_LT        -1   /* less than */
+#define MP_EQ         0   /* equal to */
+#define MP_GT         1   /* greater than */
+
+#define MP_ZPOS       0   /* positive integer */
+#define MP_NEG        1   /* negative */
+
+#define MP_OKAY       0   /* ok result */
+#define MP_MEM        -2  /* out of mem */
+#define MP_VAL        -3  /* invalid input */
+#define MP_RANGE      MP_VAL
+
+#define MP_YES        1   /* yes response */
+#define MP_NO         0   /* no response */
+
+/* Primality generation flags */
+#define LTM_PRIME_BBS      0x0001 /* BBS style prime */
+#define LTM_PRIME_SAFE     0x0002 /* Safe prime (p-1)/2 == prime */
+#define LTM_PRIME_2MSB_ON  0x0008 /* force 2nd MSB to 1 */
+
+typedef int           mp_err;
+
+/* define this to use lower memory usage routines (exptmods mostly) */
+#define MP_LOW_MEM
+
+/* default precision */
+#ifndef MP_PREC
+   #ifndef MP_LOW_MEM
+      #define MP_PREC                 32     /* default digits of precision */
+   #else
+      #define MP_PREC                 1      /* default digits of precision */
+   #endif   
+#endif
+
+/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - 
+   BITS_PER_DIGIT*2) */
+#define MP_WARRAY  (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
+
+/* the infamous mp_int structure */
+typedef struct  {
+    int used, alloc, sign;
+    mp_digit *dp;
+} mp_int;
+
+/* callback for mp_prime_random, should fill dst with random bytes and return
+   how many read [upto len] */
+typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat);
+
+
+#define USED(m)    ((m)->used)
+#define DIGIT(m,k) ((m)->dp[(k)])
+#define SIGN(m)    ((m)->sign)
+
+
+/* ---> Basic Manipulations <--- */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+#define mp_iseven(a) \
+    (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
+#define mp_isodd(a) \
+    (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
+
+
+/* number of primes */
+#ifdef MP_8BIT
+   #define PRIME_SIZE      31
+#else
+   #define PRIME_SIZE      256
+#endif
+
+#define mp_prime_random(a, t, size, bbs, cb, dat) \
+   mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat)
+
+#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len))
+#define mp_raw_size(mp)           mp_signed_bin_size(mp)
+#define mp_toraw(mp, str)         mp_to_signed_bin((mp), (str))
+#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len))
+#define mp_mag_size(mp)           mp_unsigned_bin_size(mp)
+#define mp_tomag(mp, str)         mp_to_unsigned_bin((mp), (str))
+
+#define mp_tobinary(M, S)  mp_toradix((M), (S), 2)
+#define mp_tooctal(M, S)   mp_toradix((M), (S), 8)
+#define mp_todecimal(M, S) mp_toradix((M), (S), 10)
+#define mp_tohex(M, S)     mp_toradix((M), (S), 16)
+
+#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
+
+extern const char *mp_s_rmap;
+
+/* 6 functions needed by Rsa */
+int  mp_init (mp_int * a);
+void mp_clear (mp_int * a);
+int  mp_unsigned_bin_size(mp_int * a);
+int  mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
+int  mp_to_unsigned_bin (mp_int * a, unsigned char *b);
+int  mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y);
+/* end functions needed by Rsa */
+
+/* functions added to support above needed, removed TOOM and KARATSUBA */
+int  mp_count_bits (mp_int * a);
+int  mp_init_copy (mp_int * a, mp_int * b);
+int  mp_copy (mp_int * a, mp_int * b);
+int  mp_grow (mp_int * a, int size);
+void bn_reverse (unsigned char *s, int len);
+int  mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d);
+void mp_zero (mp_int * a);
+void mp_clamp (mp_int * a);
+void mp_exch (mp_int * a, mp_int * b);
+void mp_rshd (mp_int * a, int b);
+int  mp_mod_2d (mp_int * a, int b, mp_int * c);
+int  mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
+int  mp_mul_2d (mp_int * a, int b, mp_int * c);
+int  mp_lshd (mp_int * a, int b);
+int  mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y);
+int  mp_abs (mp_int * a, mp_int * b);
+int  mp_invmod (mp_int * a, mp_int * b, mp_int * c);
+int  fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c);
+int  mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c);
+int  mp_cmp_mag (mp_int * a, mp_int * b);
+int  mp_cmp (mp_int * a, mp_int * b);
+int  mp_cmp_d(mp_int * a, mp_digit b);
+void mp_set (mp_int * a, mp_digit b);
+int  mp_mod (mp_int * a, mp_int * b, mp_int * c);
+int  mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+int  mp_div_2(mp_int * a, mp_int * b);
+int  mp_add (mp_int * a, mp_int * b, mp_int * c);
+int  s_mp_add (mp_int * a, mp_int * b, mp_int * c);
+int  s_mp_sub (mp_int * a, mp_int * b, mp_int * c);
+int  mp_sub (mp_int * a, mp_int * b, mp_int * c);
+int  mp_init (mp_int * a);
+int  mp_reduce_is_2k_l(mp_int *a);
+int  mp_reduce_is_2k(mp_int *a);
+int  mp_dr_is_modulus(mp_int *a);
+int  mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int);
+int  mp_montgomery_setup (mp_int * n, mp_digit * rho);
+int  fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho);
+int  mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho);
+void mp_dr_setup(mp_int *a, mp_digit *d);
+int  mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k);
+int  mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d);
+int  fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
+int  mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
+int  mp_reduce (mp_int * x, mp_int * m, mp_int * mu);
+int  mp_reduce_setup (mp_int * a, mp_int * b);
+int  s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
+int  mp_montgomery_calc_normalization (mp_int * a, mp_int * b);
+int  s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  s_mp_sqr (mp_int * a, mp_int * b);
+int  fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  fast_s_mp_sqr (mp_int * a, mp_int * b);
+int  mp_init_size (mp_int * a, int size);
+int  mp_div_3 (mp_int * a, mp_int *c, mp_digit * d);
+int  mp_mul_2(mp_int * a, mp_int * b);
+int  mp_mul (mp_int * a, mp_int * b, mp_int * c);
+int  mp_sqr (mp_int * a, mp_int * b);
+int  mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+int  mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
+int  mp_2expt (mp_int * a, int b);
+int  mp_reduce_2k_setup(mp_int *a, mp_digit *d);
+/* end support added functions */
+
+/* added */
+int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e,
+                  mp_int* f);
+
+#ifdef CYASSL_KEY_GEN
+    int mp_prime_is_prime (mp_int * a, int t, int *result);
+    int mp_set_int (mp_int * a, unsigned long b);
+    int mp_gcd (mp_int * a, mp_int * b, mp_int * c);
+    int mp_lcm (mp_int * a, mp_int * b, mp_int * c);
+    int mp_sub_d (mp_int * a, mp_digit b, mp_int * c);
+#endif
+
+
+#ifdef __cplusplus
+   }
+#endif
+
+
+#endif /* USE_FAST_MATH */
+
+#endif  /* CTAO_CRYPT_INTEGER_H */
+
diff -r 000000000000 -r 5045d2638c29 keys.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keys.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,613 @@
+/* keys.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#include "cyassl_int.h"
+#include "cyassl_error.h"
+#ifdef SHOW_SECRETS
+    #include <stdio.h>
+#endif
+
+
+#ifndef NO_TLS
+    int MakeTlsMasterSecret(SSL*);
+    void TLS_hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz,
+                  int content, int verify);
+#endif
+
+
+
+int SetCipherSpecs(SSL* ssl)
+{
+    switch (ssl->options.cipherSuite) {
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    case SSL_RSA_WITH_RC4_128_SHA :
+        ssl->specs.bulk_cipher_algorithm = rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    case TLS_NTRU_RSA_WITH_RC4_128_SHA :
+        ssl->specs.bulk_cipher_algorithm = rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ntru_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+        break;
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    case SSL_RSA_WITH_RC4_128_MD5 :
+        ssl->specs.bulk_cipher_algorithm = rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = md5_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = MD5_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_MD5;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+        break;
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    case SSL_RSA_WITH_3DES_EDE_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = triple_des;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = DES3_KEY_SIZE;
+        ssl->specs.block_size            = DES_BLOCK_SIZE;
+        ssl->specs.iv_size               = DES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = triple_des;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ntru_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = DES3_KEY_SIZE;
+        ssl->specs.block_size            = DES_BLOCK_SIZE;
+        ssl->specs.iv_size               = DES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    case TLS_RSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ntru_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    case TLS_RSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ntru_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    case TLS_PSK_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = psk_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    case TLS_PSK_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = psk_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    case TLS_DHE_RSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    case TLS_DHE_RSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    case TLS_RSA_WITH_HC_128_CBC_MD5 :
+        ssl->specs.bulk_cipher_algorithm = hc128;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = md5_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = MD5_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_MD5;
+        ssl->specs.key_size              = HC_128_KEY_SIZE;
+        ssl->specs.block_size            = 0;
+        ssl->specs.iv_size               = HC_128_IV_SIZE;
+
+        break;
+#endif
+            
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+        case TLS_RSA_WITH_HC_128_CBC_SHA :
+            ssl->specs.bulk_cipher_algorithm = hc128;
+            ssl->specs.cipher_type           = stream;
+            ssl->specs.mac_algorithm         = sha_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+            ssl->specs.pad_size              = PAD_SHA;
+            ssl->specs.key_size              = HC_128_KEY_SIZE;
+            ssl->specs.block_size            = 0;
+            ssl->specs.iv_size               = HC_128_IV_SIZE;
+            
+            break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    case TLS_RSA_WITH_RABBIT_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = rabbit;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = RABBIT_KEY_SIZE;
+        ssl->specs.block_size            = 0;
+        ssl->specs.iv_size               = RABBIT_IV_SIZE;
+
+        break;
+#endif
+
+    default:
+        return UNSUPPORTED_SUITE;
+    }
+
+    /* set TLS if it hasn't been turned off */
+    if (ssl->version.major == 3 && ssl->version.minor >= 1) {
+#ifndef NO_TLS
+        ssl->options.tls = 1;
+        ssl->hmac = TLS_hmac;
+        if (ssl->version.minor == 2)
+            ssl->options.tls1_1 = 1;
+#endif
+    }
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        ssl->hmac = TLS_hmac;
+#endif
+
+    return 0;
+}
+
+
+enum KeyStuff {
+    MASTER_ROUNDS = 3,
+    PREFIX        = 3,     /* up to three letters for master prefix */
+    KEY_PREFIX    = 7      /* up to 7 prefix letters for key rounds */
+
+
+};
+
+
+/* true or false, zero for error */
+static int SetPrefix(byte* sha_input, int index)
+{
+    switch (index) {
+    case 0:
+        XMEMCPY(sha_input, "A", 1);
+        break;
+    case 1:
+        XMEMCPY(sha_input, "BB", 2);
+        break;
+    case 2:
+        XMEMCPY(sha_input, "CCC", 3);
+        break;
+    case 3:
+        XMEMCPY(sha_input, "DDDD", 4);
+        break;
+    case 4:
+        XMEMCPY(sha_input, "EEEEE", 5);
+        break;
+    case 5:
+        XMEMCPY(sha_input, "FFFFFF", 6);
+        break;
+    case 6:
+        XMEMCPY(sha_input, "GGGGGGG", 7);
+        break;
+    default:
+        return 0; 
+    }
+    return 1;
+}
+
+
+static int SetKeys(Ciphers* encrypt, Ciphers* decrypt, Keys* keys,
+                   CipherSpecs* specs, byte side)
+{
+#ifdef BUILD_ARC4
+    word32 sz = specs->key_size;
+    if (specs->bulk_cipher_algorithm == rc4) {
+        if (side == CLIENT_END) {
+            Arc4SetKey(&encrypt->arc4, keys->client_write_key, sz);
+            Arc4SetKey(&decrypt->arc4, keys->server_write_key, sz);
+        }
+        else {
+            Arc4SetKey(&encrypt->arc4, keys->server_write_key, sz);
+            Arc4SetKey(&decrypt->arc4, keys->client_write_key, sz);
+        }
+    }
+#endif
+    
+#ifdef BUILD_HC128
+    if (specs->bulk_cipher_algorithm == hc128) {
+        if (side == CLIENT_END) {
+            Hc128_SetKey(&encrypt->hc128, keys->client_write_key,
+                                          keys->client_write_IV);
+            Hc128_SetKey(&decrypt->hc128, keys->server_write_key,
+                                          keys->server_write_IV);
+        }
+        else {
+            Hc128_SetKey(&encrypt->hc128, keys->server_write_key,
+                                         keys->server_write_IV);
+            Hc128_SetKey(&decrypt->hc128, keys->client_write_key,
+                                         keys->client_write_IV);
+        }
+    }
+#endif
+    
+#ifdef BUILD_RABBIT
+    if (specs->bulk_cipher_algorithm == rabbit) {
+        if (side == CLIENT_END) {
+            RabbitSetKey(&encrypt->rabbit, keys->client_write_key,
+                                           keys->client_write_IV);
+            RabbitSetKey(&decrypt->rabbit, keys->server_write_key,
+                                           keys->server_write_IV);
+        }
+        else {
+            RabbitSetKey(&encrypt->rabbit, keys->server_write_key,
+                                           keys->server_write_IV);
+            RabbitSetKey(&decrypt->rabbit, keys->client_write_key,
+                                           keys->client_write_IV);
+        }
+    }
+#endif
+    
+#ifdef BUILD_DES3
+    if (specs->bulk_cipher_algorithm == triple_des) {
+        if (side == CLIENT_END) {
+            Des3_SetKey(&encrypt->des3, keys->client_write_key,
+                        keys->client_write_IV, DES_ENCRYPTION);
+            Des3_SetKey(&decrypt->des3, keys->server_write_key,
+                        keys->server_write_IV, DES_DECRYPTION);
+        }
+        else {
+            Des3_SetKey(&encrypt->des3, keys->server_write_key,
+                        keys->server_write_IV, DES_ENCRYPTION);
+            Des3_SetKey(&decrypt->des3, keys->client_write_key,
+                keys->client_write_IV, DES_DECRYPTION);
+        }
+    }
+#endif
+
+#ifdef BUILD_AES
+    if (specs->bulk_cipher_algorithm == aes) {
+        if (side == CLIENT_END) {
+            AesSetKey(&encrypt->aes, keys->client_write_key,
+                      specs->key_size, keys->client_write_IV,
+                      AES_ENCRYPTION);
+            AesSetKey(&decrypt->aes, keys->server_write_key,
+                      specs->key_size, keys->server_write_IV,
+                      AES_DECRYPTION);
+        }
+        else {
+            AesSetKey(&encrypt->aes, keys->server_write_key,
+                      specs->key_size, keys->server_write_IV,
+                      AES_ENCRYPTION);
+            AesSetKey(&decrypt->aes, keys->client_write_key,
+                      specs->key_size, keys->client_write_IV,
+                      AES_DECRYPTION);
+        }
+    }
+#endif
+
+    keys->sequence_number      = 0;
+    keys->peer_sequence_number = 0;
+    keys->encryptionOn         = 0;
+
+    return 0;
+}
+
+
+/* TLS can call too */
+int StoreKeys(SSL* ssl, const byte* keyData)
+{
+    int sz = ssl->specs.hash_size, i;
+
+    XMEMCPY(ssl->keys.client_write_MAC_secret, keyData, sz);
+    i = sz;
+    XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz);
+    i += sz;
+
+    sz = ssl->specs.key_size;
+    XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz);
+    i += sz;
+    XMEMCPY(ssl->keys.server_write_key, &keyData[i], sz);
+    i += sz;
+
+    sz = ssl->specs.iv_size;
+    XMEMCPY(ssl->keys.client_write_IV, &keyData[i], sz);
+    i += sz;
+    XMEMCPY(ssl->keys.server_write_IV, &keyData[i], sz);
+
+    return SetKeys(&ssl->encrypt, &ssl->decrypt, &ssl->keys, &ssl->specs,
+                   ssl->options.side);
+}
+
+
+int DeriveKeys(SSL* ssl)
+{
+    int length = 2 * ssl->specs.hash_size + 
+                 2 * ssl->specs.key_size  +
+                 2 * ssl->specs.iv_size;
+    int rounds = (length + MD5_DIGEST_SIZE - 1 ) / MD5_DIGEST_SIZE, i;
+
+    byte shaOutput[SHA_DIGEST_SIZE];
+    byte md5Input[SECRET_LEN + SHA_DIGEST_SIZE];
+    byte shaInput[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN];
+  
+    Md5 md5;
+    Sha sha;
+
+    byte keyData[KEY_PREFIX * MD5_DIGEST_SIZE];  /* max size */
+
+    InitMd5(&md5);
+    InitSha(&sha);
+
+    XMEMCPY(md5Input, ssl->arrays.masterSecret, SECRET_LEN);
+
+    for (i = 0; i < rounds; ++i) {
+        int j   = i + 1;
+        int idx = j;
+
+        if (!SetPrefix(shaInput, i)) {
+            return PREFIX_ERROR;
+        }
+
+        XMEMCPY(shaInput + idx, ssl->arrays.masterSecret, SECRET_LEN);
+        idx += SECRET_LEN;
+        XMEMCPY(shaInput + idx, ssl->arrays.serverRandom, RAN_LEN);
+        idx += RAN_LEN;
+        XMEMCPY(shaInput + idx, ssl->arrays.clientRandom, RAN_LEN);
+        idx += RAN_LEN;
+
+        ShaUpdate(&sha, shaInput, sizeof(shaInput) - KEY_PREFIX + j);
+        ShaFinal(&sha, shaOutput);
+
+        XMEMCPY(&md5Input[SECRET_LEN], shaOutput, SHA_DIGEST_SIZE);
+        Md5Update(&md5, md5Input, sizeof(md5Input));
+        Md5Final(&md5, keyData + i * MD5_DIGEST_SIZE);
+    }
+
+    return StoreKeys(ssl, keyData);
+}
+
+
+void CleanPreMaster(SSL* ssl)
+{
+    int i, sz = ssl->arrays.preMasterSz;
+
+    for (i = 0; i < sz; i++)
+        ssl->arrays.preMasterSecret[i] = 0;
+
+    RNG_GenerateBlock(&ssl->rng, ssl->arrays.preMasterSecret, sz);
+
+    for (i = 0; i < sz; i++)
+        ssl->arrays.preMasterSecret[i] = 0;
+
+}
+
+
+/* Create and store the master secret see page 32, 6.1 */
+int MakeMasterSecret(SSL* ssl)
+{
+    byte   shaOutput[SHA_DIGEST_SIZE];
+    byte   md5Input[ENCRYPT_LEN + SHA_DIGEST_SIZE];
+    byte   shaInput[PREFIX + ENCRYPT_LEN + 2 * RAN_LEN];
+    int    i;
+    word32 idx;
+    word32 pmsSz = ssl->arrays.preMasterSz;
+
+    Md5 md5;
+    Sha sha;
+
+#ifdef SHOW_SECRETS
+    {
+        int j;
+        printf("pre master secret: ");
+        for (j = 0; j < pmsSz; j++)
+            printf("%02x", ssl->arrays.preMasterSecret[j]);
+        printf("\n");
+    }
+#endif
+
+#ifndef NO_TLS
+    if (ssl->options.tls) return MakeTlsMasterSecret(ssl);
+#endif
+
+    InitMd5(&md5);
+    InitSha(&sha);
+
+    XMEMCPY(md5Input, ssl->arrays.preMasterSecret, pmsSz);
+
+    for (i = 0; i < MASTER_ROUNDS; ++i) {
+        byte prefix[PREFIX];
+        if (!SetPrefix(prefix, i)) {
+            return PREFIX_ERROR;
+        }
+
+        idx = 0;
+        XMEMCPY(shaInput, prefix, i + 1);
+        idx += i + 1;
+
+        XMEMCPY(shaInput + idx, ssl->arrays.preMasterSecret, pmsSz);
+        idx += pmsSz;
+        XMEMCPY(shaInput + idx, ssl->arrays.clientRandom, RAN_LEN);
+        idx += RAN_LEN;
+        XMEMCPY(shaInput + idx, ssl->arrays.serverRandom, RAN_LEN);
+        idx += RAN_LEN;
+        ShaUpdate(&sha, shaInput, idx);
+        ShaFinal(&sha, shaOutput);
+
+        idx = pmsSz;  /* preSz */
+        XMEMCPY(md5Input + idx, shaOutput, SHA_DIGEST_SIZE);
+        idx += SHA_DIGEST_SIZE;
+        Md5Update(&md5, md5Input, idx);
+        Md5Final(&md5, &ssl->arrays.masterSecret[i * MD5_DIGEST_SIZE]);
+    }
+
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("master secret: ");
+        for (i = 0; i < SECRET_LEN; i++)
+            printf("%02x", ssl->arrays.masterSecret[i]);
+        printf("\n");
+    }
+#endif
+
+    DeriveKeys(ssl);
+    CleanPreMaster(ssl);
+
+    return 0;
+}
+
+
+
+
diff -r 000000000000 -r 5045d2638c29 md4.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/md4.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,215 @@
+/* md4.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_MD4
+
+#include "ctc_md4.h"
+#ifdef NO_INLINE
+    #include "misc.h"
+#else
+    #include "misc.c"
+#endif
+
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void InitMd4(Md4* md4)
+{
+    md4->digest[0] = 0x67452301L;
+    md4->digest[1] = 0xefcdab89L;
+    md4->digest[2] = 0x98badcfeL;
+    md4->digest[3] = 0x10325476L;
+
+    md4->buffLen = 0;
+    md4->loLen   = 0;
+    md4->hiLen   = 0;
+}
+
+
+static void Transform(Md4* md4)
+{
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+    /* Copy context->state[] to working vars  */
+    word32 A = md4->digest[0];
+    word32 B = md4->digest[1];
+    word32 C = md4->digest[2];
+    word32 D = md4->digest[3];
+
+#define function(a,b,c,d,k,s) a=rotlFixed(a+F(b,c,d)+md4->buffer[k],s);
+    function(A,B,C,D, 0, 3);
+    function(D,A,B,C, 1, 7);
+    function(C,D,A,B, 2,11);
+    function(B,C,D,A, 3,19);
+    function(A,B,C,D, 4, 3);
+    function(D,A,B,C, 5, 7);
+    function(C,D,A,B, 6,11);
+    function(B,C,D,A, 7,19);
+    function(A,B,C,D, 8, 3);
+    function(D,A,B,C, 9, 7);
+    function(C,D,A,B,10,11);
+    function(B,C,D,A,11,19);
+    function(A,B,C,D,12, 3);
+    function(D,A,B,C,13, 7);
+    function(C,D,A,B,14,11);
+    function(B,C,D,A,15,19);
+
+#undef function	  
+#define function(a,b,c,d,k,s) \
+    a=rotlFixed(a+G(b,c,d)+md4->buffer[k]+0x5a827999,s);
+
+    function(A,B,C,D, 0, 3);
+    function(D,A,B,C, 4, 5);
+    function(C,D,A,B, 8, 9);
+    function(B,C,D,A,12,13);
+    function(A,B,C,D, 1, 3);
+    function(D,A,B,C, 5, 5);
+    function(C,D,A,B, 9, 9);
+    function(B,C,D,A,13,13);
+    function(A,B,C,D, 2, 3);
+    function(D,A,B,C, 6, 5);
+    function(C,D,A,B,10, 9);
+    function(B,C,D,A,14,13);
+    function(A,B,C,D, 3, 3);
+    function(D,A,B,C, 7, 5);
+    function(C,D,A,B,11, 9);
+    function(B,C,D,A,15,13);
+
+#undef function	 
+#define function(a,b,c,d,k,s) \
+    a=rotlFixed(a+H(b,c,d)+md4->buffer[k]+0x6ed9eba1,s);
+
+    function(A,B,C,D, 0, 3);
+    function(D,A,B,C, 8, 9);
+    function(C,D,A,B, 4,11);
+    function(B,C,D,A,12,15);
+    function(A,B,C,D, 2, 3);
+    function(D,A,B,C,10, 9);
+    function(C,D,A,B, 6,11);
+    function(B,C,D,A,14,15);
+    function(A,B,C,D, 1, 3);
+    function(D,A,B,C, 9, 9);
+    function(C,D,A,B, 5,11);
+    function(B,C,D,A,13,15);
+    function(A,B,C,D, 3, 3);
+    function(D,A,B,C,11, 9);
+    function(C,D,A,B, 7,11);
+    function(B,C,D,A,15,15);
+    
+    /* Add the working vars back into digest state[]  */
+    md4->digest[0] += A;
+    md4->digest[1] += B;
+    md4->digest[2] += C;
+    md4->digest[3] += D;
+}
+
+
+static INLINE void AddLength(Md4* md4, word32 len)
+{
+    word32 tmp = md4->loLen;
+    if ( (md4->loLen += len) < tmp)
+        md4->hiLen++;                       /* carry low to high */
+}
+
+
+void Md4Update(Md4* md4, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)md4->buffer;
+
+    while (len) {
+        word32 add = min(len, MD4_BLOCK_SIZE - md4->buffLen);
+        XMEMCPY(&local[md4->buffLen], data, add);
+
+        md4->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (md4->buffLen == MD4_BLOCK_SIZE) {
+            #ifdef BIG_ENDIAN_ORDER
+                ByteReverseBytes(local, local, MD4_BLOCK_SIZE);
+            #endif
+            Transform(md4);
+            AddLength(md4, MD4_BLOCK_SIZE);
+            md4->buffLen = 0;
+        }
+    }
+}
+
+
+void Md4Final(Md4* md4, byte* hash)
+{
+    byte* local = (byte*)md4->buffer;
+
+    AddLength(md4, md4->buffLen);               /* before adding pads */
+
+    local[md4->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (md4->buffLen > MD4_PAD_SIZE) {
+        XMEMSET(&local[md4->buffLen], 0, MD4_BLOCK_SIZE - md4->buffLen);
+        md4->buffLen += MD4_BLOCK_SIZE - md4->buffLen;
+
+        #ifdef BIG_ENDIAN_ORDER
+            ByteReverseBytes(local, local, MD4_BLOCK_SIZE);
+        #endif
+        Transform(md4);
+        md4->buffLen = 0;
+    }
+    XMEMSET(&local[md4->buffLen], 0, MD4_PAD_SIZE - md4->buffLen);
+   
+    /* put lengths in bits */
+    md4->loLen = md4->loLen << 3;
+    md4->hiLen = (md4->loLen >> (8*sizeof(md4->loLen) - 3)) + 
+                 (md4->hiLen << 3);
+
+    /* store lengths */
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseBytes(local, local, MD4_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[MD4_PAD_SIZE], &md4->loLen, sizeof(word32));
+    XMEMCPY(&local[MD4_PAD_SIZE + sizeof(word32)], &md4->hiLen, sizeof(word32));
+
+    Transform(md4);
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(md4->digest, md4->digest, MD4_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, md4->digest, MD4_DIGEST_SIZE);
+
+    InitMd4(md4);  /* reset state */
+}
+
+
+#endif /* NO_MD4 */
+
diff -r 000000000000 -r 5045d2638c29 md5.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/md5.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,222 @@
+/* md5.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include "ctc_md5.h"
+#ifdef NO_INLINE
+    #include "misc.h"
+#else
+    #include "misc.c"
+#endif
+
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void InitMd5(Md5* md5)
+{
+    md5->digest[0] = 0x67452301L;
+    md5->digest[1] = 0xefcdab89L;
+    md5->digest[2] = 0x98badcfeL;
+    md5->digest[3] = 0x10325476L;
+
+    md5->buffLen = 0;
+    md5->loLen   = 0;
+    md5->hiLen   = 0;
+}
+
+
+static void Transform(Md5* md5)
+{
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, data, s) \
+    w = rotlFixed(w + f(x, y, z) + data, s) + x
+
+    /* Copy context->state[] to working vars  */
+    word32 a = md5->digest[0];
+    word32 b = md5->digest[1];
+    word32 c = md5->digest[2];
+    word32 d = md5->digest[3];
+
+    MD5STEP(F1, a, b, c, d, md5->buffer[0]  + 0xd76aa478,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[1]  + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[2]  + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[3]  + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, md5->buffer[4]  + 0xf57c0faf,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[5]  + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[6]  + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[7]  + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, md5->buffer[8]  + 0x698098d8,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[9]  + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, md5->buffer[12] + 0x6b901122,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, md5->buffer[1]  + 0xf61e2562,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[6]  + 0xc040b340,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[0]  + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, md5->buffer[5]  + 0xd62f105d,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[10] + 0x02441453,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[4]  + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, md5->buffer[9]  + 0x21e1cde6,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[14] + 0xc33707d6,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[3]  + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[8]  + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, md5->buffer[13] + 0xa9e3e905,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[2]  + 0xfcefa3f8,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[7]  + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, md5->buffer[5]  + 0xfffa3942,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[8]  + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, md5->buffer[1]  + 0xa4beea44,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[4]  + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[7]  + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, md5->buffer[13] + 0x289b7ec6,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[0]  + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[3]  + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[6]  + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, md5->buffer[9]  + 0xd9d4d039,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[2]  + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, md5->buffer[0]  + 0xf4292244,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[7]  + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[5]  + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, md5->buffer[12] + 0x655b59c3,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[3]  + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[1]  + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, md5->buffer[8]  + 0x6fa87e4f,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[6]  + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, md5->buffer[4]  + 0xf7537e82,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[2]  + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[9]  + 0xeb86d391, 21);
+    
+    /* Add the working vars back into digest state[]  */
+    md5->digest[0] += a;
+    md5->digest[1] += b;
+    md5->digest[2] += c;
+    md5->digest[3] += d;
+}
+
+
+static INLINE void AddLength(Md5* md5, word32 len)
+{
+    word32 tmp = md5->loLen;
+    if ( (md5->loLen += len) < tmp)
+        md5->hiLen++;                       /* carry low to high */
+}
+
+
+void Md5Update(Md5* md5, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)md5->buffer;
+
+    while (len) {
+        word32 add = min(len, MD5_BLOCK_SIZE - md5->buffLen);
+        XMEMCPY(&local[md5->buffLen], data, add);
+
+        md5->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (md5->buffLen == MD5_BLOCK_SIZE) {
+            #ifdef BIG_ENDIAN_ORDER
+                ByteReverseBytes(local, local, MD5_BLOCK_SIZE);
+            #endif
+            Transform(md5);
+            AddLength(md5, MD5_BLOCK_SIZE);
+            md5->buffLen = 0;
+        }
+    }
+}
+
+
+void Md5Final(Md5* md5, byte* hash)
+{
+    byte* local = (byte*)md5->buffer;
+
+    AddLength(md5, md5->buffLen);               /* before adding pads */
+
+    local[md5->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (md5->buffLen > MD5_PAD_SIZE) {
+        XMEMSET(&local[md5->buffLen], 0, MD5_BLOCK_SIZE - md5->buffLen);
+        md5->buffLen += MD5_BLOCK_SIZE - md5->buffLen;
+
+        #ifdef BIG_ENDIAN_ORDER
+            ByteReverseBytes(local, local, MD5_BLOCK_SIZE);
+        #endif
+        Transform(md5);
+        md5->buffLen = 0;
+    }
+    XMEMSET(&local[md5->buffLen], 0, MD5_PAD_SIZE - md5->buffLen);
+   
+    /* put lengths in bits */
+    md5->loLen = md5->loLen << 3;
+    md5->hiLen = (md5->loLen >> (8*sizeof(md5->loLen) - 3)) + 
+                 (md5->hiLen << 3);
+
+    /* store lengths */
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseBytes(local, local, MD5_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[MD5_PAD_SIZE], &md5->loLen, sizeof(word32));
+    XMEMCPY(&local[MD5_PAD_SIZE + sizeof(word32)], &md5->hiLen, sizeof(word32));
+
+    Transform(md5);
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(md5->digest, md5->digest, MD5_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, md5->digest, MD5_DIGEST_SIZE);
+
+    InitMd5(md5);  /* reset state */
+}
+
diff -r 000000000000 -r 5045d2638c29 misc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,171 @@
+/* misc.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include "misc.h"
+
+/* inlining these functions is a huge speed increase and a small size decrease, 
+   because the functions are smaller than function call setup/cleanup, e.g.,
+   md5 benchmark is twice as fast with inline.  If you don't want it, then
+   define NO_INLINE and compile this file into cyassl, otherwise it's used as
+   a source header
+ */
+
+#ifdef NO_INLINE
+    #define STATIC
+#else
+    #define STATIC static
+#endif
+
+
+#ifdef INTEL_INTRINSICS
+
+    #include <stdlib.h>      /* get intrinsic definitions */
+
+    #pragma intrinsic(_lrotl, _lrotr)
+
+    STATIC INLINE word32 rotlFixed(word32 x, word32 y)
+    {
+        return y ? _lrotl(x, y) : x;
+    }
+
+    STATIC INLINE word32 rotrFixed(word32 x, word32 y)
+    {
+        return y ? _lrotr(x, y) : x;
+    }
+
+#else /* generic */
+
+    STATIC INLINE word32 rotlFixed(word32 x, word32 y)
+    {
+        return (x << y) | (x >> (sizeof(y) * 8 - y));
+    }   
+
+
+    STATIC INLINE word32 rotrFixed(word32 x, word32 y)
+    {
+        return (x >> y) | (x << (sizeof(y) * 8 - y));
+    }
+
+#endif
+
+
+STATIC INLINE word32 ByteReverseWord32(word32 value)
+{
+#ifdef PPC_INTRINSICS
+    /* PPC: load reverse indexed instruction */
+    return (word32)__lwbrx(&value,0);
+#elif defined(FAST_ROTATE)
+    /* 5 instructions with rotate instruction, 9 without */
+    return (rotrFixed(value, 8U) & 0xff00ff00) |
+           (rotlFixed(value, 8U) & 0x00ff00ff);
+#else
+    /* 6 instructions with rotate instruction, 8 without */
+    value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
+    return rotlFixed(value, 16U);
+#endif
+}
+
+
+STATIC INLINE void ByteReverseWords(word32* out, const word32* in,
+                                    word32 byteCount)
+{
+    word32 count = byteCount/sizeof(word32), i;
+
+    for (i = 0; i < count; i++)
+        out[i] = ByteReverseWord32(in[i]);
+
+}
+
+
+#ifdef WORD64_AVAILABLE
+
+
+STATIC INLINE word64 rotlFixed64(word64 x, word64 y)
+{
+    return (x << y) | (x >> (sizeof(y) * 8 - y));
+}  
+
+
+STATIC INLINE word64 rotrFixed64(word64 x, word64 y)
+{
+    return (x >> y) | (x << (sizeof(y) * 8 - y));
+}
+
+
+STATIC INLINE word64 ByteReverseWord64(word64 value)
+{
+#ifdef CTAOCRYPT_SLOW_WORD64
+	return (word64)(ByteReverseWord32((word32)value)) << 32 | 
+                    ByteReverseWord32((word32)(value>>32));
+#else
+	value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) |
+            ((value & W64LIT(0x00FF00FF00FF00FF)) << 8);
+	value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) |
+            ((value & W64LIT(0x0000FFFF0000FFFF)) << 16);
+	return rotlFixed64(value, 32U);
+#endif
+}
+
+
+STATIC INLINE void ByteReverseWords64(word64* out, const word64* in,
+                                      word32 byteCount)
+{
+    word32 count = byteCount/sizeof(word64), i;
+
+    for (i = 0; i < count; i++)
+        out[i] = ByteReverseWord64(in[i]);
+
+}
+
+#endif /* WORD64_AVAILABLE */
+
+
+STATIC INLINE void ByteReverseBytes(byte* out, const byte* in, word32 byteCount)
+{
+    word32* op       = (word32*)out;
+    const word32* ip = (const word32*)in;
+
+    ByteReverseWords(op, ip, byteCount);
+}
+
+
+STATIC INLINE void XorWords(word* r, const word* a, word32 n)
+{
+    word32 i;
+
+    for (i = 0; i < n; i++) r[i] ^= a[i];
+}
+
+
+STATIC INLINE void xorbuf(byte* buf, const byte* mask, word32 count)
+{
+    if (((size_t)buf | (size_t)mask | count) % WORD_SIZE == 0)
+        XorWords( (word*)buf, (const word*)mask, count / WORD_SIZE);
+    else {
+        word32 i;
+        for (i = 0; i < count; i++) buf[i] ^= mask[i];
+    }
+}
+
+
+#undef STATIC
+
diff -r 000000000000 -r 5045d2638c29 misc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,55 @@
+/* misc.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_MISC_H
+#define CTAO_CRYPT_MISC_H
+
+
+#include "types.h"
+
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#ifdef NO_INLINE
+word32 rotlFixed(word32, word32);
+word32 rotrFixed(word32, word32);
+
+word32 ByteReverseWord32(word32);
+void   ByteReverseWords(word32*, const word32*, word32);
+void   ByteReverseBytes(byte*, const byte*, word32);
+
+void XorWords(word*, const word*, word32);
+void xorbuf(byte*, const byte*, word32);
+#endif /* NO_INLINE */
+
+
+#ifdef __cplusplus
+    }   /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_MISC_H */
+
diff -r 000000000000 -r 5045d2638c29 mpi_class.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mpi_class.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,996 @@
+#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))
+#if defined(LTM2)
+#define LTM3
+#endif
+#if defined(LTM1)
+#define LTM2
+#endif
+#define LTM1
+
+#if defined(LTM_ALL)
+#define BN_ERROR_C
+#define BN_FAST_MP_INVMOD_C
+#define BN_FAST_MP_MONTGOMERY_REDUCE_C
+#define BN_FAST_S_MP_MUL_DIGS_C
+#define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+#define BN_FAST_S_MP_SQR_C
+#define BN_MP_2EXPT_C
+#define BN_MP_ABS_C
+#define BN_MP_ADD_C
+#define BN_MP_ADD_D_C
+#define BN_MP_ADDMOD_C
+#define BN_MP_AND_C
+#define BN_MP_CLAMP_C
+#define BN_MP_CLEAR_C
+#define BN_MP_CLEAR_MULTI_C
+#define BN_MP_CMP_C
+#define BN_MP_CMP_D_C
+#define BN_MP_CMP_MAG_C
+#define BN_MP_CNT_LSB_C
+#define BN_MP_COPY_C
+#define BN_MP_COUNT_BITS_C
+#define BN_MP_DIV_C
+#define BN_MP_DIV_2_C
+#define BN_MP_DIV_2D_C
+#define BN_MP_DIV_3_C
+#define BN_MP_DIV_D_C
+#define BN_MP_DR_IS_MODULUS_C
+#define BN_MP_DR_REDUCE_C
+#define BN_MP_DR_SETUP_C
+#define BN_MP_EXCH_C
+#define BN_MP_EXPT_D_C
+#define BN_MP_EXPTMOD_C
+#define BN_MP_EXPTMOD_FAST_C
+#define BN_MP_EXTEUCLID_C
+#define BN_MP_FREAD_C
+#define BN_MP_FWRITE_C
+#define BN_MP_GCD_C
+#define BN_MP_GET_INT_C
+#define BN_MP_GROW_C
+#define BN_MP_INIT_C
+#define BN_MP_INIT_COPY_C
+#define BN_MP_INIT_MULTI_C
+#define BN_MP_INIT_SET_C
+#define BN_MP_INIT_SET_INT_C
+#define BN_MP_INIT_SIZE_C
+#define BN_MP_INVMOD_C
+#define BN_MP_INVMOD_SLOW_C
+#define BN_MP_IS_SQUARE_C
+#define BN_MP_JACOBI_C
+#define BN_MP_KARATSUBA_MUL_C
+#define BN_MP_KARATSUBA_SQR_C
+#define BN_MP_LCM_C
+#define BN_MP_LSHD_C
+#define BN_MP_MOD_C
+#define BN_MP_MOD_2D_C
+#define BN_MP_MOD_D_C
+#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+#define BN_MP_MONTGOMERY_REDUCE_C
+#define BN_MP_MONTGOMERY_SETUP_C
+#define BN_MP_MUL_C
+#define BN_MP_MUL_2_C
+#define BN_MP_MUL_2D_C
+#define BN_MP_MUL_D_C
+#define BN_MP_MULMOD_C
+#define BN_MP_N_ROOT_C
+#define BN_MP_NEG_C
+#define BN_MP_OR_C
+#define BN_MP_PRIME_FERMAT_C
+#define BN_MP_PRIME_IS_DIVISIBLE_C
+#define BN_MP_PRIME_IS_PRIME_C
+#define BN_MP_PRIME_MILLER_RABIN_C
+#define BN_MP_PRIME_NEXT_PRIME_C
+#define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+#define BN_MP_PRIME_RANDOM_EX_C
+#define BN_MP_RADIX_SIZE_C
+#define BN_MP_RADIX_SMAP_C
+#define BN_MP_RAND_C
+#define BN_MP_READ_RADIX_C
+#define BN_MP_READ_SIGNED_BIN_C
+#define BN_MP_READ_UNSIGNED_BIN_C
+#define BN_MP_REDUCE_C
+#define BN_MP_REDUCE_2K_C
+#define BN_MP_REDUCE_2K_L_C
+#define BN_MP_REDUCE_2K_SETUP_C
+#define BN_MP_REDUCE_2K_SETUP_L_C
+#define BN_MP_REDUCE_IS_2K_C
+#define BN_MP_REDUCE_IS_2K_L_C
+#define BN_MP_REDUCE_SETUP_C
+#define BN_MP_RSHD_C
+#define BN_MP_SET_C
+#define BN_MP_SET_INT_C
+#define BN_MP_SHRINK_C
+#define BN_MP_SIGNED_BIN_SIZE_C
+#define BN_MP_SQR_C
+#define BN_MP_SQRMOD_C
+#define BN_MP_SQRT_C
+#define BN_MP_SUB_C
+#define BN_MP_SUB_D_C
+#define BN_MP_SUBMOD_C
+#define BN_MP_TO_SIGNED_BIN_C
+#define BN_MP_TO_SIGNED_BIN_N_C
+#define BN_MP_TO_UNSIGNED_BIN_C
+#define BN_MP_TO_UNSIGNED_BIN_N_C
+#define BN_MP_TOOM_MUL_C
+#define BN_MP_TOOM_SQR_C
+#define BN_MP_TORADIX_C
+#define BN_MP_TORADIX_N_C
+#define BN_MP_UNSIGNED_BIN_SIZE_C
+#define BN_MP_XOR_C
+#define BN_MP_ZERO_C
+#define BN_PRIME_TAB_C
+#define BN_REVERSE_C
+#define BN_S_MP_ADD_C
+#define BN_S_MP_EXPTMOD_C
+#define BN_S_MP_MUL_DIGS_C
+#define BN_S_MP_MUL_HIGH_DIGS_C
+#define BN_S_MP_SQR_C
+#define BN_S_MP_SUB_C
+#define BNCORE_C
+#endif
+
+#if defined(BN_ERROR_C)
+   #define BN_MP_ERROR_TO_STRING_C
+#endif
+
+#if defined(BN_FAST_MP_INVMOD_C)
+   #define BN_MP_ISEVEN_C
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_COPY_C
+   #define BN_MP_MOD_C
+   #define BN_MP_SET_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_ISODD_C
+   #define BN_MP_SUB_C
+   #define BN_MP_CMP_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_CMP_D_C
+   #define BN_MP_ADD_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_FAST_MP_MONTGOMERY_REDUCE_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_DIGS_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_SQR_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_2EXPT_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_ABS_C)
+   #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_ADD_C)
+   #define BN_S_MP_ADD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_ADD_D_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_ADDMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_ADD_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_AND_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CLAMP_C)
+#endif
+
+#if defined(BN_MP_CLEAR_C)
+#endif
+
+#if defined(BN_MP_CLEAR_MULTI_C)
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CMP_C)
+   #define BN_MP_CMP_MAG_C
+#endif
+
+#if defined(BN_MP_CMP_D_C)
+#endif
+
+#if defined(BN_MP_CMP_MAG_C)
+#endif
+
+#if defined(BN_MP_CNT_LSB_C)
+   #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_COPY_C)
+   #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_COUNT_BITS_C)
+#endif
+
+#if defined(BN_MP_DIV_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_COPY_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_SET_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_ABS_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_CMP_C
+   #define BN_MP_SUB_C
+   #define BN_MP_ADD_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_MULTI_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_INIT_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_2_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_DIV_2D_C)
+   #define BN_MP_COPY_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_INIT_C
+   #define BN_MP_MOD_2D_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_DIV_3_C)
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_D_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_COPY_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_DIV_3_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DR_IS_MODULUS_C)
+#endif
+
+#if defined(BN_MP_DR_REDUCE_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_DR_SETUP_C)
+#endif
+
+#if defined(BN_MP_EXCH_C)
+#endif
+
+#if defined(BN_MP_EXPT_D_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_SET_C
+   #define BN_MP_SQR_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MUL_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_INVMOD_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_ABS_C
+   #define BN_MP_CLEAR_MULTI_C
+   #define BN_MP_REDUCE_IS_2K_L_C
+   #define BN_S_MP_EXPTMOD_C
+   #define BN_MP_DR_IS_MODULUS_C
+   #define BN_MP_REDUCE_IS_2K_C
+   #define BN_MP_ISODD_C
+   #define BN_MP_EXPTMOD_FAST_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_FAST_C)
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_INIT_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MONTGOMERY_SETUP_C
+   #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+   #define BN_MP_MONTGOMERY_REDUCE_C
+   #define BN_MP_DR_SETUP_C
+   #define BN_MP_DR_REDUCE_C
+   #define BN_MP_REDUCE_2K_SETUP_C
+   #define BN_MP_REDUCE_2K_C
+   #define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+   #define BN_MP_MULMOD_C
+   #define BN_MP_SET_C
+   #define BN_MP_MOD_C
+   #define BN_MP_COPY_C
+   #define BN_MP_SQR_C
+   #define BN_MP_MUL_C
+   #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_EXTEUCLID_C)
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_SET_C
+   #define BN_MP_COPY_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_DIV_C
+   #define BN_MP_MUL_C
+   #define BN_MP_SUB_C
+   #define BN_MP_NEG_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_FREAD_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_S_RMAP_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_CMP_D_C
+#endif
+
+#if defined(BN_MP_FWRITE_C)
+   #define BN_MP_RADIX_SIZE_C
+   #define BN_MP_TORADIX_C
+#endif
+
+#if defined(BN_MP_GCD_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_ABS_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CNT_LSB_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_EXCH_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_GET_INT_C)
+#endif
+
+#if defined(BN_MP_GROW_C)
+#endif
+
+#if defined(BN_MP_INIT_C)
+#endif
+
+#if defined(BN_MP_INIT_COPY_C)
+   #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_INIT_MULTI_C)
+   #define BN_MP_ERR_C
+   #define BN_MP_INIT_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_INIT_SET_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SET_C
+#endif
+
+#if defined(BN_MP_INIT_SET_INT_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SET_INT_C
+#endif
+
+#if defined(BN_MP_INIT_SIZE_C)
+   #define BN_MP_INIT_C
+#endif
+
+#if defined(BN_MP_INVMOD_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_ISODD_C
+   #define BN_FAST_MP_INVMOD_C
+   #define BN_MP_INVMOD_SLOW_C
+#endif
+
+#if defined(BN_MP_INVMOD_SLOW_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_MOD_C
+   #define BN_MP_COPY_C
+   #define BN_MP_ISEVEN_C
+   #define BN_MP_SET_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_ISODD_C
+   #define BN_MP_ADD_C
+   #define BN_MP_SUB_C
+   #define BN_MP_CMP_C
+   #define BN_MP_CMP_D_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_IS_SQUARE_C)
+   #define BN_MP_MOD_D_C
+   #define BN_MP_INIT_SET_INT_C
+   #define BN_MP_MOD_C
+   #define BN_MP_GET_INT_C
+   #define BN_MP_SQRT_C
+   #define BN_MP_SQR_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_JACOBI_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CNT_LSB_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_MOD_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_MUL_C)
+   #define BN_MP_MUL_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_SUB_C
+   #define BN_MP_ADD_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_SQR_C)
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_SQR_C
+   #define BN_MP_SUB_C
+   #define BN_S_MP_ADD_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_ADD_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_LCM_C)
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_GCD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_DIV_C
+   #define BN_MP_MUL_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_LSHD_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_RSHD_C
+#endif
+
+#if defined(BN_MP_MOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_DIV_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_ADD_C
+   #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_MOD_2D_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_COPY_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MOD_D_C)
+   #define BN_MP_DIV_D_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_CALC_NORMALIZATION_C)
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_2EXPT_C
+   #define BN_MP_SET_C
+   #define BN_MP_MUL_2_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_REDUCE_C)
+   #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_SETUP_C)
+#endif
+
+#if defined(BN_MP_MUL_C)
+   #define BN_MP_TOOM_MUL_C
+   #define BN_MP_KARATSUBA_MUL_C
+   #define BN_FAST_S_MP_MUL_DIGS_C
+   #define BN_S_MP_MUL_C
+   #define BN_S_MP_MUL_DIGS_C
+#endif
+
+#if defined(BN_MP_MUL_2_C)
+   #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_MUL_2D_C)
+   #define BN_MP_COPY_C
+   #define BN_MP_GROW_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MUL_D_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MULMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_MUL_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_N_ROOT_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SET_C
+   #define BN_MP_COPY_C
+   #define BN_MP_EXPT_D_C
+   #define BN_MP_MUL_C
+   #define BN_MP_SUB_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_DIV_C
+   #define BN_MP_CMP_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_NEG_C)
+   #define BN_MP_COPY_C
+   #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_OR_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_FERMAT_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_INIT_C
+   #define BN_MP_EXPTMOD_C
+   #define BN_MP_CMP_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_DIVISIBLE_C)
+   #define BN_MP_MOD_D_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_PRIME_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_PRIME_IS_DIVISIBLE_C
+   #define BN_MP_INIT_C
+   #define BN_MP_SET_C
+   #define BN_MP_PRIME_MILLER_RABIN_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_MILLER_RABIN_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_CNT_LSB_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_EXPTMOD_C
+   #define BN_MP_CMP_C
+   #define BN_MP_SQRMOD_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_NEXT_PRIME_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_SET_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_ISEVEN_C
+   #define BN_MP_MOD_D_C
+   #define BN_MP_INIT_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_PRIME_MILLER_RABIN_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_RABIN_MILLER_TRIALS_C)
+#endif
+
+#if defined(BN_MP_PRIME_RANDOM_EX_C)
+   #define BN_MP_READ_UNSIGNED_BIN_C
+   #define BN_MP_PRIME_IS_PRIME_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_MUL_2_C
+   #define BN_MP_ADD_D_C
+#endif
+
+#if defined(BN_MP_RADIX_SIZE_C)
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_DIV_D_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_RADIX_SMAP_C)
+   #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_RAND_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_LSHD_C
+#endif
+
+#if defined(BN_MP_READ_RADIX_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_S_RMAP_C
+   #define BN_MP_RADIX_SMAP_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_READ_SIGNED_BIN_C)
+   #define BN_MP_READ_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_READ_UNSIGNED_BIN_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_REDUCE_C)
+   #define BN_MP_REDUCE_SETUP_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_MUL_C
+   #define BN_S_MP_MUL_HIGH_DIGS_C
+   #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+   #define BN_MP_MOD_2D_C
+   #define BN_S_MP_MUL_DIGS_C
+   #define BN_MP_SUB_C
+   #define BN_MP_CMP_D_C
+   #define BN_MP_SET_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_ADD_C
+   #define BN_MP_CMP_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_MUL_D_C
+   #define BN_S_MP_ADD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_L_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_MUL_C
+   #define BN_S_MP_ADD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_2EXPT_C
+   #define BN_MP_CLEAR_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_L_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_2EXPT_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_C)
+   #define BN_MP_REDUCE_2K_C
+   #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_L_C)
+#endif
+
+#if defined(BN_MP_REDUCE_SETUP_C)
+   #define BN_MP_2EXPT_C
+   #define BN_MP_DIV_C
+#endif
+
+#if defined(BN_MP_RSHD_C)
+   #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_C)
+   #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_INT_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SHRINK_C)
+#endif
+
+#if defined(BN_MP_SIGNED_BIN_SIZE_C)
+   #define BN_MP_UNSIGNED_BIN_SIZE_C
+#endif
+
+#if defined(BN_MP_SQR_C)
+   #define BN_MP_TOOM_SQR_C
+   #define BN_MP_KARATSUBA_SQR_C
+   #define BN_FAST_S_MP_SQR_C
+   #define BN_S_MP_SQR_C
+#endif
+
+#if defined(BN_MP_SQRMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SQR_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_SQRT_C)
+   #define BN_MP_N_ROOT_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_DIV_C
+   #define BN_MP_ADD_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_SUB_C)
+   #define BN_S_MP_ADD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_SUB_D_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SUBMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SUB_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_C)
+   #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_N_C)
+   #define BN_MP_SIGNED_BIN_SIZE_C
+   #define BN_MP_TO_SIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_N_C)
+   #define BN_MP_UNSIGNED_BIN_SIZE_C
+   #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TOOM_MUL_C)
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_MOD_2D_C
+   #define BN_MP_COPY_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_MUL_C
+   #define BN_MP_MUL_2_C
+   #define BN_MP_ADD_C
+   #define BN_MP_SUB_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_DIV_3_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TOOM_SQR_C)
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_MOD_2D_C
+   #define BN_MP_COPY_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_SQR_C
+   #define BN_MP_MUL_2_C
+   #define BN_MP_ADD_C
+   #define BN_MP_SUB_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_DIV_3_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TORADIX_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_DIV_D_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_TORADIX_N_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_DIV_D_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_UNSIGNED_BIN_SIZE_C)
+   #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_XOR_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_ZERO_C)
+#endif
+
+#if defined(BN_PRIME_TAB_C)
+#endif
+
+#if defined(BN_REVERSE_C)
+#endif
+
+#if defined(BN_S_MP_ADD_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_S_MP_EXPTMOD_C)
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_INIT_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_REDUCE_SETUP_C
+   #define BN_MP_REDUCE_C
+   #define BN_MP_REDUCE_2K_SETUP_L_C
+   #define BN_MP_REDUCE_2K_L_C
+   #define BN_MP_MOD_C
+   #define BN_MP_COPY_C
+   #define BN_MP_SQR_C
+   #define BN_MP_MUL_C
+   #define BN_MP_SET_C
+   #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_S_MP_MUL_DIGS_C)
+   #define BN_FAST_S_MP_MUL_DIGS_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_MUL_HIGH_DIGS_C)
+   #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SQR_C)
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SUB_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BNCORE_C)
+#endif
+
+#ifdef LTM3
+#define LTM_LAST
+#endif
+#include "mpi_superclass.h"
+#include "mpi_class.h"
+#else
+#define LTM_LAST
+#endif
+
diff -r 000000000000 -r 5045d2638c29 mpi_superclass.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mpi_superclass.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,73 @@
+/* super class file for PK algos */
+
+/* default ... include all MPI */
+#define LTM_ALL
+
+/* RSA only (does not support DH/DSA/ECC) */
+/* #define SC_RSA_1 */
+
+/* For reference.... On an Athlon64 optimizing for speed...
+
+   LTM's mpi.o with all functions [striped] is 142KiB in size.
+
+*/
+
+/* Works for RSA only, mpi.o is 68KiB */
+#ifdef SC_RSA_1
+   #define BN_MP_SHRINK_C
+   #define BN_MP_LCM_C
+   #define BN_MP_PRIME_RANDOM_EX_C
+   #define BN_MP_INVMOD_C
+   #define BN_MP_GCD_C
+   #define BN_MP_MOD_C
+   #define BN_MP_MULMOD_C
+   #define BN_MP_ADDMOD_C
+   #define BN_MP_EXPTMOD_C
+   #define BN_MP_SET_INT_C
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_CLEAR_MULTI_C
+   #define BN_MP_UNSIGNED_BIN_SIZE_C
+   #define BN_MP_TO_UNSIGNED_BIN_C
+   #define BN_MP_MOD_D_C
+   #define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+   #define BN_REVERSE_C
+   #define BN_PRIME_TAB_C
+
+   /* other modifiers */
+   #define BN_MP_DIV_SMALL                    /* Slower division, not critical */
+
+   /* here we are on the last pass so we turn things off.  The functions classes are still there
+    * but we remove them specifically from the build.  This also invokes tweaks in functions
+    * like removing support for even moduli, etc...
+    */
+#ifdef LTM_LAST
+   #undef  BN_MP_TOOM_MUL_C
+   #undef  BN_MP_TOOM_SQR_C
+   #undef  BN_MP_KARATSUBA_MUL_C
+   #undef  BN_MP_KARATSUBA_SQR_C
+   #undef  BN_MP_REDUCE_C
+   #undef  BN_MP_REDUCE_SETUP_C
+   #undef  BN_MP_DR_IS_MODULUS_C
+   #undef  BN_MP_DR_SETUP_C
+   #undef  BN_MP_DR_REDUCE_C
+   #undef  BN_MP_REDUCE_IS_2K_C
+   #undef  BN_MP_REDUCE_2K_SETUP_C
+   #undef  BN_MP_REDUCE_2K_C
+   #undef  BN_S_MP_EXPTMOD_C
+   #undef  BN_MP_DIV_3_C
+   #undef  BN_S_MP_MUL_HIGH_DIGS_C
+   #undef  BN_FAST_S_MP_MUL_HIGH_DIGS_C
+   #undef  BN_FAST_MP_INVMOD_C
+
+   /* To safely undefine these you have to make sure your RSA key won't exceed the Comba threshold
+    * which is roughly 255 digits [7140 bits for 32-bit machines, 15300 bits for 64-bit machines] 
+    * which means roughly speaking you can handle upto 2536-bit RSA keys with these defined without
+    * trouble.  
+    */
+   #undef  BN_S_MP_MUL_DIGS_C
+   #undef  BN_S_MP_SQR_C
+   #undef  BN_MP_MONTGOMERY_REDUCE_C
+#endif
+
+#endif
+
diff -r 000000000000 -r 5045d2638c29 os_settings.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/os_settings.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,216 @@
+/* os_settings.h
+ *
+ * Copyright (C) 2006-2010 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* Place OS specific preprocessor flags, defines, includes here, will be
+   included into every file because types.h includes it */
+
+#ifndef CTAO_CRYPT_OS_SETTINGS_H
+#define CTAO_CRYPT_OS_SETTINGS_H
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* Uncomment next line if using IPHONE */
+/* #define IPHONE */
+
+/* Uncomment next line if using ThreadX */
+/* #define THREADX */
+
+/* Uncomment next line if using Micrium ucOS */
+/* #define MICRIUM */
+
+
+#ifdef IPHONE
+    #define SIZEOF_LONG_LONG 8
+#endif
+
+#ifdef THREADX 
+    #define SIZEOF_LONG_LONG 8
+#endif
+
+#define MBED
+
+#ifdef MBED
+
+    #define SINGLE_THREADED
+    #define CYASSL_USER_IO
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM
+    #define NO_SHA512
+    #define NO_DH
+    #define NO_DSA
+    #define NO_HC128
+
+#endif /* MBED */
+
+
+#ifdef MICRIUM
+
+    #include "net_cfg.h"
+    #include "cyassl_cfg.h"
+    #include "net_secure_os.h"
+
+    #define CYASSL_TYPES
+
+    typedef CPU_INT08U byte;
+    typedef CPU_INT16U word16;
+    typedef CPU_INT32U word32;
+
+    #if (NET_SECURE_MGR_CFG_WORD_SIZE == CPU_WORD_SIZE_32)
+        #define SIZEOF_LONG        8
+        #undef  SIZEOF_LONG_LONG
+    #else
+        #undef  SIZEOF_LONG
+        #define SIZEOF_LONG_LONG   8
+    #endif
+
+    #define STRING_USER
+
+    #define XSTRLEN(pstr) ((CPU_SIZE_T)Str_Len((CPU_CHAR *)(pstr)))
+    #define XSTRNCPY(pstr_dest, pstr_src, len_max) \
+                    ((CPU_CHAR *)Str_Copy_N((CPU_CHAR *)(pstr_dest), \
+                     (CPU_CHAR *)(pstr_src), (CPU_SIZE_T)(len_max)))
+    #define XSTRNCMP(pstr_1, pstr_2, len_max) \
+                    ((CPU_INT16S)Str_Cmp_N((CPU_CHAR *)(pstr_1), \
+                     (CPU_CHAR *)(pstr_2), (CPU_SIZE_T)(len_max)))  
+    #define XSTRSTR(pstr, pstr_srch) \
+                    ((CPU_CHAR *)Str_Str((CPU_CHAR *)(pstr), \
+                     (CPU_CHAR *)(pstr_srch)))
+    #define XMEMSET(pmem, data_val, size) \
+                    ((void)Mem_Set((void *)(pmem), (CPU_INT08U) (data_val), \
+                    (CPU_SIZE_T)(size)))
+    #define XMEMCPY(pdest, psrc, size) ((void)Mem_Copy((void *)(pdest), \
+                     (void *)(psrc), (CPU_SIZE_T)(size)))
+    #define XMEMCMP(pmem_1, pmem_2, size) \
+                   (((CPU_BOOLEAN)Mem_Cmp((void *)(pmem_1), (void *)(pmem_2), \
+                     (CPU_SIZE_T)(size))) ? DEF_NO : DEF_YES)
+
+    #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+        #define MICRIUM_MALLOC
+        #define XMALLOC(s, h, type) (((type) <= DYNAMIC_TYPE_SIGNER) ? \
+                                 ((void *)NetSecure_Malloc((CPU_INT08U)(type), \
+                                 (CPU_SIZE_T)(s))) : malloc(s))
+        #define XFREE(p, h, type)   (((type) <= DYNAMIC_TYPE_SIGNER) ? \
+                          (NetSecure_Free((CPU_INT08U)(type), (p))) : free((p)))
+        #define XREALLOC(p, n, h, t) realloc((p), (n))
+    #endif
+
+    #if (NET_SECURE_MGR_CFG_FS_EN == DEF_ENABLED)
+        #undef  NO_FILESYSTEM
+    #else
+        #define NO_FILESYSTEM
+    #endif
+
+    #if (CYASSL_CFG_TRACE_LEVEL == CYASSL_TRACE_LEVEL_DBG)
+        #define DEBUG_CYASSL
+    #else
+        #undef  DEBUG_CYASSL
+    #endif
+
+    #if (CYASSL_CFG_OPENSSL_EN == DEF_ENABLED)
+        #define OPENSSL_EXTRA
+    #else
+        #undef  OPENSSL_EXTRA
+    #endif
+
+    #if (CYASSL_CFG_MULTI_THREAD_EN == DEF_ENABLED)
+        #undef  SINGLE_THREADED
+    #else
+        #define SINGLE_THREADED
+    #endif
+
+    #if (CYASSL_CFG_DH_EN == DEF_ENABLED)
+        #undef  NO_DH
+    #else
+        #define NO_DH
+    #endif
+
+    #if (CYASSL_CFG_DSA_EN == DEF_ENABLED)
+        #undef  NO_DSA
+    #else
+        #define NO_DSA
+    #endif
+
+    #if (CYASSL_CFG_PSK_EN == DEF_ENABLED)
+        #undef  NO_PSK
+    #else
+        #define NO_PSK
+    #endif
+
+    #if (CYASSL_CFG_3DES_EN == DEF_ENABLED)
+        #undef  NO_DES
+    #else
+        #define NO_DES
+    #endif
+
+    #if (CYASSL_CFG_AES_EN == DEF_ENABLED)
+        #undef  NO_AES
+    #else
+        #define NO_AES
+    #endif
+
+    #if (CYASSL_CFG_RC4_EN == DEF_ENABLED)
+        #undef  NO_RC4
+    #else
+        #define NO_RC4
+    #endif
+
+    #if (CYASSL_CFG_RABBIT_EN == DEF_ENABLED)
+        #undef  NO_RABBIT
+    #else
+        #define NO_RABBIT
+    #endif
+
+    #if (CYASSL_CFG_HC128_EN == DEF_ENABLED)
+        #undef  NO_HC128
+    #else
+        #define NO_HC128
+    #endif
+
+    #if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG)
+        #define BIG_ENDIAN_ORDER
+    #else
+        #undef  BIG_ENDIAN_ORDER
+        #define LITTLE_ENDIAN_ORDER
+    #endif
+
+
+    #define  NO_MD4
+    #define  NO_WRITEV
+    #define  NO_DEV_RANDOM
+    #define  CYASSL_USER_IO
+    #define  LARGE_STATIC_BUFFERS
+    #define  CYASSL_DER_LOAD
+    #undef   CYASSL_DTLS
+
+#endif /* MICRIUM */
+
+/* Place any other flags or defines here */
+
+
+#ifdef __cplusplus
+    }   /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_OS_SETTINGS_H */
+
diff -r 000000000000 -r 5045d2638c29 pwdbased.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pwdbased.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,76 @@
+/* pwdbased.c
+ *
+ * Copyright (C) 2006-2010 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_PWDBASED
+
+#include "pwdbased.h"
+
+
+int PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt,
+           int sLen, int iterations, int kLen, int hashType)
+{
+    Md5  md5;
+    Sha  sha;
+    int  hLen = (hashType == MD5) ? MD5_DIGEST_SIZE : SHA_DIGEST_SIZE;
+    int  i;
+    byte buffer[SHA_DIGEST_SIZE];  /* max size */
+
+    if (hashType != MD5 && hashType != SHA)
+        return -1;
+
+    if (kLen > hLen)
+        return -1;
+
+    if (iterations < 1)
+        return -1;
+
+    if (hashType == MD5) {
+        InitMd5(&md5);
+        Md5Update(&md5, passwd, pLen);
+        Md5Update(&md5, salt,   sLen);
+        Md5Final(&md5,  buffer);
+    }
+    else {
+        InitSha(&sha);
+        ShaUpdate(&sha, passwd, pLen);
+        ShaUpdate(&sha, salt,   sLen);
+        ShaFinal(&sha,  buffer);
+    }
+
+    for (i = 1; i < iterations; i++) {
+        if (hashType == MD5) {
+            Md5Update(&md5, buffer, hLen);
+            Md5Final(&md5,  buffer);
+        }
+        else {
+            ShaUpdate(&sha, buffer, hLen);
+            ShaFinal(&sha,  buffer);
+        }
+    }
+    XMEMCPY(output, buffer, kLen);
+
+    return 0;
+}
+
+
+#endif /* NO_PWDBASED */
+
diff -r 000000000000 -r 5045d2638c29 pwdbased.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pwdbased.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,47 @@
+/* pwdbased.h
+ *
+ * Copyright (C) 2006-2010 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_PWDBASED
+
+#ifndef CTAO_CRYPT_PWDBASED_H
+#define CTAO_CRYPT_PWDBASED_H
+
+#include "types.h"
+#include "ctc_md5.h"       /* for hash type */
+#include "ctc_sha.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+int PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt,
+           int sLen, int iterations, int kLen, int hashType);
+
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_PWDBASED_H */
+#endif /* NO_PWDBASED */
diff -r 000000000000 -r 5045d2638c29 rabbit.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rabbit.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,239 @@
+/* rabbit.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_RABBIT
+
+#include "rabbit.h"
+#include "misc.c"
+
+
+#ifdef BIG_ENDIAN_ORDER
+    #define LITTLE32(x) ByteReverseWord32(x)
+#else
+    #define LITTLE32(x) (x)
+#endif
+
+#define U32V(x) (word32)(x)
+
+
+/* Square a 32-bit unsigned integer to obtain the 64-bit result and return */
+/* the upper 32 bits XOR the lower 32 bits */
+static word32 RABBIT_g_func(word32 x)
+{
+    /* Temporary variables */
+    word32 a, b, h, l;
+
+    /* Construct high and low argument for squaring */
+    a = x&0xFFFF;
+    b = x>>16;
+
+    /* Calculate high and low result of squaring */
+    h = (((U32V(a*a)>>17) + U32V(a*b))>>15) + b*b;
+    l = x*x;
+
+    /* Return high XOR low */
+    return U32V(h^l);
+}
+
+
+/* Calculate the next internal state */
+static void RABBIT_next_state(RabbitCtx* ctx)
+{
+    /* Temporary variables */
+    word32 g[8], c_old[8], i;
+
+    /* Save old counter values */
+    for (i=0; i<8; i++)
+        c_old[i] = ctx->c[i];
+
+    /* Calculate new counter values */
+    ctx->c[0] = U32V(ctx->c[0] + 0x4D34D34D + ctx->carry);
+    ctx->c[1] = U32V(ctx->c[1] + 0xD34D34D3 + (ctx->c[0] < c_old[0]));
+    ctx->c[2] = U32V(ctx->c[2] + 0x34D34D34 + (ctx->c[1] < c_old[1]));
+    ctx->c[3] = U32V(ctx->c[3] + 0x4D34D34D + (ctx->c[2] < c_old[2]));
+    ctx->c[4] = U32V(ctx->c[4] + 0xD34D34D3 + (ctx->c[3] < c_old[3]));
+    ctx->c[5] = U32V(ctx->c[5] + 0x34D34D34 + (ctx->c[4] < c_old[4]));
+    ctx->c[6] = U32V(ctx->c[6] + 0x4D34D34D + (ctx->c[5] < c_old[5]));
+    ctx->c[7] = U32V(ctx->c[7] + 0xD34D34D3 + (ctx->c[6] < c_old[6]));
+    ctx->carry = (ctx->c[7] < c_old[7]);
+   
+    /* Calculate the g-values */
+    for (i=0;i<8;i++)
+        g[i] = RABBIT_g_func(U32V(ctx->x[i] + ctx->c[i]));
+
+    /* Calculate new state values */
+    ctx->x[0] = U32V(g[0] + rotlFixed(g[7],16) + rotlFixed(g[6], 16));
+    ctx->x[1] = U32V(g[1] + rotlFixed(g[0], 8) + g[7]);
+    ctx->x[2] = U32V(g[2] + rotlFixed(g[1],16) + rotlFixed(g[0], 16));
+    ctx->x[3] = U32V(g[3] + rotlFixed(g[2], 8) + g[1]);
+    ctx->x[4] = U32V(g[4] + rotlFixed(g[3],16) + rotlFixed(g[2], 16));
+    ctx->x[5] = U32V(g[5] + rotlFixed(g[4], 8) + g[3]);
+    ctx->x[6] = U32V(g[6] + rotlFixed(g[5],16) + rotlFixed(g[4], 16));
+    ctx->x[7] = U32V(g[7] + rotlFixed(g[6], 8) + g[5]);
+}
+
+
+/* IV setup */
+static void RabbitSetIV(Rabbit* ctx, const byte* iv)
+{
+    /* Temporary variables */
+    word32 i0, i1, i2, i3, i;
+      
+    /* Generate four subvectors */
+    i0 = LITTLE32(*(word32*)(iv+0));
+    i2 = LITTLE32(*(word32*)(iv+4));
+    i1 = (i0>>16) | (i2&0xFFFF0000);
+    i3 = (i2<<16) | (i0&0x0000FFFF);
+
+    /* Modify counter values */
+    ctx->workCtx.c[0] = ctx->masterCtx.c[0] ^ i0;
+    ctx->workCtx.c[1] = ctx->masterCtx.c[1] ^ i1;
+    ctx->workCtx.c[2] = ctx->masterCtx.c[2] ^ i2;
+    ctx->workCtx.c[3] = ctx->masterCtx.c[3] ^ i3;
+    ctx->workCtx.c[4] = ctx->masterCtx.c[4] ^ i0;
+    ctx->workCtx.c[5] = ctx->masterCtx.c[5] ^ i1;
+    ctx->workCtx.c[6] = ctx->masterCtx.c[6] ^ i2;
+    ctx->workCtx.c[7] = ctx->masterCtx.c[7] ^ i3;
+
+    /* Copy state variables */
+    for (i=0; i<8; i++)
+        ctx->workCtx.x[i] = ctx->masterCtx.x[i];
+    ctx->workCtx.carry = ctx->masterCtx.carry;
+
+    /* Iterate the system four times */
+    for (i=0; i<4; i++)
+        RABBIT_next_state(&(ctx->workCtx));
+}
+
+
+/* Key setup */
+void RabbitSetKey(Rabbit* ctx, const byte* key, const byte* iv)
+{
+    /* Temporary variables */
+    word32 k0, k1, k2, k3, i;
+
+    /* Generate four subkeys */
+    k0 = LITTLE32(*(word32*)(key+ 0));
+    k1 = LITTLE32(*(word32*)(key+ 4));
+    k2 = LITTLE32(*(word32*)(key+ 8));
+    k3 = LITTLE32(*(word32*)(key+12));
+
+    /* Generate initial state variables */
+    ctx->masterCtx.x[0] = k0;
+    ctx->masterCtx.x[2] = k1;
+    ctx->masterCtx.x[4] = k2;
+    ctx->masterCtx.x[6] = k3;
+    ctx->masterCtx.x[1] = U32V(k3<<16) | (k2>>16);
+    ctx->masterCtx.x[3] = U32V(k0<<16) | (k3>>16);
+    ctx->masterCtx.x[5] = U32V(k1<<16) | (k0>>16);
+    ctx->masterCtx.x[7] = U32V(k2<<16) | (k1>>16);
+
+    /* Generate initial counter values */
+    ctx->masterCtx.c[0] = rotlFixed(k2, 16);
+    ctx->masterCtx.c[2] = rotlFixed(k3, 16);
+    ctx->masterCtx.c[4] = rotlFixed(k0, 16);
+    ctx->masterCtx.c[6] = rotlFixed(k1, 16);
+    ctx->masterCtx.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF);
+    ctx->masterCtx.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF);
+    ctx->masterCtx.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF);
+    ctx->masterCtx.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF);
+
+    /* Clear carry bit */
+    ctx->masterCtx.carry = 0;
+
+    /* Iterate the system four times */
+    for (i=0; i<4; i++)
+        RABBIT_next_state(&(ctx->masterCtx));
+
+    /* Modify the counters */
+    for (i=0; i<8; i++)
+        ctx->masterCtx.c[i] ^= ctx->masterCtx.x[(i+4)&0x7];
+
+    /* Copy master instance to work instance */
+    for (i=0; i<8; i++) {
+        ctx->workCtx.x[i] = ctx->masterCtx.x[i];
+        ctx->workCtx.c[i] = ctx->masterCtx.c[i];
+    }
+    ctx->workCtx.carry = ctx->masterCtx.carry;
+
+    if (iv) RabbitSetIV(ctx, iv);    
+}
+
+
+/* Encrypt/decrypt a message of any size */
+void RabbitProcess(Rabbit* ctx, byte* output, const byte* input, word32 msglen)
+{
+
+    /* Encrypt/decrypt all full blocks */
+    while (msglen >= 16) {
+        /* Iterate the system */
+        RABBIT_next_state(&(ctx->workCtx));
+
+        /* Encrypt/decrypt 16 bytes of data */
+        *(word32*)(output+ 0) = *(word32*)(input+ 0) ^
+                   LITTLE32(ctx->workCtx.x[0] ^ (ctx->workCtx.x[5]>>16) ^
+                   U32V(ctx->workCtx.x[3]<<16));
+        *(word32*)(output+ 4) = *(word32*)(input+ 4) ^
+                   LITTLE32(ctx->workCtx.x[2] ^ (ctx->workCtx.x[7]>>16) ^
+                   U32V(ctx->workCtx.x[5]<<16));
+        *(word32*)(output+ 8) = *(word32*)(input+ 8) ^
+                   LITTLE32(ctx->workCtx.x[4] ^ (ctx->workCtx.x[1]>>16) ^
+                   U32V(ctx->workCtx.x[7]<<16));
+        *(word32*)(output+12) = *(word32*)(input+12) ^
+                   LITTLE32(ctx->workCtx.x[6] ^ (ctx->workCtx.x[3]>>16) ^
+                   U32V(ctx->workCtx.x[1]<<16));
+
+        /* Increment pointers and decrement length */
+        input += 16;
+        output += 16;
+        msglen -= 16;
+    }
+
+    /* Encrypt/decrypt remaining data */
+    if (msglen) {
+
+        word32 i;
+        word32 tmp[4];
+        byte*  buffer = (byte*)tmp;
+
+        /* Iterate the system */
+        RABBIT_next_state(&(ctx->workCtx));
+
+        /* Generate 16 bytes of pseudo-random data */
+        tmp[0] = LITTLE32(ctx->workCtx.x[0] ^
+                  (ctx->workCtx.x[5]>>16) ^ U32V(ctx->workCtx.x[3]<<16));
+        tmp[1] = LITTLE32(ctx->workCtx.x[2] ^ 
+                  (ctx->workCtx.x[7]>>16) ^ U32V(ctx->workCtx.x[5]<<16));
+        tmp[2] = LITTLE32(ctx->workCtx.x[4] ^ 
+                  (ctx->workCtx.x[1]>>16) ^ U32V(ctx->workCtx.x[7]<<16));
+        tmp[3] = LITTLE32(ctx->workCtx.x[6] ^ 
+                  (ctx->workCtx.x[3]>>16) ^ U32V(ctx->workCtx.x[1]<<16));
+
+        /* Encrypt/decrypt the data */
+        for (i=0; i<msglen; i++)
+            output[i] = input[i] ^ buffer[i];
+    }
+}
+
+
+
+#endif /* NO_RABBIT */
diff -r 000000000000 -r 5045d2638c29 rabbit.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rabbit.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,60 @@
+/* rabbit.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_RABBIT
+
+#ifndef CTAO_CRYPT_RABBIT_H
+#define CTAO_CRYPT_RABBIT_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* Rabbit Context */
+typedef struct RabbitCtx {
+    word32 x[8];
+    word32 c[8];
+    word32 carry;
+} RabbitCtx;
+    
+
+/* Rabbit stream cipher */
+typedef struct Rabbit {
+    RabbitCtx masterCtx;
+    RabbitCtx workCtx;
+} Rabbit;
+
+
+void RabbitProcess(Rabbit*, byte*, const byte*, word32);
+void RabbitSetKey(Rabbit*, const byte* key, const byte* iv);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_RABBIT_H */
+
+#endif /* NO_RABBIT */
diff -r 000000000000 -r 5045d2638c29 random.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/random.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,184 @@
+/* random.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/* on HPUX 11 you may need to install /dev/random see
+   http://h20293.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber=KRNG11I
+
+*/
+
+#include "random.h"
+#include "error.h"
+
+
+#if defined(USE_WINDOWS_API)
+    #define _WIN32_WINNT 0x0400
+    #include <windows.h>
+    #include <wincrypt.h>
+#else
+    #ifndef NO_DEV_RANDOM
+        #include <fcntl.h>
+        #include <unistd.h>
+    #else
+        /* include headers that may be needed to get good seed */
+    #endif
+#endif /* USE_WINDOWS_API */
+
+
+
+/* Get seed and key cipher */
+int InitRng(RNG* rng)
+{
+    byte key[32];
+    byte junk[256];
+
+    int  ret = GenerateSeed(&rng->seed, key, sizeof(key));
+
+    if (ret == 0) {
+        Arc4SetKey(&rng->cipher, key, sizeof(key));
+        RNG_GenerateBlock(rng, junk, sizeof(junk));  /* rid initial state */
+    }
+
+    return ret;
+}
+
+
+/* place a generated block in output */
+void RNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
+{
+    XMEMSET(output, 0, sz);
+    Arc4Process(&rng->cipher, output, output, sz);
+}
+
+
+byte RNG_GenerateByte(RNG* rng)
+{
+    byte b;
+    RNG_GenerateBlock(rng, &b, 1);
+
+    return b;
+}
+
+
+#if defined(USE_WINDOWS_API)
+
+
+int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    if(!CryptAcquireContext(&os->handle, 0, 0, PROV_RSA_FULL,
+                            CRYPT_VERIFYCONTEXT))
+        return WINCRYPT_E;
+
+    if (!CryptGenRandom(os->handle, sz, output))
+        return CRYPTGEN_E;
+
+    CryptReleaseContext(os->handle, 0);
+
+    return 0;
+}
+
+
+#elif defined(THREADX)
+
+#include "rtprand.h"   /* rtp_rand () */
+#include "rtptime.h"   /* rtp_get_system_msec() */
+
+
+int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    int i;
+    rtp_srand(rtp_get_system_msec());
+
+    for (i = 0; i < sz; i++ ) {
+        output[i] = rtp_rand() % 256;
+        if ( (i % 8) == 7)
+            rtp_srand(rtp_get_system_msec());
+    }
+
+    return 0;
+}
+
+
+#elif defined(MICRIUM)
+
+int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+        NetSecure_InitSeed(output, sz);
+    #endif
+    return 0;
+}
+
+
+#elif defined(MBED)
+
+int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    int i;
+    
+    for (i = 0; i < sz; i++)
+        output[i] = i;
+
+    return 0;
+}
+
+
+#elif defined(NO_DEV_RANDOM)
+
+#error "you need to write an os specific GenerateSeed() here"
+
+
+#else /* !USE_WINDOWS_API && !THREADX && !MICRIUM && !NO_DEV_RANDOM */
+
+
+/* may block */
+int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    os->fd = open("/dev/urandom",O_RDONLY);
+    if (os->fd == -1) {
+        /* may still have /dev/random */
+        os->fd = open("/dev/random",O_RDONLY);
+        if (os->fd == -1)
+            return OPEN_RAN_E;
+    }
+
+    while (sz) {
+        int len = read(os->fd, output, sz);
+        if (len == -1) 
+            return READ_RAN_E;
+
+        sz     -= len;
+        output += len;
+
+        if (sz)
+#ifdef BLOCKING
+            sleep(0);             /* context switch */
+#else
+            return RAN_BLOCK_E;
+#endif
+    }
+    close(os->fd);
+
+    return 0;
+}
+
+#endif /* USE_WINDOWS_API */
+
diff -r 000000000000 -r 5045d2638c29 random.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/random.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,72 @@
+/* random.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_RANDOM_H
+#define CTAO_CRYPT_RANDOM_H
+
+#include "arc4.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#if defined(USE_WINDOWS_API)
+    #if defined(_WIN64)
+        typedef unsigned __int64 ProviderHandle;
+        /* type HCRYPTPROV, avoid #include <windows.h> */
+    #else
+        typedef unsigned long ProviderHandle;
+    #endif
+#endif
+
+
+/* OS specific seeder */
+typedef struct OS_Seed {
+    #if defined(USE_WINDOWS_API)
+        ProviderHandle handle;
+    #else
+        int fd;
+    #endif
+} OS_Seed;
+
+int GenerateSeed(OS_Seed* os, byte* seed, word32 sz);
+
+
+/* secure Random Nnumber Generator */
+typedef struct RNG {
+    OS_Seed seed;
+    Arc4    cipher;
+} RNG;
+
+
+int  InitRng(RNG*);
+void RNG_GenerateBlock(RNG*, byte*, word32 sz);
+byte RNG_GenerateByte(RNG*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_RANDOM_H */
+
diff -r 000000000000 -r 5045d2638c29 rsa.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rsa.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,535 @@
+/* rsa.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#include "ctc_rsa.h"
+#include "random.h"
+#include "error.h"
+
+#ifdef SHOW_GEN
+    #include <stdio.h>
+#endif
+
+
+enum {
+    RSA_PUBLIC_ENCRYPT  = 0,
+    RSA_PUBLIC_DECRYPT  = 1,
+    RSA_PRIVATE_ENCRYPT = 2,
+    RSA_PRIVATE_DECRYPT = 3,
+
+    RSA_BLOCK_TYPE_1 = 1,
+    RSA_BLOCK_TYPE_2 = 2,
+
+    RSA_MIN_SIZE = 512,
+    RSA_MAX_SIZE = 4096,
+
+    RSA_MIN_PAD_SZ   = 11      /* seperator + 0 + pad value + 8 pads */
+};
+
+
+void InitRsaKey(RsaKey* key, void* heap)
+{
+    key->type = -1;  /* haven't decdied yet */
+    key->heap = heap;
+
+/* TomsFastMath doesn't use memory allocation */
+#ifndef USE_FAST_MATH
+    key->n.dp = key->e.dp = 0;  /* public  alloc parts */
+
+    key->d.dp = key->p.dp  = 0;  /* private alloc parts */
+    key->q.dp = key->dP.dp = 0;  
+    key->u.dp = key->dQ.dp = 0;
+#endif
+}
+
+
+void FreeRsaKey(RsaKey* key)
+{
+/* TomsFastMath doesn't use memory allocation */
+#ifndef USE_FAST_MATH
+    if (key->type == RSA_PRIVATE) {
+        mp_clear(&key->u);
+        mp_clear(&key->dQ);
+        mp_clear(&key->dP);
+        mp_clear(&key->q);
+        mp_clear(&key->p);
+        mp_clear(&key->d);
+    }
+    mp_clear(&key->e);
+    mp_clear(&key->n);
+#endif
+}
+
+static void RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock,
+                   word32 pkcsBlockLen, byte padValue, RNG* rng)
+{
+    if (inputLen == 0) return;
+
+    pkcsBlock[0] = 0x0;       /* set first byte to zero and advance */
+    pkcsBlock++; pkcsBlockLen--;
+    pkcsBlock[0] = padValue;  /* insert padValue */
+
+    if (padValue == RSA_BLOCK_TYPE_1)
+        /* pad with 0xff bytes */
+        XMEMSET(&pkcsBlock[1], 0xFF, pkcsBlockLen - inputLen - 2);
+    else {
+        /* pad with non-zero random bytes */
+        word32 padLen = pkcsBlockLen - inputLen - 1, i;
+        RNG_GenerateBlock(rng, &pkcsBlock[1], padLen);
+
+        /* remove zeros */
+        for (i = 1; i < padLen; i++)
+            if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01;
+    }
+
+    pkcsBlock[pkcsBlockLen-inputLen-1] = 0;     /* separator */
+    XMEMCPY(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen);
+}
+
+
+static word32 RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen,
+                       byte **output, byte padValue)
+{
+    word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0,
+           invalid = 0,
+           i = 1,
+           outputLen;
+
+    if (pkcsBlock[0] != 0x0) /* skip past zero */
+        invalid = 1;
+    pkcsBlock++; pkcsBlockLen--;
+
+    /* Require block type padValue */
+    invalid = (pkcsBlock[0] != padValue) || invalid;
+
+    /* skip past the padding until we find the separator */
+    while (i<pkcsBlockLen && pkcsBlock[i++]) { /* null body */
+        }
+    if(!(i==pkcsBlockLen || pkcsBlock[i-1]==0))
+        return 0;
+
+    outputLen = pkcsBlockLen - i;
+    invalid = (outputLen > maxOutputLen) || invalid;
+
+    if (invalid)
+        return 0;
+
+    *output = (byte *)(pkcsBlock + i);
+    return outputLen;
+}
+
+
+static int RsaFunction(const byte* in, word32 inLen, byte* out, word32* outLen,
+                       int type, RsaKey* key)
+{
+    #define ERROR_OUT(x) { ret = x; goto done;}
+
+    mp_int tmp;
+    int    ret = 0;
+    word32 keyLen, len;
+
+    if (mp_init(&tmp) != MP_OKAY)
+        return MP_INIT_E;
+
+    if (mp_read_unsigned_bin(&tmp, (byte*)in, inLen) != MP_OKAY)
+        ERROR_OUT(MP_READ_E);
+
+    if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) {
+        #ifdef RSA_LOW_MEM      /* half as much memory but twice as slow */
+            if (mp_exptmod(&tmp, &key->d, &key->n, &tmp) != MP_OKAY)
+                ERROR_OUT(MP_EXPTMOD_E);
+        #else
+            #define INNER_ERROR_OUT(x) { ret = x; goto inner_done; }
+
+            mp_int tmpa, tmpb;
+
+            if (mp_init(&tmpa) != MP_OKAY)
+                ERROR_OUT(MP_INIT_E);
+
+            if (mp_init(&tmpb) != MP_OKAY) {
+                mp_clear(&tmpa);
+                ERROR_OUT(MP_INIT_E);
+            }
+
+            /* tmpa = tmp^dP mod p */
+            if (mp_exptmod(&tmp, &key->dP, &key->p, &tmpa) != MP_OKAY)
+                INNER_ERROR_OUT(MP_EXPTMOD_E);
+
+            /* tmpb = tmp^dQ mod q */
+            if (mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb) != MP_OKAY)
+                INNER_ERROR_OUT(MP_EXPTMOD_E);
+
+            /* tmp = (tmpa - tmpb) * qInv (mod p) */
+            if (mp_sub(&tmpa, &tmpb, &tmp) != MP_OKAY)
+                INNER_ERROR_OUT(MP_SUB_E);
+
+            if (mp_mulmod(&tmp, &key->u, &key->p, &tmp) != MP_OKAY)
+                INNER_ERROR_OUT(MP_MULMOD_E);
+
+            /* tmp = tmpb + q * tmp */
+            if (mp_mul(&tmp, &key->q, &tmp) != MP_OKAY)
+                INNER_ERROR_OUT(MP_MUL_E);
+
+            if (mp_add(&tmp, &tmpb, &tmp) != MP_OKAY)
+                INNER_ERROR_OUT(MP_ADD_E);
+
+        inner_done:
+            mp_clear(&tmpa);
+            mp_clear(&tmpb);
+
+            if (ret != 0) return ret;
+
+        #endif   /* RSA_LOW_MEM */
+    }
+    else if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) {
+        if (mp_exptmod(&tmp, &key->e, &key->n, &tmp) != MP_OKAY)
+            ERROR_OUT(MP_EXPTMOD_E);
+    }
+    else
+        ERROR_OUT(RSA_WRONG_TYPE_E);
+
+    keyLen = mp_unsigned_bin_size(&key->n);
+    if (keyLen > *outLen)
+        ERROR_OUT(RSA_BUFFER_E);
+
+    len = mp_unsigned_bin_size(&tmp);
+
+    /* pad front w/ zeros to match key length */
+    while (len < keyLen) {
+        *out++ = 0x00;
+        len++;
+    }
+
+    *outLen = keyLen;
+
+    /* convert */
+    if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY)
+        ERROR_OUT(MP_TO_E);
+   
+done: 
+    mp_clear(&tmp);
+    return ret;
+}
+
+
+
+int RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
+                     RsaKey* key, RNG* rng)
+{
+    int sz = mp_unsigned_bin_size(&key->n), ret;
+
+    if (sz > (int)outLen)
+        return RSA_BUFFER_E;
+
+    if (inLen > (word32)(sz - RSA_MIN_PAD_SZ))
+        return RSA_BUFFER_E;
+
+    RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_2, rng);
+
+    if ((ret = RsaFunction(out, sz, out, &outLen, RSA_PUBLIC_ENCRYPT, key)) < 0)
+        sz = ret;
+
+    return sz;
+}
+
+
+int RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key)
+{
+    int plainLen, ret;
+
+    if ((ret = RsaFunction(in, inLen, in, &inLen, RSA_PRIVATE_DECRYPT, key))
+            < 0) {
+        return ret;
+    }
+ 
+    plainLen = RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_2);
+
+    return plainLen;
+}
+
+int RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
+                     RsaKey* key)
+{
+    int plainLen, ret;
+    byte*  tmp;
+    byte*  pad = 0;
+
+    if ( !(tmp = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_RSA)) )
+        return MEMORY_E;
+
+    XMEMCPY(tmp, in, inLen);
+
+    if ((ret = plainLen = RsaPrivateDecryptInline(tmp, inLen, &pad, key))
+            < 0) {
+        XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+        return ret;
+    }
+    XMEMCPY(out, pad, plainLen);
+    XMEMSET(tmp, 0x00, inLen); 
+
+    XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+    return plainLen;
+}
+
+
+/* for Rsa Verify */
+int RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key)
+{
+    int plainLen, ret;
+
+    if ((ret = RsaFunction(in, inLen, in, &inLen, RSA_PUBLIC_DECRYPT, key))
+            < 0) {
+        return ret;
+    }
+  
+    plainLen = RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_1);
+
+    return plainLen;
+}
+
+int RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen,
+                     RsaKey* key)
+{
+    int plainLen, ret;
+    byte*  tmp;
+    byte*  pad = 0;
+
+    if ( !(tmp = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_RSA)) )
+        return MEMORY_E;
+
+    XMEMCPY(tmp, in, inLen);
+
+    if ((ret = plainLen = RsaSSL_VerifyInline(tmp, inLen, &pad, key))
+            < 0) {
+        XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+        return ret;
+    }
+  
+    XMEMCPY(out, pad, plainLen);
+    XMEMSET(tmp, 0x00, inLen); 
+
+    XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+    return plainLen;
+}
+
+
+/* for Rsa Sign */
+int RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
+                      RsaKey* key, RNG* rng)
+{
+    int sz = mp_unsigned_bin_size(&key->n), ret;
+
+    if (sz > (int)outLen)
+        return RSA_BUFFER_E;
+
+    if (inLen > (word32)(sz - RSA_MIN_PAD_SZ))
+        return RSA_BUFFER_E;
+
+    RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_1, rng);
+
+    if ((ret = RsaFunction(out, sz, out, &outLen, RSA_PRIVATE_ENCRYPT,key)) < 0)
+        sz = ret;
+    
+    return sz;
+}
+
+
+int RsaEncryptSize(RsaKey* key)
+{
+    return mp_unsigned_bin_size(&key->n);
+}
+
+
+#ifdef CYASSL_KEY_GEN
+
+static const int USE_BBS = 1;
+
+static int rand_prime(mp_int* N, int len, RNG* rng, void* heap)
+{
+    int   err, res, type;
+    byte* buf;
+
+    if (N == NULL || rng == NULL)
+       return -1; 
+
+    /* get type */
+    if (len < 0) {
+        type = USE_BBS;
+        len = -len;
+    } else {
+        type = 0;
+    }
+
+    /* allow sizes between 2 and 512 bytes for a prime size */
+    if (len < 2 || len > 512) { 
+        return -1;
+    }
+   
+    /* allocate buffer to work with */
+    buf = XCALLOC(1, len, heap);
+    if (buf == NULL) {
+        return -1;
+    }
+
+    do {
+#ifdef SHOW_GEN
+        printf(".");
+        fflush(stdout);
+#endif
+        /* generate value */
+        RNG_GenerateBlock(rng, buf, len);
+
+        /* munge bits */
+        buf[0]     |= 0x80 | 0x40;
+        buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00);
+ 
+        /* load value */
+        if ((err = mp_read_unsigned_bin(N, buf, len)) != MP_OKAY) {
+            XFREE(buf, heap, DYNAMIC_TYPE_RSA);
+            return err;
+        }
+
+        /* test */
+        if ((err = mp_prime_is_prime(N, 8, &res)) != MP_OKAY) {
+            XFREE(buf, heap, DYNAMIC_TYPE_RSA);
+            return err;
+        }
+    } while (res == MP_NO);
+
+#ifdef LTC_CLEAN_STACK
+    XMEMSET(buf, 0, len);
+#endif
+
+    XFREE(buf, heap, DYNAMIC_TYPE_RSA);
+    return 0;
+}
+
+
+/* Make an RSA key for size bits, with e specified, 65537 is a good e */
+int MakeRsaKey(RsaKey* key, int size, long e, RNG* rng)
+{
+    mp_int p, q, tmp1, tmp2, tmp3;
+    int    err;
+
+    if (key == NULL || rng == NULL)
+        return -1;
+
+    if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE)
+        return -1;
+
+    if (e < 3 || (e & 1) == 0)
+        return -1;
+
+    if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY)
+        return err;
+
+    err = mp_set_int(&tmp3, e);
+
+    /* make p */
+    if (err == MP_OKAY) {
+        do {
+            err = rand_prime(&p, size/16, rng, key->heap); /* size in bytes/2 */
+
+            if (err == MP_OKAY)
+                err = mp_sub_d(&p, 1, &tmp1);  /* tmp1 = p-1 */
+
+            if (err == MP_OKAY)
+                err = mp_gcd(&tmp1, &tmp3, &tmp2);  /* tmp2 = gcd(p-1, e) */
+        } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0);  /* e divdes p-1 */
+    }
+
+    /* make q */
+    if (err == MP_OKAY) {
+        do {
+            err = rand_prime(&q, size/16, rng, key->heap); /* size in bytes/2 */
+
+            if (err == MP_OKAY)
+                err = mp_sub_d(&q, 1, &tmp1);  /* tmp1 = q-1 */
+
+            if (err == MP_OKAY)
+                err = mp_gcd(&tmp1, &tmp3, &tmp2);  /* tmp2 = gcd(q-1, e) */
+        } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0);  /* e divdes q-1 */
+    }
+
+    if (err == MP_OKAY)
+        err = mp_init_multi(&key->n, &key->e, &key->d, &key->p, &key->q, NULL);
+
+    if (err == MP_OKAY)
+        err = mp_init_multi(&key->dP, &key->dP, &key->u, NULL, NULL, NULL);
+
+    if (err == MP_OKAY)
+        err = mp_sub_d(&p, 1, &tmp2);  /* tmp2 = p-1 */
+
+    if (err == MP_OKAY)
+        err = mp_lcm(&tmp1, &tmp2, &tmp1);  /* tmp1 = lcm(p-1, q-1),last loop */
+
+    /* make key */
+    if (err == MP_OKAY)
+        err = mp_set_int(&key->e, e);  /* key->e = e */
+
+    if (err == MP_OKAY)                /* key->d = 1/e mod lcm(p-1, q-1) */
+        err = mp_invmod(&key->e, &tmp1, &key->d);
+
+    if (err == MP_OKAY)
+        err = mp_mul(&p, &q, &key->n);  /* key->n = pq */
+
+    if (err == MP_OKAY)
+        err = mp_sub_d(&p, 1, &tmp1);
+
+    if (err == MP_OKAY)
+        err = mp_sub_d(&q, 1, &tmp2);
+
+    if (err == MP_OKAY)
+        err = mp_mod(&key->d, &tmp1, &key->dP);
+
+    if (err == MP_OKAY)
+        err = mp_mod(&key->d, &tmp2, &key->dQ);
+
+    if (err == MP_OKAY)
+        err = mp_invmod(&q, &p, &key->u);
+
+    if (err == MP_OKAY)
+        err = mp_copy(&p, &key->p);
+
+    if (err == MP_OKAY)
+        err = mp_copy(&q, &key->q);
+
+    if (err == MP_OKAY)
+        key->type = RSA_PRIVATE; 
+
+    mp_clear(&tmp3); 
+    mp_clear(&tmp2); 
+    mp_clear(&tmp1); 
+    mp_clear(&q); 
+    mp_clear(&p);
+
+    if (err != MP_OKAY) {
+        FreeRsaKey(key);        
+        return err;
+    }
+
+    return 0;
+}
+
+
+#endif /* CYASLS_KEY_GEN */
+
diff -r 000000000000 -r 5045d2638c29 sha.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sha.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,198 @@
+/* sha.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include "ctc_sha.h"
+#ifdef NO_INLINE
+    #include "misc.h"
+#else
+    #include "misc.c"
+#endif
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void InitSha(Sha* sha)
+{
+    sha->digest[0] = 0x67452301L;
+    sha->digest[1] = 0xEFCDAB89L;
+    sha->digest[2] = 0x98BADCFEL;
+    sha->digest[3] = 0x10325476L;
+    sha->digest[4] = 0xC3D2E1F0L;
+
+    sha->buffLen = 0;
+    sha->loLen   = 0;
+    sha->hiLen   = 0;
+}
+
+#define blk0(i) (W[i] = sha->buffer[i])
+#define blk1(i) (W[i&15] = \
+                   rotlFixed(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15],1))
+
+#define f1(x,y,z) (z^(x &(y^z)))
+#define f2(x,y,z) (x^y^z)
+#define f3(x,y,z) ((x&y)|(z&(x|y)))
+#define f4(x,y,z) (x^y^z)
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+= f1(w,x,y) + blk0(i) + 0x5A827999+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+#define R1(v,w,x,y,z,i) z+= f1(w,x,y) + blk1(i) + 0x5A827999+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+#define R2(v,w,x,y,z,i) z+= f2(w,x,y) + blk1(i) + 0x6ED9EBA1+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+#define R3(v,w,x,y,z,i) z+= f3(w,x,y) + blk1(i) + 0x8F1BBCDC+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+#define R4(v,w,x,y,z,i) z+= f4(w,x,y) + blk1(i) + 0xCA62C1D6+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+
+
+static void Transform(Sha* sha)
+{
+    word32 W[SHA_BLOCK_SIZE / sizeof(word32)];
+
+    /* Copy context->state[] to working vars */ 
+    word32 a = sha->digest[0];
+    word32 b = sha->digest[1];
+    word32 c = sha->digest[2];
+    word32 d = sha->digest[3];
+    word32 e = sha->digest[4];
+
+    /* nearly 1 K bigger in code size but 25% faster  */
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+    /* Add the working vars back into digest state[] */
+    sha->digest[0] += a;
+    sha->digest[1] += b;
+    sha->digest[2] += c;
+    sha->digest[3] += d;
+    sha->digest[4] += e;
+}
+
+
+static INLINE void AddLength(Sha* sha, word32 len)
+{
+    word32 tmp = sha->loLen;
+    if ( (sha->loLen += len) < tmp)
+        sha->hiLen++;                       /* carry low to high */
+}
+
+
+void ShaUpdate(Sha* sha, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)sha->buffer;
+
+    while (len) {
+        word32 add = min(len, SHA_BLOCK_SIZE - sha->buffLen);
+        XMEMCPY(&local[sha->buffLen], data, add);
+
+        sha->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (sha->buffLen == SHA_BLOCK_SIZE) {
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseBytes(local, local, SHA_BLOCK_SIZE);
+            #endif
+            Transform(sha);
+            AddLength(sha, SHA_BLOCK_SIZE);
+            sha->buffLen = 0;
+        }
+    }
+}
+
+
+void ShaFinal(Sha* sha, byte* hash)
+{
+    byte* local = (byte*)sha->buffer;
+
+    AddLength(sha, sha->buffLen);               /* before adding pads */
+
+    local[sha->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (sha->buffLen > SHA_PAD_SIZE) {
+        XMEMSET(&local[sha->buffLen], 0, SHA_BLOCK_SIZE - sha->buffLen);
+        sha->buffLen += SHA_BLOCK_SIZE - sha->buffLen;
+
+        #ifdef LITTLE_ENDIAN_ORDER
+            ByteReverseBytes(local, local, SHA_BLOCK_SIZE);
+        #endif
+        Transform(sha);
+        sha->buffLen = 0;
+    }
+    XMEMSET(&local[sha->buffLen], 0, SHA_PAD_SIZE - sha->buffLen);
+   
+    /* put lengths in bits */
+    sha->loLen = sha->loLen << 3;
+    sha->hiLen = (sha->loLen >> (8*sizeof(sha->loLen) - 3)) + 
+                 (sha->hiLen << 3);
+
+    /* store lengths */
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseBytes(local, local, SHA_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[SHA_PAD_SIZE], &sha->hiLen, sizeof(word32));
+    XMEMCPY(&local[SHA_PAD_SIZE + sizeof(word32)], &sha->loLen, sizeof(word32));
+
+    Transform(sha);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE);
+
+    InitSha(sha);  /* reset state */
+}
+
diff -r 000000000000 -r 5045d2638c29 sha256.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sha256.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,206 @@
+/* sha256.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* code submitted by raphael.huck@efixo.com */
+
+
+
+#ifndef NO_SHA256
+
+#include "sha256.h"
+#ifdef NO_INLINE
+    #include "misc.h"
+#else
+    #include "misc.c"
+#endif
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void InitSha256(Sha256* sha256)
+{
+    sha256->digest[0] = 0x6A09E667L;
+    sha256->digest[1] = 0xBB67AE85L;
+    sha256->digest[2] = 0x3C6EF372L;
+    sha256->digest[3] = 0xA54FF53AL;
+    sha256->digest[4] = 0x510E527FL;
+    sha256->digest[5] = 0x9B05688CL;
+    sha256->digest[6] = 0x1F83D9ABL;
+    sha256->digest[7] = 0x5BE0CD19L;
+
+    sha256->buffLen = 0;
+    sha256->loLen   = 0;
+    sha256->hiLen   = 0;
+}
+
+static const word32 K[64] = {
+    0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L, 0x3956C25BL,
+    0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L, 0xD807AA98L, 0x12835B01L,
+    0x243185BEL, 0x550C7DC3L, 0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L,
+    0xC19BF174L, 0xE49B69C1L, 0xEFBE4786L, 0x0FC19DC6L, 0x240CA1CCL,
+    0x2DE92C6FL, 0x4A7484AAL, 0x5CB0A9DCL, 0x76F988DAL, 0x983E5152L,
+    0xA831C66DL, 0xB00327C8L, 0xBF597FC7L, 0xC6E00BF3L, 0xD5A79147L,
+    0x06CA6351L, 0x14292967L, 0x27B70A85L, 0x2E1B2138L, 0x4D2C6DFCL,
+    0x53380D13L, 0x650A7354L, 0x766A0ABBL, 0x81C2C92EL, 0x92722C85L,
+    0xA2BFE8A1L, 0xA81A664BL, 0xC24B8B70L, 0xC76C51A3L, 0xD192E819L,
+    0xD6990624L, 0xF40E3585L, 0x106AA070L, 0x19A4C116L, 0x1E376C08L,
+    0x2748774CL, 0x34B0BCB5L, 0x391C0CB3L, 0x4ED8AA4AL, 0x5B9CCA4FL,
+    0x682E6FF3L, 0x748F82EEL, 0x78A5636FL, 0x84C87814L, 0x8CC70208L,
+    0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L
+};
+
+#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)      (((x | y) & z) | (x & y))
+#define S(x, n)         rotrFixed(x, n)
+#define R(x, n)         (((x)&0xFFFFFFFFL)>>(n))
+#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+
+#define RND(a,b,c,d,e,f,g,h,i) \
+     t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+     t1 = Sigma0(a) + Maj(a, b, c); \
+     d += t0; \
+     h  = t0 + t1;
+
+
+static void Transform(Sha256* sha256)
+{
+    word32 S[8], W[64], t0, t1;
+    int i;
+
+    /* Copy context->state[] to working vars */
+    for (i = 0; i < 8; i++)
+        S[i] = sha256->digest[i];
+
+    for (i = 0; i < 16; i++)
+        W[i] = sha256->buffer[i];
+
+    for (i = 16; i < 64; i++)
+        W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15]) + W[i-16];
+
+    for (i = 0; i < 64; i += 8) {
+        RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
+        RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
+        RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
+        RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
+        RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
+        RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
+        RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
+        RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
+    }
+
+    /* Add the working vars back into digest state[] */
+    for (i = 0; i < 8; i++) {
+        sha256->digest[i] += S[i];
+    }
+}
+
+
+static INLINE void AddLength(Sha256* sha256, word32 len)
+{
+    word32 tmp = sha256->loLen;
+    if ( (sha256->loLen += len) < tmp)
+        sha256->hiLen++;                       /* carry low to high */
+}
+
+
+void Sha256Update(Sha256* sha256, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)sha256->buffer;
+
+    while (len) {
+        word32 add = min(len, SHA256_BLOCK_SIZE - sha256->buffLen);
+        XMEMCPY(&local[sha256->buffLen], data, add);
+
+        sha256->buffLen += add;
+        data            += add;
+        len             -= add;
+
+        if (sha256->buffLen == SHA256_BLOCK_SIZE) {
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseBytes(local, local, SHA256_BLOCK_SIZE);
+            #endif
+            Transform(sha256);
+            AddLength(sha256, SHA256_BLOCK_SIZE);
+            sha256->buffLen = 0;
+        }
+    }
+}
+
+
+void Sha256Final(Sha256* sha256, byte* hash)
+{
+    byte* local = (byte*)sha256->buffer;
+
+    AddLength(sha256, sha256->buffLen);  /* before adding pads */
+
+    local[sha256->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (sha256->buffLen > SHA256_PAD_SIZE) {
+        XMEMSET(&local[sha256->buffLen], 0, SHA256_BLOCK_SIZE - sha256->buffLen);
+        sha256->buffLen += SHA256_BLOCK_SIZE - sha256->buffLen;
+
+        #ifdef LITTLE_ENDIAN_ORDER
+            ByteReverseBytes(local, local, SHA256_BLOCK_SIZE);
+        #endif
+        Transform(sha256);
+        sha256->buffLen = 0;
+    }
+    XMEMSET(&local[sha256->buffLen], 0, SHA256_PAD_SIZE - sha256->buffLen);
+
+    /* put lengths in bits */
+    sha256->loLen = sha256->loLen << 3;
+    sha256->hiLen = (sha256->loLen >> (8*sizeof(sha256->loLen) - 3)) +
+                 (sha256->hiLen << 3);
+
+    /* store lengths */
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseBytes(local, local, SHA256_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[SHA256_PAD_SIZE], &sha256->hiLen, sizeof(word32));
+    XMEMCPY(&local[SHA256_PAD_SIZE + sizeof(word32)], &sha256->loLen,
+            sizeof(word32));
+
+    Transform(sha256);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(sha256->digest, sha256->digest, SHA256_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha256->digest, SHA256_DIGEST_SIZE);
+
+    InitSha256(sha256);  /* reset state */
+}
+
+
+#endif /* NO_SHA256 */
+
diff -r 000000000000 -r 5045d2638c29 sha256.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sha256.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,69 @@
+/* sha256.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/* code submitted by raphael.huck@efixo.com */
+
+
+#ifndef NO_SHA256
+
+#ifndef CTAO_CRYPT_SHA256_H
+#define CTAO_CRYPT_SHA256_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+/* in bytes */
+enum {
+    SHA256              =  2,   /* hash type unique */
+    SHA256_BLOCK_SIZE   = 64,
+    SHA256_DIGEST_SIZE  = 32,
+    SHA256_PAD_SIZE     = 56
+};
+
+
+/* Sha256 digest */
+typedef struct Sha256 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[SHA256_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[SHA256_BLOCK_SIZE  / sizeof(word32)];
+} Sha256;
+
+
+void InitSha256(Sha256*);
+void Sha256Update(Sha256*, const byte*, word32);
+void Sha256Final(Sha256*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_SHA256_H */
+#endif /* NO_SHA256 */
+
diff -r 000000000000 -r 5045d2638c29 sha512.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sha512.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,65 @@
+/* sha512.h
+ *
+ * Copyright (C) 2006-2010 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef CYASSL_SHA512
+
+#ifndef CTAO_CRYPT_SHA512_H
+#define CTAO_CRYPT_SHA512_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+/* in bytes */
+enum {
+    SHA512              =   4,   /* hash type unique */
+    SHA512_BLOCK_SIZE   = 128,
+    SHA512_DIGEST_SIZE  =  64,
+    SHA512_PAD_SIZE     = 112 
+};
+
+
+/* Sha512 digest */
+typedef struct Sha512 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word64  digest[SHA512_DIGEST_SIZE / sizeof(word64)];
+    word64  buffer[SHA512_BLOCK_SIZE  / sizeof(word64)];
+} Sha512;
+
+
+void InitSha512(Sha512*);
+void Sha512Update(Sha512*, const byte*, word32);
+void Sha512Final(Sha512*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_SHA512_H */
+#endif /* CYASSL_SHA512 */
diff -r 000000000000 -r 5045d2638c29 ssl.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,3415 @@
+/* ssl.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include "ssl.h"
+#include "cyassl_int.h"
+#include "cyassl_error.h"
+#include "coding.h"
+
+#ifdef OPENSSL_EXTRA
+    /* openssl headers begin */
+    #include "evp.h"
+    #include "hmac.h"
+    #include "crypto.h"
+    #include "des.h"
+    /* openssl headers end, cyassl internal headers next */
+    #include "ctc_hmac.h"
+    #include "random.h"
+    #include "des3.h"
+    #include "ctc_md4.h"
+    #include "coding.h"
+#endif
+
+#ifdef HAVE_ERRNO_H 
+    #include <errno.h>
+#endif
+
+#define TRUE  1
+#define FALSE 0
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+
+SSL_CTX* SSL_CTX_new(SSL_METHOD* method)
+{
+    SSL_CTX* ctx = (SSL_CTX*) XMALLOC(sizeof(SSL_CTX), 0, DYNAMIC_TYPE_CTX);
+    if (ctx)
+        InitSSL_Ctx(ctx, method);
+
+    return ctx;
+}
+
+
+void SSL_CTX_free(SSL_CTX* ctx)
+{
+    if (ctx)
+        FreeSSL_Ctx(ctx);
+}
+
+
+SSL* SSL_new(SSL_CTX* ctx)
+{
+
+    SSL* ssl = (SSL*) XMALLOC(sizeof(SSL), ctx->heap, DYNAMIC_TYPE_SSL);
+    if (ssl)
+        if (InitSSL(ssl, ctx) < 0) {
+            FreeSSL(ssl);
+            ssl = 0;
+        }
+
+    return ssl;
+}
+
+
+void SSL_free(SSL* ssl)
+{
+    CYASSL_ENTER("SSL_free");
+    if (ssl)
+        FreeSSL(ssl);
+    CYASSL_LEAVE("SSL_free", 0);
+}
+
+
+int SSL_set_fd(SSL* ssl, int fd)
+{
+    ssl->rfd = fd;      /* not used directly to allow IO callbacks */
+    ssl->wfd = fd;
+
+    ssl->IOCB_ReadCtx  = &ssl->rfd;
+    ssl->IOCB_WriteCtx = &ssl->wfd;
+
+    return SSL_SUCCESS;
+}
+
+
+int SSL_get_fd(const SSL* ssl)
+{
+    return ssl->rfd;
+}
+
+
+int CyaSSL_negotiate(SSL* ssl)
+{
+    int err = -1;
+
+#ifndef NO_CYASSL_SERVER
+    if (ssl->options.side == SERVER_END)
+        err = SSL_accept(ssl);
+#endif
+
+#ifndef NO_CYASSL_CLIENT
+    if (ssl->options.side == CLIENT_END)
+        err = SSL_connect(ssl);
+#endif
+
+    if (err == SSL_SUCCESS)
+        return 0;
+    else
+        return err;
+}
+
+
+int SSL_write(SSL* ssl, const void* buffer, int sz)
+{
+    int ret;
+
+    CYASSL_ENTER("SSL_write()");
+
+#ifdef HAVE_ERRNO_H 
+    errno = 0;
+#endif
+
+    ret = SendData(ssl, buffer, sz);
+
+    CYASSL_LEAVE("SSL_write()", ret);
+
+    if (ret < 0)
+        return SSL_FATAL_ERROR;
+    else
+        return ret;
+}
+
+
+int SSL_read(SSL* ssl, void* buffer, int sz)
+{
+    int ret; 
+
+    CYASSL_ENTER("SSL_read()");
+
+#ifdef HAVE_ERRNO_H 
+        errno = 0;
+#endif
+
+    ret = ReceiveData(ssl, (byte*)buffer, min(sz, OUTPUT_RECORD_SIZE));
+
+    CYASSL_LEAVE("SSL_read()", ret);
+
+    if (ret < 0)
+        return SSL_FATAL_ERROR;
+    else
+        return ret;
+}
+
+
+int SSL_shutdown(SSL* ssl)
+{
+    CYASSL_ENTER("SSL_shutdown()");
+
+    if (ssl->options.quietShutdown) {
+        CYASSL_MSG("quiet shutdown, no close notify sent"); 
+        return 0;
+    }
+
+    /* try to send close notify, not an error if can't */
+    if (!ssl->options.isClosed && !ssl->options.connReset &&
+                                  !ssl->options.sentNotify) {
+        ssl->error = SendAlert(ssl, alert_warning, close_notify);
+        if (ssl->error < 0) {
+            CYASSL_ERROR(ssl->error);
+            return SSL_FATAL_ERROR;
+        }
+        ssl->options.sentNotify = 1;  /* don't send close_notify twice */
+    }
+
+    CYASSL_LEAVE("SSL_shutdown()", ssl->error);
+
+    ssl->error = SSL_ERROR_SYSCALL;   /* simulate OpenSSL behavior */
+
+    return 0;
+}
+
+
+int SSL_get_error(SSL* ssl, int dummy)
+{
+    if (ssl->error == WANT_READ)
+        return SSL_ERROR_WANT_READ;         /* convert to OpenSSL type */
+    else if (ssl->error == WANT_WRITE)
+        return SSL_ERROR_WANT_WRITE;        /* convert to OpenSSL type */
+    else if (ssl->error == ZERO_RETURN) 
+        return SSL_ERROR_ZERO_RETURN;       /* convert to OpenSSL type */
+    return ssl->error;
+}
+
+
+int SSL_want_read(SSL* ssl)
+{
+    if (ssl->error == WANT_READ)
+        return 1;
+
+    return 0;
+}
+
+
+int SSL_want_write(SSL* ssl)
+{
+    if (ssl->error == WANT_WRITE)
+        return 1;
+
+    return 0;
+}
+
+
+char* ERR_error_string(unsigned long errNumber, char* buffer)
+{
+    static char* msg = "Please supply a buffer for error string";
+
+    if (buffer) {
+        SetErrorString(errNumber, buffer);
+        return buffer;
+    }
+
+    return msg;
+}
+
+
+void ERR_error_string_n(unsigned long e, char* buf, size_t len)
+{
+    if (len) ERR_error_string(e, buf);
+}
+
+
+#ifndef NO_FILESYSTEM
+
+void ERR_print_errors_fp(FILE* fp, int err)
+{
+    char buffer[MAX_ERROR_SZ + 1];
+
+    SetErrorString(err, buffer);
+    fprintf(fp, "%s", buffer);
+}
+
+#endif
+
+
+int SSL_pending(SSL* ssl)
+{
+    return ssl->buffers.clearOutputBuffer.length;
+}
+
+
+/* owns der */
+static int AddCA(SSL_CTX* ctx, buffer der)
+{
+    word32      ret;
+    DecodedCert cert;
+    Signer*     signer = 0;
+
+    InitDecodedCert(&cert, der.buffer, ctx->heap);
+    ret = ParseCert(&cert, der.length, CA_TYPE, ctx->verifyPeer, 0);
+
+    if (ret == 0) {
+        /* take over signer parts */
+        signer = MakeSigner(ctx->heap);
+        if (!signer)
+            ret = MEMORY_ERROR;
+        else {
+            signer->keyOID     = cert.keyOID;
+            signer->publicKey  = cert.publicKey;
+            signer->pubKeySize = cert.pubKeySize;
+            signer->name = cert.subjectCN;
+            XMEMCPY(signer->hash, cert.subjectHash, SHA_DIGEST_SIZE);
+
+            cert.publicKey = 0;  /* don't free here */
+            cert.subjectCN = 0;
+
+            signer->next = ctx->caList;
+            ctx->caList  = signer;   /* takes ownership */
+        }
+    }
+
+    FreeDecodedCert(&cert);
+    XFREE(der.buffer, ctx->heap, DYNAMIC_TYPE_CA);
+
+    if (ret == 0) return SSL_SUCCESS;
+    return ret;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+    /* basic config gives a cache with 33 sessions, adequate for clients and
+       embedded servers
+
+       BIG_SESSION_CACHE allows 1055 sessions, adequate for servers that aren't
+       under heavy load, basically allows 200 new sessions per minute
+
+       HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load,
+       allows over 13,000 new sessions per minute or over 200 new sessions per
+       second
+    */
+    #ifdef HUGE_SESSION_CACHE
+        #define SESSIONS_PER_ROW 11
+        #define SESSION_ROWS 5981
+    #elif defined(BIG_SESSION_CACHE)
+        #define SESSIONS_PER_ROW 5
+        #define SESSION_ROWS 211
+    #else
+        #define SESSIONS_PER_ROW 3
+        #define SESSION_ROWS 11
+    #endif
+
+    typedef struct SessionRow {
+        int nextIdx;                           /* where to place next one   */
+        int totalCount;                        /* sessions ever on this row */
+        SSL_SESSION Sessions[SESSIONS_PER_ROW];
+    } SessionRow;
+
+    static SessionRow SessionCache[SESSION_ROWS];
+
+    static CyaSSL_Mutex mutex;   /* SessionCache mutex */
+
+#endif /* NO_SESSION_CACHE */
+
+
+    static int PemToDer(const unsigned char* buff, long sz, int type,
+                        buffer* der, void* heap, EncryptedInfo* info)
+    {
+        char  header[PEM_LINE_LEN];
+        char  footer[PEM_LINE_LEN];
+        char* headerEnd;
+        char* footerEnd;
+        long  neededSz;
+        int   pkcs8 = 0;
+        int   dynamicType;
+
+        if (type == CERT_TYPE || type == CA_TYPE)  {
+            XSTRNCPY(header, "-----BEGIN CERTIFICATE-----", sizeof(header));
+            XSTRNCPY(footer, "-----END CERTIFICATE-----", sizeof(footer));
+            dynamicType = (type == CA_TYPE) ? DYNAMIC_TYPE_CA :
+                                              DYNAMIC_TYPE_CERT;
+        } else {
+            XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----", sizeof(header));
+            XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----", sizeof(footer));
+            dynamicType = DYNAMIC_TYPE_KEY;
+        }
+
+        /* find header */
+        headerEnd = XSTRSTR((char*)buff, header);
+        if (!headerEnd && type == PRIVATEKEY_TYPE) {  /* may be pkcs8 */
+            XSTRNCPY(header, "-----BEGIN PRIVATE KEY-----", sizeof(header));
+            XSTRNCPY(footer, "-----END PRIVATE KEY-----", sizeof(footer));
+        
+            headerEnd = XSTRSTR((char*)buff, header);
+            if (headerEnd)
+                pkcs8 = 1;
+            /*
+            else
+                maybe encrypted "-----BEGIN ENCRYPTED PRIVATE KEY-----"
+            */
+        }
+        if (!headerEnd)
+            return SSL_BAD_FILE;
+        headerEnd += XSTRLEN(header);
+
+        /* get next line */
+        if (headerEnd[0] == '\n')
+            headerEnd++;
+        else if (headerEnd[1] == '\n')
+            headerEnd += 2;
+        else
+            return SSL_BAD_FILE;
+
+#ifdef OPENSSL_EXTRA
+    {
+        /* remove encrypted header if there */
+        char encHeader[] = "Proc-Type";
+        char* line = XSTRSTR((char*)buff, encHeader);
+        if (line) {
+            char* newline;
+            char* finish;
+            char* start  = XSTRSTR(line, "DES");
+    
+            if (!start)
+                start = XSTRSTR(line, "AES");
+            
+            if (!start) return SSL_BAD_FILE;
+            if (!info)  return SSL_BAD_FILE;
+            
+            finish = XSTRSTR(start, ",");
+
+            if (start && finish && (start < finish)) {
+                newline = XSTRSTR(finish, "\r");
+
+                XMEMCPY(info->name, start, finish - start);
+                info->name[finish - start] = 0;
+                XMEMCPY(info->iv, finish + 1, sizeof(info->iv));
+
+                if (!newline) newline = XSTRSTR(finish, "\n");
+                if (newline && (newline > finish)) {
+                    info->ivSz = (word32)(newline - (finish + 1));
+                    info->set = 1;
+                }
+                else
+                    return SSL_BAD_FILE;
+            }
+            else
+                return SSL_BAD_FILE;
+
+            /* eat blank line */
+            while (*newline == '\r' || *newline == '\n')
+                newline++;
+            headerEnd = newline;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
+
+        /* find footer */
+        footerEnd = XSTRSTR((char*)buff, footer);
+        if (!footerEnd) return SSL_BAD_FILE;
+
+        /* set up der buffer */
+        neededSz = (long)(footerEnd - headerEnd);
+        if (neededSz > sz || neededSz < 0) return SSL_BAD_FILE;
+        der->buffer = (byte*) XMALLOC(neededSz, heap, dynamicType);
+        if (!der->buffer) return MEMORY_ERROR;
+        der->length = neededSz;
+
+        if (Base64Decode((byte*)headerEnd, neededSz, der->buffer,
+                         &der->length) < 0)
+            return SSL_BAD_FILE;
+
+        if (pkcs8)
+            return ToTraditional(der->buffer, der->length);
+
+        /* not full support yet 
+         if (pkcs8Enc)
+            return ToTraditionalEnc(der->buffer, der->length);
+        */
+
+        return 0;
+    }
+
+
+    static int ProcessBuffer(SSL_CTX* ctx, const unsigned char* buff,
+                             long sz, int format, int type)
+    {
+        EncryptedInfo info;
+        buffer        der;        /* holds DER or RAW (for NTRU */
+        int           dynamicType;
+
+        info.set   = 0;
+        der.buffer = 0;
+
+        if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM 
+                                        && format != SSL_FILETYPE_RAW)
+            return SSL_BAD_FILETYPE;
+
+        if (type == CA_TYPE)
+            dynamicType = DYNAMIC_TYPE_CA;
+        else if (type == CERT_TYPE)
+            dynamicType = DYNAMIC_TYPE_CERT;
+        else
+            dynamicType = DYNAMIC_TYPE_KEY;
+
+        if (format == SSL_FILETYPE_PEM) {
+            if (PemToDer(buff, sz, type, &der, ctx->heap, &info) < 0) {
+                XFREE(der.buffer, ctx->heap, dynamicType);
+                return SSL_BAD_FILE;
+            }
+        }
+        else {  /* ASN1 (DER) or RAW (NTRU) */
+            der.buffer = (byte*) XMALLOC(sz, ctx->heap, dynamicType);
+            if (!der.buffer) return MEMORY_ERROR;
+            XMEMCPY(der.buffer, buff, sz);
+            der.length = sz;
+        }
+
+#ifdef OPENSSL_EXTRA
+        if (info.set) {
+            /* decrypt */
+            char password[80];
+            int  passwordSz;
+
+            byte key[AES_256_KEY_SIZE];
+            byte  iv[AES_IV_SIZE];
+
+            if (!ctx->passwd_cb) return -1;
+
+            /* use file's salt for key derivation, hex decode first */
+            if (Base16Decode(info.iv, info.ivSz, info.iv, &info.ivSz) != 0)
+                return -1;
+
+            passwordSz = ctx->passwd_cb(password, sizeof(password), 0,
+                                    ctx->userdata);
+            if (EVP_BytesToKey(info.name, "MD5", info.iv, (byte*)password,
+                               passwordSz, 1, key, iv) <= 0)
+                return -1;
+
+            if (XSTRNCMP(info.name, "DES-CBC", 7) == 0) {
+                Des des;
+                Des_SetKey(&des, key, info.iv, DES_DECRYPTION);
+                Des_CbcDecrypt(&des, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "DES-EDE3-CBC", 13) == 0) {
+                Des3 des;
+                Des3_SetKey(&des, key, info.iv, DES_DECRYPTION);
+                Des3_CbcDecrypt(&des, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-128-CBC", 13) == 0) {
+                Aes aes;
+                AesSetKey(&aes, key, AES_128_KEY_SIZE, info.iv, AES_DECRYPTION);
+                AesCbcDecrypt(&aes, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-192-CBC", 13) == 0) {
+                Aes aes;
+                AesSetKey(&aes, key, AES_192_KEY_SIZE, info.iv, AES_DECRYPTION);
+                AesCbcDecrypt(&aes, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-256-CBC", 13) == 0) {
+                Aes aes;
+                AesSetKey(&aes, key, AES_256_KEY_SIZE, info.iv, AES_DECRYPTION);
+                AesCbcDecrypt(&aes, der.buffer, der.buffer, der.length);
+            }
+            else 
+                return SSL_BAD_FILE;
+        }
+#endif /* OPENSSL_EXTRA */
+
+        if (type == CA_TYPE)
+            return AddCA(ctx, der);     /* takes der over */
+        else if (type == CERT_TYPE) {
+            if (ctx->certificate.buffer)
+                XFREE(ctx->certificate.buffer, ctx->heap, dynamicType);
+            ctx->certificate = der;     /* takes der over */
+        }
+        else if (type == PRIVATEKEY_TYPE) {
+            if (ctx->privateKey.buffer)
+                XFREE(ctx->privateKey.buffer, ctx->heap, dynamicType);
+            ctx->privateKey = der;      /* takes der over */
+        }
+        else {
+            XFREE(der.buffer, ctx->heap, dynamicType);
+            return SSL_BAD_CERTTYPE;
+        }
+
+        if (type == PRIVATEKEY_TYPE && format != SSL_FILETYPE_RAW) {
+            /* make sure RSA key can be used */
+            RsaKey key;
+            word32 idx = 0;
+        
+            InitRsaKey(&key, 0);
+            if (RsaPrivateKeyDecode(der.buffer, &idx, &key, der.length) != 0) {
+                FreeRsaKey(&key);
+                return SSL_BAD_FILE;
+            }
+        
+            FreeRsaKey(&key);
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+#ifndef NO_FILESYSTEM
+
+#ifndef MICRIUM
+    #define XFILE      FILE
+    #define XFOPEN     fopen 
+    #define XFSEEK     fseek
+    #define XFTELL     ftell
+    #define XREWIND    rewind
+    #define XFREAD     fread
+    #define XFCLOSE    fclose
+    #define XSEEK_END  SEEK_END
+#else
+    #include <fs.h>
+    #define XFILE      FS_FILE
+    #define XFOPEN     fs_fopen 
+    #define XFSEEK     fs_fseek
+    #define XFTELL     fs_ftell
+    #define XREWIND    fs_rewind
+    #define XFREAD     fs_fread
+    #define XFCLOSE    fs_fclose
+    #define XSEEK_END  FS_SEEK_END
+#endif
+
+static int ProcessFile(SSL_CTX* ctx, const char* fname, int format, int type)
+{
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+    byte*  buffer = staticBuffer;
+    int    dynamic = 0;
+    int    ret;
+    long   sz = 0;
+    XFILE* file = XFOPEN(fname, "rb"); 
+
+    if (!file) return SSL_BAD_FILE;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > sizeof(staticBuffer)) {
+        buffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE);
+        if (buffer == NULL) {
+            XFCLOSE(file);
+            return SSL_BAD_FILE;
+        }
+        dynamic = 1;
+    }
+
+    if ( (ret = XFREAD(buffer, sz, 1, file)) < 0)
+        ret = SSL_BAD_FILE;
+    else
+        ret = ProcessBuffer(ctx, buffer, sz, format, type);
+
+    XFCLOSE(file);
+    if (dynamic) XFREE(buffer, ctx->heap, DYNAMIC_TYPE_FILE);
+
+    return ret;
+}
+
+
+/* just one for now TODO: add dir support from path */
+int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file,
+                                  const char* path)
+{
+    if (ProcessFile(ctx, file, SSL_FILETYPE_PEM, CA_TYPE) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+#ifdef CYASSL_DER_LOAD
+
+/* Add format parameter to allow DER load of CA files */
+int CyaSSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, int format)
+{
+    if (ProcessFile(ctx, file, format, CA_TYPE) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+#endif /* CYASSL_DER_LOAD */
+
+
+#ifdef CYASSL_CERT_GEN
+
+/* load pem cert from file into der buffer, return der size or error */
+int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz) 
+{
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+    byte*  fileBuf = staticBuffer;
+    int    dynamic = 0;
+    int    ret;
+    long   sz = 0;
+    XFILE* file = XFOPEN(fileName, "rb"); 
+    EncryptedInfo info;
+    buffer        converted;
+
+    converted.buffer = 0;
+
+    if (!file) return SSL_BAD_FILE;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > sizeof(staticBuffer)) {
+        fileBuf = (byte*) XMALLOC(sz, 0, DYNAMIC_TYPE_FILE);
+        if (fileBuf == NULL) {
+            XFCLOSE(file);
+            return SSL_BAD_FILE;
+        }
+        dynamic = 1;
+    }
+
+    if ( (ret = XFREAD(fileBuf, sz, 1, file)) < 0)
+        ret = SSL_BAD_FILE;
+    else
+        ret = PemToDer(fileBuf, sz, CA_TYPE, &converted, 0, &info);
+
+    if (ret == 0) {
+        if (converted.length < derSz) {
+            memcpy(derBuf, converted.buffer, converted.length);
+            ret = converted.length;
+        }
+        else
+            ret = BUFFER_E;
+    }       
+
+    XFREE(converted.buffer, 0, DYNAMIC_TYPE_CA); 
+    if (dynamic)
+        XFREE(fileBuf, 0, DYNAMIC_TYPE_FILE); 
+    XFCLOSE(file);
+
+    return ret;
+}
+
+#endif /* CYASSL_CERT_GEN */
+
+
+int SSL_CTX_use_certificate_file(SSL_CTX* ctx, const char* file, int format)
+{
+    if (ProcessFile(ctx, file, format, CERT_TYPE) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* file, int format)
+{
+    if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int SSL_CTX_use_certificate_chain_file(SSL_CTX* ctx, const char* file)
+{
+    /* add first to ctx, all tested implementations support this */
+   if (ProcessFile(ctx, file, SSL_FILETYPE_PEM, CERT_TYPE) == SSL_SUCCESS)
+       return SSL_SUCCESS;
+
+   return SSL_FAILURE;
+}
+
+
+#ifdef HAVE_NTRU
+
+int CyaSSL_CTX_use_NTRUPrivateKey_file(SSL_CTX* ctx, const char* file)
+{
+    if (ProcessFile(ctx, file, SSL_FILETYPE_RAW, PRIVATEKEY_TYPE)
+                         == SSL_SUCCESS) {
+        ctx->haveNTRU = 1;
+        return SSL_SUCCESS;
+    }
+
+    return SSL_FAILURE;
+}
+
+#endif /* HAVE_NTRU */
+
+
+
+#ifdef OPENSSL_EXTRA
+
+    int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX* ctx,const char* file,int format)
+    {
+        if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE) == SSL_SUCCESS)
+            return SSL_SUCCESS;
+
+        return SSL_FAILURE;
+    }
+
+#endif /* OPENSSL_EXTRA */
+
+#endif /* NO_FILESYSTEM */
+
+
+void SSL_CTX_set_verify(SSL_CTX* ctx, int mode, VerifyCallback vc)
+{
+    if (mode & SSL_VERIFY_PEER) {
+        ctx->verifyPeer = 1;
+        ctx->verifyNone = 0;  /* in case perviously set */
+    }
+
+    if (mode == SSL_VERIFY_NONE) {
+        ctx->verifyNone = 1;
+        ctx->verifyPeer = 0;  /* in case previously set */
+    }
+
+    if (mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+        ctx->failNoCert = 1;
+
+    ctx->verifyCallback = vc;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+SSL_SESSION* SSL_get_session(SSL* ssl)
+{
+    return GetSession(ssl, 0);
+}
+
+
+int SSL_set_session(SSL* ssl, SSL_SESSION* session)
+{
+    if (session)
+        return SetSession(ssl, session);
+
+    return SSL_FAILURE;
+}
+
+#endif /* NO_SESSION_CACHE */
+
+
+void SSL_load_error_strings(void)   /* compatibility only */
+{}
+
+
+int SSL_library_init(void)
+{
+    if (InitCyaSSL() == 0)
+        return SSL_SUCCESS;
+    else
+        return -1;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+/* on by default if built in but allow user to turn off */
+long SSL_CTX_set_session_cache_mode(SSL_CTX* ctx, long mode)
+{
+    if (mode == SSL_SESS_CACHE_OFF)
+        ctx->sessionCacheOff = 1;
+
+    if (mode == SSL_SESS_CACHE_NO_AUTO_CLEAR)
+        ctx->sessionCacheFlushOff = 1;
+
+    return SSL_SUCCESS;
+}
+
+#endif /* NO_SESSION_CACHE */
+
+
+int SSL_CTX_set_cipher_list(SSL_CTX* ctx, const char* list)
+{
+    if (SetCipherList(ctx, list))
+        return SSL_SUCCESS;
+    else
+        return SSL_FAILURE;
+}
+
+
+/* client only parts */
+#ifndef NO_CYASSL_CLIENT
+
+    SSL_METHOD* SSLv3_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeSSLv3());
+        return method;
+    }
+
+    #ifdef CYASSL_DTLS
+        SSL_METHOD* DTLSv1_client_method(void)
+        {
+            SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            if (method)
+                InitSSL_Method(method, MakeDTLSv1());
+            return method;
+        }
+    #endif
+
+
+    /* please see note at top of README if you get an error from connect */
+    int SSL_connect(SSL* ssl)
+    {
+        int neededState;
+
+        CYASSL_ENTER("SSL_connect()");
+
+        #ifdef HAVE_ERRNO_H 
+            errno = 0;
+        #endif
+
+        if (ssl->options.side != CLIENT_END) {
+            CYASSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        #ifdef CYASSL_DTLS
+            if (ssl->version.major == DTLS_MAJOR && 
+                                      ssl->version.minor == DTLS_MINOR) {
+                ssl->options.dtls   = 1;
+                ssl->options.tls    = 1;
+                ssl->options.tls1_1 = 1;
+            }
+        #endif
+
+        if (ssl->buffers.outputBuffer.length > 0) {
+            if ( (ssl->error = SendBuffered(ssl)) == 0) {
+                ssl->options.connectState++;
+                CYASSL_MSG("connect state: Advanced from buffered send");
+            }
+            else {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+        }
+
+        switch (ssl->options.connectState) {
+
+        case CONNECT_BEGIN :
+            /* always send client hello first */
+            if ( (ssl->error = SendClientHello(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.connectState = CLIENT_HELLO_SENT;
+            CYASSL_MSG("connect state: CLIENT_HELLO_SENT");
+
+        case CLIENT_HELLO_SENT :
+            neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE :
+                                          SERVER_HELLODONE_COMPLETE;
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls && !ssl->options.resuming)
+                    neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+            #endif
+            /* get response */
+            while (ssl->options.serverState < neededState) {
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+                /* if resumption failed, reset needed state */
+                else if (neededState == SERVER_FINISHED_COMPLETE)
+                    if (!ssl->options.resuming) {
+                        if (!ssl->options.dtls)
+                            neededState = SERVER_HELLODONE_COMPLETE;
+                        else
+                            neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+                    }
+            }
+
+            ssl->options.connectState = HELLO_AGAIN;
+            CYASSL_MSG("connect state: HELLO_AGAIN");
+
+        case HELLO_AGAIN :
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls && !ssl->options.resuming) {
+                    /* re-init hashes, exclude first hello and verify request */
+                    InitMd5(&ssl->hashMd5);
+                    InitSha(&ssl->hashSha);
+                    if ( (ssl->error = SendClientHello(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+                }
+            #endif
+
+            ssl->options.connectState = HELLO_AGAIN_REPLY;
+            CYASSL_MSG("connect state: HELLO_AGAIN_REPLY");
+
+        case HELLO_AGAIN_REPLY :
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls) {
+                    neededState = ssl->options.resuming ?
+                           SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE;
+            
+                    /* get response */
+                    while (ssl->options.serverState < neededState) {
+                        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                                CYASSL_ERROR(ssl->error);
+                                return SSL_FATAL_ERROR;
+                        }
+                        /* if resumption failed, reset needed state */
+                        else if (neededState == SERVER_FINISHED_COMPLETE)
+                            if (!ssl->options.resuming)
+                                neededState = SERVER_HELLODONE_COMPLETE;
+                    }
+                }
+            #endif
+
+            ssl->options.connectState = FIRST_REPLY_DONE;
+            CYASSL_MSG("connect state: FIRST_REPLY_DONE");
+
+        case FIRST_REPLY_DONE :
+            if (ssl->options.sendVerify)
+                if ( (ssl->error = SendCertificate(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+
+            ssl->options.connectState = FIRST_REPLY_FIRST;
+            CYASSL_MSG("connect state: FIRST_REPLY_FIRST");
+
+        case FIRST_REPLY_FIRST :
+            if (!ssl->options.resuming)
+                if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+
+            ssl->options.connectState = FIRST_REPLY_SECOND;
+            CYASSL_MSG("connect state: FIRST_REPLY_SECOND");
+
+        case FIRST_REPLY_SECOND :
+            if (ssl->options.sendVerify)
+                if ( (ssl->error = SendCertificateVerify(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+            }
+            ssl->options.connectState = FIRST_REPLY_THIRD;
+            CYASSL_MSG("connect state: FIRST_REPLY_THIRD");
+
+        case FIRST_REPLY_THIRD :
+            if ( (ssl->error = SendChangeCipher(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.connectState = FIRST_REPLY_FOURTH;
+            CYASSL_MSG("connect state: FIRST_REPLY_FOURTH");
+
+        case FIRST_REPLY_FOURTH :
+            if ( (ssl->error = SendFinished(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+
+            ssl->options.connectState = FINISHED_DONE;
+            CYASSL_MSG("connect state: FINISHED_DONE");
+
+        case FINISHED_DONE :
+            /* get response */
+            while (ssl->options.serverState < SERVER_FINISHED_COMPLETE)
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+          
+            ssl->options.connectState = SECOND_REPLY_DONE;
+            CYASSL_MSG("connect state: SECOND_REPLY_DONE");
+
+        case SECOND_REPLY_DONE:
+            if (ssl->buffers.inputBuffer.dynamicFlag)
+                ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+            CYASSL_LEAVE("SSL_connect()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default:
+            CYASSL_MSG("Unknown connect state ERROR");
+            return SSL_FATAL_ERROR; /* unknown connect state */
+        }
+    }
+
+#endif /* NO_CYASSL_CLIENT */
+
+
+/* server only parts */
+#ifndef NO_CYASSL_SERVER
+
+    SSL_METHOD* SSLv3_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeSSLv3());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+
+    #ifdef CYASSL_DTLS
+        SSL_METHOD* DTLSv1_server_method(void)
+        {
+            SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            if (method) {
+                InitSSL_Method(method, MakeDTLSv1());
+                method->side = SERVER_END;
+            }
+            return method;
+        }
+    #endif
+
+
+    int SSL_accept(SSL* ssl)
+    {
+        CYASSL_ENTER("SSL_accept()");
+
+        #ifdef HAVE_ERRNO_H 
+            errno = 0;
+        #endif
+
+        if (ssl->options.side != SERVER_END) {
+            CYASSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        #ifdef CYASSL_DTLS
+            if (ssl->version.major == DTLS_MAJOR &&
+                                      ssl->version.minor == DTLS_MINOR) {
+                ssl->options.dtls   = 1;
+                ssl->options.tls    = 1;
+                ssl->options.tls1_1 = 1;
+            }
+        #endif
+
+        if (ssl->buffers.outputBuffer.length > 0) {
+            if ( (ssl->error = SendBuffered(ssl)) == 0) {
+                ssl->options.acceptState++;
+                CYASSL_MSG("accept state: Advanced from buffered send");
+            }
+            else {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+        }
+
+        switch (ssl->options.acceptState) {
+    
+        case ACCEPT_BEGIN :
+            /* get response */
+            while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE;
+            CYASSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
+
+        case ACCEPT_CLIENT_HELLO_DONE :
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls && !ssl->options.resuming)
+                    if ( (ssl->error = SendHelloVerifyRequest(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            #endif
+            ssl->options.acceptState = HELLO_VERIFY_SENT;
+            CYASSL_MSG("accept state HELLO_VERIFY_SENT");
+
+        case HELLO_VERIFY_SENT:
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls && !ssl->options.resuming) {
+                    ssl->options.clientState = NULL_STATE;  /* get again */
+                    /* re-init hashes, exclude first hello and verify request */
+                    InitMd5(&ssl->hashMd5);
+                    InitSha(&ssl->hashSha);
+
+                    while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
+                        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                            CYASSL_ERROR(ssl->error);
+                            return SSL_FATAL_ERROR;
+                        }
+                }
+            #endif
+            ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
+            CYASSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
+
+        case ACCEPT_FIRST_REPLY_DONE :
+            if ( (ssl->error = SendServerHello(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = SERVER_HELLO_SENT;
+            CYASSL_MSG("accept state SERVER_HELLO_SENT");
+
+        case SERVER_HELLO_SENT :
+            if (!ssl->options.resuming) 
+                if ( (ssl->error = SendCertificate(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = CERT_SENT;
+            CYASSL_MSG("accept state CERT_SENT");
+
+        case CERT_SENT :
+            if (!ssl->options.resuming) 
+                if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = KEY_EXCHANGE_SENT;
+            CYASSL_MSG("accept state KEY_EXCHANGE_SENT");
+
+        case KEY_EXCHANGE_SENT :
+            if (!ssl->options.resuming) 
+                if (ssl->options.verifyPeer)
+                    if ( (ssl->error = SendCertificateRequest(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            ssl->options.acceptState = CERT_REQ_SENT;
+            CYASSL_MSG("accept state CERT_REQ_SENT");
+
+        case CERT_REQ_SENT :
+            if (!ssl->options.resuming) 
+                if ( (ssl->error = SendServerHelloDone(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = SERVER_HELLO_DONE;
+            CYASSL_MSG("accept state SERVER_HELLO_DONE");
+
+        case SERVER_HELLO_DONE :
+            if (!ssl->options.resuming) {
+                while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE)
+                    if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            }
+            ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE;
+            CYASSL_MSG("accept state  ACCEPT_SECOND_REPLY_DONE");
+          
+        case ACCEPT_SECOND_REPLY_DONE : 
+            if ( (ssl->error = SendChangeCipher(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = CHANGE_CIPHER_SENT;
+            CYASSL_MSG("accept state  CHANGE_CIPHER_SENT");
+
+        case CHANGE_CIPHER_SENT : 
+            if ( (ssl->error = SendFinished(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+
+            ssl->options.acceptState = ACCEPT_FINISHED_DONE;
+            CYASSL_MSG("accept state ACCEPT_FINISHED_DONE");
+
+        case ACCEPT_FINISHED_DONE :
+            if (ssl->options.resuming)
+                while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE)
+                    if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+
+            ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE;
+            CYASSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE");
+
+        case ACCEPT_THIRD_REPLY_DONE :
+            if (ssl->buffers.inputBuffer.dynamicFlag)
+                ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+            CYASSL_LEAVE("SSL_accept()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default :
+            CYASSL_MSG("Unknown accept state ERROR");
+            return SSL_FATAL_ERROR;
+        }
+    }
+
+#endif /* NO_CYASSL_SERVER */
+
+
+int InitCyaSSL(void)
+{
+    if (InitMutex(&mutex) == 0)
+        return 0;
+    else
+        return -1;
+}
+
+
+int FreeCyaSSL(void)
+{
+    if (FreeMutex(&mutex) == 0)
+        return 0;
+    else
+        return -1;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+
+static INLINE word32 HashSession(const byte* sessionID)
+{
+    /* id is random, just make 32 bit number from first 4 bytes for now */
+    return (sessionID[0] << 24) | (sessionID[1] << 16) | (sessionID[2] <<  8) |
+            sessionID[3];
+}
+
+
+void SSL_flush_sessions(SSL_CTX* ctx, long tm)
+{
+    /* static table now, no flusing needed */
+}
+
+
+SSL_SESSION* GetSession(SSL* ssl, byte* masterSecret)
+{
+    SSL_SESSION* ret = 0;
+    const byte*  id = ssl->arrays.sessionID;
+    word32       row;
+    int          idx;
+    
+    if (ssl->options.sessionCacheOff)
+        return 0;
+
+    row = HashSession(id) % SESSION_ROWS;
+
+    if (LockMutex(&mutex) != 0)
+        return 0;
+   
+    if (SessionCache[row].totalCount >= SESSIONS_PER_ROW)
+        idx = SESSIONS_PER_ROW - 1;
+    else
+        idx = SessionCache[row].nextIdx - 1;
+
+    for (; idx >= 0; idx--) {
+        SSL_SESSION* current;
+        
+        if (idx >= SESSIONS_PER_ROW)    /* server could have restarted, idx  */
+            break;                      /* would be word32(-1) and seg fault */
+        
+        current = &SessionCache[row].Sessions[idx];
+        if (XMEMCMP(current->sessionID, id, ID_LEN) == 0) {
+            if (LowResTimer() < (current->bornOn + current->timeout)) {
+                ret = current;
+                if (masterSecret)
+                    XMEMCPY(masterSecret, current->masterSecret, SECRET_LEN);
+            }
+            break;
+        }   
+    }
+
+    UnLockMutex(&mutex);
+    
+    return ret;
+}
+
+
+int SetSession(SSL* ssl, SSL_SESSION* session)
+{
+    if (ssl->options.sessionCacheOff)
+        return SSL_FAILURE;
+
+    if (LowResTimer() < (session->bornOn + session->timeout)) {
+        ssl->session  = *session;
+        ssl->options.resuming = 1;
+
+#ifdef SESSION_CERTS
+        ssl->version             = session->version;
+        ssl->options.cipherSuite = session->cipherSuite;
+#endif
+
+        return SSL_SUCCESS;
+    }
+    return SSL_FAILURE;  /* session timed out */
+}
+
+
+int AddSession(SSL* ssl)
+{
+    word32 row, idx;
+
+    if (ssl->options.sessionCacheOff)
+        return 0;
+
+    row = HashSession(ssl->arrays.sessionID) % SESSION_ROWS;
+
+    if (LockMutex(&mutex) != 0)
+        return -1;
+
+    idx = SessionCache[row].nextIdx++;
+
+    XMEMCPY(SessionCache[row].Sessions[idx].masterSecret,
+           ssl->arrays.masterSecret, SECRET_LEN);
+    XMEMCPY(SessionCache[row].Sessions[idx].sessionID, ssl->arrays.sessionID,
+           ID_LEN);
+
+    SessionCache[row].Sessions[idx].timeout = DEFAULT_TIMEOUT;
+    SessionCache[row].Sessions[idx].bornOn  = LowResTimer();
+
+#ifdef SESSION_CERTS
+    SessionCache[row].Sessions[idx].chain.count = ssl->session.chain.count;
+    XMEMCPY(SessionCache[row].Sessions[idx].chain.certs,
+           ssl->session.chain.certs, sizeof(x509_buffer) * MAX_CHAIN_DEPTH);
+
+    SessionCache[row].Sessions[idx].version     = ssl->version;
+    SessionCache[row].Sessions[idx].cipherSuite = ssl->options.cipherSuite;
+#endif
+
+    SessionCache[row].totalCount++;
+    if (SessionCache[row].nextIdx == SESSIONS_PER_ROW)
+        SessionCache[row].nextIdx = 0;
+
+    if (UnLockMutex(&mutex) != 0)
+        return -1;
+
+    return 0;
+}
+
+
+    #ifdef SESSION_STATS
+
+    void PrintSessionStats(void)
+    {
+        word32 totalSessionsSeen = 0;
+        word32 totalSessionsNow = 0;
+        word32 rowNow;
+        int    i;
+        double E;               /* expected freq */
+        double chiSquare = 0;
+        
+        for (i = 0; i < SESSION_ROWS; i++) {
+            totalSessionsSeen += SessionCache[i].totalCount;
+
+            if (SessionCache[i].totalCount >= SESSIONS_PER_ROW)
+                rowNow = SESSIONS_PER_ROW;
+            else if (SessionCache[i].nextIdx == 0)
+                rowNow = 0;
+            else
+                rowNow = SessionCache[i].nextIdx;
+        
+            totalSessionsNow += rowNow;
+        }
+
+        printf("Total Sessions Seen = %d\n", totalSessionsSeen);
+        printf("Total Sessions Now  = %d\n", totalSessionsNow);
+
+        E = (double)totalSessionsSeen / SESSION_ROWS;
+
+        for (i = 0; i < SESSION_ROWS; i++) {
+            double diff = SessionCache[i].totalCount - E;
+            diff *= diff;                /* sqaure    */
+            diff /= E;                   /* normalize */
+
+            chiSquare += diff;
+        }
+        printf("  chi-square = %5.1f, d.f. = %d\n", chiSquare,
+                                                     SESSION_ROWS - 1);
+        if (SESSION_ROWS == 11)
+            printf(" .05 p value =  18.3, chi-square should be less\n");
+        else if (SESSION_ROWS == 211)
+            printf(".05 p value  = 244.8, chi-square should be less\n");
+        else if (SESSION_ROWS == 5981)
+            printf(".05 p value  = 6161.0, chi-square should be less\n");
+        printf("\n");
+    }
+
+    #endif /* SESSION_STATS */
+
+#endif /* NO_SESSION_CACHE */
+
+
+/* call before SSL_connect, if verifying will add name check to
+   date check and signature check */
+int CyaSSL_check_domain_name(SSL* ssl, const char* dn)
+{
+    if (ssl->buffers.domainName.buffer)
+        XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+
+    ssl->buffers.domainName.length = (word32)XSTRLEN(dn) + 1;
+    ssl->buffers.domainName.buffer = (byte*) XMALLOC(
+                ssl->buffers.domainName.length, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+
+    if (ssl->buffers.domainName.buffer) {
+        XSTRNCPY((char*)ssl->buffers.domainName.buffer, dn,
+                ssl->buffers.domainName.length);
+        return SSL_SUCCESS;
+    }
+    else {
+        ssl->error = MEMORY_ERROR;
+        return SSL_FAILURE;
+    }
+}
+
+
+/* turn on CyaSSL zlib compression
+   returns 0 for success, else error (not built in)
+*/
+int CyaSSL_set_compression(SSL* ssl)
+{
+#ifdef HAVE_LIBZ
+    ssl->options.usingCompression = 1;
+    return 0;
+#else
+    return -1;
+#endif
+}
+
+
+#ifndef USE_WINDOWS_API 
+    #ifndef NO_WRITEV
+
+        /* simulate writev semantics, doesn't actually do block at a time though
+           because of SSL_write behavior and because front adds may be small */
+        int CyaSSL_writev(SSL* ssl, const struct iovec* iov, int iovcnt)
+        {
+            byte  tmp[OUTPUT_RECORD_SIZE];
+            byte* buffer    = tmp;
+            int   send      = 0;
+            int   newBuffer = 0;
+            int   idx       = 0;
+            int   i;
+            int   ret;
+
+            for (i = 0; i < iovcnt; i++)
+                send += iov[i].iov_len;
+
+            if (send > sizeof(tmp)) {
+                byte* tmp2 = (byte*) XMALLOC(send, ssl->heap,
+                                             DYNAMIC_TYPE_WRITEV);
+                if (!tmp2)
+                    return MEMORY_ERROR;
+                buffer = tmp2;
+                newBuffer = 1;
+            }
+
+            for (i = 0; i < iovcnt; i++) {
+                XMEMCPY(&buffer[idx], iov[i].iov_base, iov[i].iov_len);
+                idx += iov[i].iov_len;
+            }
+
+            ret = SSL_write(ssl, buffer, send);
+
+            if (newBuffer) XFREE(buffer, ssl->heap, DYNAMIC_TYPE_WRITEV);
+
+            return ret;
+        }
+    #endif
+#endif
+
+
+#ifdef CYASSL_CALLBACKS
+
+    typedef struct itimerval Itimerval;
+
+    /* don't keep calling simple functions while setting up timer and singals
+       if no inlining these are the next best */
+
+    #define AddTimes(a, b, c)                       \
+        do {                                        \
+            c.tv_sec  = a.tv_sec  + b.tv_sec;       \
+            c.tv_usec = a.tv_usec + b.tv_usec;      \
+            if (c.tv_sec >=  1000000) {             \
+                c.tv_sec++;                         \
+                c.tv_usec -= 1000000;               \
+            }                                       \
+        } while (0)
+
+
+    #define SubtractTimes(a, b, c)                  \
+        do {                                        \
+            c.tv_sec  = a.tv_sec  - b.tv_sec;       \
+            c.tv_usec = a.tv_usec - b.tv_usec;      \
+            if (c.tv_sec < 0) {                     \
+                c.tv_sec--;                         \
+                c.tv_usec += 1000000;               \
+            }                                       \
+        } while (0)
+
+    #define CmpTimes(a, b, cmp)                     \
+        ((a.tv_sec  ==  b.tv_sec) ?                 \
+            (a.tv_usec cmp b.tv_usec) :             \
+            (a.tv_sec  cmp b.tv_sec))               \
+
+
+    /* do nothing handler */
+    static void myHandler(int signo)
+    {
+        return;
+    }
+
+
+    static int CyaSSL_ex_wrapper(SSL* ssl, HandShakeCallBack hsCb,
+                                 TimeoutCallBack toCb, Timeval timeout)
+    {
+        int       ret        = -1;
+        int       oldTimerOn = 0;   /* was timer already on */
+        Timeval   startTime;
+        Timeval   endTime;
+        Timeval   totalTime;
+        Itimerval myTimeout;
+        Itimerval oldTimeout; /* if old timer adjust from total time to reset */
+        struct sigaction act, oact;
+       
+        #define ERR_OUT(x) { ssl->hsInfoOn = 0; ssl->toInfoOn = 0; return x; }
+
+        if (hsCb) {
+            ssl->hsInfoOn = 1;
+            InitHandShakeInfo(&ssl->handShakeInfo);
+        }
+        if (toCb) {
+            ssl->toInfoOn = 1;
+            InitTimeoutInfo(&ssl->timeoutInfo);
+            
+            if (gettimeofday(&startTime, 0) < 0)
+                ERR_OUT(GETTIME_ERROR);
+
+            /* use setitimer to simulate getitimer, init 0 myTimeout */
+            myTimeout.it_interval.tv_sec  = 0;
+            myTimeout.it_interval.tv_usec = 0;
+            myTimeout.it_value.tv_sec     = 0;
+            myTimeout.it_value.tv_usec    = 0;
+            if (setitimer(ITIMER_REAL, &myTimeout, &oldTimeout) < 0)
+                ERR_OUT(SETITIMER_ERROR);
+
+            if (oldTimeout.it_value.tv_sec || oldTimeout.it_value.tv_usec) {
+                oldTimerOn = 1;
+                
+                /* is old timer going to expire before ours */
+                if (CmpTimes(oldTimeout.it_value, timeout, <)) { 
+                    timeout.tv_sec  = oldTimeout.it_value.tv_sec;
+                    timeout.tv_usec = oldTimeout.it_value.tv_usec;
+                }       
+            }
+            myTimeout.it_value.tv_sec  = timeout.tv_sec;
+            myTimeout.it_value.tv_usec = timeout.tv_usec;
+            
+            /* set up signal handler, don't restart socket send/recv */
+            act.sa_handler = myHandler;
+            sigemptyset(&act.sa_mask);
+            act.sa_flags = 0;
+#ifdef SA_INTERRUPT
+            act.sa_flags |= SA_INTERRUPT;
+#endif
+            if (sigaction(SIGALRM, &act, &oact) < 0)
+                ERR_OUT(SIGACT_ERROR);
+
+            if (setitimer(ITIMER_REAL, &myTimeout, 0) < 0)
+                ERR_OUT(SETITIMER_ERROR);
+        }
+
+        /* do main work */
+#ifndef NO_CYASSL_CLIENT
+        if (ssl->options.side == CLIENT_END)
+            ret = SSL_connect(ssl);
+#endif
+#ifndef NO_CYASSL_SERVER
+        if (ssl->options.side == SERVER_END)
+            ret = SSL_accept(ssl);
+#endif
+       
+        /* do callbacks */ 
+        if (toCb) {
+            if (oldTimerOn) {
+                gettimeofday(&endTime, 0);
+                SubtractTimes(endTime, startTime, totalTime);
+                /* adjust old timer for elapsed time */
+                if (CmpTimes(totalTime, oldTimeout.it_value, <))
+                    SubtractTimes(oldTimeout.it_value, totalTime,
+                                  oldTimeout.it_value);
+                else {
+                    /* reset value to interval, may be off */
+                    oldTimeout.it_value.tv_sec = oldTimeout.it_interval.tv_sec;
+                    oldTimeout.it_value.tv_usec =oldTimeout.it_interval.tv_usec;
+                }
+                /* keep iter the same whether there or not */
+            }
+            /* restore old handler */
+            if (sigaction(SIGALRM, &oact, 0) < 0)
+                ret = SIGACT_ERROR;    /* more pressing error, stomp */
+            else
+                /* use old settings which may turn off (expired or not there) */
+                if (setitimer(ITIMER_REAL, &oldTimeout, 0) < 0)
+                    ret = SETITIMER_ERROR;
+            
+            /* if we had a timeout call callback */
+            if (ssl->timeoutInfo.timeoutName[0]) {
+                ssl->timeoutInfo.timeoutValue.tv_sec  = timeout.tv_sec;
+                ssl->timeoutInfo.timeoutValue.tv_usec = timeout.tv_usec;
+                (toCb)(&ssl->timeoutInfo);
+            }
+            /* clean up */
+            FreeTimeoutInfo(&ssl->timeoutInfo, ssl->heap);
+            ssl->toInfoOn = 0;
+        }
+        if (hsCb) {
+            FinishHandShakeInfo(&ssl->handShakeInfo, ssl);
+            (hsCb)(&ssl->handShakeInfo);
+            ssl->hsInfoOn = 0;
+        }
+        return ret;
+    }
+
+
+#ifndef NO_CYASSL_CLIENT
+
+    int CyaSSL_connect_ex(SSL* ssl, HandShakeCallBack hsCb,
+                          TimeoutCallBack toCb, Timeval timeout)
+    {
+        return CyaSSL_ex_wrapper(ssl, hsCb, toCb, timeout);
+    }
+
+#endif
+
+
+#ifndef NO_CYASSL_SERVER
+
+    int CyaSSL_accept_ex(SSL* ssl, HandShakeCallBack hsCb,
+                         TimeoutCallBack toCb,Timeval timeout)
+    {
+        return CyaSSL_ex_wrapper(ssl, hsCb, toCb, timeout);
+    }
+
+#endif
+
+#endif /* CYASSL_CALLBACKS */
+
+
+#ifndef NO_PSK
+
+    void SSL_CTX_set_psk_client_callback(SSL_CTX* ctx, psk_client_callback cb)
+    {
+        ctx->havePSK = 1;
+        ctx->client_psk_cb = cb;
+    }
+
+
+    void SSL_set_psk_client_callback(SSL* ssl, psk_client_callback cb)
+    {
+        ssl->options.havePSK = 1;
+        ssl->options.client_psk_cb = cb;
+
+        InitSuites(&ssl->suites, ssl->version,TRUE,TRUE, ssl->options.haveNTRU);
+    }
+
+
+    void SSL_CTX_set_psk_server_callback(SSL_CTX* ctx, psk_server_callback cb)
+    {
+        ctx->havePSK = 1;
+        ctx->server_psk_cb = cb;
+    }
+
+
+    void SSL_set_psk_server_callback(SSL* ssl, psk_server_callback cb)
+    {
+        ssl->options.havePSK = 1;
+        ssl->options.server_psk_cb = cb;
+
+        InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, TRUE,
+                   ssl->options.haveNTRU);
+    }
+
+
+    const char* SSL_get_psk_identity_hint(const SSL* ssl)
+    {
+        return ssl->arrays.server_hint;
+    }
+
+
+    const char* SSL_get_psk_identity(const SSL* ssl)
+    {
+        return ssl->arrays.client_identity;
+    }
+
+
+    int SSL_CTX_use_psk_identity_hint(SSL_CTX* ctx, const char* hint)
+    {
+        if (hint == 0)
+            ctx->server_hint[0] = 0;
+        else
+            XSTRNCPY(ctx->server_hint, hint, MAX_PSK_ID_LEN);
+        return SSL_SUCCESS;
+    }
+
+
+    int SSL_use_psk_identity_hint(SSL* ssl, const char* hint)
+    {
+        if (hint == 0)
+            ssl->arrays.server_hint[0] = 0;
+        else
+            XSTRNCPY(ssl->arrays.server_hint, hint, MAX_PSK_ID_LEN);
+        return SSL_SUCCESS;
+    }
+
+#endif /* NO_PSK */
+
+
+#if defined(NO_FILESYSTEM) || defined(MICRIUM)
+
+    /* CyaSSL extension allows DER files to be loaded from buffers as well */
+    int CyaSSL_CTX_load_verify_buffer(SSL_CTX* ctx, const unsigned char* buffer,
+                                      long sz, int format)
+    {
+        return ProcessBuffer(ctx, buffer, sz, format, CA_TYPE);
+    }
+
+
+    int CyaSSL_CTX_use_certificate_buffer(SSL_CTX* ctx,
+                                 const unsigned char* buffer,long sz,int format)
+    {
+        return ProcessBuffer(ctx, buffer, sz, format, CERT_TYPE);
+    }
+
+
+    int CyaSSL_CTX_use_PrivateKey_buffer(SSL_CTX* ctx,
+                                 const unsigned char* buffer,long sz,int format)
+    {
+        return ProcessBuffer(ctx, buffer, sz, format, PRIVATEKEY_TYPE);
+    }
+
+
+    int CyaSSL_CTX_use_certificate_chain_buffer(SSL_CTX* ctx,
+                                 const unsigned char* buffer, long sz)
+    {
+        /* add first to ctx, all tested implementations support this */
+        return ProcessBuffer(ctx, buffer, sz, SSL_FILETYPE_PEM, CA_TYPE);
+    }
+
+#endif /* NO_FILESYSTEM || MICRIUM */
+
+
+#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+
+
+    int SSLeay_add_ssl_algorithms(void)
+    {
+        OpenSSL_add_all_algorithms(); 
+        return SSL_SUCCESS;
+    }
+
+
+    long SSL_CTX_sess_set_cache_size(SSL_CTX* ctx, long sz)
+    {
+        /* cache size fixed at compile time in CyaSSL */
+        return 0;
+    }
+
+
+    void SSL_CTX_set_quiet_shutdown(SSL_CTX* ctx, int mode)
+    {
+        if (mode)
+            ctx->quietShutdown = 1;
+    }
+
+
+    int SSL_CTX_check_private_key(SSL_CTX* ctx)
+    {
+        /* TODO: check private against public for RSA match */
+        return SSL_SUCCESS;
+    }
+
+
+    void SSL_set_bio(SSL* ssl, BIO* rd, BIO* wr)
+    {
+        SSL_set_rfd(ssl, rd->fd);
+        SSL_set_wfd(ssl, wr->fd);
+
+        ssl->biord = rd;
+        ssl->biowr = wr;
+    }
+
+
+    void SSL_CTX_set_client_CA_list(SSL_CTX* ctx, STACK_OF(X509_NAME)* names)
+    {
+   
+    }
+
+
+    STACK_OF(X509_NAME)* SSL_load_client_CA_file(const char* fname)
+    {
+        return 0;
+    }
+
+
+    int SSL_CTX_set_default_verify_paths(SSL_CTX* ctx)
+    {
+        /* TODO:, not needed in goahead */
+        return SSL_NOT_IMPLEMENTED;
+    }
+
+
+    void SSL_set_accept_state(SSL* ssl)
+    {
+        byte havePSK = 0;
+
+        ssl->options.side = SERVER_END;
+        /* reset suites in case user switched */
+#ifndef NO_PSK
+        havePSK = ssl->options.havePSK;
+#endif
+        InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, havePSK,
+                   ssl->options.haveNTRU);
+    }
+
+
+    void OpenSSL_add_all_algorithms(void)
+    {
+        InitCyaSSL(); 
+    }
+
+
+    int SSLeay_add_all_algorithms(void)
+    {
+        OpenSSL_add_all_algorithms(); 
+        return SSL_SUCCESS;
+    }
+
+    
+    void SSL_CTX_set_tmp_rsa_callback(SSL_CTX* ctx, RSA*(*f)(SSL*, int, int))
+    {
+        /* CyaSSL verifies all these internally */   
+    }
+
+
+    void SSL_set_shutdown(SSL* ssl, int opt)
+    {
+       
+    }
+
+
+    long SSL_CTX_set_options(SSL_CTX* ctx, long opt)
+    {
+        /* goahead calls with 0, do nothing */ 
+        return opt;
+    }
+
+
+    int SSL_set_rfd(SSL* ssl, int rfd)
+    {
+        ssl->rfd = rfd;      /* not used directly to allow IO callbacks */
+
+        ssl->IOCB_ReadCtx  = &ssl->rfd;
+
+        return SSL_SUCCESS;
+    }
+
+
+    int SSL_set_wfd(SSL* ssl, int wfd)
+    {
+        ssl->wfd = wfd;      /* not used directly to allow IO callbacks */
+
+        ssl->IOCB_WriteCtx  = &ssl->wfd;
+
+        return SSL_SUCCESS;
+    }
+
+
+    RSA* RSA_generate_key(int len, unsigned long bits, void(*f)(int,
+                                                        int, void*), void* data)
+    {
+        /* no tmp key needed, actual generation not supported */
+        return 0;
+    }
+
+
+    X509_NAME* X509_get_issuer_name(X509* cert)
+    {
+        return &cert->issuer;
+    }
+
+
+    X509_NAME* X509_get_subject_name(X509* cert)
+    {
+        return &cert->subject;
+    }
+
+
+    /* copy name into buffer, at most sz bytes, if buffer is null will
+       malloc buffer, call responsible for freeing                     */
+    char* X509_NAME_oneline(X509_NAME* name, char* buffer, int sz)
+    {
+        int copySz = min(sz, name->sz);
+        if (!name->sz) return buffer;
+
+        if (!buffer) {
+            buffer = (char*)XMALLOC(name->sz, 0, DYNAMIC_TYPE_OPENSSL);
+            if (!buffer) return buffer;
+            copySz = name->sz;
+        }
+
+        if (copySz == 0)
+            return buffer;
+
+        XMEMCPY(buffer, name->name, copySz - 1);
+        buffer[copySz - 1] = 0;
+
+        return buffer;
+    }
+
+
+    X509* X509_STORE_CTX_get_current_cert(X509_STORE_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    int X509_STORE_CTX_get_error(X509_STORE_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    int X509_STORE_CTX_get_error_depth(X509_STORE_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    BIO_METHOD* BIO_f_buffer(void)
+    {
+        static BIO_METHOD meth;
+        meth.type = BIO_BUFFER;
+
+        return &meth;
+    }
+
+
+    long BIO_set_write_buffer_size(BIO* bio, long size)
+    {
+        /* CyaSSL has internal buffer, compatibility only */
+        return size; 
+    }
+
+
+    BIO_METHOD* BIO_f_ssl(void)
+    {
+        static BIO_METHOD meth;
+        meth.type = BIO_SSL;
+
+        return &meth;
+    }
+
+
+    BIO* BIO_new_socket(int sfd, int close)
+    {
+        BIO* bio = (BIO*) XMALLOC(sizeof(BIO), 0, DYNAMIC_TYPE_OPENSSL);
+        if (bio) { 
+            bio->type  = BIO_SOCKET;
+            bio->close = close;
+            bio->eof   = 0;
+            bio->ssl   = 0;
+            bio->fd    = sfd;
+            bio->prev  = 0;
+            bio->next  = 0;
+        }
+        return bio; 
+    }
+
+
+    int BIO_eof(BIO* b)
+    {
+        if (b->eof)
+            return 1;
+
+        return 0;        
+    }
+
+
+    long BIO_set_ssl(BIO* b, SSL* ssl, int close)
+    {
+        b->ssl   = ssl;
+        b->close = close;
+    /* add to ssl for bio free if SSL_free called before/instead of free_all? */
+
+        return 0;
+    }
+
+
+    BIO* BIO_new(BIO_METHOD* method)
+    {
+        BIO* bio = (BIO*) XMALLOC(sizeof(BIO), 0, DYNAMIC_TYPE_OPENSSL);
+        if (bio) {
+            bio->type  = method->type;
+            bio->close = 0;
+            bio->eof   = 0;
+            bio->ssl   = 0;
+            bio->fd    = 0;
+            bio->prev  = 0;
+            bio->next  = 0;
+        }
+        return bio;
+    }
+
+
+#ifdef USE_WINDOWS_API 
+    #define CloseSocket(s) closesocket(s)
+#else
+    #define CloseSocket(s) close(s)
+#endif
+
+    int BIO_free(BIO* bio)
+    {
+        /* unchain?, doesn't matter in goahead since from free all */
+        if (bio) {
+            if (bio->close) {
+                if (bio->ssl)
+                    SSL_free(bio->ssl);
+                if (bio->fd)
+                    CloseSocket(bio->fd);
+            }
+            XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL);
+        }
+        return 0;
+    }
+
+
+    int BIO_free_all(BIO* bio)
+    {
+        BIO* next = bio;
+
+        while ( (bio = next) ) {
+            next = bio->next;
+            BIO_free(bio);
+        }
+        return 0;
+    }
+
+
+    int BIO_read(BIO* bio, void* buf, int len)
+    {
+        int  ret;
+        SSL* ssl = 0;
+        BIO* front = bio;
+
+        /* already got eof, again is error */
+        if (front->eof)
+            return -1;
+
+        while(bio && ((ssl = bio->ssl) == 0) )
+            bio = bio->next;
+
+        if (ssl == 0) return -1;
+
+        ret = SSL_read(ssl, buf, len);
+        if (ret == 0)
+            front->eof = 1;
+        else if (ret < 0) {
+            int err = SSL_get_error(ssl, 0);
+            if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
+                front->eof = 1;
+        }
+        return ret;
+    }
+
+
+    int BIO_write(BIO* bio, const void* data, int len)
+    {
+        int  ret;
+        SSL* ssl = 0;
+        BIO* front = bio;
+
+        /* already got eof, again is error */
+        if (front->eof)
+            return -1;
+
+        while(bio && ((ssl = bio->ssl) == 0) )
+            bio = bio->next;
+
+        if (ssl == 0) return -1;
+
+        ret = SSL_write(ssl, data, len);
+        if (ret == 0)
+            front->eof = 1;
+        else if (ret < 0) {
+            int err = SSL_get_error(ssl, 0);
+            if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
+                front->eof = 1;
+        }
+
+        return ret;
+    }
+
+
+    BIO* BIO_push(BIO* top, BIO* append)
+    {
+        top->next    = append;
+        append->prev = top;
+
+        return top;
+    }
+
+
+    int BIO_flush(BIO* bio)
+    {
+        /* for CyaSSL no flushing needed */
+        return 1;
+    }
+
+
+#endif /* OPENSSL_EXTRA || GOAHEAD_WS */
+
+
+#ifdef OPENSSL_EXTRA
+
+    unsigned long SSLeay(void)
+    {
+        return SSLEAY_VERSION_NUMBER;
+    }
+
+
+    const char* SSLeay_version(int type)
+    {
+        static const char* version = "SSLeay CyaSSL compatibility";
+        return version;
+    }
+
+
+    void MD5_Init(MD5_CTX* md5)
+    {
+        typedef char md5_test[sizeof(MD5_CTX) >= sizeof(Md5) ? 1 : -1];
+        (void)sizeof(md5_test);
+
+        InitMd5((Md5*)md5);
+    }
+
+
+    void MD5_Update(MD5_CTX* md5, const void* input, unsigned long sz)
+    {
+        Md5Update((Md5*)md5, (const byte*)input, sz);
+    }
+
+
+    void MD5_Final(byte* input, MD5_CTX* md5)
+    {
+        Md5Final((Md5*)md5, input);
+    }
+
+
+    void SHA_Init(SHA_CTX* sha)
+    {
+        typedef char sha_test[sizeof(SHA_CTX) >= sizeof(Sha) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        InitSha((Sha*)sha);
+    }
+
+
+    void SHA_Update(SHA_CTX* sha, const void* input, unsigned long sz)
+    {
+        ShaUpdate((Sha*)sha, (const byte*)input, sz);
+    }
+
+
+    void SHA_Final(byte* input, SHA_CTX* sha)
+    {
+        ShaFinal((Sha*)sha, input);
+    }
+
+
+    const EVP_MD* EVP_md5(void)
+    {
+        static const char* type = "MD5";
+        return type;
+    }
+
+
+    const EVP_MD* EVP_sha1(void)
+    {
+        static const char* type = "SHA";
+        return type;
+    }
+
+
+    void EVP_MD_CTX_init(EVP_MD_CTX* ctx)
+    {
+        /* do nothing */ 
+    }
+
+
+    int EVP_MD_CTX_cleanup(EVP_MD_CTX* ctx)
+    {
+        return 0;
+    }    
+
+
+    int EVP_DigestInit(EVP_MD_CTX* ctx, const EVP_MD* type)
+    {
+        if (XSTRNCMP(type, "MD5", 3) == 0) {
+             ctx->macType = MD5;
+             MD5_Init((MD5_CTX*)&ctx->hash);
+        }
+        else if (XSTRNCMP(type, "SHA", 3) == 0) {
+             ctx->macType = SHA;
+             SHA_Init((SHA_CTX*)&ctx->hash);
+        }
+        else
+             return -1;
+
+        return 0;
+    }
+
+
+    int EVP_DigestUpdate(EVP_MD_CTX* ctx, const void* data, size_t sz)
+    {
+        if (ctx->macType == MD5) 
+            MD5_Update((MD5_CTX*)&ctx->hash, data, (unsigned long)sz);
+        else if (ctx->macType == SHA) 
+            SHA_Update((SHA_CTX*)&ctx->hash, data, (unsigned long)sz);
+        else
+            return -1;
+
+        return 0;
+    }
+
+
+    int EVP_DigestFinal(EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s)
+    {
+        if (ctx->macType == MD5) {
+            MD5_Final(md, (MD5_CTX*)&ctx->hash);
+            if (s) *s = MD5_DIGEST_SIZE;
+        }
+        else if (ctx->macType == SHA) {
+            SHA_Final(md, (SHA_CTX*)&ctx->hash);
+            if (s) *s = SHA_DIGEST_SIZE;
+        }
+        else
+            return -1;
+
+        return 0;
+    }
+
+
+    int EVP_DigestFinal_ex(EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s)
+    {
+        return EVP_DigestFinal(ctx, md, s);
+    }
+
+
+    unsigned char* HMAC(const EVP_MD* evp_md, const void* key, int key_len,
+        const unsigned char* d, int n, unsigned char* md, unsigned int* md_len)
+    {
+        Hmac hmac;
+
+        if (!md) return 0;  /* no static buffer support */
+
+        if (XSTRNCMP(evp_md, "MD5", 3) == 0) {
+            HmacSetKey(&hmac, MD5, key, key_len);
+            if (md_len) *md_len = MD5_DIGEST_SIZE;
+        }
+        else if (XSTRNCMP(evp_md, "SHA", 3) == 0) {
+            HmacSetKey(&hmac, SHA, key, key_len);    
+            if (md_len) *md_len = SHA_DIGEST_SIZE;
+        }
+        else
+            return 0;
+
+        HmacUpdate(&hmac, d, n);
+        HmacFinal(&hmac, md);
+    
+        return md;
+    }
+
+    unsigned long ERR_get_error(void)
+    {
+        /* TODO: */
+        return 0;
+    }
+
+    void ERR_clear_error(void)
+    {
+        /* TODO: */
+    }
+
+
+    int RAND_status(void)
+    {
+        return 1;  /* CTaoCrypt provides enough seed internally */
+    }
+
+
+    int RAND_bytes(unsigned char* buf, int num)
+    {
+        RNG rng;
+
+        if (InitRng(&rng))
+           return 0;
+
+        RNG_GenerateBlock(&rng, buf, num);
+
+        return 1;
+    }
+
+
+    int DES_key_sched(const_DES_cblock* key, DES_key_schedule* schedule)
+    {
+        XMEMCPY(schedule, key, sizeof(const_DES_cblock));
+        return 0;
+    }
+
+
+    void DES_cbc_encrypt(const unsigned char* input, unsigned char* output,
+                     long length, DES_key_schedule* schedule, DES_cblock* ivec,
+                     int enc)
+    {
+        Des des;
+        Des_SetKey(&des, (const byte*)schedule, (const byte*)ivec, !enc);
+
+        if (enc)
+            Des_CbcEncrypt(&des, output, input, length);
+        else
+            Des_CbcDecrypt(&des, output, input, length);
+    }
+
+
+    /* correctly sets ivec for next call */
+    void DES_ncbc_encrypt(const unsigned char* input, unsigned char* output,
+                     long length, DES_key_schedule* schedule, DES_cblock* ivec,
+                     int enc)
+    {
+        Des des;
+        Des_SetKey(&des, (const byte*)schedule, (const byte*)ivec, !enc);
+
+        if (enc)
+            Des_CbcEncrypt(&des, output, input, length);
+        else
+            Des_CbcDecrypt(&des, output, input, length);
+
+        XMEMCPY(ivec, output + length - sizeof(DES_cblock), sizeof(DES_cblock));
+    }
+
+
+    void ERR_free_strings(void)
+    {
+        /* handled internally */
+    }
+
+
+    void ERR_remove_state(unsigned long state)
+    {
+        /* TODO: GetErrors().Remove(); */
+    }
+
+
+    void EVP_cleanup(void)
+    {
+        /* nothing to do here */
+    }
+
+
+    void CRYPTO_cleanup_all_ex_data(void)
+    {
+        /* nothing to do here */
+    }
+
+
+    long SSL_CTX_set_mode(SSL_CTX* ctx, long mode)
+    {
+        /* SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is CyaSSL default mode */
+
+        if (mode == SSL_MODE_ENABLE_PARTIAL_WRITE)
+            ctx->partialWrite = 1;
+
+        return mode;
+    }
+
+
+    long SSL_CTX_get_mode(SSL_CTX* ctx)
+    {
+        /* TODO: */
+        return 0;
+    }
+
+
+    void SSL_CTX_set_default_read_ahead(SSL_CTX* ctx, int m)
+    {
+        /* TODO: maybe? */
+    }
+
+
+    int SSL_CTX_set_session_id_context(SSL_CTX* ctx,
+                                       const unsigned char* sid_ctx,
+                                       unsigned int sid_ctx_len)
+    {
+        /* No application specific context needed for cyaSSL */
+        return SSL_SUCCESS;
+    }
+
+
+    long SSL_CTX_sess_get_cache_size(SSL_CTX* ctx)
+    {
+        /* TODO: maybe? */
+        return (~0);
+    }
+
+    unsigned long ERR_get_error_line_data(const char** file, int* line,
+                                          const char** data, int *flags)
+    {
+        /* Not implemented */
+        return 0;
+    }
+
+
+    X509* SSL_get_peer_certificate(SSL* ssl)
+    {
+        if (ssl->peerCert.issuer.sz)
+            return &ssl->peerCert;
+        else
+            return 0;
+    }
+
+
+
+    int SSL_set_ex_data(SSL* ssl, int idx, void* data)
+    {
+        return 0;
+    }
+
+
+    int SSL_get_shutdown(const SSL* ssl)
+    {
+        return 0;
+    }
+
+
+    int SSL_set_session_id_context(SSL* ssl, const unsigned char* id,
+                                   unsigned int len)
+    {
+        return 0;
+    }
+
+
+    void SSL_set_connect_state(SSL* ssl)
+    {
+        /* client by default */ 
+    }
+
+
+    int SSL_session_reused(SSL* ssl)
+    {
+        return ssl->options.resuming;
+    }
+
+
+    void SSL_SESSION_free(SSL_SESSION* session)
+    {
+     
+    }
+
+
+    const char* SSL_get_version(SSL* ssl)
+    {
+        if (ssl->version.major == 3) {
+            switch (ssl->version.minor) {
+                case 0 :
+                    return "SSLv3";
+                case 1 :
+                    return "TLSv1";
+                case 2 :
+                    return "TLSv1.1";
+                case 3 :
+                    return "TLSv1.2";
+            }
+        }
+        return "unknown";
+    }
+
+
+    SSL_CIPHER*  SSL_get_current_cipher(SSL* ssl)
+    {
+        return &ssl->cipher;
+    }
+
+
+    const char* SSL_CIPHER_get_name(const SSL_CIPHER* cipher)
+    {
+        if (cipher) {
+            switch (cipher->ssl->options.cipherSuite) {
+                case SSL_RSA_WITH_RC4_128_SHA :
+                    return "SSL_RSA_WITH_RC4_128_SHA";
+                case SSL_RSA_WITH_RC4_128_MD5 :
+                    return "SSL_RSA_WITH_RC4_128_MD5";
+                case SSL_RSA_WITH_3DES_EDE_CBC_SHA :
+                    return "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
+                case TLS_RSA_WITH_AES_128_CBC_SHA :
+                    return "TLS_RSA_WITH_AES_128_CBC_SHA";
+                case TLS_RSA_WITH_AES_256_CBC_SHA :
+                    return "TLS_RSA_WITH_AES_256_CBC_SHA";
+                case TLS_PSK_WITH_AES_128_CBC_SHA :
+                    return "TLS_PSK_WITH_AES_128_CBC_SHA";
+                case TLS_PSK_WITH_AES_256_CBC_SHA :
+                    return "TLS_PSK_WITH_AES_256_CBC_SHA";
+                case TLS_DHE_RSA_WITH_AES_128_CBC_SHA :
+                    return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
+                case TLS_DHE_RSA_WITH_AES_256_CBC_SHA :
+                    return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
+                case TLS_RSA_WITH_HC_128_CBC_MD5 :
+                    return "TLS_RSA_WITH_HC_128_CBC_MD5";
+                case TLS_RSA_WITH_HC_128_CBC_SHA :
+                    return "TLS_RSA_WITH_HC_128_CBC_SHA";
+                case TLS_RSA_WITH_RABBIT_CBC_SHA :
+                    return "TLS_RSA_WITH_RABBIT_CBC_SHA";
+                case TLS_NTRU_RSA_WITH_RC4_128_SHA :
+                    return "TLS_NTRU_RSA_WITH_RC4_128_SHA";
+                case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
+                    return "TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA";
+                case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA :
+                    return "TLS_NTRU_RSA_WITH_AES_128_CBC_SHA";
+                case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA :
+                    return "TLS_NTRU_RSA_WITH_AES_256_CBC_SHA";
+            }
+        }
+
+        return "NONE";
+    }
+
+
+    char* SSL_CIPHER_description(SSL_CIPHER* cipher, char* buffer, int len)
+    {
+        return 0;
+    }
+
+
+    SSL_SESSION* SSL_get1_session(SSL* ssl)  /* what's ref count */
+    {
+        return 0;
+    }
+
+
+    void X509_free(X509* buf)
+    {
+       
+    }
+
+
+    void OPENSSL_free(void* buf)
+    {
+  
+    }
+
+
+    int OCSP_parse_url(char* url, char** host, char** port, char** path,
+                       int* ssl)
+    {
+        return 0;
+    }
+
+
+    SSL_METHOD* SSLv2_client_method(void)
+    {
+        return 0;
+    }
+
+
+    SSL_METHOD* SSLv2_server_method(void)
+    {
+        return 0;
+    }
+
+
+#ifndef NO_MD4
+
+    void MD4_Init(MD4_CTX* md4)
+    {
+        /* make sure we have a big enough buffer */
+        typedef char ok[sizeof(md4->buffer) >= sizeof(Md4) ? 1 : -1];
+        (void) sizeof(ok);
+ 
+        InitMd4((Md4*)md4);    
+    }
+
+
+    void MD4_Update(MD4_CTX* md4, const void* data, size_t len)
+    {
+        Md4Update((Md4*)md4, (const byte*)data, (word32)len); 
+    }
+
+
+    void MD4_Final(unsigned char* digest, MD4_CTX* md4)
+    {
+        Md4Final((Md4*)md4, digest); 
+    }
+
+#endif /* NO_MD4 */
+
+
+    BIO* BIO_pop(BIO* top)
+    {
+        return 0;
+    }
+
+
+    int BIO_pending(BIO* bio)
+    {
+        return 0;
+    }
+
+
+
+    BIO_METHOD* BIO_s_mem(void)
+    {
+        return 0;
+    }
+
+
+    BIO_METHOD* BIO_f_base64(void)
+    {
+        return 0;
+    }
+
+
+    void BIO_set_flags(BIO* bio, int flags)
+    {
+     
+    }
+
+
+
+    void RAND_screen(void)
+    {
+    
+    }
+
+
+    const char* RAND_file_name(char* fname, size_t len)
+    {
+        return 0;
+    }
+
+
+    int RAND_write_file(const char* fname)
+    {
+        return 0;
+    }
+
+
+    int RAND_load_file(const char* fname, long len)
+    {
+        /* CTaoCrypt provides enough entropy internally or will report error */
+        if (len == -1)
+            return 1024;
+        else
+            return (int)len;
+    }
+
+
+    int RAND_egd(const char* path)
+    {
+        return 0;
+    }
+
+
+
+    COMP_METHOD* COMP_zlib(void)
+    {
+        return 0;
+    }
+
+
+    COMP_METHOD* COMP_rle(void)
+    {
+        return 0;
+    }
+
+
+    int SSL_COMP_add_compression_method(int method, void* data)
+    {
+        return 0;
+    }
+
+
+
+    int SSL_get_ex_new_index(long idx, void* data, void* cb1, void* cb2,
+                             void* cb3)
+    {
+        return 0;
+    }
+
+
+    int CRYPTO_num_locks(void)
+    {
+        return 0;
+    }
+
+
+    void CRYPTO_set_id_callback(unsigned long (*f)(void))
+    {
+    
+    }
+
+
+    void CRYPTO_set_locking_callback(void (*f)(int, int, const char*, int))
+    {
+      
+    }
+
+
+    void CRYPTO_set_dynlock_create_callback(CRYPTO_dynlock_value* (*f)(
+                                                              const char*, int))
+    {
+     
+    }
+
+
+    void CRYPTO_set_dynlock_lock_callback(void (*f)(int, CRYPTO_dynlock_value*,
+                                                const char*, int))
+    {
+     
+    }
+
+
+    void CRYPTO_set_dynlock_destroy_callback(void (*f)(CRYPTO_dynlock_value*,
+                                                   const char*, int))
+    {
+      
+    }
+
+
+
+    const char* X509_verify_cert_error_string(long err)
+    {
+        return 0;
+    }
+
+
+
+    int X509_LOOKUP_add_dir(X509_LOOKUP* lookup, const char* dir, long len)
+    {
+        return 0;
+    }
+
+
+    int X509_LOOKUP_load_file(X509_LOOKUP* lookup, const char* file, long len)
+    {
+        return 0;
+    }
+
+
+    X509_LOOKUP_METHOD* X509_LOOKUP_hash_dir(void)
+    {
+        return 0;
+    }
+
+
+    X509_LOOKUP_METHOD* X509_LOOKUP_file(void)
+    {
+        return 0;
+    }
+
+
+
+    X509_LOOKUP* X509_STORE_add_lookup(X509_STORE* store, X509_LOOKUP_METHOD* m)
+    {
+        return 0;
+    }
+
+
+    X509_STORE* X509_STORE_new(void)
+    {
+        return 0;
+    }
+
+
+    int X509_STORE_get_by_subject(X509_STORE_CTX* ctx, int idx, X509_NAME* name,
+                                       X509_OBJECT* obj)
+    {
+        return 0;
+    }
+
+
+    int X509_STORE_CTX_init(X509_STORE_CTX* ctx, X509_STORE* store, X509* x509,
+                            STACK_OF(X509)* sk)
+    {
+        return 0;
+    }
+
+
+    void X509_STORE_CTX_cleanup(X509_STORE_CTX* ctx)
+    {
+ 
+    }
+
+
+
+    ASN1_TIME* X509_CRL_get_lastUpdate(X509_CRL* crl)
+    {
+        return 0;
+    }
+
+
+    ASN1_TIME* X509_CRL_get_nextUpdate(X509_CRL* crl)
+    {
+        return 0;
+    }
+
+
+
+    EVP_PKEY* X509_get_pubkey(X509* x509)
+    {
+        return 0;
+    }
+
+
+    int X509_CRL_verify(X509_CRL* crl, EVP_PKEY* key)
+    {
+        return 0;
+    }
+
+
+    void X509_STORE_CTX_set_error(X509_STORE_CTX* ctx, int err)
+    {
+ 
+    }
+
+
+    void X509_OBJECT_free_contents(X509_OBJECT* obj)
+    {
+  
+    }
+
+
+    void EVP_PKEY_free(EVP_PKEY* key)
+    {
+     
+    }
+
+
+    int X509_cmp_current_time(const ASN1_TIME* time)
+    {
+        return 0;
+    }
+
+
+    int sk_X509_REVOKED_num(X509_REVOKED* revoked)
+    {
+        return 0;
+    }
+
+
+
+    X509_REVOKED* X509_CRL_get_REVOKED(X509_CRL* crl)
+    {
+        return 0;
+    }
+
+
+    X509_REVOKED* sk_X509_REVOKED_value(X509_REVOKED* revoked, int value)
+    {
+        return 0;
+    }
+
+
+
+    ASN1_INTEGER* X509_get_serialNumber(X509* x509)
+    {
+        return 0;
+    }
+
+
+
+    int ASN1_TIME_print(BIO* bio, const ASN1_TIME* time)
+    {
+        return 0;
+    }
+
+
+
+    int ASN1_INTEGER_cmp(const ASN1_INTEGER* a, const ASN1_INTEGER* b)
+    {
+        return 0;
+    }
+
+
+    long ASN1_INTEGER_get(const ASN1_INTEGER* i)
+    {
+        return 0;
+    }
+
+
+
+    void* X509_STORE_CTX_get_ex_data(X509_STORE_CTX* ctx, int idx)
+    {
+        return 0;
+    }
+
+
+    int SSL_get_ex_data_X509_STORE_CTX_idx(void)
+    {
+        return 0;
+    }
+
+
+    void* SSL_get_ex_data(const SSL* ssl, int idx)
+    {
+        return 0;
+    }
+
+
+    void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX* ctx, void* userdata)
+    {
+        ctx->userdata = userdata;
+    }
+
+
+    void SSL_CTX_set_default_passwd_cb(SSL_CTX* ctx, pem_password_cb cb)
+    {
+        ctx->passwd_cb = cb;
+    }
+
+
+    long SSL_CTX_set_timeout(SSL_CTX* ctx, long to)
+    {
+        return 0;
+    }
+
+
+    void SSL_CTX_set_info_callback(SSL_CTX* ctx, void (*f)())
+    {
+        
+    }
+
+
+    unsigned long ERR_peek_error(void)
+    {
+        return 0;
+    }
+
+
+    int ERR_GET_REASON(int err)
+    {
+        return 0;
+    }
+
+
+    char* SSL_alert_type_string_long(int alert)
+    {
+        return 0;
+    }
+
+
+    char* SSL_alert_desc_string_long(int alert)
+    {
+        return 0;
+    }
+
+
+    char* SSL_state_string_long(SSL* ssl)
+    {
+        return 0;
+    }
+
+
+
+    void RSA_free(RSA* rsa)
+    {
+        
+    }
+
+
+    int PEM_def_callback(char* name, int num, int w, void* key)
+    {
+        return 0;
+    }
+    
+
+    long SSL_CTX_sess_accept(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_connect(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_accept_good(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_connect_good(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_accept_renegotiate(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_connect_renegotiate(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_hits(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_cb_hits(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_cache_full(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_misses(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_timeouts(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_number(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    void DES_set_key_unchecked(const_DES_cblock* des, DES_key_schedule* key)
+    {
+    }
+
+
+    void DES_set_odd_parity(DES_cblock* des)
+    {
+    }
+
+    
+    void DES_ecb_encrypt(DES_cblock* desa, DES_cblock* desb,
+                         DES_key_schedule* key, int len)
+    {
+    }
+
+    int BIO_printf(BIO* bio, const char* format, ...)
+    {
+        return 0;
+    }
+
+
+    int ASN1_UTCTIME_print(BIO* bio, const ASN1_UTCTIME* a)
+    {
+        return 0;
+    }
+    
+
+    int  sk_num(X509_REVOKED* rev)
+    {
+        return 0;
+    }
+
+
+    void* sk_value(X509_REVOKED* rev, int i)
+    {
+        return 0;
+    }
+
+
+    int EVP_BytesToKey(const EVP_CIPHER* type, const EVP_MD* md,
+                       const byte* salt, const byte* data, int sz, int count,
+                       byte* key, byte* iv)
+    {
+        int keyLen = 0;
+        int ivLen  = 0;
+
+        Md5    myMD;
+        byte   digest[MD5_DIGEST_SIZE];
+
+        int j;
+        int keyLeft;
+        int ivLeft;
+        int keyOutput = 0;
+
+        InitMd5(&myMD);
+
+        /* only support MD5 for now */
+        if (XSTRNCMP(md, "MD5", 3)) return 0;
+
+        /* only support CBC DES and AES for now */
+        if (XSTRNCMP(type, "DES-CBC", 7) == 0) {
+            keyLen = DES_KEY_SIZE;
+            ivLen  = DES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "DES-EDE3-CBC", 12) == 0) {
+            keyLen = DES3_KEY_SIZE;
+            ivLen  = DES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "AES-128-CBC", 11) == 0) {
+            keyLen = AES_128_KEY_SIZE;
+            ivLen  = AES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "AES-192-CBC", 11) == 0) {
+            keyLen = AES_192_KEY_SIZE;
+            ivLen  = AES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "AES-256-CBC", 11) == 0) {
+            keyLen = AES_256_KEY_SIZE;
+            ivLen  = AES_IV_SIZE;
+        }
+        else
+            return 0;
+
+        keyLeft   = keyLen;
+        ivLeft    = ivLen;
+
+        while (keyOutput < (keyLen + ivLen)) {
+            int digestLeft = MD5_DIGEST_SIZE;
+            /* D_(i - 1) */
+            if (keyOutput)                      /* first time D_0 is empty */
+                Md5Update(&myMD, digest, MD5_DIGEST_SIZE);
+            /* data */
+            Md5Update(&myMD, data, sz);
+            /* salt */
+            if (salt)
+                Md5Update(&myMD, salt, EVP_SALT_SIZE);
+            Md5Final(&myMD, digest);
+            /* count */
+            for (j = 1; j < count; j++) {
+                Md5Update(&myMD, digest, MD5_DIGEST_SIZE);
+                Md5Final(&myMD, digest);
+            }
+
+            if (keyLeft) {
+                int store = min(keyLeft, MD5_DIGEST_SIZE);
+                XMEMCPY(&key[keyLen - keyLeft], digest, store);
+
+                keyOutput  += store;
+                keyLeft    -= store;
+                digestLeft -= store;
+            }
+
+            if (ivLeft && digestLeft) {
+                int store = min(ivLeft, digestLeft);
+                XMEMCPY(&iv[ivLen - ivLeft], &digest[MD5_DIGEST_SIZE -
+                                                    digestLeft], store);
+                keyOutput += store;
+                ivLeft    -= store;
+            }
+        }
+        if (keyOutput != (keyLen + ivLen))
+            return 0;
+        return keyOutput;
+    }
+
+    /* stunnel 4.28 needs */
+    void* SSL_CTX_get_ex_data(const SSL_CTX* ctx, int d)
+    {
+        return 0;
+    }
+
+
+    int SSL_CTX_set_ex_data(SSL_CTX* ctx, int d, void* p)
+    {
+        return SSL_SUCCESS;
+    }
+
+
+    void SSL_CTX_sess_set_get_cb(SSL_CTX* ctx, SSL_SESSION*(*f)(SSL*,
+                                                    unsigned char*, int, int*))
+    {
+       
+    }
+
+
+    void SSL_CTX_sess_set_new_cb(SSL_CTX* ctx, int (*f)(SSL*, SSL_SESSION*))
+    {
+
+    }
+
+
+    void SSL_CTX_sess_set_remove_cb(SSL_CTX* ctx, void (*f)(SSL_CTX*,
+                                                            SSL_SESSION*))
+    {
+
+    }
+
+
+    int i2d_SSL_SESSION(SSL_SESSION* sess, unsigned char** p)
+    {
+        return sizeof(SSL_SESSION);
+    }
+
+
+    SSL_SESSION* d2i_SSL_SESSION(SSL_SESSION** sess, const unsigned char** p,
+                                 long i)
+    {
+        return *sess;
+    }
+
+
+    long SSL_SESSION_get_timeout(const SSL_SESSION* sess)
+    {
+        return sess->timeout;
+    }
+
+
+    long SSL_SESSION_get_time(const SSL_SESSION* sess)
+    {
+        return sess->bornOn;
+    }
+
+
+    int SSL_CTX_get_ex_new_index(long idx, void* arg, void* a, void* b, void* c)
+    {
+        return 0; 
+    }
+
+
+#endif /* OPENSSL_EXTRA */
+
+
+#ifdef SESSION_CERTS
+
+
+/* Get peer's certificate chain */
+X509_CHAIN* CyaSSL_get_peer_chain(SSL* ssl)
+{
+    if (ssl)
+        return &ssl->session.chain;
+
+    return 0;
+}
+
+
+/* Get peer's certificate chain total count */
+int CyaSSL_get_chain_count(X509_CHAIN* chain)
+{
+    if (chain)
+        return chain->count;
+
+    return 0;
+}
+
+
+/* Get peer's ASN.1 DER ceritifcate at index (idx) length in bytes */
+int CyaSSL_get_chain_length(X509_CHAIN* chain, int idx)
+{
+    if (chain)
+        return chain->certs[idx].length;
+
+    return 0;
+}
+
+
+/* Get peer's ASN.1 DER ceritifcate at index (idx) */
+byte* CyaSSL_get_chain_cert(X509_CHAIN* chain, int idx)
+{
+    if (chain)
+        return chain->certs[idx].buffer;
+
+    return 0;
+}
+
+
+/* Get peer's PEM ceritifcate at index (idx), output to buffer if inLen big
+   enough else return error (-1), output length is in *outLen */
+int  CyaSSL_get_chain_cert_pem(X509_CHAIN* chain, int idx,
+                               unsigned char* buffer, int inLen, int* outLen)
+{
+    const char header[] = "-----BEGIN CERTIFICATE-----\n";
+    const char footer[] = "-----END CERTIFICATE-----\n";
+
+    int headerLen = sizeof(header) - 1;
+    int footerLen = sizeof(footer) - 1;
+    int i;
+
+    if (!chain || !outLen || !buffer)
+        return -1;
+
+    /* don't even try if inLen too short */
+    if (inLen < headerLen + footerLen + chain->certs[idx].length)
+        return -1;
+
+    /* header */
+    XMEMCPY(buffer, header, headerLen);
+    i = headerLen;
+
+    /* body */
+    *outLen = inLen;  /* input to Base64Encode */
+    if (Base64Encode(chain->certs[idx].buffer, chain->certs[idx].length,
+                     buffer + i, (word32*)outLen) < 0)
+        return -1;
+    i += *outLen;
+
+    /* footer */
+    if ( (i + footerLen) > inLen)
+        return -1;
+    XMEMCPY(buffer + i, footer, footerLen);
+    *outLen += headerLen + footerLen; 
+
+    return 0;
+}
+
+
+/* get session ID */
+const byte* CyaSSL_get_sessionID(const SSL_SESSION* session)
+{
+    return session->sessionID;
+}
+
+
+#endif /* SESSION_CERTS */
+
diff -r 000000000000 -r 5045d2638c29 ssl.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,675 @@
+/* ssl.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  ssl.h defines openssl compatibility layer 
+ *
+ */
+
+
+
+#ifndef CYASSL_OPENSSL_H_
+#define CYASSL_OPENSSL_H_
+
+#include "os_settings.h"   /* for users not using preprocessor flags */
+
+#ifndef NO_FILESYTEM
+    #include <stdio.h>   /* ERR_print fp */
+#endif
+
+#ifdef YASSL_PREFIX
+    #include "prefix_ssl.h"
+#endif
+
+#undef X509_NAME   /* wincrypt.h clash */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+typedef struct SSL          SSL;          
+typedef struct SSL_SESSION  SSL_SESSION;
+typedef struct SSL_METHOD   SSL_METHOD;
+typedef struct SSL_CTX      SSL_CTX;
+
+typedef struct X509       X509;
+typedef struct X509_NAME  X509_NAME;
+typedef struct X509_CHAIN X509_CHAIN;
+
+
+/* redeclare guard */
+#define SSL_TYPES_DEFINED
+
+
+
+
+typedef struct EVP_PKEY       EVP_PKEY;
+typedef struct RSA            RSA;
+typedef struct BIO            BIO;
+typedef struct BIO_METHOD     BIO_METHOD;
+typedef struct SSL_CIPHER     SSL_CIPHER;
+typedef struct X509_LOOKUP    X509_LOOKUP;
+typedef struct X509_LOOKUP_METHOD X509_LOOKUP_METHOD;
+typedef struct X509_CRL       X509_CRL;
+typedef struct X509_EXTENSION X509_EXTENSION;
+typedef struct ASN1_TIME      ASN1_TIME;
+typedef struct ASN1_INTEGER   ASN1_INTEGER;
+typedef struct ASN1_OBJECT    ASN1_OBJECT;
+typedef struct ASN1_STRING    ASN1_STRING;
+typedef struct CRYPTO_dynlock_value CRYPTO_dynlock_value;
+
+#define ASN1_UTCTIME ASN1_TIME
+
+typedef struct MD4_CTX {
+    int buffer[32];      /* big enough to hold, check size in Init */
+} MD4_CTX;
+
+
+typedef struct COMP_METHOD {
+    int type;            /* stunnel dereference */
+} COMP_METHOD;
+
+
+typedef struct X509_STORE {
+    int cache;          /* stunnel dereference */
+} X509_STORE;
+
+
+typedef struct X509_REVOKED {
+    ASN1_INTEGER* serialNumber;          /* stunnel dereference */
+} X509_REVOKED;
+
+
+typedef struct X509_OBJECT {
+    union {
+        char* ptr;
+        X509_CRL* crl;           /* stunnel dereference */
+    } data;
+} X509_OBJECT;
+
+
+/* in cyassl_int.h too, change there !! */
+typedef struct X509_STORE_CTX {
+    int   error;
+    int   error_depth;
+    X509* current_cert;          /* stunnel dereference */
+    char* domain;                /* subject CN domain name */
+    /* in cyassl_int.h too, change there !! */
+} X509_STORE_CTX;
+
+
+SSL_METHOD *SSLv3_server_method(void);
+SSL_METHOD *SSLv3_client_method(void);
+SSL_METHOD *TLSv1_server_method(void);  
+SSL_METHOD *TLSv1_client_method(void);
+SSL_METHOD *TLSv1_1_server_method(void);  
+SSL_METHOD *TLSv1_1_client_method(void);
+SSL_METHOD *TLSv1_2_server_method(void);  
+SSL_METHOD *TLSv1_2_client_method(void);
+
+#ifdef CYASSL_DTLS
+    SSL_METHOD *DTLSv1_client_method(void);
+    SSL_METHOD *DTLSv1_server_method(void);
+#endif
+
+#ifndef NO_FILESYSTEM
+
+int SSL_CTX_use_certificate_file(SSL_CTX*, const char*, int);
+int SSL_CTX_use_PrivateKey_file(SSL_CTX*, const char*, int);
+int SSL_CTX_load_verify_locations(SSL_CTX*, const char*, const char*);
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file);
+int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX*, const char*, int);
+
+#ifdef CYASSL_DER_LOAD
+    int CyaSSL_CTX_load_verify_locations(SSL_CTX*, const char*, int);
+#endif
+
+#ifdef HAVE_NTRU
+    int CyaSSL_CTX_use_NTRUPrivateKey_file(SSL_CTX*, const char*); /* load NTRU 
+                                                             private key blob */
+#endif
+
+int CyaSSL_PemCertToDer(const char*, unsigned char*, int);
+
+#endif /* NO_FILESYSTEM */
+
+SSL_CTX* SSL_CTX_new(SSL_METHOD*);
+SSL* SSL_new(SSL_CTX*);
+int  SSL_set_fd (SSL*, int);
+int  SSL_get_fd(const SSL*);
+int  SSL_connect(SSL*);                   /* please see note at top of README
+                                             if you get an error from connect */
+int  SSL_write(SSL*, const void*, int);
+int  SSL_read(SSL*, void*, int);
+int  SSL_accept(SSL*);
+void SSL_CTX_free(SSL_CTX*);
+void SSL_free(SSL*);
+int  SSL_shutdown(SSL*);
+
+void SSL_CTX_set_quiet_shutdown(SSL_CTX*, int);
+
+int  SSL_get_error(SSL*, int);
+
+int          SSL_set_session(SSL *ssl, SSL_SESSION *session);
+SSL_SESSION* SSL_get_session(SSL* ssl);
+void         SSL_flush_sessions(SSL_CTX *ctx, long tm);
+
+
+typedef int (*VerifyCallback)(int, X509_STORE_CTX*);
+typedef int (*pem_password_cb)(char*, int, int, void*);
+
+void SSL_CTX_set_verify(SSL_CTX*, int, VerifyCallback verify_callback);
+
+
+int  SSL_pending(SSL*);
+
+
+void SSL_load_error_strings(void);
+int  SSL_library_init(void);
+long SSL_CTX_set_session_cache_mode(SSL_CTX*, long);
+
+/* only supports full name from cipher_name[] delimited by : */
+int  SSL_CTX_set_cipher_list(SSL_CTX*, const char*);
+
+char* ERR_error_string(unsigned long,char*);
+void  ERR_error_string_n(unsigned long e, char *buf, size_t len);
+
+
+/* extras */
+
+#define STACK_OF(x) x
+
+int  SSL_set_ex_data(SSL*, int, void*);
+int  SSL_get_shutdown(const SSL*);
+int  SSL_set_rfd(SSL*, int);
+int  SSL_set_wfd(SSL*, int);
+void SSL_set_shutdown(SSL*, int);
+int  SSL_set_session_id_context(SSL*, const unsigned char*, unsigned int);
+void SSL_set_connect_state(SSL*);
+void SSL_set_accept_state(SSL*);
+int  SSL_session_reused(SSL*);
+void SSL_SESSION_free(SSL_SESSION* session);
+
+const char*  SSL_get_version(SSL*);
+SSL_CIPHER*  SSL_get_current_cipher(SSL*);
+char*        SSL_CIPHER_description(SSL_CIPHER*, char*, int);
+const char*  SSL_CIPHER_get_name(const SSL_CIPHER* cipher);
+SSL_SESSION* SSL_get1_session(SSL* ssl);  /* what's ref count */
+
+void X509_free(X509*);
+void OPENSSL_free(void*);
+
+int OCSP_parse_url(char* url, char** host, char** port, char** path, int* ssl);
+
+SSL_METHOD* SSLv23_client_method(void);
+SSL_METHOD* SSLv2_client_method(void);
+SSL_METHOD* SSLv2_server_method(void);
+
+void MD4_Init(MD4_CTX*);
+void MD4_Update(MD4_CTX*, const void*, size_t);
+void MD4_Final(unsigned char*, MD4_CTX*);
+
+BIO* BIO_new(BIO_METHOD*);
+int  BIO_free(BIO*);
+int  BIO_free_all(BIO*);
+int  BIO_read(BIO*, void*, int);
+int  BIO_write(BIO*, const void*, int);
+BIO* BIO_push(BIO*, BIO* append);
+BIO* BIO_pop(BIO*);
+int  BIO_flush(BIO*);
+int  BIO_pending(BIO*);
+
+BIO_METHOD* BIO_f_buffer(void);
+long        BIO_set_write_buffer_size(BIO*, long size);
+BIO_METHOD* BIO_f_ssl(void);
+BIO*        BIO_new_socket(int sfd, int flag);
+void        SSL_set_bio(SSL*, BIO* rd, BIO* wr);
+int         BIO_eof(BIO*);
+long        BIO_set_ssl(BIO*, SSL*, int flag);
+
+BIO_METHOD* BIO_s_mem(void);
+BIO_METHOD* BIO_f_base64(void);
+void        BIO_set_flags(BIO*, int);
+
+void OpenSSL_add_all_algorithms(void);
+int  SSLeay_add_ssl_algorithms(void);
+int  SSLeay_add_all_algorithms(void);
+
+void        RAND_screen(void);
+const char* RAND_file_name(char*, size_t);
+int         RAND_write_file(const char*);
+int         RAND_load_file(const char*, long);
+int         RAND_egd(const char*);
+
+COMP_METHOD* COMP_zlib(void);
+COMP_METHOD* COMP_rle(void);
+int SSL_COMP_add_compression_method(int, void*);
+
+int SSL_get_ex_new_index(long, void*, void*, void*, void*);
+
+void CRYPTO_set_id_callback(unsigned long (*f)(void));
+void CRYPTO_set_locking_callback(void (*f)(int, int, const char*, int));
+void CRYPTO_set_dynlock_create_callback(CRYPTO_dynlock_value* (*f)(const char*,
+                                                                   int));
+void CRYPTO_set_dynlock_lock_callback(void (*f)(int, CRYPTO_dynlock_value*,
+                                                const char*, int));
+void CRYPTO_set_dynlock_destroy_callback(void (*f)(CRYPTO_dynlock_value*,
+                                                   const char*, int));
+
+X509* X509_STORE_CTX_get_current_cert(X509_STORE_CTX*);
+int   X509_STORE_CTX_get_error(X509_STORE_CTX*);
+int   X509_STORE_CTX_get_error_depth(X509_STORE_CTX*);
+
+char*       X509_NAME_oneline(X509_NAME*, char*, int);
+X509_NAME*  X509_get_issuer_name(X509*);
+X509_NAME*  X509_get_subject_name(X509*);
+const char* X509_verify_cert_error_string(long);
+
+int                 X509_LOOKUP_add_dir(X509_LOOKUP*, const char*, long);
+int                 X509_LOOKUP_load_file(X509_LOOKUP*, const char*, long);
+X509_LOOKUP_METHOD* X509_LOOKUP_hash_dir(void);
+X509_LOOKUP_METHOD* X509_LOOKUP_file(void);
+
+X509_LOOKUP* X509_STORE_add_lookup(X509_STORE*, X509_LOOKUP_METHOD*);
+X509_STORE*  X509_STORE_new(void);
+int          X509_STORE_get_by_subject(X509_STORE_CTX*, int, X509_NAME*,
+                                       X509_OBJECT*);
+int  X509_STORE_CTX_init(X509_STORE_CTX*, X509_STORE*, X509*, STACK_OF(X509)*);
+void X509_STORE_CTX_cleanup(X509_STORE_CTX*);
+
+ASN1_TIME* X509_CRL_get_lastUpdate(X509_CRL*);
+ASN1_TIME* X509_CRL_get_nextUpdate(X509_CRL*);
+
+EVP_PKEY* X509_get_pubkey(X509*);
+int       X509_CRL_verify(X509_CRL*, EVP_PKEY*);
+void      X509_STORE_CTX_set_error(X509_STORE_CTX*, int);
+void      X509_OBJECT_free_contents(X509_OBJECT*);
+void      EVP_PKEY_free(EVP_PKEY*);
+int       X509_cmp_current_time(const ASN1_TIME*);
+int       sk_X509_REVOKED_num(X509_REVOKED*);
+
+X509_REVOKED* X509_CRL_get_REVOKED(X509_CRL*);
+X509_REVOKED* sk_X509_REVOKED_value(X509_REVOKED*, int);
+
+ASN1_INTEGER* X509_get_serialNumber(X509*);
+
+int ASN1_TIME_print(BIO*, const ASN1_TIME*);
+
+int  ASN1_INTEGER_cmp(const ASN1_INTEGER*, const ASN1_INTEGER*);
+long ASN1_INTEGER_get(const ASN1_INTEGER*);
+
+STACK_OF(X509_NAME)* SSL_load_client_CA_file(const char*);
+
+void  SSL_CTX_set_client_CA_list(SSL_CTX*, STACK_OF(X509_NAME)*);
+void* X509_STORE_CTX_get_ex_data(X509_STORE_CTX*, int);
+int   SSL_get_ex_data_X509_STORE_CTX_idx(void);
+void* SSL_get_ex_data(const SSL*, int);
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX*, void* userdata);
+void SSL_CTX_set_default_passwd_cb(SSL_CTX*, pem_password_cb);
+
+
+long SSL_CTX_set_timeout(SSL_CTX*, long);
+void SSL_CTX_set_info_callback(SSL_CTX*, void (*)());
+
+unsigned long ERR_peek_error(void);
+int           ERR_GET_REASON(int);
+
+char* SSL_alert_type_string_long(int);
+char* SSL_alert_desc_string_long(int);
+char* SSL_state_string_long(SSL*);
+
+void RSA_free(RSA*);
+RSA* RSA_generate_key(int, unsigned long, void(*)(int, int, void*), void*);
+void SSL_CTX_set_tmp_rsa_callback(SSL_CTX*, RSA*(*)(SSL*, int, int));
+
+int PEM_def_callback(char*, int num, int w, void* key);
+
+long SSL_CTX_sess_accept(SSL_CTX*);
+long SSL_CTX_sess_connect(SSL_CTX*);
+long SSL_CTX_sess_accept_good(SSL_CTX*);
+long SSL_CTX_sess_connect_good(SSL_CTX*);
+long SSL_CTX_sess_accept_renegotiate(SSL_CTX*);
+long SSL_CTX_sess_connect_renegotiate(SSL_CTX*);
+long SSL_CTX_sess_hits(SSL_CTX*);
+long SSL_CTX_sess_cb_hits(SSL_CTX*);
+long SSL_CTX_sess_cache_full(SSL_CTX*);
+long SSL_CTX_sess_misses(SSL_CTX*);
+long SSL_CTX_sess_timeouts(SSL_CTX*);
+long SSL_CTX_sess_number(SSL_CTX*);
+long SSL_CTX_sess_get_cache_size(SSL_CTX*);
+
+
+#define SSL_DEFAULT_CIPHER_LIST ""   /* default all */
+#define RSA_F4 0x10001L
+
+enum {
+    OCSP_NOCERTS     = 1,
+    OCSP_NOINTERN    = 2,
+    OCSP_NOSIGS      = 4,
+    OCSP_NOCHAIN     = 8,
+    OCSP_NOVERIFY    = 16,
+    OCSP_NOEXPLICIT  = 32,
+    OCSP_NOCASIGN    = 64,
+    OCSP_NODELEGATED = 128,
+    OCSP_NOCHECKS    = 256,
+    OCSP_TRUSTOTHER  = 512,
+    OCSP_RESPID_KEY  = 1024,
+    OCSP_NOTIME      = 2048,
+
+    OCSP_CERTID   = 2,
+    OCSP_REQUEST  = 4,
+    OCSP_RESPONSE = 8,
+    OCSP_BASICRESP = 16,
+
+    ASN1_GENERALIZEDTIME = 4,
+
+    SSL_OP_MICROSOFT_SESS_ID_BUG = 1,
+    SSL_OP_NETSCAPE_CHALLENGE_BUG = 2,
+    SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 3,
+    SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = 4,
+    SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 5,
+    SSL_OP_MSIE_SSLV2_RSA_PADDING = 6,
+    SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 7,
+    SSL_OP_TLS_D5_BUG = 8,
+    SSL_OP_TLS_BLOCK_PADDING_BUG = 9,
+    SSL_OP_TLS_ROLLBACK_BUG = 10,
+    SSL_OP_ALL = 11,
+    SSL_OP_EPHEMERAL_RSA = 12,
+    SSL_OP_NO_SSLv3 = 13,
+    SSL_OP_NO_TLSv1 = 14,
+    SSL_OP_PKCS1_CHECK_1 = 15,
+    SSL_OP_PKCS1_CHECK_2 = 16,
+    SSL_OP_NETSCAPE_CA_DN_BUG = 17,
+    SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = 18,
+    SSL_OP_SINGLE_DH_USE = 19,
+    SSL_OP_NO_TICKET = 20,
+    SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 21,
+    SSL_OP_NO_QUERY_MTU = 22,
+    SSL_OP_COOKIE_EXCHANGE = 23,
+    SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 24,
+    SSL_OP_SINGLE_ECDH_USE = 25,
+    SSL_OP_CIPHER_SERVER_PREFERENCE = 26,
+
+    SSL_MAX_SSL_SESSION_ID_LENGTH = 32,
+
+    EVP_R_BAD_DECRYPT = 2,
+
+    SSL_CB_LOOP = 4,
+    SSL_ST_CONNECT = 5,
+    SSL_ST_ACCEPT  = 6,
+    SSL_CB_ALERT   = 7,
+    SSL_CB_READ    = 8,
+    SSL_CB_HANDSHAKE_DONE = 9,
+
+    SSL_MODE_ENABLE_PARTIAL_WRITE = 2,
+
+    BIO_FLAGS_BASE64_NO_NL = 1,
+    BIO_CLOSE   = 1,
+    BIO_NOCLOSE = 0,
+
+    NID_undef = 0,
+
+    X509_FILETYPE_PEM = 8,
+    X509_LU_X509      = 9,
+    X509_LU_CRL       = 12,
+    
+    X509_V_ERR_CRL_SIGNATURE_FAILURE = 13,
+    X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 14,
+    X509_V_ERR_CRL_HAS_EXPIRED                = 15,
+    X509_V_ERR_CERT_REVOKED                   = 16,
+    X509_V_ERR_CERT_CHAIN_TOO_LONG            = 17,
+    X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT      = 18,
+    X509_V_ERR_CERT_NOT_YET_VALID             = 19,
+    X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 20,
+    X509_V_ERR_CERT_HAS_EXPIRED               = 21,
+    X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD  = 22,
+
+    X509_V_OK = 0,
+
+    CRYPTO_LOCK = 1,
+    CRYPTO_NUM_LOCKS = 10,
+
+};
+
+/* extras end */
+
+#ifndef NO_FILESYSTEM
+/* CyaSSL extension, provide last error from SSL_get_error
+   since not using thread storage error queue */
+void  ERR_print_errors_fp(FILE*, int err);
+#endif
+
+enum { /* ssl Constants */
+    SSL_ERROR_NONE      =  0,   /* for most functions */
+    SSL_FAILURE         =  0,   /* for some functions */
+    SSL_SUCCESS            =  1,
+
+    SSL_BAD_CERTTYPE    = -8,
+    SSL_BAD_STAT        = -7,
+    SSL_BAD_PATH        = -6,
+    SSL_BAD_FILETYPE    = -5,
+    SSL_BAD_FILE        = -4,
+    SSL_NOT_IMPLEMENTED = -3,
+    SSL_UNKNOWN         = -2,
+    SSL_FATAL_ERROR     = -1,
+
+    SSL_FILETYPE_ASN1    = 2,
+    SSL_FILETYPE_PEM     = 1,
+    SSL_FILETYPE_DEFAULT = 2, /* ASN1 */
+    SSL_FILETYPE_RAW     = 3, /* NTRU raw key blob */
+
+    SSL_VERIFY_NONE                 = 0,
+    SSL_VERIFY_PEER                 = 1,
+    SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2,
+    SSL_VERIFY_CLIENT_ONCE          = 4,
+
+    SSL_SESS_CACHE_OFF                = 30,
+    SSL_SESS_CACHE_CLIENT             = 31,
+    SSL_SESS_CACHE_SERVER             = 32,
+    SSL_SESS_CACHE_BOTH               = 33,
+    SSL_SESS_CACHE_NO_AUTO_CLEAR      = 34,
+    SSL_SESS_CACHE_NO_INTERNAL_LOOKUP = 35,
+
+    SSL_ERROR_WANT_READ        =  2,
+    SSL_ERROR_WANT_WRITE       =  3,
+    SSL_ERROR_WANT_CONNECT     =  7,
+    SSL_ERROR_WANT_ACCEPT      =  8,
+    SSL_ERROR_SYSCALL          =  5,
+    SSL_ERROR_WANT_X509_LOOKUP = 83,
+    SSL_ERROR_ZERO_RETURN      =  6,
+    SSL_ERROR_SSL              = 85,
+
+    SSL_SENT_SHUTDOWN     = 1,
+    SSL_RECEIVED_SHUTDOWN = 2,
+    SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = 4,
+    SSL_OP_NO_SSLv2       = 8,
+
+    SSL_R_SSL_HANDSHAKE_FAILURE           = 101,
+    SSL_R_TLSV1_ALERT_UNKNOWN_CA          = 102,
+    SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN = 103,
+    SSL_R_SSLV3_ALERT_BAD_CERTIFICATE     = 104,
+
+    PEM_BUFSIZE = 1024,
+};
+
+
+#ifndef NO_PSK
+    typedef unsigned int (*psk_client_callback)(SSL*, const char*, char*,
+                          unsigned int, unsigned char*, unsigned int);
+    void SSL_CTX_set_psk_client_callback(SSL_CTX*, psk_client_callback);
+    void SSL_set_psk_client_callback(SSL*, psk_client_callback);
+
+    const char* SSL_get_psk_identity_hint(const SSL*);
+    const char* SSL_get_psk_identity(const SSL*);
+
+    int SSL_CTX_use_psk_identity_hint(SSL_CTX*, const char*);
+    int SSL_use_psk_identity_hint(SSL*, const char*);
+
+    typedef unsigned int (*psk_server_callback)(SSL*, const char*,
+                          unsigned char*, unsigned int);
+    void SSL_CTX_set_psk_server_callback(SSL_CTX*, psk_server_callback);
+    void SSL_set_psk_server_callback(SSL*, psk_server_callback);
+
+    #define PSK_TYPES_DEFINED
+#endif /* NO_PSK */
+
+
+/* extra begins */
+
+enum {  /* ERR Constants */
+    ERR_TXT_STRING = 1,
+};
+
+unsigned long ERR_get_error_line_data(const char**, int*, const char**, int *);
+
+unsigned long ERR_get_error(void);
+void          ERR_clear_error(void);
+
+
+int  RAND_status(void);
+int  RAND_bytes(unsigned char* buf, int num);
+SSL_METHOD *SSLv23_server_method(void);
+long SSL_CTX_set_options(SSL_CTX*, long);
+int  SSL_CTX_check_private_key(SSL_CTX*);
+
+
+void ERR_free_strings(void);
+void ERR_remove_state(unsigned long);
+void EVP_cleanup(void);
+
+void CRYPTO_cleanup_all_ex_data(void);
+long SSL_CTX_set_mode(SSL_CTX* ctx, long mode);
+long SSL_CTX_get_mode(SSL_CTX* ctx);
+void SSL_CTX_set_default_read_ahead(SSL_CTX* ctx, int m);
+
+long SSL_CTX_sess_set_cache_size(SSL_CTX*, long);
+
+int  SSL_CTX_set_default_verify_paths(SSL_CTX*);
+int  SSL_CTX_set_session_id_context(SSL_CTX*, const unsigned char*,
+                                    unsigned int);
+
+X509*      SSL_get_peer_certificate(SSL* ssl);
+
+int SSL_want_read(SSL*);
+int SSL_want_write(SSL*);
+
+int BIO_printf(BIO*, const char*, ...);
+int ASN1_UTCTIME_print(BIO*, const ASN1_UTCTIME*);
+
+int   sk_num(X509_REVOKED*);
+void* sk_value(X509_REVOKED*, int);
+
+/* stunnel 4.28 needs */
+void* SSL_CTX_get_ex_data(const SSL_CTX*, int);
+int   SSL_CTX_set_ex_data(SSL_CTX*, int, void*);
+void  SSL_CTX_sess_set_get_cb(SSL_CTX*, SSL_SESSION*(*f)(SSL*, unsigned char*,
+                                                         int, int*));
+void  SSL_CTX_sess_set_new_cb(SSL_CTX*, int (*f)(SSL*, SSL_SESSION*));
+void  SSL_CTX_sess_set_remove_cb(SSL_CTX*, void (*f)(SSL_CTX*, SSL_SESSION*));
+
+int          i2d_SSL_SESSION(SSL_SESSION*, unsigned char**);
+SSL_SESSION* d2i_SSL_SESSION(SSL_SESSION**,const unsigned char**, long);
+
+long SSL_SESSION_get_timeout(const SSL_SESSION*);
+long SSL_SESSION_get_time(const SSL_SESSION*);
+int  SSL_CTX_get_ex_new_index(long, void*, void*, void*, void*);
+
+/* extra ends */
+
+
+/* CyaSSL extensions */
+
+/* call before SSL_connect, if verifying will add name check to
+   date check and signature check */
+int CyaSSL_check_domain_name(SSL* ssl, const char* dn);
+
+int InitCyaSSL(void);   /* need to call once to load library (session cache) */
+int FreeCyaSSL(void);   /* call when done to free session cache mutex        */
+
+int  CyaSSL_Debugging_ON(void);   /* turn logging on, only if compiled in */
+void CyaSSL_Debugging_OFF(void);  /* turn logging off */
+
+int CyaSSL_set_compression(SSL* ssl);  /* turn on CyaSSL data compression */
+
+int CyaSSL_CTX_use_NTRUPrivateKey_file(SSL_CTX*, const char*); /* load NTRU
+                                                             private key blob */
+X509_CHAIN* CyaSSL_get_peer_chain(SSL* ssl);   /* get CyaSSL peer X509_CHAIN */
+int  CyaSSL_get_chain_count(X509_CHAIN* chain);   /* peer chain count */
+int  CyaSSL_get_chain_length(X509_CHAIN*, int idx); /* index cert length */
+unsigned char* CyaSSL_get_chain_cert(X509_CHAIN*, int idx);   /* index cert */
+int  CyaSSL_get_chain_cert_pem(X509_CHAIN*, int idx, unsigned char* buffer,
+                          int inLen, int* outLen); /* get index cert in PEM */
+const unsigned char* CyaSSL_get_sessionID(const SSL_SESSION* session);
+
+#ifndef _WIN32
+    #ifndef NO_WRITEV
+        #include <sys/uio.h>
+        /* allow writev style writing */
+        int CyaSSL_writev(SSL* ssl, const struct iovec* iov, int iovcnt);
+    #endif
+#endif
+
+#if defined(NO_FILESYSTEM) || defined(MICRIUM)
+
+int CyaSSL_CTX_load_verify_buffer(SSL_CTX*, const unsigned char*, long, int);
+int CyaSSL_CTX_use_certificate_buffer(SSL_CTX*, const unsigned char*, long,int);
+int CyaSSL_CTX_use_PrivateKey_buffer(SSL_CTX*, const unsigned char*, long, int);
+int CyaSSL_CTX_use_certificate_chain_buffer(SSL_CTX*,const unsigned char*,long);
+
+#endif /* NO_FILESYSTEM || MICRIUM */
+
+
+/* I/O callbacks */
+typedef int (*CallbackIORecv)(char *buf, int sz, void *ctx);
+typedef int (*CallbackIOSend)(char *buf, int sz, void *ctx);
+
+void CyaSSL_SetIORecv(SSL_CTX*, CallbackIORecv);
+void CyaSSL_SetIOSend(SSL_CTX*, CallbackIOSend);
+
+void CyaSSL_SetIOReadCtx(SSL* ssl, void *ctx);
+void CyaSSL_SetIOWriteCtx(SSL* ssl, void *ctx);
+
+
+#ifdef CYASSL_CALLBACKS
+
+/* used internally by CyaSSL while OpenSSL types aren't */
+#include "cyassl_callbacks.h"
+
+typedef int (*HandShakeCallBack)(HandShakeInfo*);
+typedef int (*TimeoutCallBack)(TimeoutInfo*);
+
+/* CyaSSL connect extension allowing HandShakeCallBack and/or TimeoutCallBack
+   for diagnostics */
+int CyaSSL_connect_ex(SSL*, HandShakeCallBack, TimeoutCallBack, Timeval);
+int CyaSSL_accept_ex(SSL*, HandShakeCallBack, TimeoutCallBack, Timeval);
+
+#endif /* CYASSL_CALLBACKS */
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CyaSSL_openssl_h__ */
diff -r 000000000000 -r 5045d2638c29 tfm.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tfm.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,651 @@
+/* tfm.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+/*
+ * Based on public domain TomsFastMath 0.10 by Tom St Denis, tomstdenis@iahu.ca,
+ * http://math.libtomcrypt.com
+ */
+
+
+/**
+ *  Edited by Moisés Guimarães (moises.guimaraes@phoebus.com.br)
+ *  to fit CyaSSL's needs.
+ */
+
+
+#ifndef CTAO_CRYPT_TFM_H
+#define CTAO_CRYPT_TFM_H
+
+#include "types.h"
+#ifndef CHAR_BIT
+    #include <limits.h>
+#endif
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifndef MIN
+   #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+   #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+/* externally define this symbol to ignore the default settings, useful for changing the build from the make process */
+#ifndef TFM_ALREADY_SET
+
+/* do we want the large set of small multiplications ? 
+   Enable these if you are going to be doing a lot of small (<= 16 digit) multiplications say in ECC
+   Or if you're on a 64-bit machine doing RSA as a 1024-bit integer == 16 digits ;-)
+ */
+/* need to refactor the function */
+/*#define TFM_SMALL_SET */
+
+/* do we want huge code 
+   Enable these if you are doing 20, 24, 28, 32, 48, 64 digit multiplications (useful for RSA)
+   Less important on 64-bit machines as 32 digits == 2048 bits
+ */
+#if 0
+#define TFM_MUL3
+#define TFM_MUL4
+#define TFM_MUL6
+#define TFM_MUL7
+#define TFM_MUL8
+#define TFM_MUL9
+#define TFM_MUL12
+#define TFM_MUL17
+#endif
+#ifdef TFM_SMALL_SET
+#define TFM_MUL20
+#define TFM_MUL24
+#define TFM_MUL28
+#define TFM_MUL32
+#define TFM_MUL48
+#define TFM_MUL64
+#endif
+
+#if 0
+#define TFM_SQR3
+#define TFM_SQR4
+#define TFM_SQR6
+#define TFM_SQR7
+#define TFM_SQR8
+#define TFM_SQR9
+#define TFM_SQR12
+#define TFM_SQR17
+#endif
+#ifdef TFM_SMALL_SET
+#define TFM_SQR20
+#define TFM_SQR24
+#define TFM_SQR28
+#define TFM_SQR32
+#define TFM_SQR48
+#define TFM_SQR64
+#endif
+
+/* do we want some overflow checks
+   Not required if you make sure your numbers are within range (e.g. by default a modulus for fp_exptmod() can only be upto 2048 bits long)
+ */
+/* #define TFM_CHECK */
+
+/* Is the target a P4 Prescott
+ */
+/* #define TFM_PRESCOTT */
+
+/* Do we want timing resistant fp_exptmod() ?
+ * This makes it slower but also timing invariant with respect to the exponent 
+ */
+/* #define TFM_TIMING_RESISTANT */
+
+#endif
+
+/* Max size of any number in bits.  Basically the largest size you will be multiplying
+ * should be half [or smaller] of FP_MAX_SIZE-four_digit
+ *
+ * You can externally define this or it defaults to 4096-bits [allowing multiplications upto 2048x2048 bits ]
+ */
+#ifndef FP_MAX_SIZE
+   #define FP_MAX_SIZE           (4096+(8*DIGIT_BIT))
+#endif
+
+/* will this lib work? */
+#if (CHAR_BIT & 7)
+   #error CHAR_BIT must be a multiple of eight.
+#endif
+#if FP_MAX_SIZE % CHAR_BIT
+   #error FP_MAX_SIZE must be a multiple of CHAR_BIT
+#endif
+
+/* autodetect x86-64 and make sure we are using 64-bit digits with x86-64 asm */
+#if defined(__x86_64__)
+   #if defined(TFM_X86) || defined(TFM_SSE2) || defined(TFM_ARM) 
+       #error x86-64 detected, x86-32/SSE2/ARM optimizations are not valid!
+   #endif
+   #if !defined(TFM_X86_64) && !defined(TFM_NO_ASM)
+      #define TFM_X86_64
+   #endif
+#endif
+#if defined(TFM_X86_64)
+    #if !defined(FP_64BIT)
+       #define FP_64BIT
+    #endif
+#endif
+
+/* try to detect x86-32 */
+#if defined(__i386__) && !defined(TFM_SSE2)
+   #if defined(TFM_X86_64) || defined(TFM_ARM) 
+       #error x86-32 detected, x86-64/ARM optimizations are not valid!
+   #endif
+   #if !defined(TFM_X86) && !defined(TFM_NO_ASM)
+      #define TFM_X86
+   #endif
+#endif
+
+/* make sure we're 32-bit for x86-32/sse/arm/ppc32 */
+#if (defined(TFM_X86) || defined(TFM_SSE2) || defined(TFM_ARM) || defined(TFM_PPC32)) && defined(FP_64BIT)
+   #warning x86-32, SSE2 and ARM, PPC32 optimizations require 32-bit digits (undefining)
+   #undef FP_64BIT
+#endif
+
+/* multi asms? */
+#ifdef TFM_X86
+   #define TFM_ASM
+#endif
+#ifdef TFM_X86_64
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_SSE2
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_ARM
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_PPC32
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_PPC64
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_AVR32
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+
+/* we want no asm? */
+#ifdef TFM_NO_ASM
+   #undef TFM_X86
+   #undef TFM_X86_64
+   #undef TFM_SSE2
+   #undef TFM_ARM
+   #undef TFM_PPC32
+   #undef TFM_PPC64
+   #undef TFM_AVR32
+   #undef TFM_ASM   
+#endif
+
+/* ECC helpers */
+#ifdef TFM_ECC192
+   #ifdef FP_64BIT
+       #define TFM_MUL3
+       #define TFM_SQR3
+   #else
+       #define TFM_MUL6
+       #define TFM_SQR6
+   #endif
+#endif
+
+#ifdef TFM_ECC224
+   #ifdef FP_64BIT
+       #define TFM_MUL4
+       #define TFM_SQR4
+   #else
+       #define TFM_MUL7
+       #define TFM_SQR7
+   #endif
+#endif
+
+#ifdef TFM_ECC256
+   #ifdef FP_64BIT
+       #define TFM_MUL4
+       #define TFM_SQR4
+   #else
+       #define TFM_MUL8
+       #define TFM_SQR8
+   #endif
+#endif
+
+#ifdef TFM_ECC384
+   #ifdef FP_64BIT
+       #define TFM_MUL6
+       #define TFM_SQR6
+   #else
+       #define TFM_MUL12
+       #define TFM_SQR12
+   #endif
+#endif
+
+#ifdef TFM_ECC521
+   #ifdef FP_64BIT
+       #define TFM_MUL9
+       #define TFM_SQR9
+   #else
+       #define TFM_MUL17
+       #define TFM_SQR17
+   #endif
+#endif
+
+
+/* some default configurations.
+ */
+#if defined(FP_64BIT)
+   /* for GCC only on supported platforms */
+#ifndef CRYPT
+   typedef unsigned long ulong64;
+#endif
+   typedef ulong64            fp_digit;
+   typedef unsigned long      fp_word __attribute__ ((mode(TI)));
+#else
+   /* this is to make porting into LibTomCrypt easier :-) */
+#ifndef CRYPT
+   #if defined(_MSC_VER) || defined(__BORLANDC__) 
+      typedef unsigned __int64   ulong64;
+      typedef signed __int64     long64;
+   #else
+      typedef unsigned long long ulong64;
+      typedef signed long long   long64;
+   #endif
+#endif
+   typedef unsigned long      fp_digit;
+   typedef ulong64            fp_word;
+#endif
+
+/* # of digits this is */
+#define DIGIT_BIT  (int)((CHAR_BIT) * sizeof(fp_digit))
+#define FP_MASK    (fp_digit)(-1)
+#define FP_SIZE    (FP_MAX_SIZE/DIGIT_BIT)
+
+/* signs */
+#define FP_ZPOS     0
+#define FP_NEG      1
+
+/* return codes */
+#define FP_OKAY     0
+#define FP_VAL      1
+#define FP_MEM      2
+
+/* equalities */
+#define FP_LT        -1   /* less than */
+#define FP_EQ         0   /* equal to */
+#define FP_GT         1   /* greater than */
+
+/* replies */
+#define FP_YES        1   /* yes response */
+#define FP_NO         0   /* no response */
+
+/* a FP type */
+typedef struct {
+    fp_digit dp[FP_SIZE];
+    int      used, 
+             sign;
+} fp_int;
+
+/* functions */
+
+/* returns a TFM ident string useful for debugging... */
+/*const char *fp_ident(void);*/
+
+/* initialize [or zero] an fp int */
+#define fp_init(a)  (void)XMEMSET((a), 0, sizeof(fp_int))
+#define fp_zero(a)  fp_init(a)
+
+/* zero/even/odd ? */
+#define fp_iszero(a) (((a)->used == 0) ? FP_YES : FP_NO)
+#define fp_iseven(a) (((a)->used >= 0 && (((a)->dp[0] & 1) == 0)) ? FP_YES : FP_NO)
+#define fp_isodd(a)  (((a)->used > 0  && (((a)->dp[0] & 1) == 1)) ? FP_YES : FP_NO)
+
+/* set to a small digit */
+void fp_set(fp_int *a, fp_digit b);
+
+/* copy from a to b */
+#define fp_copy(a, b)  (void)(((a) != (b)) ? (XMEMCPY((b), (a), sizeof(fp_int))) : (void)0)
+#define fp_init_copy(a, b) fp_copy(b, a)
+
+/* clamp digits */
+#define fp_clamp(a)   { while ((a)->used && (a)->dp[(a)->used-1] == 0) --((a)->used); (a)->sign = (a)->used ? (a)->sign : FP_ZPOS; }
+
+/* negate and absolute */
+#define fp_neg(a, b)  { fp_copy(a, b); (b)->sign ^= 1; fp_clamp(b); }
+#define fp_abs(a, b)  { fp_copy(a, b); (b)->sign  = 0; }
+
+/* right shift x digits */
+void fp_rshd(fp_int *a, int x);
+
+/* left shift x digits */
+void fp_lshd(fp_int *a, int x);
+
+/* signed comparison */
+int fp_cmp(fp_int *a, fp_int *b);
+
+/* unsigned comparison */
+int fp_cmp_mag(fp_int *a, fp_int *b);
+
+/* power of 2 operations */
+void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d);
+void fp_mod_2d(fp_int *a, int b, fp_int *c);
+void fp_mul_2d(fp_int *a, int b, fp_int *c);
+void fp_2expt (fp_int *a, int b);
+void fp_mul_2(fp_int *a, fp_int *c);
+void fp_div_2(fp_int *a, fp_int *c);
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+/*int fp_cnt_lsb(fp_int *a);*/
+
+/* c = a + b */
+void fp_add(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = a - b */
+void fp_sub(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = a * b */
+void fp_mul(fp_int *a, fp_int *b, fp_int *c);
+
+/* b = a*a  */
+void fp_sqr(fp_int *a, fp_int *b);
+
+/* a/b => cb + d == a */
+int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* c = a mod b, 0 <= c < b  */
+int fp_mod(fp_int *a, fp_int *b, fp_int *c);
+
+/* compare against a single digit */
+int fp_cmp_d(fp_int *a, fp_digit b);
+
+/* c = a + b */
+/*void fp_add_d(fp_int *a, fp_digit b, fp_int *c);*/
+
+/* c = a - b */
+/*void fp_sub_d(fp_int *a, fp_digit b, fp_int *c);*/
+
+/* c = a * b */
+void fp_mul_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* a/b => cb + d == a */
+/*int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d);*/
+
+/* c = a mod b, 0 <= c < b  */
+/*int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c);*/
+
+/* ---> number theory <--- */
+/* d = a + b (mod c) */
+/*int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);*/
+
+/* d = a - b (mod c) */
+/*int fp_submod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);*/
+
+/* d = a * b (mod c) */
+int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* c = a * a (mod b) */
+/*int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c);*/
+
+/* c = 1/a (mod b) */
+int fp_invmod(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = (a, b) */
+/*void fp_gcd(fp_int *a, fp_int *b, fp_int *c);*/
+
+/* c = [a, b] */
+/*void fp_lcm(fp_int *a, fp_int *b, fp_int *c);*/
+
+/* setups the montgomery reduction */
+int fp_montgomery_setup(fp_int *a, fp_digit *mp);
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+void fp_montgomery_calc_normalization(fp_int *a, fp_int *b);
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp);
+
+/* d = a**b (mod c) */
+int fp_exptmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* primality stuff */
+
+/* perform a Miller-Rabin test of a to the base b and store result in "result" */
+/*void fp_prime_miller_rabin (fp_int * a, fp_int * b, int *result);*/
+
+/* 256 trial divisions + 8 Miller-Rabins, returns FP_YES if probable prime  */
+/*int fp_isprime(fp_int *a);*/
+
+/* Primality generation flags */
+/*#define TFM_PRIME_BBS      0x0001 */ /* BBS style prime */
+/*#define TFM_PRIME_SAFE     0x0002 */ /* Safe prime (p-1)/2 == prime */
+/*#define TFM_PRIME_2MSB_OFF 0x0004 */ /* force 2nd MSB to 0 */
+/*#define TFM_PRIME_2MSB_ON  0x0008 */ /* force 2nd MSB to 1 */
+
+/* callback for fp_prime_random, should fill dst with random bytes and return how many read [upto len] */
+/*typedef int tfm_prime_callback(unsigned char *dst, int len, void *dat);*/
+
+/*#define fp_prime_random(a, t, size, bbs, cb, dat) fp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?TFM_PRIME_BBS:0, cb, dat)*/
+
+/*int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback cb, void *dat);*/
+
+/* radix conersions */
+int fp_count_bits(fp_int *a);
+
+int fp_unsigned_bin_size(fp_int *a);
+void fp_read_unsigned_bin(fp_int *a, unsigned char *b, int c);
+void fp_to_unsigned_bin(fp_int *a, unsigned char *b);
+
+/*int fp_signed_bin_size(fp_int *a);*/
+/*void fp_read_signed_bin(fp_int *a, unsigned char *b, int c);*/
+/*void fp_to_signed_bin(fp_int *a, unsigned char *b);*/
+
+/*int fp_read_radix(fp_int *a, char *str, int radix);*/
+/*int fp_toradix(fp_int *a, char *str, int radix);*/
+/*int fp_toradix_n(fp_int * a, char *str, int radix, int maxlen);*/
+
+
+/* VARIOUS LOW LEVEL STUFFS */
+void s_fp_add(fp_int *a, fp_int *b, fp_int *c);
+void s_fp_sub(fp_int *a, fp_int *b, fp_int *c);
+void fp_reverse(unsigned char *s, int len);
+
+void fp_mul_comba(fp_int *A, fp_int *B, fp_int *C);
+
+#ifdef TFM_SMALL_SET
+void fp_mul_comba_small(fp_int *A, fp_int *B, fp_int *C);
+#endif
+
+#ifdef TFM_MUL3
+void fp_mul_comba3(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL4
+void fp_mul_comba4(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL6
+void fp_mul_comba6(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL7
+void fp_mul_comba7(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL8
+void fp_mul_comba8(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL9
+void fp_mul_comba9(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL12
+void fp_mul_comba12(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL17
+void fp_mul_comba17(fp_int *A, fp_int *B, fp_int *C);
+#endif
+
+#ifdef TFM_MUL20
+void fp_mul_comba20(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL24
+void fp_mul_comba24(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL28
+void fp_mul_comba28(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL32
+void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL48
+void fp_mul_comba48(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL64
+void fp_mul_comba64(fp_int *A, fp_int *B, fp_int *C);
+#endif
+
+void fp_sqr_comba(fp_int *A, fp_int *B);
+
+#ifdef TFM_SMALL_SET
+void fp_sqr_comba_small(fp_int *A, fp_int *B);
+#endif
+
+#ifdef TFM_SQR3
+void fp_sqr_comba3(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR4
+void fp_sqr_comba4(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR6
+void fp_sqr_comba6(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR7
+void fp_sqr_comba7(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR8
+void fp_sqr_comba8(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR9
+void fp_sqr_comba9(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR12
+void fp_sqr_comba12(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR17
+void fp_sqr_comba17(fp_int *A, fp_int *B);
+#endif
+
+#ifdef TFM_SQR20
+void fp_sqr_comba20(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR24
+void fp_sqr_comba24(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR28
+void fp_sqr_comba28(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR32
+void fp_sqr_comba32(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR48
+void fp_sqr_comba48(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR64
+void fp_sqr_comba64(fp_int *A, fp_int *B);
+#endif
+/*extern const char *fp_s_rmap;*/
+
+
+/**
+ * Used by CyaSSL 
+ */
+
+/* Types */
+    typedef fp_digit mp_digit;
+    typedef fp_word  mp_word;
+    typedef fp_int mp_int;
+
+/* Constants */
+    #define MP_LT   FP_LT   /* less than    */
+    #define MP_EQ   FP_EQ   /* equal to     */
+    #define MP_GT   FP_GT   /* greater than */
+    #define MP_OKAY FP_OKAY /* ok result    */
+    #define MP_NO   FP_NO   /* yes/no result */
+    #define MP_YES  FP_YES  /* yes/no result */
+
+/* Prototypes */
+int  mp_init (mp_int * a);
+void mp_clear (mp_int * a);
+int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, mp_int* f);
+
+int  mp_add (mp_int * a, mp_int * b, mp_int * c);
+int  mp_sub (mp_int * a, mp_int * b, mp_int * c);
+
+int  mp_mul (mp_int * a, mp_int * b, mp_int * c);
+int  mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+int  mp_mod(mp_int *a, mp_int *b, mp_int *c);
+int  mp_invmod(mp_int *a, mp_int *b, mp_int *c);
+int  mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y);
+
+int  mp_cmp(mp_int *a, mp_int *b);
+int  mp_cmp_d(mp_int *a, mp_digit b);
+
+int  mp_unsigned_bin_size(mp_int * a);
+int  mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
+int  mp_to_unsigned_bin (mp_int * a, unsigned char *b);
+
+#ifdef CYASSL_KEY_GEN
+int  mp_set_int(fp_int *a, fp_digit b);
+int  mp_gcd(fp_int *a, fp_int *b, fp_int *c);
+int  mp_lcm(fp_int *a, fp_int *b, fp_int *c);
+int  mp_copy(fp_int* a, fp_int* b);
+int  mp_sub_d(fp_int *a, fp_digit b, fp_int *c);
+int  mp_prime_is_prime(mp_int* a, int t, int* result);
+#endif /* CYASSL_KEY_GEN */
+
+#ifdef __cplusplus
+   }
+#endif
+
+
+#endif  /* CTAO_CRYPT_TFM_H */
diff -r 000000000000 -r 5045d2638c29 tls.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tls.c	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,451 @@
+/* tls.c
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include "ssl.h"
+#include "cyassl_int.h"
+#include "cyassl_error.h"
+#include "ctc_hmac.h"
+
+
+
+#ifndef NO_TLS
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+/* calculate XOR for TLSv1 PRF */
+static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
+{
+    word32 i;
+
+    for (i = 0; i < digLen; i++) 
+        digest[i] = md5[i] ^ sha[i];
+}
+
+
+
+/* compute p_hash for MD5, SHA-1, or SHA-256 for TLSv1 PRF */
+void p_hash(byte* result, word32 resLen, const byte* secret, word32 secLen,
+            const byte* seed, word32 seedLen, int hash)
+{
+    word32   len = hash == md5_mac ? MD5_DIGEST_SIZE : hash == sha_mac ?
+                                           SHA_DIGEST_SIZE : SHA256_DIGEST_SIZE;
+    word32   times = resLen / len;
+    word32   lastLen = resLen % len;
+    word32   lastTime;
+    word32   i;
+    word32   idx = 0;
+    byte     previous[SHA256_DIGEST_SIZE];  /* max size */
+    byte     current[SHA256_DIGEST_SIZE];   /* max size */
+
+    Hmac hmac;
+
+    if (lastLen) times += 1;
+    lastTime = times - 1;
+
+    HmacSetKey(&hmac, hash == md5_mac ? MD5 : hash == sha_mac ? SHA : SHA256,
+               secret, secLen);
+    HmacUpdate(&hmac, seed, seedLen);       /* A0 = seed */
+    HmacFinal(&hmac, previous);             /* A1 */
+
+    for (i = 0; i < times; i++) {
+        HmacUpdate(&hmac, previous, len);
+        HmacUpdate(&hmac, seed, seedLen);
+        HmacFinal(&hmac, current);
+
+        if ( (i == lastTime) && lastLen)
+            XMEMCPY(&result[idx], current, lastLen);
+        else {
+            XMEMCPY(&result[idx], current, len);
+            idx += len;
+            HmacUpdate(&hmac, previous, len);
+            HmacFinal(&hmac, previous);
+        }
+    }
+}
+
+
+
+/* compute TLSv1 PRF (pseudo random function using HMAC) */
+static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen,
+            const byte* label, word32 labLen, const byte* seed, word32 seedLen,
+            int useSha256)
+{
+    word32 half = (secLen + 1) / 2;
+
+    byte md5_half[MAX_PRF_HALF];        /* half is real size */
+    byte sha_half[MAX_PRF_HALF];        /* half is real size */
+    byte labelSeed[MAX_PRF_LABSEED];    /* labLen + seedLen is real size */
+    byte md5_result[MAX_PRF_DIG];       /* digLen is real size */
+    byte sha_result[MAX_PRF_DIG];       /* digLen is real size */
+
+    if (half > MAX_PRF_HALF)
+        return;
+    if (labLen + seedLen > MAX_PRF_LABSEED)
+        return;
+    if (digLen > MAX_PRF_DIG)
+        return;
+    
+    XMEMCPY(md5_half, secret, half);
+    XMEMCPY(sha_half, secret + half - secLen % 2, half);
+
+    XMEMCPY(labelSeed, label, labLen);
+    XMEMCPY(labelSeed + labLen, seed, seedLen);
+
+    if (useSha256) {
+        p_hash(digest, digLen, secret, secLen, labelSeed, labLen + seedLen,
+               sha256_mac);
+        return;
+    }
+
+    p_hash(md5_result, digLen, md5_half, half, labelSeed, labLen + seedLen,
+           md5_mac);
+    p_hash(sha_result, digLen, sha_half, half, labelSeed, labLen + seedLen,
+           sha_mac);
+    get_xor(digest, digLen, md5_result, sha_result);
+}
+
+
+void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+    const byte* side;
+    byte handshake_hash[FINISHED_SZ];
+
+    Md5Final(&ssl->hashMd5, handshake_hash);
+    ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
+   
+    if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
+        side = tls_client;
+    else
+        side = tls_server;
+
+    PRF(hashes->md5, TLS_FINISHED_SZ, ssl->arrays.masterSecret, SECRET_LEN,
+        side, FINISHED_LABEL_SZ, handshake_hash, FINISHED_SZ,
+        IsAtLeastTLSv1_2(ssl));
+}
+
+
+ProtocolVersion MakeTLSv1(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_MINOR;
+
+    return pv;
+}
+
+
+ProtocolVersion MakeTLSv1_1(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_1_MINOR;
+
+    return pv;
+}
+
+
+ProtocolVersion MakeTLSv1_2(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_2_MINOR;
+
+    return pv;
+}
+
+
+static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
+static const byte key_label   [KEY_LABEL_SZ + 1]    = "key expansion";
+
+
+int DeriveTlsKeys(SSL* ssl)
+{
+    int length = 2 * ssl->specs.hash_size + 
+                 2 * ssl->specs.key_size  +
+                 2 * ssl->specs.iv_size;
+    byte         seed[SEED_LEN];
+    byte         key_data[MAX_PRF_DIG];
+
+    XMEMCPY(seed, ssl->arrays.serverRandom, RAN_LEN);
+    XMEMCPY(&seed[RAN_LEN], ssl->arrays.clientRandom, RAN_LEN);
+
+    PRF(key_data, length, ssl->arrays.masterSecret, SECRET_LEN, key_label,
+        KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl));
+
+    return StoreKeys(ssl, key_data);
+}
+
+
+int MakeTlsMasterSecret(SSL* ssl)
+{
+    byte seed[SEED_LEN];
+    
+    XMEMCPY(seed, ssl->arrays.clientRandom, RAN_LEN);
+    XMEMCPY(&seed[RAN_LEN], ssl->arrays.serverRandom, RAN_LEN);
+
+    PRF(ssl->arrays.masterSecret, SECRET_LEN,
+        ssl->arrays.preMasterSecret, ssl->arrays.preMasterSz,
+        master_label, MASTER_LABEL_SZ, 
+        seed, SEED_LEN, IsAtLeastTLSv1_2(ssl));
+
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("master secret: ");
+        for (i = 0; i < SECRET_LEN; i++)
+            printf("%02x", ssl->arrays.masterSecret[i]);
+        printf("\n");
+    }
+#endif
+
+    return DeriveTlsKeys(ssl);
+}
+
+
+/*** next for static INLINE s copied from cyassl_int.c ***/
+
+/* convert 16 bit integer to opaque */
+static void INLINE c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+
+/* convert 32 bit integer to opaque */
+static INLINE void c32toa(word32 u32, byte* c)
+{
+    c[0] = (u32 >> 24) & 0xff;
+    c[1] = (u32 >> 16) & 0xff;
+    c[2] = (u32 >>  8) & 0xff;
+    c[3] =  u32 & 0xff;
+}
+
+
+static INLINE word32 GetSEQIncrement(SSL* ssl, int verify)
+{
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        if (verify)
+            return ssl->keys.dtls_peer_sequence_number; /* explicit from peer */
+        else
+            return ssl->keys.dtls_sequence_number - 1; /* already incremented */
+    }
+#endif
+    if (verify)
+        return ssl->keys.peer_sequence_number++; 
+    else
+        return ssl->keys.sequence_number++; 
+}
+
+
+#ifdef CYASSL_DTLS
+
+static INLINE word32 GetEpoch(SSL* ssl, int verify)
+{
+    if (verify)
+        return ssl->keys.dtls_peer_epoch; 
+    else
+        return ssl->keys.dtls_epoch; 
+}
+
+#endif /* CYASSL_DTLS */
+
+
+static INLINE const byte* GetMacSecret(SSL* ssl, int verify)
+{
+    if ( (ssl->options.side == CLIENT_END && !verify) ||
+         (ssl->options.side == SERVER_END &&  verify) )
+        return ssl->keys.client_write_MAC_secret;
+    else
+        return ssl->keys.server_write_MAC_secret;
+}
+
+/*** end copy ***/
+
+
+/* TLS type HAMC */
+void TLS_hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz,
+              int content, int verify)
+{
+    Hmac hmac;
+    byte seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 };
+    byte length[LENGTH_SZ];
+    byte inner[ENUM_LEN + VERSION_SZ + LENGTH_SZ]; /* type + version +len */
+    int  type;
+
+    c16toa((word16)sz, length);
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        c16toa(GetEpoch(ssl, verify), seq);
+#endif
+    c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
+    
+    if (ssl->specs.mac_algorithm == md5_mac)
+        type = MD5;
+    else
+        type = SHA;
+    HmacSetKey(&hmac, type, GetMacSecret(ssl, verify), ssl->specs.hash_size);
+    
+    HmacUpdate(&hmac, seq, SEQ_SZ);                               /* seq_num */
+    inner[0] = content;                                           /* type */
+    inner[ENUM_LEN] = ssl->version.major;
+    inner[ENUM_LEN + ENUM_LEN] = ssl->version.minor;              /* version */
+    XMEMCPY(&inner[ENUM_LEN + VERSION_SZ], length, LENGTH_SZ);     /* length */
+    HmacUpdate(&hmac, inner, sizeof(inner));
+    HmacUpdate(&hmac, buffer, sz);                                /* content */
+    HmacFinal(&hmac, digest);
+}
+
+
+#ifndef NO_CYASSL_CLIENT
+
+    SSL_METHOD* TLSv1_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1());
+        return method;
+    }
+
+
+    SSL_METHOD* TLSv1_1_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1_1());
+        return method;
+    }
+
+
+    SSL_METHOD* TLSv1_2_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1_2());
+        return method;
+    }
+
+
+    /* TODO: add downgrade */
+    SSL_METHOD* SSLv23_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1());
+        return method;
+    }
+
+
+#endif /* NO_CYASSL_CLIENT */
+
+
+
+#ifndef NO_CYASSL_SERVER
+
+    SSL_METHOD* TLSv1_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, 
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+
+    SSL_METHOD* TLSv1_1_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1_1());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+
+    SSL_METHOD* TLSv1_2_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1_2());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+
+    SSL_METHOD *SSLv23_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1());
+            method->side      = SERVER_END;
+            method->downgrade = 1;
+        }
+        return method;
+    }
+
+
+
+#endif /* NO_CYASSL_SERVER */
+
+#else /* NO_TLS */
+
+/* catch CyaSSL programming errors */
+void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+   
+}
+
+
+int DeriveTlsKeys(SSL* ssl)
+{
+    return -1;
+}
+
+
+int MakeTlsMasterSecret(SSL* ssl)
+{ 
+    return -1;
+}
+
+#endif /* NO_TLS */
+
diff -r 000000000000 -r 5045d2638c29 types.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/types.h	Sat Feb 05 01:09:17 2011 +0000
@@ -0,0 +1,191 @@
+/* types.h
+ *
+ * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_TYPES_H
+#define CTAO_CRYPT_TYPES_H
+
+#include "os_settings.h"
+
+#ifdef HAVE_CONFIG_H
+    #include "config.h"
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#if defined(WORDS_BIGENDIAN) || (defined(__MWERKS__) && !defined(__INTEL__))
+    #define BIG_ENDIAN_ORDER
+#endif
+
+#ifndef BIG_ENDIAN_ORDER
+    #define LITTLE_ENDIAN_ORDER
+#endif
+
+#ifndef CYASSL_TYPES
+    typedef unsigned char  byte;
+    typedef unsigned short word16;
+    typedef unsigned int   word32;
+#endif
+
+#if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
+    #define WORD64_AVAILABLE
+    #define W64LIT(x) x##ui64
+    typedef unsigned __int64 word64;
+#elif SIZEOF_LONG == 8
+    #define WORD64_AVAILABLE
+    #define W64LIT(x) x##LL
+    typedef unsigned long word64;
+#elif SIZEOF_LONG_LONG == 8 
+    #define WORD64_AVAILABLE
+    #define W64LIT(x) x##LL
+    typedef unsigned long long word64;
+#else
+    #define MP_16BIT  /* for mp_int, mp_word needs to be twice as big as
+                         mp_digit, no 64 bit type so make mp_digit 16 bit */
+#endif
+
+
+/* These platforms have 64-bit CPU registers.  */
+#if (defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || \
+     defined(__mips64)  || defined(__x86_64__)) 
+    typedef word64 word;
+#else
+    typedef word32 word;
+    #ifdef WORD64_AVAILABLE
+        #define CTAOCRYPT_SLOW_WORD64
+    #endif
+#endif
+
+
+enum {
+    WORD_SIZE  = sizeof(word),
+    BIT_SIZE   = 8,
+    WORD_BITS  = WORD_SIZE * BIT_SIZE
+};
+
+
+/* use inlining if compiler allows */
+#ifndef INLINE
+#ifndef NO_INLINE
+    #ifdef _MSC_VER
+        #define INLINE __inline
+    #elif defined(__GNUC__)
+        #define INLINE inline
+    #elif defined(THREADX)
+        #define INLINE _Inline
+    #else
+        #define INLINE 
+    #endif
+#else
+    #define INLINE 
+#endif
+#endif
+
+
+/* set up rotate style */
+#if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
+	#define INTEL_INTRINSICS
+	#define FAST_ROTATE
+#elif defined(__MWERKS__) && TARGET_CPU_PPC
+	#define PPC_INTRINSICS
+	#define FAST_ROTATE
+#elif defined(__GNUC__) && defined(__i386__)
+        /* GCC does peephole optimizations which should result in using rotate
+           instructions  */
+	#define FAST_ROTATE
+#endif
+
+
+/* Micrium will use Visual Studio for compilation but not the Win32 API */
+#if defined(_WIN32) && !defined(MICRIUM)
+    #define USE_WINDOWS_API
+#endif
+
+
+/* idea to add global alloc override by Moisés Guimarães  */
+/* default to libc stuff */
+/* XREALLOC is used once in mormal math lib, not in fast math lib */
+/* XFREE on some embeded systems doesn't like free(0) so test  */
+#ifdef XMALLOC_USER
+    /* prototypes for user heap override functions */
+    #include <stddef.h>  /* for size_t */
+    extern void *XMALLOC(size_t n, void* heap, int type);
+    extern void *XREALLOC(void *p, size_t n, void* heap, int type);
+    extern void XFREE(void *p, void* heap, int type);
+#elif !defined(MICRIUM_MALLOC)
+    /* defaults to C runtime if user doesn't override and not Micrium */
+    #include <stdlib.h>
+    #define XMALLOC(s, h, t)     malloc((s))
+    #define XFREE(p, h, t)       {void* xp = (p); if((xp)) free((xp));}
+    #define XREALLOC(p, n, h, t) realloc((p), (n))
+#endif
+
+#ifndef STRING_USER
+    #include <string.h>
+    #define XMEMCPY(d,s,l)    memcpy((d),(s),(l))
+    #define XMEMSET(b,c,l)    memset((b),(c),(l))
+    #define XMEMCMP(s1,s2,n)  memcmp((s1),(s2),(n))
+    #define XMEMMOVE(d,s,l)   memmove((d),(s),(l))
+
+    #define XSTRLEN(s1)       strlen((s1))
+    #define XSTRNCPY(s1,s2,n) strncpy((s1),(s2),(n))
+    /* strstr and strncmp only used by CyaSSL proper, not required for
+       CTaoCrypt only */
+    #define XSTRSTR(s1,s2)    strstr((s1),(s2))
+    #define XSTRNCMP(s1,s2,n) strncmp((s1),(s2),(n))
+#endif
+
+
+/* memory allocation types for user hints */
+enum {
+    DYNAMIC_TYPE_CA         = 1,
+    DYNAMIC_TYPE_CERT       = 2,
+    DYNAMIC_TYPE_KEY        = 3,
+    DYNAMIC_TYPE_FILE       = 4,
+    DYNAMIC_TYPE_ISSUER_CN  = 5,
+    DYNAMIC_TYPE_PUBLIC_KEY = 6,
+    DYNAMIC_TYPE_SIGNER     = 7,
+    DYNAMIC_TYPE_NONE       = 8,
+    DYNAMIC_TYPE_BIGINT     = 9,
+    DYNAMIC_TYPE_RSA        = 10,
+    DYNAMIC_TYPE_METHOD     = 11,
+    DYNAMIC_TYPE_OUT_BUFFER = 12,
+    DYNAMIC_TYPE_IN_BUFFER  = 13,
+    DYNAMIC_TYPE_INFO       = 14,
+    DYNAMIC_TYPE_DH         = 15,
+    DYNAMIC_TYPE_DOMAIN     = 16,
+    DYNAMIC_TYPE_SSL        = 17,
+    DYNAMIC_TYPE_CTX        = 18,
+    DYNAMIC_TYPE_WRITEV     = 19,
+    DYNAMIC_TYPE_OPENSSL    = 20 
+};
+
+
+#ifdef __cplusplus
+    }   /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_TYPES_H */
+