aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Axolotl.svg1007
-rw-r--r--LICENSE177
-rw-r--r--include/axolotl/axolotl.hh167
-rw-r--r--include/axolotl/crypto.hh123
-rw-r--r--include/axolotl/list.hh114
-rw-r--r--include/axolotl/memory.hh17
-rw-r--r--include/axolotl/message.hh76
-rw-r--r--lib/crypto-algorithms/README.md17
-rw-r--r--lib/crypto-algorithms/aes.c1072
-rw-r--r--lib/crypto-algorithms/aes.h123
-rw-r--r--lib/crypto-algorithms/aes_test.c276
-rw-r--r--lib/crypto-algorithms/arcfour.c45
-rw-r--r--lib/crypto-algorithms/arcfour.h30
-rw-r--r--lib/crypto-algorithms/arcfour_test.c47
-rw-r--r--lib/crypto-algorithms/base64.c135
-rw-r--r--lib/crypto-algorithms/base64.h27
-rw-r--r--lib/crypto-algorithms/base64_test.c54
-rw-r--r--lib/crypto-algorithms/blowfish.c269
-rw-r--r--lib/crypto-algorithms/blowfish.h32
-rw-r--r--lib/crypto-algorithms/blowfish_test.c68
-rw-r--r--lib/crypto-algorithms/des.c269
-rw-r--r--lib/crypto-algorithms/des.h37
-rw-r--r--lib/crypto-algorithms/des_test.c83
-rw-r--r--lib/crypto-algorithms/md2.c104
-rw-r--r--lib/crypto-algorithms/md2.h33
-rw-r--r--lib/crypto-algorithms/md2_test.c58
-rw-r--r--lib/crypto-algorithms/md5.c189
-rw-r--r--lib/crypto-algorithms/md5.h34
-rw-r--r--lib/crypto-algorithms/md5_test.c60
-rw-r--r--lib/crypto-algorithms/rot-13.c35
-rw-r--r--lib/crypto-algorithms/rot-13.h20
-rw-r--r--lib/crypto-algorithms/rot-13_test.c44
-rw-r--r--lib/crypto-algorithms/sha1.c149
-rw-r--r--lib/crypto-algorithms/sha1.h35
-rw-r--r--lib/crypto-algorithms/sha1_test.c58
-rw-r--r--lib/crypto-algorithms/sha256.c158
-rw-r--r--lib/crypto-algorithms/sha256.h34
-rw-r--r--lib/crypto-algorithms/sha256_test.c61
-rw-r--r--lib/curve25519-donna/.gitignore12
-rw-r--r--lib/curve25519-donna/LICENSE.md46
-rw-r--r--lib/curve25519-donna/Makefile56
-rw-r--r--lib/curve25519-donna/README40
-rw-r--r--lib/curve25519-donna/contrib/Curve25519Donna.c118
-rw-r--r--lib/curve25519-donna/contrib/Curve25519Donna.h53
-rw-r--r--lib/curve25519-donna/contrib/Curve25519Donna.java77
-rw-r--r--lib/curve25519-donna/contrib/make-snippets68
-rw-r--r--lib/curve25519-donna/curve25519-donna-c64.c449
-rw-r--r--lib/curve25519-donna/curve25519-donna.c860
-rw-r--r--lib/curve25519-donna/curve25519-donna.podspec13
-rw-r--r--lib/curve25519-donna/python-src/curve25519/__init__.py4
-rw-r--r--lib/curve25519-donna/python-src/curve25519/curve25519module.c105
-rw-r--r--lib/curve25519-donna/python-src/curve25519/keys.py46
-rw-r--r--lib/curve25519-donna/python-src/curve25519/test/__init__.py0
-rwxr-xr-xlib/curve25519-donna/python-src/curve25519/test/test_curve25519.py99
-rwxr-xr-xlib/curve25519-donna/python-src/curve25519/test/test_speed.py46
-rwxr-xr-xlib/curve25519-donna/setup.py38
-rw-r--r--lib/curve25519-donna/speed-curve25519.c50
-rw-r--r--lib/curve25519-donna/test-curve25519.c54
-rw-r--r--lib/curve25519-donna/test-noncanon.c39
-rw-r--r--lib/curve25519-donna/test-sc-curve25519.c72
-rw-r--r--lib/curve25519-donna/test-sc-curve25519.s8
-rw-r--r--lib/ed25519/ed25519_32.dll (renamed from ed25519_32.dll)bin127488 -> 127488 bytes
-rw-r--r--lib/ed25519/ed25519_64.dll (renamed from ed25519_64.dll)bin112128 -> 112128 bytes
-rw-r--r--lib/ed25519/readme.md (renamed from readme.md)0
-rw-r--r--lib/ed25519/src/add_scalar.c (renamed from src/add_scalar.c)0
-rw-r--r--lib/ed25519/src/ed25519.h (renamed from src/ed25519.h)0
-rw-r--r--lib/ed25519/src/fe.c (renamed from src/fe.c)0
-rw-r--r--lib/ed25519/src/fe.h (renamed from src/fe.h)0
-rw-r--r--lib/ed25519/src/fixedint.h (renamed from src/fixedint.h)0
-rw-r--r--lib/ed25519/src/ge.c (renamed from src/ge.c)0
-rw-r--r--lib/ed25519/src/ge.h (renamed from src/ge.h)0
-rw-r--r--lib/ed25519/src/key_exchange.c (renamed from src/key_exchange.c)0
-rw-r--r--lib/ed25519/src/keypair.c (renamed from src/keypair.c)0
-rw-r--r--lib/ed25519/src/precomp_data.h (renamed from src/precomp_data.h)0
-rw-r--r--lib/ed25519/src/sc.c (renamed from src/sc.c)0
-rw-r--r--lib/ed25519/src/sc.h (renamed from src/sc.h)0
-rw-r--r--lib/ed25519/src/seed.c (renamed from src/seed.c)0
-rw-r--r--lib/ed25519/src/sha512.c (renamed from src/sha512.c)0
-rw-r--r--lib/ed25519/src/sha512.h (renamed from src/sha512.h)0
-rw-r--r--lib/ed25519/src/sign.c (renamed from src/sign.c)0
-rw-r--r--lib/ed25519/src/verify.c (renamed from src/verify.c)0
-rw-r--r--lib/ed25519/test.c (renamed from test.c)0
-rw-r--r--src/axolotl.cpp439
-rw-r--r--src/crypto.cpp256
-rw-r--r--src/libs.cpp19
-rw-r--r--src/memory.cpp11
-rw-r--r--src/message.cpp184
-rwxr-xr-xtest.py32
-rw-r--r--tests/include/unittest.hh84
-rw-r--r--tests/test_axolotl.cpp174
-rw-r--r--tests/test_crypto.cpp218
-rw-r--r--tests/test_list.cpp70
-rw-r--r--tests/test_message.cpp65
94 files changed, 9243 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..378eac2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+build
diff --git a/Axolotl.svg b/Axolotl.svg
new file mode 100644
index 0000000..934f3ab
--- /dev/null
+++ b/Axolotl.svg
@@ -0,0 +1,1007 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="892.75781"
+ height="561"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="Axolotl.svg">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend"
+ style="overflow:visible">
+ <path
+ id="path4029"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.98994949"
+ inkscape:cx="630.66152"
+ inkscape:cy="166.30515"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1855"
+ inkscape:window-height="1056"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0.5,0.5)">
+ <g
+ id="g2991">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="48"
+ width="256"
+ id="rect2985"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987"
+ y="32"
+ x="8"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ style="font-size:24px"
+ y="32"
+ x="8"
+ id="tspan2989"
+ sodipodi:role="line">Initial Shared Secret</tspan></text>
+ </g>
+ <g
+ id="g4701"
+ transform="translate(192,100)">
+ <g
+ id="hkdf_chain_keys">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="80"
+ width="256"
+ id="rect3023"
+ style="fill:none;stroke:#000000" />
+ <g
+ id="g3031">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3019"
+ width="64"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="18"
+ id="text3025"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3027"
+ x="32"
+ y="18">Secret</tspan></text>
+ </g>
+ <text
+ sodipodi:linespacing="125%"
+ id="text3052"
+ y="48"
+ x="128"
+ style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="48"
+ x="128"
+ id="tspan3054"
+ sodipodi:role="line">HKDF</tspan></text>
+ <g
+ transform="translate(0,56)"
+ id="g3073">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="128"
+ id="rect3075"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3077"
+ y="18"
+ x="64"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="64"
+ id="tspan3079"
+ sodipodi:role="line">Root Key</tspan></text>
+ </g>
+ <g
+ id="g3081"
+ transform="translate(128,56)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3083"
+ width="128"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="64"
+ y="18"
+ id="text3085"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3087"
+ x="64"
+ y="18">Chain Key</tspan></text>
+ </g>
+ <g
+ id="g4802"
+ transform="translate(192,0)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect4804"
+ width="64"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="18"
+ id="text4806"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4808"
+ x="32"
+ y="18">Info</tspan></text>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+ d="m 32,-60 0,56"
+ id="path4810"
+ inkscape:connector-curvature="0" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text4812"
+ y="-64"
+ x="32"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="-64"
+ x="32"
+ id="tspan4814"
+ sodipodi:role="line">&quot;AXOLOTL_ROOT&quot;</tspan></text>
+ </g>
+ <g
+ transform="translate(64,0)"
+ id="g4830">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="64"
+ id="rect4832"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text4834"
+ y="18"
+ x="32"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="32"
+ id="tspan4836"
+ sodipodi:role="line">Salt</tspan></text>
+ <path
+ inkscape:connector-curvature="0"
+ id="path4838"
+ d="m 32,-28 0,24"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="-32"
+ id="text4840"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4842"
+ x="32"
+ y="-32">&quot;&quot;</tspan></text>
+ </g>
+ </g>
+ <g
+ id="hmac_chain_key"
+ transform="translate(128,160)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3147"
+ width="128"
+ height="80"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <g
+ id="g3149">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="64"
+ id="rect3151"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3153"
+ y="18"
+ x="32"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="32"
+ id="tspan3155"
+ sodipodi:role="line">Key</tspan></text>
+ </g>
+ <g
+ id="g3157"
+ transform="translate(64,0)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3159"
+ width="64"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="18"
+ id="text3161"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3163"
+ x="32"
+ y="18">Data</tspan></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="64"
+ y="48"
+ id="text3173"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3175"
+ x="64"
+ y="48">HMAC</tspan></text>
+ <g
+ transform="translate(0,56)"
+ id="g3185">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="128"
+ id="rect3187"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3189"
+ y="18"
+ x="64"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="64"
+ id="tspan3191"
+ sodipodi:role="line">Chain Key</tspan></text>
+ </g>
+ <text
+ sodipodi:linespacing="125%"
+ id="text3225"
+ y="-32"
+ x="96"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="-32"
+ x="96"
+ id="tspan3227"
+ sodipodi:role="line">&quot;\x02&quot;</tspan></text>
+ <path
+ inkscape:connector-curvature="0"
+ id="path3231"
+ d="m 96,-28 0,24"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+ d="m 32,-76 0,72"
+ id="path4639"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(320,56)"
+ id="hmac_message_key">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4641"
+ d="m -60,12 56,0"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="96"
+ y="-32"
+ id="text4633"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4635"
+ x="96"
+ y="-32">&quot;\x01&quot;</tspan></text>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+ d="m 96,-28 0,24"
+ id="path4630"
+ inkscape:connector-curvature="0" />
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="80"
+ width="128"
+ id="rect3195"
+ style="fill:none;stroke:#000000" />
+ <g
+ id="g3197">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3199"
+ width="64"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="18"
+ id="text3201"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3203"
+ x="32"
+ y="18">Key</tspan></text>
+ </g>
+ <g
+ transform="translate(64,0)"
+ id="g3205">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="64"
+ id="rect3207"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3209"
+ y="18"
+ x="32"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="32"
+ id="tspan3211"
+ sodipodi:role="line">Data</tspan></text>
+ </g>
+ <text
+ sodipodi:linespacing="125%"
+ id="text3213"
+ y="48"
+ x="64"
+ style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="48"
+ x="64"
+ id="tspan3215"
+ sodipodi:role="line">HMAC</tspan></text>
+ <g
+ id="g3217"
+ transform="translate(0,56)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3219"
+ width="128"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="64"
+ y="18"
+ id="text3221"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3223"
+ x="64"
+ y="18">Message Key</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(320,168)"
+ id="hkdf_message_keys">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3091"
+ width="320"
+ height="80"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <g
+ id="g3093">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="128"
+ id="rect3095"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3097"
+ y="18"
+ x="64"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="64"
+ id="tspan3099"
+ sodipodi:role="line">Secret</tspan></text>
+ <path
+ inkscape:connector-curvature="0"
+ id="path4644"
+ d="m 64,-28 0,24"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" />
+ </g>
+ <g
+ id="g3101"
+ transform="translate(128,0)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3103"
+ width="64"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="18"
+ id="text3105"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3107"
+ x="32"
+ y="18">Salt</tspan></text>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+ d="m 32,-28 0,24"
+ id="path4660"
+ inkscape:connector-curvature="0" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3225-6"
+ y="-32"
+ x="32"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="-32"
+ x="32"
+ id="tspan3227-8"
+ sodipodi:role="line">&quot;&quot;</tspan></text>
+ </g>
+ <g
+ transform="translate(256,0)"
+ id="g3109">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="64"
+ id="rect3111"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3113"
+ y="18"
+ x="32"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="32"
+ id="tspan3115"
+ sodipodi:role="line">Info</tspan></text>
+ <path
+ inkscape:connector-curvature="0"
+ id="path4664"
+ d="m 32,-60 0,56"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="-64"
+ id="text4693"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4695"
+ x="32"
+ y="-64">&quot;AXOLOTL_KEYS&quot;</tspan></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="160"
+ y="48"
+ id="text3117"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3119"
+ x="160"
+ y="48">HKDF</tspan></text>
+ <g
+ id="g3121"
+ transform="translate(0,56)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3123"
+ width="128"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="64"
+ y="18"
+ id="text3125"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3127"
+ x="64"
+ y="18">Cipher Key</tspan></text>
+ </g>
+ <g
+ transform="translate(128,56)"
+ id="g3129">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="128"
+ id="rect3131"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3133"
+ y="18"
+ x="64"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="64"
+ id="tspan3135"
+ sodipodi:role="line">Mac Key</tspan></text>
+ </g>
+ <g
+ id="g3137"
+ transform="translate(256,56)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect3139"
+ width="64"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="18"
+ id="text3141"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3143"
+ x="32"
+ y="18">IV</tspan></text>
+ </g>
+ </g>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+ d="m 32,-48 0,44"
+ id="path5157"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g4858"
+ transform="translate(192,480)">
+ <g
+ id="g4860">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect4862"
+ width="256"
+ height="80"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <g
+ id="g4864">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="64"
+ id="rect4866"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text4868"
+ y="18"
+ x="32"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="32"
+ id="tspan4870"
+ sodipodi:role="line">Secret</tspan></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="128"
+ y="48"
+ id="text4872"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4874"
+ x="128"
+ y="48">HKDF</tspan></text>
+ <g
+ id="g4876"
+ transform="translate(0,56)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect4878"
+ width="128"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="64"
+ y="18"
+ id="text4880"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4882"
+ x="64"
+ y="18">Root Key</tspan></text>
+ </g>
+ <g
+ transform="translate(128,56)"
+ id="g4884">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="128"
+ id="rect4886"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text4888"
+ y="18"
+ x="64"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="64"
+ id="tspan4890"
+ sodipodi:role="line">Chain Key</tspan></text>
+ </g>
+ <g
+ transform="translate(192,0)"
+ id="g4892">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="64"
+ id="rect4894"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text4896"
+ y="18"
+ x="32"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="32"
+ id="tspan4898"
+ sodipodi:role="line">Info</tspan></text>
+ <path
+ inkscape:connector-curvature="0"
+ id="path4900"
+ d="m 32,-60 0,56"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="-64"
+ id="text4902"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4904"
+ x="32"
+ y="-64">&quot;AXOLOTL_RATCHET&quot;</tspan></text>
+ </g>
+ <g
+ id="g4906"
+ transform="translate(64,0)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect4908"
+ width="64"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="32"
+ y="18"
+ id="text4910"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4912"
+ x="32"
+ y="18">Salt</tspan></text>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+ d="M 32,-296 32,-4"
+ id="path5070"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path5154"
+ d="m 32,-96 0,92"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" />
+ </g>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="20"
+ y="150"
+ id="text5162"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan5164"
+ x="20"
+ y="140">Alice's Chain</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="20"
+ y="530"
+ id="text5166"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan5168"
+ x="20"
+ y="528.07648">Bob's Chain</tspan></text>
+ </g>
+ <g
+ id="g5074"
+ transform="translate(0.5,300.5)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect5076"
+ width="256"
+ height="80"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <g
+ id="g5078">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="128"
+ id="rect5080"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text5082"
+ y="18"
+ x="64"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="64"
+ id="tspan5084"
+ sodipodi:role="line">Bob's Key</tspan></text>
+ </g>
+ <g
+ id="g5086"
+ transform="translate(128,0)">
+ <rect
+ style="fill:none;stroke:#000000"
+ id="rect5088"
+ width="128"
+ height="24"
+ x="0"
+ y="0"
+ rx="8"
+ ry="8" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="64"
+ y="18"
+ id="text5090"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan5092"
+ x="64"
+ y="18">Alice's Key</tspan></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="128"
+ y="48"
+ id="text5094"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan5096"
+ x="128"
+ y="48">ECDH</tspan></text>
+ <g
+ transform="translate(0,56)"
+ id="g5098">
+ <rect
+ ry="8"
+ rx="8"
+ y="0"
+ x="0"
+ height="24"
+ width="256"
+ id="rect5100"
+ style="fill:none;stroke:#000000" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text5102"
+ y="18"
+ x="128"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="18"
+ x="128"
+ id="tspan5104"
+ sodipodi:role="line">Shared Secret</tspan></text>
+ </g>
+ </g>
+</svg>
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f433b1a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/include/axolotl/axolotl.hh b/include/axolotl/axolotl.hh
new file mode 100644
index 0000000..9d7ff9a
--- /dev/null
+++ b/include/axolotl/axolotl.hh
@@ -0,0 +1,167 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "axolotl/crypto.hh"
+#include "axolotl/list.hh"
+
+namespace axolotl {
+
+typedef std::uint8_t SharedKey[32];
+
+
+struct ChainKey {
+ std::uint32_t index;
+ SharedKey key;
+};
+
+
+struct MessageKey {
+ std::uint32_t index;
+ Aes256Key cipher_key;
+ SharedKey mac_key;
+ Aes256Iv iv;
+};
+
+
+struct SenderChain {
+ Curve25519KeyPair ratchet_key;
+ ChainKey chain_key;
+};
+
+
+struct ReceiverChain {
+ Curve25519PublicKey ratchet_key;
+ ChainKey chain_key;
+};
+
+
+struct SkippedMessageKey {
+ Curve25519PublicKey ratchet_key;
+ MessageKey message_key;
+};
+
+
+enum struct ErrorCode {
+ SUCCESS = 0, /*!< There wasn't an error */
+ NOT_ENOUGH_RANDOM = 1, /*!< Not enough entropy was supplied */
+ OUTPUT_BUFFER_TOO_SMALL = 2, /*!< Supplied output buffer is too small */
+ BAD_MESSAGE_VERSION = 3, /*!< The message version is unsupported */
+ BAD_MESSAGE_FORMAT = 4, /*!< The message couldn't be decoded */
+ BAD_MESSAGE_MAC = 5, /*!< The message couldn't be decrypted */
+};
+
+
+static std::size_t const MAX_RECEIVER_CHAINS = 5;
+static std::size_t const MAX_SKIPPED_MESSAGE_KEYS = 40;
+
+
+struct KdfInfo {
+ std::uint8_t const * root_info;
+ std::size_t root_info_length;
+ std::uint8_t const * ratchet_info;
+ std::size_t ratchet_info_length;
+ std::uint8_t const * message_info;
+ std::size_t message_info_length;
+};
+
+
+struct Session {
+
+ Session(
+ KdfInfo const & kdf_info
+ );
+
+ /** A some strings identifing the application to feed into the KDF. */
+ KdfInfo kdf_info;
+
+ /** The last error that happened encypting or decrypting a message. */
+ ErrorCode last_error;
+
+ /** The root key is used to generate chain keys from the ephemeral keys.
+ * A new root_key derived each time a chain key is derived. */
+ SharedKey root_key;
+
+ /** The sender chain is used to send messages. Each time a new ephemeral
+ * key is received from the remote server we generate a new sender chain
+ * with a new empheral key when we next send a message. */
+ List<SenderChain, 1> sender_chain;
+
+ /** The receiver chain is used to decrypt recieved messages. We store the
+ * last few chains so we can decrypt any out of order messages we haven't
+ * received yet. */
+ List<ReceiverChain, MAX_RECEIVER_CHAINS> receiver_chains;
+
+ /** List of message keys we've skipped over when advancing the receiver
+ * chain. */
+ List<SkippedMessageKey, MAX_SKIPPED_MESSAGE_KEYS> skipped_message_keys;
+
+ /** Initialise the session using a shared secret and the public part of the
+ * remote's first ratchet key */
+ void initialise_as_bob(
+ std::uint8_t const * shared_secret, std::size_t shared_secret_length,
+ Curve25519PublicKey const & their_ratchet_key
+ );
+
+ /** Intialise the session using a shared secret and the public/private key
+ * pair for the first ratchet key */
+ void initialise_as_alice(
+ std::uint8_t const * shared_secret, std::size_t shared_secret_length,
+ Curve25519KeyPair const & our_ratchet_key
+ );
+
+ /** The maximum number of bytes of output the encrypt method will write for
+ * a given message length. */
+ std::size_t encrypt_max_output_length(
+ std::size_t plaintext_length
+ );
+
+ /** The number of bytes of random data the encrypt method will need to
+ * encrypt a message. This will be 32 bytes if the session needs to
+ * generate a new ephemeral key, or will be 0 bytes otherwise.*/
+ std::size_t encrypt_random_length();
+
+ /** Encrypt some plaintext. Returns the length of the encrypted message
+ * or std::size_t(-1) on failure. On failure last_error will be set with
+ * an error code. The last_error will be NOT_ENOUGH_RANDOM if the number
+ * of random bytes is too small. The last_error will be
+ * OUTPUT_BUFFER_TOO_SMALL if the output buffer is too small. */
+ std::size_t encrypt(
+ std::uint8_t const * plaintext, std::size_t plaintext_length,
+ std::uint8_t const * random, std::size_t random_length,
+ std::uint8_t * output, std::size_t max_output_length
+ );
+
+ /** An upper bound on the number of bytes of plaintext the decrypt method
+ * will write for a given input message length. */
+ std::size_t decrypt_max_plaintext_length(
+ std::size_t input_length
+ );
+
+ /** Decrypt a message. Returns the length of the decrypted plaintext or
+ * std::size_t(-1) on failure. On failure last_error will be set with an
+ * error code. The last_error will be OUTPUT_BUFFER_TOO_SMALL if the
+ * plaintext buffer is too small. The last_error will be
+ * BAD_MESSAGE_VERSION if the message was encrypted with an unsupported
+ * version of the protocol. The last_error will be BAD_MESSAGE_FORMAT if
+ * the message headers could not be decoded. The last_error will be
+ * BAD_MESSAGE_MAC if the message could not be verified */
+ std::size_t decrypt(
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * plaintext, std::size_t max_plaintext_length
+ );
+};
+
+
+} // namespace axolotl
diff --git a/include/axolotl/crypto.hh b/include/axolotl/crypto.hh
new file mode 100644
index 0000000..162099f
--- /dev/null
+++ b/include/axolotl/crypto.hh
@@ -0,0 +1,123 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdint>
+#include <cstddef>
+
+namespace axolotl {
+
+
+struct Curve25519PublicKey {
+ static const int LENGTH = 32;
+ std::uint8_t public_key[32];
+};
+
+
+struct Curve25519KeyPair : public Curve25519PublicKey {
+ std::uint8_t private_key[32];
+};
+
+
+/** Generate a curve25519 key pair from 32 random bytes. */
+void generate_key(
+ std::uint8_t const * random_32_bytes,
+ Curve25519KeyPair & key_pair
+);
+
+
+const std::size_t CURVE25519_SHARED_SECRET_LENGTH = 32;
+
+
+/** Create a shared secret using our private key and their public key.
+ * The output buffer must be at least 32 bytes long. */
+void curve25519_shared_secret(
+ Curve25519KeyPair const & our_key,
+ Curve25519PublicKey const & their_key,
+ std::uint8_t * output
+);
+
+
+struct Aes256Key {
+ static const int LENGTH = 32;
+ std::uint8_t key[32];
+};
+
+
+struct Aes256Iv {
+ static const int LENGTH = 16;
+ std::uint8_t iv[16];
+};
+
+
+/** The length of output the aes_encrypt_cbc function will write */
+std::size_t aes_encrypt_cbc_length(
+ std::size_t input_length
+);
+
+
+/** Encrypts the input using AES256 in CBC mode with PKCS#7 padding.
+ * The output buffer must be big enough to hold the output including padding */
+void aes_encrypt_cbc(
+ Aes256Key const & key,
+ Aes256Iv const & iv,
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * output
+);
+
+
+/** Decrypts the input using AES256 in CBC mode. The output buffer must be at
+ * least the same size as the input buffer. Returns the length of the plaintext
+ * without padding on success or std::size_t(-1) if the padding is invalid.
+ */
+std::size_t aes_decrypt_cbc(
+ Aes256Key const & key,
+ Aes256Iv const & iv,
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * output
+);
+
+
+/** Computes SHA-256 of the input. The output buffer must be a least 32
+ * bytes long. */
+void sha256(
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * output
+);
+
+
+const std::size_t HMAC_SHA256_OUTPUT_LENGTH = 32;
+
+
+/** HMAC: Keyed-Hashing for Message Authentication
+ * http://tools.ietf.org/html/rfc2104
+ * Computes HMAC-SHA-256 of the input for the key. The output buffer must
+ * be at least 32 bytes long. */
+void hmac_sha256(
+ std::uint8_t const * key, std::size_t key_length,
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * output
+);
+
+
+/** HMAC-based Key Derivation Function (HKDF)
+ * https://tools.ietf.org/html/rfc5869
+ * Derives key material from the input bytes. */
+void hkdf_sha256(
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t const * info, std::size_t info_length,
+ std::uint8_t const * salt, std::size_t salt_length,
+ std::uint8_t * output, std::size_t output_length
+);
+
+} // namespace axolotl
diff --git a/include/axolotl/list.hh b/include/axolotl/list.hh
new file mode 100644
index 0000000..d1407b8
--- /dev/null
+++ b/include/axolotl/list.hh
@@ -0,0 +1,114 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstddef>
+
+namespace axolotl {
+
+template<typename T, std::size_t max_size>
+class List {
+public:
+ List() : _end(_data) {}
+
+ typedef T * iterator;
+ typedef T const * const_iterator;
+
+ T * begin() { return _data; }
+ T * end() { return _end; }
+ T const * begin() const { return _data; }
+ T const * end() const { return _end; }
+
+ /**
+ * Is the list empty?
+ */
+ bool empty() const { return _end == _data; }
+
+ /**
+ * The number of items in the list.
+ */
+ std::size_t size() const { return _end - _data; }
+
+ T & operator[](std::size_t index) { return _data[index]; }
+
+ T const & operator[](std::size_t index) const { return _data[index]; }
+
+ /**
+ * Erase the item from the list at the given position.
+ */
+ void erase(T * pos) {
+ --_end;
+ while (pos != _end) {
+ *pos = *(pos + 1);
+ ++pos;
+ }
+ }
+
+ /**
+ * Make space for an item in the list at a given position.
+ * If inserting the item makes the list longer than max_size then
+ * the end of the list is discarded.
+ * Returns the where the item is inserted.
+ */
+ T * insert(T * pos) {
+ if (_end != _data + max_size) {
+ ++_end;
+ } else if (pos == _end) {
+ --pos;
+ }
+ T * tmp = pos;
+ while (tmp != _end - 1) {
+ *(tmp + 1) = *tmp;
+ ++tmp;
+ }
+ return pos;
+ }
+
+ /**
+ * Make space for an item in the list at the start of the list
+ */
+ T * insert() { return insert(begin()); }
+
+ /**
+ * Insert an item into the list at a given position.
+ * If inserting the item makes the list longer than max_size then
+ * the end of the list is discarded.
+ * Returns the where the item is inserted.
+ */
+ T * insert(T * pos, T const & value) {
+ pos = insert(pos);
+ *pos = value;
+ return pos;
+ }
+
+ List<T, max_size> & operator=(List<T, max_size> const & other) {
+ if (this = &other) {
+ return *this;
+ }
+ T * this_pos = _data;
+ T * const other_pos = other._data;
+ while (other_pos != other._end) {
+ *this_pos = *other;
+ ++this_pos;
+ ++other_pos;
+ }
+ _end = this_pos;
+ return *this;
+ }
+
+private:
+ T * _end;
+ T _data[max_size];
+};
+
+} // namespace axolotl
diff --git a/include/axolotl/memory.hh b/include/axolotl/memory.hh
new file mode 100644
index 0000000..7749c54
--- /dev/null
+++ b/include/axolotl/memory.hh
@@ -0,0 +1,17 @@
+#include <cstddef>
+
+namespace axolotl {
+
+/** Clear the memory held in the buffer */
+void unset(
+ volatile void * buffer, std::size_t buffer_length
+);
+
+/** Clear the memory backing an object */
+template<typename T>
+void unset(T & value) {
+ unset(reinterpret_cast<volatile void *>(&value), sizeof(T));
+}
+
+
+} // namespace axolotl
diff --git a/include/axolotl/message.hh b/include/axolotl/message.hh
new file mode 100644
index 0000000..5cd4211
--- /dev/null
+++ b/include/axolotl/message.hh
@@ -0,0 +1,76 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstddef>
+#include <cstdint>
+
+
+namespace axolotl {
+
+/**
+ * The length of the buffer needed to hold a message.
+ */
+std::size_t encode_message_length(
+ std::uint32_t counter,
+ std::size_t ratchet_key_length,
+ std::size_t ciphertext_length,
+ std::size_t mac_length
+);
+
+
+struct MessageWriter {
+ std::size_t body_length;
+ std::uint8_t * ratchet_key;
+ std::uint8_t * ciphertext;
+ std::uint8_t * mac;
+};
+
+
+struct MessageReader {
+ std::size_t body_length;
+ std::uint8_t version;
+ std::uint32_t counter;
+ std::size_t ratchet_key_length;
+ std::size_t ciphertext_length;
+ std::uint8_t const * ratchet_key;
+ std::uint8_t const * ciphertext;
+ std::uint8_t const * mac;
+};
+
+
+/**
+ * Writes the message headers into the output buffer.
+ * Returns a writer struct populated with pointers into the output buffer.
+ */
+MessageWriter encode_message(
+ std::uint8_t version,
+ std::uint32_t counter,
+ std::size_t ratchet_key_length,
+ std::size_t ciphertext_length,
+ std::uint8_t * output
+);
+
+
+/**
+ * Reads the message headers from the input buffer.
+ * Returns a reader struct populated with pointers into the input buffer.
+ * On failure the returned body_length will be 0.
+ */
+MessageReader decode_message(
+ std::uint8_t const * input, std::size_t input_length,
+ std::size_t mac_length
+);
+
+
+} // namespace axolotl
diff --git a/lib/crypto-algorithms/README.md b/lib/crypto-algorithms/README.md
new file mode 100644
index 0000000..64eafd2
--- /dev/null
+++ b/lib/crypto-algorithms/README.md
@@ -0,0 +1,17 @@
+crypto-algorithms
+=================
+
+
+About
+---
+These are basic implementations of standard cryptography algorithms, written by Brad Conte (brad@bradconte.com) from scratch and without any cross-licensing. They exist to provide publically accessible, restriction-free implementations of popular cryptographic algorithms, like AES and SHA-1. These are primarily intended for educational and pragmatic purposes (such as comparing a specification to actual implementation code, or for building an internal application that computes test vectors for a product). The algorithms have been tested against standard test vectors.
+
+This code is released into the public domain free of any restrictions. The author requests acknowledgement if the code is used, but does not require it. This code is provided free of any liability and without any quality claims by the author.
+
+Note that these are *not* cryptographically secure implementations. They have no resistence to side-channel attacks and should not be used in contexts that need cryptographically secure implementations.
+
+These algorithms are not optimized for speed or space. They are primarily designed to be easy to read, although some basic optimization techniques have been employed.
+
+Building
+---
+The source code for each algorithm will come in a pair of a source code file and a header file. There should be no inter-header file dependencies, no additional libraries, no platform-specific header files, or any other complicating matters. Compiling them should be as easy as adding the relevent source code to the project. \ No newline at end of file
diff --git a/lib/crypto-algorithms/aes.c b/lib/crypto-algorithms/aes.c
new file mode 100644
index 0000000..948e36f
--- /dev/null
+++ b/lib/crypto-algorithms/aes.c
@@ -0,0 +1,1072 @@
+/*********************************************************************
+* Filename: aes.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: This code is the implementation of the AES algorithm and
+ the CTR, CBC, and CCM modes of operation it can be used in.
+ AES is, specified by the NIST in in publication FIPS PUB 197,
+ availible at:
+ * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf .
+ The CBC and CTR modes of operation are specified by
+ NIST SP 800-38 A, available at:
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf .
+ The CCM mode of operation is specified by NIST SP80-38 C, available at:
+ * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include <memory.h>
+#include "aes.h"
+
+#include <stdio.h>
+
+/****************************** MACROS ******************************/
+// The least significant byte of the word is rotated to the end.
+#define KE_ROTWORD(x) (((x) << 8) | ((x) >> 24))
+
+#define TRUE 1
+#define FALSE 0
+
+/**************************** DATA TYPES ****************************/
+#define AES_128_ROUNDS 10
+#define AES_192_ROUNDS 12
+#define AES_256_ROUNDS 14
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void ccm_prepare_first_ctr_blk(BYTE counter[], const BYTE nonce[], int nonce_len, int payload_len_store_size);
+void ccm_prepare_first_format_blk(BYTE buf[], int assoc_len, int payload_len, int payload_len_store_size, int mac_len, const BYTE nonce[], int nonce_len);
+void ccm_format_assoc_data(BYTE buf[], int *end_of_buf, const BYTE assoc[], int assoc_len);
+void ccm_format_payload_data(BYTE buf[], int *end_of_buf, const BYTE payload[], int payload_len);
+
+/**************************** VARIABLES *****************************/
+// This is the specified AES SBox. To look up a substitution value, put the first
+// nibble in the first index (row) and the second nibble in the second index (column).
+static const BYTE aes_sbox[16][16] = {
+ {0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76},
+ {0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0},
+ {0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15},
+ {0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75},
+ {0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84},
+ {0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF},
+ {0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8},
+ {0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2},
+ {0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73},
+ {0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB},
+ {0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79},
+ {0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08},
+ {0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A},
+ {0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E},
+ {0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF},
+ {0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16}
+};
+
+static const BYTE aes_invsbox[16][16] = {
+ {0x52,0x09,0x6A,0xD5,0x30,0x36,0xA5,0x38,0xBF,0x40,0xA3,0x9E,0x81,0xF3,0xD7,0xFB},
+ {0x7C,0xE3,0x39,0x82,0x9B,0x2F,0xFF,0x87,0x34,0x8E,0x43,0x44,0xC4,0xDE,0xE9,0xCB},
+ {0x54,0x7B,0x94,0x32,0xA6,0xC2,0x23,0x3D,0xEE,0x4C,0x95,0x0B,0x42,0xFA,0xC3,0x4E},
+ {0x08,0x2E,0xA1,0x66,0x28,0xD9,0x24,0xB2,0x76,0x5B,0xA2,0x49,0x6D,0x8B,0xD1,0x25},
+ {0x72,0xF8,0xF6,0x64,0x86,0x68,0x98,0x16,0xD4,0xA4,0x5C,0xCC,0x5D,0x65,0xB6,0x92},
+ {0x6C,0x70,0x48,0x50,0xFD,0xED,0xB9,0xDA,0x5E,0x15,0x46,0x57,0xA7,0x8D,0x9D,0x84},
+ {0x90,0xD8,0xAB,0x00,0x8C,0xBC,0xD3,0x0A,0xF7,0xE4,0x58,0x05,0xB8,0xB3,0x45,0x06},
+ {0xD0,0x2C,0x1E,0x8F,0xCA,0x3F,0x0F,0x02,0xC1,0xAF,0xBD,0x03,0x01,0x13,0x8A,0x6B},
+ {0x3A,0x91,0x11,0x41,0x4F,0x67,0xDC,0xEA,0x97,0xF2,0xCF,0xCE,0xF0,0xB4,0xE6,0x73},
+ {0x96,0xAC,0x74,0x22,0xE7,0xAD,0x35,0x85,0xE2,0xF9,0x37,0xE8,0x1C,0x75,0xDF,0x6E},
+ {0x47,0xF1,0x1A,0x71,0x1D,0x29,0xC5,0x89,0x6F,0xB7,0x62,0x0E,0xAA,0x18,0xBE,0x1B},
+ {0xFC,0x56,0x3E,0x4B,0xC6,0xD2,0x79,0x20,0x9A,0xDB,0xC0,0xFE,0x78,0xCD,0x5A,0xF4},
+ {0x1F,0xDD,0xA8,0x33,0x88,0x07,0xC7,0x31,0xB1,0x12,0x10,0x59,0x27,0x80,0xEC,0x5F},
+ {0x60,0x51,0x7F,0xA9,0x19,0xB5,0x4A,0x0D,0x2D,0xE5,0x7A,0x9F,0x93,0xC9,0x9C,0xEF},
+ {0xA0,0xE0,0x3B,0x4D,0xAE,0x2A,0xF5,0xB0,0xC8,0xEB,0xBB,0x3C,0x83,0x53,0x99,0x61},
+ {0x17,0x2B,0x04,0x7E,0xBA,0x77,0xD6,0x26,0xE1,0x69,0x14,0x63,0x55,0x21,0x0C,0x7D}
+};
+
+// This table stores pre-calculated values for all possible GF(2^8) calculations.This
+// table is only used by the (Inv)MixColumns steps.
+// USAGE: The second index (column) is the coefficient of multiplication. Only 7 different
+// coefficients are used: 0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e, but multiplication by
+// 1 is negligible leaving only 6 coefficients. Each column of the table is devoted to one
+// of these coefficients, in the ascending order of value, from values 0x00 to 0xFF.
+static const BYTE gf_mul[256][6] = {
+ {0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x03,0x09,0x0b,0x0d,0x0e},
+ {0x04,0x06,0x12,0x16,0x1a,0x1c},{0x06,0x05,0x1b,0x1d,0x17,0x12},
+ {0x08,0x0c,0x24,0x2c,0x34,0x38},{0x0a,0x0f,0x2d,0x27,0x39,0x36},
+ {0x0c,0x0a,0x36,0x3a,0x2e,0x24},{0x0e,0x09,0x3f,0x31,0x23,0x2a},
+ {0x10,0x18,0x48,0x58,0x68,0x70},{0x12,0x1b,0x41,0x53,0x65,0x7e},
+ {0x14,0x1e,0x5a,0x4e,0x72,0x6c},{0x16,0x1d,0x53,0x45,0x7f,0x62},
+ {0x18,0x14,0x6c,0x74,0x5c,0x48},{0x1a,0x17,0x65,0x7f,0x51,0x46},
+ {0x1c,0x12,0x7e,0x62,0x46,0x54},{0x1e,0x11,0x77,0x69,0x4b,0x5a},
+ {0x20,0x30,0x90,0xb0,0xd0,0xe0},{0x22,0x33,0x99,0xbb,0xdd,0xee},
+ {0x24,0x36,0x82,0xa6,0xca,0xfc},{0x26,0x35,0x8b,0xad,0xc7,0xf2},
+ {0x28,0x3c,0xb4,0x9c,0xe4,0xd8},{0x2a,0x3f,0xbd,0x97,0xe9,0xd6},
+ {0x2c,0x3a,0xa6,0x8a,0xfe,0xc4},{0x2e,0x39,0xaf,0x81,0xf3,0xca},
+ {0x30,0x28,0xd8,0xe8,0xb8,0x90},{0x32,0x2b,0xd1,0xe3,0xb5,0x9e},
+ {0x34,0x2e,0xca,0xfe,0xa2,0x8c},{0x36,0x2d,0xc3,0xf5,0xaf,0x82},
+ {0x38,0x24,0xfc,0xc4,0x8c,0xa8},{0x3a,0x27,0xf5,0xcf,0x81,0xa6},
+ {0x3c,0x22,0xee,0xd2,0x96,0xb4},{0x3e,0x21,0xe7,0xd9,0x9b,0xba},
+ {0x40,0x60,0x3b,0x7b,0xbb,0xdb},{0x42,0x63,0x32,0x70,0xb6,0xd5},
+ {0x44,0x66,0x29,0x6d,0xa1,0xc7},{0x46,0x65,0x20,0x66,0xac,0xc9},
+ {0x48,0x6c,0x1f,0x57,0x8f,0xe3},{0x4a,0x6f,0x16,0x5c,0x82,0xed},
+ {0x4c,0x6a,0x0d,0x41,0x95,0xff},{0x4e,0x69,0x04,0x4a,0x98,0xf1},
+ {0x50,0x78,0x73,0x23,0xd3,0xab},{0x52,0x7b,0x7a,0x28,0xde,0xa5},
+ {0x54,0x7e,0x61,0x35,0xc9,0xb7},{0x56,0x7d,0x68,0x3e,0xc4,0xb9},
+ {0x58,0x74,0x57,0x0f,0xe7,0x93},{0x5a,0x77,0x5e,0x04,0xea,0x9d},
+ {0x5c,0x72,0x45,0x19,0xfd,0x8f},{0x5e,0x71,0x4c,0x12,0xf0,0x81},
+ {0x60,0x50,0xab,0xcb,0x6b,0x3b},{0x62,0x53,0xa2,0xc0,0x66,0x35},
+ {0x64,0x56,0xb9,0xdd,0x71,0x27},{0x66,0x55,0xb0,0xd6,0x7c,0x29},
+ {0x68,0x5c,0x8f,0xe7,0x5f,0x03},{0x6a,0x5f,0x86,0xec,0x52,0x0d},
+ {0x6c,0x5a,0x9d,0xf1,0x45,0x1f},{0x6e,0x59,0x94,0xfa,0x48,0x11},
+ {0x70,0x48,0xe3,0x93,0x03,0x4b},{0x72,0x4b,0xea,0x98,0x0e,0x45},
+ {0x74,0x4e,0xf1,0x85,0x19,0x57},{0x76,0x4d,0xf8,0x8e,0x14,0x59},
+ {0x78,0x44,0xc7,0xbf,0x37,0x73},{0x7a,0x47,0xce,0xb4,0x3a,0x7d},
+ {0x7c,0x42,0xd5,0xa9,0x2d,0x6f},{0x7e,0x41,0xdc,0xa2,0x20,0x61},
+ {0x80,0xc0,0x76,0xf6,0x6d,0xad},{0x82,0xc3,0x7f,0xfd,0x60,0xa3},
+ {0x84,0xc6,0x64,0xe0,0x77,0xb1},{0x86,0xc5,0x6d,0xeb,0x7a,0xbf},
+ {0x88,0xcc,0x52,0xda,0x59,0x95},{0x8a,0xcf,0x5b,0xd1,0x54,0x9b},
+ {0x8c,0xca,0x40,0xcc,0x43,0x89},{0x8e,0xc9,0x49,0xc7,0x4e,0x87},
+ {0x90,0xd8,0x3e,0xae,0x05,0xdd},{0x92,0xdb,0x37,0xa5,0x08,0xd3},
+ {0x94,0xde,0x2c,0xb8,0x1f,0xc1},{0x96,0xdd,0x25,0xb3,0x12,0xcf},
+ {0x98,0xd4,0x1a,0x82,0x31,0xe5},{0x9a,0xd7,0x13,0x89,0x3c,0xeb},
+ {0x9c,0xd2,0x08,0x94,0x2b,0xf9},{0x9e,0xd1,0x01,0x9f,0x26,0xf7},
+ {0xa0,0xf0,0xe6,0x46,0xbd,0x4d},{0xa2,0xf3,0xef,0x4d,0xb0,0x43},
+ {0xa4,0xf6,0xf4,0x50,0xa7,0x51},{0xa6,0xf5,0xfd,0x5b,0xaa,0x5f},
+ {0xa8,0xfc,0xc2,0x6a,0x89,0x75},{0xaa,0xff,0xcb,0x61,0x84,0x7b},
+ {0xac,0xfa,0xd0,0x7c,0x93,0x69},{0xae,0xf9,0xd9,0x77,0x9e,0x67},
+ {0xb0,0xe8,0xae,0x1e,0xd5,0x3d},{0xb2,0xeb,0xa7,0x15,0xd8,0x33},
+ {0xb4,0xee,0xbc,0x08,0xcf,0x21},{0xb6,0xed,0xb5,0x03,0xc2,0x2f},
+ {0xb8,0xe4,0x8a,0x32,0xe1,0x05},{0xba,0xe7,0x83,0x39,0xec,0x0b},
+ {0xbc,0xe2,0x98,0x24,0xfb,0x19},{0xbe,0xe1,0x91,0x2f,0xf6,0x17},
+ {0xc0,0xa0,0x4d,0x8d,0xd6,0x76},{0xc2,0xa3,0x44,0x86,0xdb,0x78},
+ {0xc4,0xa6,0x5f,0x9b,0xcc,0x6a},{0xc6,0xa5,0x56,0x90,0xc1,0x64},
+ {0xc8,0xac,0x69,0xa1,0xe2,0x4e},{0xca,0xaf,0x60,0xaa,0xef,0x40},
+ {0xcc,0xaa,0x7b,0xb7,0xf8,0x52},{0xce,0xa9,0x72,0xbc,0xf5,0x5c},
+ {0xd0,0xb8,0x05,0xd5,0xbe,0x06},{0xd2,0xbb,0x0c,0xde,0xb3,0x08},
+ {0xd4,0xbe,0x17,0xc3,0xa4,0x1a},{0xd6,0xbd,0x1e,0xc8,0xa9,0x14},
+ {0xd8,0xb4,0x21,0xf9,0x8a,0x3e},{0xda,0xb7,0x28,0xf2,0x87,0x30},
+ {0xdc,0xb2,0x33,0xef,0x90,0x22},{0xde,0xb1,0x3a,0xe4,0x9d,0x2c},
+ {0xe0,0x90,0xdd,0x3d,0x06,0x96},{0xe2,0x93,0xd4,0x36,0x0b,0x98},
+ {0xe4,0x96,0xcf,0x2b,0x1c,0x8a},{0xe6,0x95,0xc6,0x20,0x11,0x84},
+ {0xe8,0x9c,0xf9,0x11,0x32,0xae},{0xea,0x9f,0xf0,0x1a,0x3f,0xa0},
+ {0xec,0x9a,0xeb,0x07,0x28,0xb2},{0xee,0x99,0xe2,0x0c,0x25,0xbc},
+ {0xf0,0x88,0x95,0x65,0x6e,0xe6},{0xf2,0x8b,0x9c,0x6e,0x63,0xe8},
+ {0xf4,0x8e,0x87,0x73,0x74,0xfa},{0xf6,0x8d,0x8e,0x78,0x79,0xf4},
+ {0xf8,0x84,0xb1,0x49,0x5a,0xde},{0xfa,0x87,0xb8,0x42,0x57,0xd0},
+ {0xfc,0x82,0xa3,0x5f,0x40,0xc2},{0xfe,0x81,0xaa,0x54,0x4d,0xcc},
+ {0x1b,0x9b,0xec,0xf7,0xda,0x41},{0x19,0x98,0xe5,0xfc,0xd7,0x4f},
+ {0x1f,0x9d,0xfe,0xe1,0xc0,0x5d},{0x1d,0x9e,0xf7,0xea,0xcd,0x53},
+ {0x13,0x97,0xc8,0xdb,0xee,0x79},{0x11,0x94,0xc1,0xd0,0xe3,0x77},
+ {0x17,0x91,0xda,0xcd,0xf4,0x65},{0x15,0x92,0xd3,0xc6,0xf9,0x6b},
+ {0x0b,0x83,0xa4,0xaf,0xb2,0x31},{0x09,0x80,0xad,0xa4,0xbf,0x3f},
+ {0x0f,0x85,0xb6,0xb9,0xa8,0x2d},{0x0d,0x86,0xbf,0xb2,0xa5,0x23},
+ {0x03,0x8f,0x80,0x83,0x86,0x09},{0x01,0x8c,0x89,0x88,0x8b,0x07},
+ {0x07,0x89,0x92,0x95,0x9c,0x15},{0x05,0x8a,0x9b,0x9e,0x91,0x1b},
+ {0x3b,0xab,0x7c,0x47,0x0a,0xa1},{0x39,0xa8,0x75,0x4c,0x07,0xaf},
+ {0x3f,0xad,0x6e,0x51,0x10,0xbd},{0x3d,0xae,0x67,0x5a,0x1d,0xb3},
+ {0x33,0xa7,0x58,0x6b,0x3e,0x99},{0x31,0xa4,0x51,0x60,0x33,0x97},
+ {0x37,0xa1,0x4a,0x7d,0x24,0x85},{0x35,0xa2,0x43,0x76,0x29,0x8b},
+ {0x2b,0xb3,0x34,0x1f,0x62,0xd1},{0x29,0xb0,0x3d,0x14,0x6f,0xdf},
+ {0x2f,0xb5,0x26,0x09,0x78,0xcd},{0x2d,0xb6,0x2f,0x02,0x75,0xc3},
+ {0x23,0xbf,0x10,0x33,0x56,0xe9},{0x21,0xbc,0x19,0x38,0x5b,0xe7},
+ {0x27,0xb9,0x02,0x25,0x4c,0xf5},{0x25,0xba,0x0b,0x2e,0x41,0xfb},
+ {0x5b,0xfb,0xd7,0x8c,0x61,0x9a},{0x59,0xf8,0xde,0x87,0x6c,0x94},
+ {0x5f,0xfd,0xc5,0x9a,0x7b,0x86},{0x5d,0xfe,0xcc,0x91,0x76,0x88},
+ {0x53,0xf7,0xf3,0xa0,0x55,0xa2},{0x51,0xf4,0xfa,0xab,0x58,0xac},
+ {0x57,0xf1,0xe1,0xb6,0x4f,0xbe},{0x55,0xf2,0xe8,0xbd,0x42,0xb0},
+ {0x4b,0xe3,0x9f,0xd4,0x09,0xea},{0x49,0xe0,0x96,0xdf,0x04,0xe4},
+ {0x4f,0xe5,0x8d,0xc2,0x13,0xf6},{0x4d,0xe6,0x84,0xc9,0x1e,0xf8},
+ {0x43,0xef,0xbb,0xf8,0x3d,0xd2},{0x41,0xec,0xb2,0xf3,0x30,0xdc},
+ {0x47,0xe9,0xa9,0xee,0x27,0xce},{0x45,0xea,0xa0,0xe5,0x2a,0xc0},
+ {0x7b,0xcb,0x47,0x3c,0xb1,0x7a},{0x79,0xc8,0x4e,0x37,0xbc,0x74},
+ {0x7f,0xcd,0x55,0x2a,0xab,0x66},{0x7d,0xce,0x5c,0x21,0xa6,0x68},
+ {0x73,0xc7,0x63,0x10,0x85,0x42},{0x71,0xc4,0x6a,0x1b,0x88,0x4c},
+ {0x77,0xc1,0x71,0x06,0x9f,0x5e},{0x75,0xc2,0x78,0x0d,0x92,0x50},
+ {0x6b,0xd3,0x0f,0x64,0xd9,0x0a},{0x69,0xd0,0x06,0x6f,0xd4,0x04},
+ {0x6f,0xd5,0x1d,0x72,0xc3,0x16},{0x6d,0xd6,0x14,0x79,0xce,0x18},
+ {0x63,0xdf,0x2b,0x48,0xed,0x32},{0x61,0xdc,0x22,0x43,0xe0,0x3c},
+ {0x67,0xd9,0x39,0x5e,0xf7,0x2e},{0x65,0xda,0x30,0x55,0xfa,0x20},
+ {0x9b,0x5b,0x9a,0x01,0xb7,0xec},{0x99,0x58,0x93,0x0a,0xba,0xe2},
+ {0x9f,0x5d,0x88,0x17,0xad,0xf0},{0x9d,0x5e,0x81,0x1c,0xa0,0xfe},
+ {0x93,0x57,0xbe,0x2d,0x83,0xd4},{0x91,0x54,0xb7,0x26,0x8e,0xda},
+ {0x97,0x51,0xac,0x3b,0x99,0xc8},{0x95,0x52,0xa5,0x30,0x94,0xc6},
+ {0x8b,0x43,0xd2,0x59,0xdf,0x9c},{0x89,0x40,0xdb,0x52,0xd2,0x92},
+ {0x8f,0x45,0xc0,0x4f,0xc5,0x80},{0x8d,0x46,0xc9,0x44,0xc8,0x8e},
+ {0x83,0x4f,0xf6,0x75,0xeb,0xa4},{0x81,0x4c,0xff,0x7e,0xe6,0xaa},
+ {0x87,0x49,0xe4,0x63,0xf1,0xb8},{0x85,0x4a,0xed,0x68,0xfc,0xb6},
+ {0xbb,0x6b,0x0a,0xb1,0x67,0x0c},{0xb9,0x68,0x03,0xba,0x6a,0x02},
+ {0xbf,0x6d,0x18,0xa7,0x7d,0x10},{0xbd,0x6e,0x11,0xac,0x70,0x1e},
+ {0xb3,0x67,0x2e,0x9d,0x53,0x34},{0xb1,0x64,0x27,0x96,0x5e,0x3a},
+ {0xb7,0x61,0x3c,0x8b,0x49,0x28},{0xb5,0x62,0x35,0x80,0x44,0x26},
+ {0xab,0x73,0x42,0xe9,0x0f,0x7c},{0xa9,0x70,0x4b,0xe2,0x02,0x72},
+ {0xaf,0x75,0x50,0xff,0x15,0x60},{0xad,0x76,0x59,0xf4,0x18,0x6e},
+ {0xa3,0x7f,0x66,0xc5,0x3b,0x44},{0xa1,0x7c,0x6f,0xce,0x36,0x4a},
+ {0xa7,0x79,0x74,0xd3,0x21,0x58},{0xa5,0x7a,0x7d,0xd8,0x2c,0x56},
+ {0xdb,0x3b,0xa1,0x7a,0x0c,0x37},{0xd9,0x38,0xa8,0x71,0x01,0x39},
+ {0xdf,0x3d,0xb3,0x6c,0x16,0x2b},{0xdd,0x3e,0xba,0x67,0x1b,0x25},
+ {0xd3,0x37,0x85,0x56,0x38,0x0f},{0xd1,0x34,0x8c,0x5d,0x35,0x01},
+ {0xd7,0x31,0x97,0x40,0x22,0x13},{0xd5,0x32,0x9e,0x4b,0x2f,0x1d},
+ {0xcb,0x23,0xe9,0x22,0x64,0x47},{0xc9,0x20,0xe0,0x29,0x69,0x49},
+ {0xcf,0x25,0xfb,0x34,0x7e,0x5b},{0xcd,0x26,0xf2,0x3f,0x73,0x55},
+ {0xc3,0x2f,0xcd,0x0e,0x50,0x7f},{0xc1,0x2c,0xc4,0x05,0x5d,0x71},
+ {0xc7,0x29,0xdf,0x18,0x4a,0x63},{0xc5,0x2a,0xd6,0x13,0x47,0x6d},
+ {0xfb,0x0b,0x31,0xca,0xdc,0xd7},{0xf9,0x08,0x38,0xc1,0xd1,0xd9},
+ {0xff,0x0d,0x23,0xdc,0xc6,0xcb},{0xfd,0x0e,0x2a,0xd7,0xcb,0xc5},
+ {0xf3,0x07,0x15,0xe6,0xe8,0xef},{0xf1,0x04,0x1c,0xed,0xe5,0xe1},
+ {0xf7,0x01,0x07,0xf0,0xf2,0xf3},{0xf5,0x02,0x0e,0xfb,0xff,0xfd},
+ {0xeb,0x13,0x79,0x92,0xb4,0xa7},{0xe9,0x10,0x70,0x99,0xb9,0xa9},
+ {0xef,0x15,0x6b,0x84,0xae,0xbb},{0xed,0x16,0x62,0x8f,0xa3,0xb5},
+ {0xe3,0x1f,0x5d,0xbe,0x80,0x9f},{0xe1,0x1c,0x54,0xb5,0x8d,0x91},
+ {0xe7,0x19,0x4f,0xa8,0x9a,0x83},{0xe5,0x1a,0x46,0xa3,0x97,0x8d}
+};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+// XORs the in and out buffers, storing the result in out. Length is in bytes.
+void xor_buf(const BYTE in[], BYTE out[], size_t len)
+{
+ size_t idx;
+
+ for (idx = 0; idx < len; idx++)
+ out[idx] ^= in[idx];
+}
+
+/*******************
+* AES - CBC
+*******************/
+int aes_encrypt_cbc(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[])
+{
+ BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE];
+ int blocks, idx;
+
+ if (in_len % AES_BLOCK_SIZE != 0)
+ return(FALSE);
+
+ blocks = in_len / AES_BLOCK_SIZE;
+
+ memcpy(buf_out, iv, AES_BLOCK_SIZE);
+
+ for (idx = 0; idx < blocks; idx++) {
+ memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE);
+ xor_buf(buf_out, buf_in, AES_BLOCK_SIZE);
+ aes_encrypt(buf_in, buf_out, key, keysize);
+ memcpy(&out[idx * AES_BLOCK_SIZE], buf_out, AES_BLOCK_SIZE);
+ }
+
+ return(TRUE);
+}
+
+int aes_encrypt_cbc_mac(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[])
+{
+ BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE];
+ int blocks, idx;
+
+ if (in_len % AES_BLOCK_SIZE != 0)
+ return(FALSE);
+
+ blocks = in_len / AES_BLOCK_SIZE;
+
+ memcpy(buf_out, iv, AES_BLOCK_SIZE);
+
+ for (idx = 0; idx < blocks; idx++) {
+ memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE);
+ xor_buf(buf_out, buf_in, AES_BLOCK_SIZE);
+ aes_encrypt(buf_in, buf_out, key, keysize);
+ // Do not output all encrypted blocks.
+ }
+
+ memcpy(out, buf_out, AES_BLOCK_SIZE); // Only output the last block.
+
+ return(TRUE);
+}
+
+// No need for an aes_decrypt_cbc() for just CCM.
+
+/*******************
+* AES - CTR
+*******************/
+void increment_iv(BYTE iv[], int counter_size)
+{
+ int idx;
+
+ // Use counter_size bytes at the end of the IV as the big-endian integer to increment.
+ for (idx = AES_BLOCK_SIZE - 1; idx >= AES_BLOCK_SIZE - counter_size; idx--) {
+ iv[idx]++;
+ if (iv[idx] != 0 || idx == AES_BLOCK_SIZE - counter_size)
+ break;
+ }
+}
+
+// Performs the encryption in-place, the input and output buffers may be the same.
+// Input may be an arbitrary length (in bytes).
+void aes_encrypt_ctr(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[])
+{
+ size_t idx = 0, last_block_length;
+ BYTE iv_buf[AES_BLOCK_SIZE], out_buf[AES_BLOCK_SIZE];
+
+ if (in != out)
+ memcpy(out, in, in_len);
+
+ memcpy(iv_buf, iv, AES_BLOCK_SIZE);
+ last_block_length = in_len - AES_BLOCK_SIZE;
+
+ if (in_len > AES_BLOCK_SIZE) {
+ for (idx = 0; idx < last_block_length; idx += AES_BLOCK_SIZE) {
+ aes_encrypt(iv_buf, out_buf, key, keysize);
+ xor_buf(out_buf, &out[idx], AES_BLOCK_SIZE);
+ increment_iv(iv_buf, AES_BLOCK_SIZE);
+ }
+ }
+
+ aes_encrypt(iv_buf, out_buf, key, keysize);
+ xor_buf(out_buf, &out[idx], in_len - idx); // Use the Most Significant bytes.
+}
+
+void aes_decrypt_ctr(const BYTE in[], size_t in_len, BYTE out[], const WORD key[], int keysize, const BYTE iv[])
+{
+ // CTR encryption is its own inverse function.
+ aes_encrypt_ctr(in, in_len, out, key, keysize, iv);
+}
+
+/*******************
+* AES - CCM
+*******************/
+// out_len = payload_len + assoc_len
+int aes_encrypt_ccm(const BYTE payload[], WORD payload_len, const BYTE assoc[], unsigned short assoc_len,
+ const BYTE nonce[], unsigned short nonce_len, BYTE out[], WORD *out_len,
+ WORD mac_len, const BYTE key_str[], int keysize)
+{
+ BYTE temp_iv[AES_BLOCK_SIZE], counter[AES_BLOCK_SIZE], mac[16], *buf;
+ int end_of_buf, payload_len_store_size;
+ WORD key[60];
+
+ if (mac_len != 4 && mac_len != 6 && mac_len != 8 && mac_len != 10 &&
+ mac_len != 12 && mac_len != 14 && mac_len != 16)
+ return(FALSE);
+
+ if (nonce_len < 7 || nonce_len > 13)
+ return(FALSE);
+
+ if (assoc_len > 32768 /* = 2^15 */)
+ return(FALSE);
+
+ buf = (BYTE*)malloc(payload_len + assoc_len + 48 /*Round both payload and associated data up a block size and add an extra block.*/);
+ if (! buf)
+ return(FALSE);
+
+ // Prepare the key for usage.
+ aes_key_setup(key_str, key, keysize);
+
+ // Format the first block of the formatted data.
+ payload_len_store_size = AES_BLOCK_SIZE - 1 - nonce_len;
+ ccm_prepare_first_format_blk(buf, assoc_len, payload_len, payload_len_store_size, mac_len, nonce, nonce_len);
+ end_of_buf = AES_BLOCK_SIZE;
+
+ // Format the Associated Data, aka, assoc[].
+ ccm_format_assoc_data(buf, &end_of_buf, assoc, assoc_len);
+
+ // Format the Payload, aka payload[].
+ ccm_format_payload_data(buf, &end_of_buf, payload, payload_len);
+
+ // Create the first counter block.
+ ccm_prepare_first_ctr_blk(counter, nonce, nonce_len, payload_len_store_size);
+
+ // Perform the CBC operation with an IV of zeros on the formatted buffer to calculate the MAC.
+ memset(temp_iv, 0, AES_BLOCK_SIZE);
+ aes_encrypt_cbc_mac(buf, end_of_buf, mac, key, keysize, temp_iv);
+
+ // Copy the Payload and MAC to the output buffer.
+ memcpy(out, payload, payload_len);
+ memcpy(&out[payload_len], mac, mac_len);
+
+ // Encrypt the Payload with CTR mode with a counter starting at 1.
+ memcpy(temp_iv, counter, AES_BLOCK_SIZE);
+ increment_iv(temp_iv, AES_BLOCK_SIZE - 1 - mac_len); // Last argument is the byte size of the counting portion of the counter block. /*BUG?*/
+ aes_encrypt_ctr(out, payload_len, out, key, keysize, temp_iv);
+
+ // Encrypt the MAC with CTR mode with a counter starting at 0.
+ aes_encrypt_ctr(&out[payload_len], mac_len, &out[payload_len], key, keysize, counter);
+
+ free(buf);
+ *out_len = payload_len + mac_len;
+
+ return(TRUE);
+}
+
+// plaintext_len = ciphertext_len - mac_len
+// Needs a flag for whether the MAC matches.
+int aes_decrypt_ccm(const BYTE ciphertext[], WORD ciphertext_len, const BYTE assoc[], unsigned short assoc_len,
+ const BYTE nonce[], unsigned short nonce_len, BYTE plaintext[], WORD *plaintext_len,
+ WORD mac_len, int *mac_auth, const BYTE key_str[], int keysize)
+{
+ BYTE temp_iv[AES_BLOCK_SIZE], counter[AES_BLOCK_SIZE], mac[16], mac_buf[16], *buf;
+ int end_of_buf, plaintext_len_store_size;
+ WORD key[60];
+
+ if (ciphertext_len <= mac_len)
+ return(FALSE);
+
+ buf = (BYTE*)malloc(assoc_len + ciphertext_len /*ciphertext_len = plaintext_len + mac_len*/ + 48);
+ if (! buf)
+ return(FALSE);
+
+ // Prepare the key for usage.
+ aes_key_setup(key_str, key, keysize);
+
+ // Copy the plaintext and MAC to the output buffers.
+ *plaintext_len = ciphertext_len - mac_len;
+ plaintext_len_store_size = AES_BLOCK_SIZE - 1 - nonce_len;
+ memcpy(plaintext, ciphertext, *plaintext_len);
+ memcpy(mac, &ciphertext[*plaintext_len], mac_len);
+
+ // Prepare the first counter block for use in decryption.
+ ccm_prepare_first_ctr_blk(counter, nonce, nonce_len, plaintext_len_store_size);
+
+ // Decrypt the Payload with CTR mode with a counter starting at 1.
+ memcpy(temp_iv, counter, AES_BLOCK_SIZE);
+ increment_iv(temp_iv, AES_BLOCK_SIZE - 1 - mac_len); // (AES_BLOCK_SIZE - 1 - mac_len) is the byte size of the counting portion of the counter block.
+ aes_decrypt_ctr(plaintext, *plaintext_len, plaintext, key, keysize, temp_iv);
+
+ // Setting mac_auth to NULL disables the authentication check.
+ if (mac_auth != NULL) {
+ // Decrypt the MAC with CTR mode with a counter starting at 0.
+ aes_decrypt_ctr(mac, mac_len, mac, key, keysize, counter);
+
+ // Format the first block of the formatted data.
+ plaintext_len_store_size = AES_BLOCK_SIZE - 1 - nonce_len;
+ ccm_prepare_first_format_blk(buf, assoc_len, *plaintext_len, plaintext_len_store_size, mac_len, nonce, nonce_len);
+ end_of_buf = AES_BLOCK_SIZE;
+
+ // Format the Associated Data into the authentication buffer.
+ ccm_format_assoc_data(buf, &end_of_buf, assoc, assoc_len);
+
+ // Format the Payload into the authentication buffer.
+ ccm_format_payload_data(buf, &end_of_buf, plaintext, *plaintext_len);
+
+ // Perform the CBC operation with an IV of zeros on the formatted buffer to calculate the MAC.
+ memset(temp_iv, 0, AES_BLOCK_SIZE);
+ aes_encrypt_cbc_mac(buf, end_of_buf, mac_buf, key, keysize, temp_iv);
+
+ // Compare the calculated MAC against the MAC embedded in the ciphertext to see if they are the same.
+ if (! memcmp(mac, mac_buf, mac_len)) {
+ *mac_auth = TRUE;
+ }
+ else {
+ *mac_auth = FALSE;
+ memset(plaintext, 0, *plaintext_len);
+ }
+ }
+
+ free(buf);
+
+ return(TRUE);
+}
+
+// Creates the first counter block. First byte is flags, then the nonce, then the incremented part.
+void ccm_prepare_first_ctr_blk(BYTE counter[], const BYTE nonce[], int nonce_len, int payload_len_store_size)
+{
+ memset(counter, 0, AES_BLOCK_SIZE);
+ counter[0] = (payload_len_store_size - 1) & 0x07;
+ memcpy(&counter[1], nonce, nonce_len);
+}
+
+void ccm_prepare_first_format_blk(BYTE buf[], int assoc_len, int payload_len, int payload_len_store_size, int mac_len, const BYTE nonce[], int nonce_len)
+{
+ // Set the flags for the first byte of the first block.
+ buf[0] = ((((mac_len - 2) / 2) & 0x07) << 3) | ((payload_len_store_size - 1) & 0x07);
+ if (assoc_len > 0)
+ buf[0] += 0x40;
+ // Format the rest of the first block, storing the nonce and the size of the payload.
+ memcpy(&buf[1], nonce, nonce_len);
+ memset(&buf[1 + nonce_len], 0, AES_BLOCK_SIZE - 1 - nonce_len);
+ buf[15] = payload_len & 0x000000FF;
+ buf[14] = (payload_len >> 8) & 0x000000FF;
+}
+
+void ccm_format_assoc_data(BYTE buf[], int *end_of_buf, const BYTE assoc[], int assoc_len)
+{
+ int pad;
+
+ buf[*end_of_buf + 1] = assoc_len & 0x00FF;
+ buf[*end_of_buf] = (assoc_len >> 8) & 0x00FF;
+ *end_of_buf += 2;
+ memcpy(&buf[*end_of_buf], assoc, assoc_len);
+ *end_of_buf += assoc_len;
+ pad = AES_BLOCK_SIZE - (*end_of_buf % AES_BLOCK_SIZE); /*BUG?*/
+ memset(&buf[*end_of_buf], 0, pad);
+ *end_of_buf += pad;
+}
+
+void ccm_format_payload_data(BYTE buf[], int *end_of_buf, const BYTE payload[], int payload_len)
+{
+ int pad;
+
+ memcpy(&buf[*end_of_buf], payload, payload_len);
+ *end_of_buf += payload_len;
+ pad = *end_of_buf % AES_BLOCK_SIZE;
+ if (pad != 0)
+ pad = AES_BLOCK_SIZE - pad;
+ memset(&buf[*end_of_buf], 0, pad);
+ *end_of_buf += pad;
+}
+
+/*******************
+* AES
+*******************/
+/////////////////
+// KEY EXPANSION
+/////////////////
+
+// Substitutes a word using the AES S-Box.
+WORD SubWord(WORD word)
+{
+ unsigned int result;
+
+ result = (int)aes_sbox[(word >> 4) & 0x0000000F][word & 0x0000000F];
+ result += (int)aes_sbox[(word >> 12) & 0x0000000F][(word >> 8) & 0x0000000F] << 8;
+ result += (int)aes_sbox[(word >> 20) & 0x0000000F][(word >> 16) & 0x0000000F] << 16;
+ result += (int)aes_sbox[(word >> 28) & 0x0000000F][(word >> 24) & 0x0000000F] << 24;
+ return(result);
+}
+
+// Performs the action of generating the keys that will be used in every round of
+// encryption. "key" is the user-supplied input key, "w" is the output key schedule,
+// "keysize" is the length in bits of "key", must be 128, 192, or 256.
+void aes_key_setup(const BYTE key[], WORD w[], int keysize)
+{
+ int Nb=4,Nr,Nk,idx;
+ WORD temp,Rcon[]={0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000,
+ 0x40000000,0x80000000,0x1b000000,0x36000000,0x6c000000,0xd8000000,
+ 0xab000000,0x4d000000,0x9a000000};
+
+ switch (keysize) {
+ case 128: Nr = 10; Nk = 4; break;
+ case 192: Nr = 12; Nk = 6; break;
+ case 256: Nr = 14; Nk = 8; break;
+ default: return;
+ }
+
+ for (idx=0; idx < Nk; ++idx) {
+ w[idx] = ((key[4 * idx]) << 24) | ((key[4 * idx + 1]) << 16) |
+ ((key[4 * idx + 2]) << 8) | ((key[4 * idx + 3]));
+ }
+
+ for (idx = Nk; idx < Nb * (Nr+1); ++idx) {
+ temp = w[idx - 1];
+ if ((idx % Nk) == 0)
+ temp = SubWord(KE_ROTWORD(temp)) ^ Rcon[(idx-1)/Nk];
+ else if (Nk > 6 && (idx % Nk) == 4)
+ temp = SubWord(temp);
+ w[idx] = w[idx-Nk] ^ temp;
+ }
+}
+
+/////////////////
+// ADD ROUND KEY
+/////////////////
+
+// Performs the AddRoundKey step. Each round has its own pre-generated 16-byte key in the
+// form of 4 integers (the "w" array). Each integer is XOR'd by one column of the state.
+// Also performs the job of InvAddRoundKey(); since the function is a simple XOR process,
+// it is its own inverse.
+void AddRoundKey(BYTE state[][4], const WORD w[])
+{
+ BYTE subkey[4];
+
+ // memcpy(subkey,&w[idx],4); // Not accurate for big endian machines
+ // Subkey 1
+ subkey[0] = w[0] >> 24;
+ subkey[1] = w[0] >> 16;
+ subkey[2] = w[0] >> 8;
+ subkey[3] = w[0];
+ state[0][0] ^= subkey[0];
+ state[1][0] ^= subkey[1];
+ state[2][0] ^= subkey[2];
+ state[3][0] ^= subkey[3];
+ // Subkey 2
+ subkey[0] = w[1] >> 24;
+ subkey[1] = w[1] >> 16;
+ subkey[2] = w[1] >> 8;
+ subkey[3] = w[1];
+ state[0][1] ^= subkey[0];
+ state[1][1] ^= subkey[1];
+ state[2][1] ^= subkey[2];
+ state[3][1] ^= subkey[3];
+ // Subkey 3
+ subkey[0] = w[2] >> 24;
+ subkey[1] = w[2] >> 16;
+ subkey[2] = w[2] >> 8;
+ subkey[3] = w[2];
+ state[0][2] ^= subkey[0];
+ state[1][2] ^= subkey[1];
+ state[2][2] ^= subkey[2];
+ state[3][2] ^= subkey[3];
+ // Subkey 4
+ subkey[0] = w[3] >> 24;
+ subkey[1] = w[3] >> 16;
+ subkey[2] = w[3] >> 8;
+ subkey[3] = w[3];
+ state[0][3] ^= subkey[0];
+ state[1][3] ^= subkey[1];
+ state[2][3] ^= subkey[2];
+ state[3][3] ^= subkey[3];
+}
+
+/////////////////
+// (Inv)SubBytes
+/////////////////
+
+// Performs the SubBytes step. All bytes in the state are substituted with a
+// pre-calculated value from a lookup table.
+void SubBytes(BYTE state[][4])
+{
+ state[0][0] = aes_sbox[state[0][0] >> 4][state[0][0] & 0x0F];
+ state[0][1] = aes_sbox[state[0][1] >> 4][state[0][1] & 0x0F];
+ state[0][2] = aes_sbox[state[0][2] >> 4][state[0][2] & 0x0F];
+ state[0][3] = aes_sbox[state[0][3] >> 4][state[0][3] & 0x0F];
+ state[1][0] = aes_sbox[state[1][0] >> 4][state[1][0] & 0x0F];
+ state[1][1] = aes_sbox[state[1][1] >> 4][state[1][1] & 0x0F];
+ state[1][2] = aes_sbox[state[1][2] >> 4][state[1][2] & 0x0F];
+ state[1][3] = aes_sbox[state[1][3] >> 4][state[1][3] & 0x0F];
+ state[2][0] = aes_sbox[state[2][0] >> 4][state[2][0] & 0x0F];
+ state[2][1] = aes_sbox[state[2][1] >> 4][state[2][1] & 0x0F];
+ state[2][2] = aes_sbox[state[2][2] >> 4][state[2][2] & 0x0F];
+ state[2][3] = aes_sbox[state[2][3] >> 4][state[2][3] & 0x0F];
+ state[3][0] = aes_sbox[state[3][0] >> 4][state[3][0] & 0x0F];
+ state[3][1] = aes_sbox[state[3][1] >> 4][state[3][1] & 0x0F];
+ state[3][2] = aes_sbox[state[3][2] >> 4][state[3][2] & 0x0F];
+ state[3][3] = aes_sbox[state[3][3] >> 4][state[3][3] & 0x0F];
+}
+
+void InvSubBytes(BYTE state[][4])
+{
+ state[0][0] = aes_invsbox[state[0][0] >> 4][state[0][0] & 0x0F];
+ state[0][1] = aes_invsbox[state[0][1] >> 4][state[0][1] & 0x0F];
+ state[0][2] = aes_invsbox[state[0][2] >> 4][state[0][2] & 0x0F];
+ state[0][3] = aes_invsbox[state[0][3] >> 4][state[0][3] & 0x0F];
+ state[1][0] = aes_invsbox[state[1][0] >> 4][state[1][0] & 0x0F];
+ state[1][1] = aes_invsbox[state[1][1] >> 4][state[1][1] & 0x0F];
+ state[1][2] = aes_invsbox[state[1][2] >> 4][state[1][2] & 0x0F];
+ state[1][3] = aes_invsbox[state[1][3] >> 4][state[1][3] & 0x0F];
+ state[2][0] = aes_invsbox[state[2][0] >> 4][state[2][0] & 0x0F];
+ state[2][1] = aes_invsbox[state[2][1] >> 4][state[2][1] & 0x0F];
+ state[2][2] = aes_invsbox[state[2][2] >> 4][state[2][2] & 0x0F];
+ state[2][3] = aes_invsbox[state[2][3] >> 4][state[2][3] & 0x0F];
+ state[3][0] = aes_invsbox[state[3][0] >> 4][state[3][0] & 0x0F];
+ state[3][1] = aes_invsbox[state[3][1] >> 4][state[3][1] & 0x0F];
+ state[3][2] = aes_invsbox[state[3][2] >> 4][state[3][2] & 0x0F];
+ state[3][3] = aes_invsbox[state[3][3] >> 4][state[3][3] & 0x0F];
+}
+
+/////////////////
+// (Inv)ShiftRows
+/////////////////
+
+// Performs the ShiftRows step. All rows are shifted cylindrically to the left.
+void ShiftRows(BYTE state[][4])
+{
+ int t;
+
+ // Shift left by 1
+ t = state[1][0];
+ state[1][0] = state[1][1];
+ state[1][1] = state[1][2];
+ state[1][2] = state[1][3];
+ state[1][3] = t;
+ // Shift left by 2
+ t = state[2][0];
+ state[2][0] = state[2][2];
+ state[2][2] = t;
+ t = state[2][1];
+ state[2][1] = state[2][3];
+ state[2][3] = t;
+ // Shift left by 3
+ t = state[3][0];
+ state[3][0] = state[3][3];
+ state[3][3] = state[3][2];
+ state[3][2] = state[3][1];
+ state[3][1] = t;
+}
+
+// All rows are shifted cylindrically to the right.
+void InvShiftRows(BYTE state[][4])
+{
+ int t;
+
+ // Shift right by 1
+ t = state[1][3];
+ state[1][3] = state[1][2];
+ state[1][2] = state[1][1];
+ state[1][1] = state[1][0];
+ state[1][0] = t;
+ // Shift right by 2
+ t = state[2][3];
+ state[2][3] = state[2][1];
+ state[2][1] = t;
+ t = state[2][2];
+ state[2][2] = state[2][0];
+ state[2][0] = t;
+ // Shift right by 3
+ t = state[3][3];
+ state[3][3] = state[3][0];
+ state[3][0] = state[3][1];
+ state[3][1] = state[3][2];
+ state[3][2] = t;
+}
+
+/////////////////
+// (Inv)MixColumns
+/////////////////
+
+// Performs the MixColums step. The state is multiplied by itself using matrix
+// multiplication in a Galios Field 2^8. All multiplication is pre-computed in a table.
+// Addition is equivilent to XOR. (Must always make a copy of the column as the original
+// values will be destoyed.)
+void MixColumns(BYTE state[][4])
+{
+ BYTE col[4];
+
+ // Column 1
+ col[0] = state[0][0];
+ col[1] = state[1][0];
+ col[2] = state[2][0];
+ col[3] = state[3][0];
+ state[0][0] = gf_mul[col[0]][0];
+ state[0][0] ^= gf_mul[col[1]][1];
+ state[0][0] ^= col[2];
+ state[0][0] ^= col[3];
+ state[1][0] = col[0];
+ state[1][0] ^= gf_mul[col[1]][0];
+ state[1][0] ^= gf_mul[col[2]][1];
+ state[1][0] ^= col[3];
+ state[2][0] = col[0];
+ state[2][0] ^= col[1];
+ state[2][0] ^= gf_mul[col[2]][0];
+ state[2][0] ^= gf_mul[col[3]][1];
+ state[3][0] = gf_mul[col[0]][1];
+ state[3][0] ^= col[1];
+ state[3][0] ^= col[2];
+ state[3][0] ^= gf_mul[col[3]][0];
+ // Column 2
+ col[0] = state[0][1];
+ col[1] = state[1][1];
+ col[2] = state[2][1];
+ col[3] = state[3][1];
+ state[0][1] = gf_mul[col[0]][0];
+ state[0][1] ^= gf_mul[col[1]][1];
+ state[0][1] ^= col[2];
+ state[0][1] ^= col[3];
+ state[1][1] = col[0];
+ state[1][1] ^= gf_mul[col[1]][0];
+ state[1][1] ^= gf_mul[col[2]][1];
+ state[1][1] ^= col[3];
+ state[2][1] = col[0];
+ state[2][1] ^= col[1];
+ state[2][1] ^= gf_mul[col[2]][0];
+ state[2][1] ^= gf_mul[col[3]][1];
+ state[3][1] = gf_mul[col[0]][1];
+ state[3][1] ^= col[1];
+ state[3][1] ^= col[2];
+ state[3][1] ^= gf_mul[col[3]][0];
+ // Column 3
+ col[0] = state[0][2];
+ col[1] = state[1][2];
+ col[2] = state[2][2];
+ col[3] = state[3][2];
+ state[0][2] = gf_mul[col[0]][0];
+ state[0][2] ^= gf_mul[col[1]][1];
+ state[0][2] ^= col[2];
+ state[0][2] ^= col[3];
+ state[1][2] = col[0];
+ state[1][2] ^= gf_mul[col[1]][0];
+ state[1][2] ^= gf_mul[col[2]][1];
+ state[1][2] ^= col[3];
+ state[2][2] = col[0];
+ state[2][2] ^= col[1];
+ state[2][2] ^= gf_mul[col[2]][0];
+ state[2][2] ^= gf_mul[col[3]][1];
+ state[3][2] = gf_mul[col[0]][1];
+ state[3][2] ^= col[1];
+ state[3][2] ^= col[2];
+ state[3][2] ^= gf_mul[col[3]][0];
+ // Column 4
+ col[0] = state[0][3];
+ col[1] = state[1][3];
+ col[2] = state[2][3];
+ col[3] = state[3][3];
+ state[0][3] = gf_mul[col[0]][0];
+ state[0][3] ^= gf_mul[col[1]][1];
+ state[0][3] ^= col[2];
+ state[0][3] ^= col[3];
+ state[1][3] = col[0];
+ state[1][3] ^= gf_mul[col[1]][0];
+ state[1][3] ^= gf_mul[col[2]][1];
+ state[1][3] ^= col[3];
+ state[2][3] = col[0];
+ state[2][3] ^= col[1];
+ state[2][3] ^= gf_mul[col[2]][0];
+ state[2][3] ^= gf_mul[col[3]][1];
+ state[3][3] = gf_mul[col[0]][1];
+ state[3][3] ^= col[1];
+ state[3][3] ^= col[2];
+ state[3][3] ^= gf_mul[col[3]][0];
+}
+
+void InvMixColumns(BYTE state[][4])
+{
+ BYTE col[4];
+
+ // Column 1
+ col[0] = state[0][0];
+ col[1] = state[1][0];
+ col[2] = state[2][0];
+ col[3] = state[3][0];
+ state[0][0] = gf_mul[col[0]][5];
+ state[0][0] ^= gf_mul[col[1]][3];
+ state[0][0] ^= gf_mul[col[2]][4];
+ state[0][0] ^= gf_mul[col[3]][2];
+ state[1][0] = gf_mul[col[0]][2];
+ state[1][0] ^= gf_mul[col[1]][5];
+ state[1][0] ^= gf_mul[col[2]][3];
+ state[1][0] ^= gf_mul[col[3]][4];
+ state[2][0] = gf_mul[col[0]][4];
+ state[2][0] ^= gf_mul[col[1]][2];
+ state[2][0] ^= gf_mul[col[2]][5];
+ state[2][0] ^= gf_mul[col[3]][3];
+ state[3][0] = gf_mul[col[0]][3];
+ state[3][0] ^= gf_mul[col[1]][4];
+ state[3][0] ^= gf_mul[col[2]][2];
+ state[3][0] ^= gf_mul[col[3]][5];
+ // Column 2
+ col[0] = state[0][1];
+ col[1] = state[1][1];
+ col[2] = state[2][1];
+ col[3] = state[3][1];
+ state[0][1] = gf_mul[col[0]][5];
+ state[0][1] ^= gf_mul[col[1]][3];
+ state[0][1] ^= gf_mul[col[2]][4];
+ state[0][1] ^= gf_mul[col[3]][2];
+ state[1][1] = gf_mul[col[0]][2];
+ state[1][1] ^= gf_mul[col[1]][5];
+ state[1][1] ^= gf_mul[col[2]][3];
+ state[1][1] ^= gf_mul[col[3]][4];
+ state[2][1] = gf_mul[col[0]][4];
+ state[2][1] ^= gf_mul[col[1]][2];
+ state[2][1] ^= gf_mul[col[2]][5];
+ state[2][1] ^= gf_mul[col[3]][3];
+ state[3][1] = gf_mul[col[0]][3];
+ state[3][1] ^= gf_mul[col[1]][4];
+ state[3][1] ^= gf_mul[col[2]][2];
+ state[3][1] ^= gf_mul[col[3]][5];
+ // Column 3
+ col[0] = state[0][2];
+ col[1] = state[1][2];
+ col[2] = state[2][2];
+ col[3] = state[3][2];
+ state[0][2] = gf_mul[col[0]][5];
+ state[0][2] ^= gf_mul[col[1]][3];
+ state[0][2] ^= gf_mul[col[2]][4];
+ state[0][2] ^= gf_mul[col[3]][2];
+ state[1][2] = gf_mul[col[0]][2];
+ state[1][2] ^= gf_mul[col[1]][5];
+ state[1][2] ^= gf_mul[col[2]][3];
+ state[1][2] ^= gf_mul[col[3]][4];
+ state[2][2] = gf_mul[col[0]][4];
+ state[2][2] ^= gf_mul[col[1]][2];
+ state[2][2] ^= gf_mul[col[2]][5];
+ state[2][2] ^= gf_mul[col[3]][3];
+ state[3][2] = gf_mul[col[0]][3];
+ state[3][2] ^= gf_mul[col[1]][4];
+ state[3][2] ^= gf_mul[col[2]][2];
+ state[3][2] ^= gf_mul[col[3]][5];
+ // Column 4
+ col[0] = state[0][3];
+ col[1] = state[1][3];
+ col[2] = state[2][3];
+ col[3] = state[3][3];
+ state[0][3] = gf_mul[col[0]][5];
+ state[0][3] ^= gf_mul[col[1]][3];
+ state[0][3] ^= gf_mul[col[2]][4];
+ state[0][3] ^= gf_mul[col[3]][2];
+ state[1][3] = gf_mul[col[0]][2];
+ state[1][3] ^= gf_mul[col[1]][5];
+ state[1][3] ^= gf_mul[col[2]][3];
+ state[1][3] ^= gf_mul[col[3]][4];
+ state[2][3] = gf_mul[col[0]][4];
+ state[2][3] ^= gf_mul[col[1]][2];
+ state[2][3] ^= gf_mul[col[2]][5];
+ state[2][3] ^= gf_mul[col[3]][3];
+ state[3][3] = gf_mul[col[0]][3];
+ state[3][3] ^= gf_mul[col[1]][4];
+ state[3][3] ^= gf_mul[col[2]][2];
+ state[3][3] ^= gf_mul[col[3]][5];
+}
+
+/////////////////
+// (En/De)Crypt
+/////////////////
+
+void aes_encrypt(const BYTE in[], BYTE out[], const WORD key[], int keysize)
+{
+ BYTE state[4][4];
+
+ // Copy input array (should be 16 bytes long) to a matrix (sequential bytes are ordered
+ // by row, not col) called "state" for processing.
+ // *** Implementation note: The official AES documentation references the state by
+ // column, then row. Accessing an element in C requires row then column. Thus, all state
+ // references in AES must have the column and row indexes reversed for C implementation.
+ state[0][0] = in[0];
+ state[1][0] = in[1];
+ state[2][0] = in[2];
+ state[3][0] = in[3];
+ state[0][1] = in[4];
+ state[1][1] = in[5];
+ state[2][1] = in[6];
+ state[3][1] = in[7];
+ state[0][2] = in[8];
+ state[1][2] = in[9];
+ state[2][2] = in[10];
+ state[3][2] = in[11];
+ state[0][3] = in[12];
+ state[1][3] = in[13];
+ state[2][3] = in[14];
+ state[3][3] = in[15];
+
+ // Perform the necessary number of rounds. The round key is added first.
+ // The last round does not perform the MixColumns step.
+ AddRoundKey(state,&key[0]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[4]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[8]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[12]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[16]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[20]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[24]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[28]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[32]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[36]);
+ if (keysize != 128) {
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[40]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[44]);
+ if (keysize != 192) {
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[48]);
+ SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[52]);
+ SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[56]);
+ }
+ else {
+ SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[48]);
+ }
+ }
+ else {
+ SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[40]);
+ }
+
+ // Copy the state to the output array.
+ out[0] = state[0][0];
+ out[1] = state[1][0];
+ out[2] = state[2][0];
+ out[3] = state[3][0];
+ out[4] = state[0][1];
+ out[5] = state[1][1];
+ out[6] = state[2][1];
+ out[7] = state[3][1];
+ out[8] = state[0][2];
+ out[9] = state[1][2];
+ out[10] = state[2][2];
+ out[11] = state[3][2];
+ out[12] = state[0][3];
+ out[13] = state[1][3];
+ out[14] = state[2][3];
+ out[15] = state[3][3];
+}
+
+void aes_decrypt(const BYTE in[], BYTE out[], const WORD key[], int keysize)
+{
+ BYTE state[4][4];
+
+ // Copy the input to the state.
+ state[0][0] = in[0];
+ state[1][0] = in[1];
+ state[2][0] = in[2];
+ state[3][0] = in[3];
+ state[0][1] = in[4];
+ state[1][1] = in[5];
+ state[2][1] = in[6];
+ state[3][1] = in[7];
+ state[0][2] = in[8];
+ state[1][2] = in[9];
+ state[2][2] = in[10];
+ state[3][2] = in[11];
+ state[0][3] = in[12];
+ state[1][3] = in[13];
+ state[2][3] = in[14];
+ state[3][3] = in[15];
+
+ // Perform the necessary number of rounds. The round key is added first.
+ // The last round does not perform the MixColumns step.
+ if (keysize > 128) {
+ if (keysize > 192) {
+ AddRoundKey(state,&key[56]);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[52]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[48]);InvMixColumns(state);
+ }
+ else {
+ AddRoundKey(state,&key[48]);
+ }
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[44]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[40]);InvMixColumns(state);
+ }
+ else {
+ AddRoundKey(state,&key[40]);
+ }
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[36]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[32]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[28]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[24]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[20]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[16]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[12]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[8]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[4]);InvMixColumns(state);
+ InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[0]);
+
+ // Copy the state to the output array.
+ out[0] = state[0][0];
+ out[1] = state[1][0];
+ out[2] = state[2][0];
+ out[3] = state[3][0];
+ out[4] = state[0][1];
+ out[5] = state[1][1];
+ out[6] = state[2][1];
+ out[7] = state[3][1];
+ out[8] = state[0][2];
+ out[9] = state[1][2];
+ out[10] = state[2][2];
+ out[11] = state[3][2];
+ out[12] = state[0][3];
+ out[13] = state[1][3];
+ out[14] = state[2][3];
+ out[15] = state[3][3];
+}
+
+/*******************
+** AES DEBUGGING FUNCTIONS
+*******************/
+/*
+// This prints the "state" grid as a linear hex string.
+void print_state(BYTE state[][4])
+{
+ int idx,idx2;
+
+ for (idx=0; idx < 4; idx++)
+ for (idx2=0; idx2 < 4; idx2++)
+ printf("%02x",state[idx2][idx]);
+ printf("\n");
+}
+
+// This prints the key (4 consecutive ints) used for a given round as a linear hex string.
+void print_rnd_key(WORD key[])
+{
+ int idx;
+
+ for (idx=0; idx < 4; idx++)
+ printf("%08x",key[idx]);
+ printf("\n");
+}
+*/
diff --git a/lib/crypto-algorithms/aes.h b/lib/crypto-algorithms/aes.h
new file mode 100644
index 0000000..25721c8
--- /dev/null
+++ b/lib/crypto-algorithms/aes.h
@@ -0,0 +1,123 @@
+/*********************************************************************
+* Filename: aes.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding AES implementation.
+*********************************************************************/
+
+#ifndef AES_H
+#define AES_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/****************************** MACROS ******************************/
+#define AES_BLOCK_SIZE 16 // AES operates on 16 bytes at a time
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
+
+/*********************** FUNCTION DECLARATIONS **********************/
+///////////////////
+// AES
+///////////////////
+// Key setup must be done before any AES en/de-cryption functions can be used.
+void aes_key_setup(const BYTE key[], // The key, must be 128, 192, or 256 bits
+ WORD w[], // Output key schedule to be used later
+ int keysize); // Bit length of the key, 128, 192, or 256
+
+void aes_encrypt(const BYTE in[], // 16 bytes of plaintext
+ BYTE out[], // 16 bytes of ciphertext
+ const WORD key[], // From the key setup
+ int keysize); // Bit length of the key, 128, 192, or 256
+
+void aes_decrypt(const BYTE in[], // 16 bytes of ciphertext
+ BYTE out[], // 16 bytes of plaintext
+ const WORD key[], // From the key setup
+ int keysize); // Bit length of the key, 128, 192, or 256
+
+///////////////////
+// AES - CBC
+///////////////////
+int aes_encrypt_cbc(const BYTE in[], // Plaintext
+ size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
+ BYTE out[], // Ciphertext, same length as plaintext
+ const WORD key[], // From the key setup
+ int keysize, // Bit length of the key, 128, 192, or 256
+ const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
+
+// Only output the CBC-MAC of the input.
+int aes_encrypt_cbc_mac(const BYTE in[], // plaintext
+ size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
+ BYTE out[], // Output MAC
+ const WORD key[], // From the key setup
+ int keysize, // Bit length of the key, 128, 192, or 256
+ const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
+
+///////////////////
+// AES - CTR
+///////////////////
+void increment_iv(BYTE iv[], // Must be a multiple of AES_BLOCK_SIZE
+ int counter_size); // Bytes of the IV used for counting (low end)
+
+void aes_encrypt_ctr(const BYTE in[], // Plaintext
+ size_t in_len, // Any byte length
+ BYTE out[], // Ciphertext, same length as plaintext
+ const WORD key[], // From the key setup
+ int keysize, // Bit length of the key, 128, 192, or 256
+ const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
+
+void aes_decrypt_ctr(const BYTE in[], // Ciphertext
+ size_t in_len, // Any byte length
+ BYTE out[], // Plaintext, same length as ciphertext
+ const WORD key[], // From the key setup
+ int keysize, // Bit length of the key, 128, 192, or 256
+ const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
+
+///////////////////
+// AES - CCM
+///////////////////
+// Returns True if the input parameters do not violate any constraint.
+int aes_encrypt_ccm(const BYTE plaintext[], // IN - Plaintext.
+ WORD plaintext_len, // IN - Plaintext length.
+ const BYTE associated_data[], // IN - Associated Data included in authentication, but not encryption.
+ unsigned short associated_data_len, // IN - Associated Data length in bytes.
+ const BYTE nonce[], // IN - The Nonce to be used for encryption.
+ unsigned short nonce_len, // IN - Nonce length in bytes.
+ BYTE ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC.
+ WORD *ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len.
+ WORD mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16.
+ const BYTE key[], // IN - The AES key for encryption.
+ int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256.
+
+// Returns True if the input parameters do not violate any constraint.
+// Use mac_auth to ensure decryption/validation was preformed correctly.
+// If authentication does not succeed, the plaintext is zeroed out. To overwride
+// this, call with mac_auth = NULL. The proper proceedure is to decrypt with
+// authentication enabled (mac_auth != NULL) and make a second call to that
+// ignores authentication explicitly if the first call failes.
+int aes_decrypt_ccm(const BYTE ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC.
+ WORD ciphertext_len, // IN - Ciphertext length in bytes.
+ const BYTE assoc[], // IN - The Associated Data, required for authentication.
+ unsigned short assoc_len, // IN - Associated Data length in bytes.
+ const BYTE nonce[], // IN - The Nonce to use for decryption, same one as for encryption.
+ unsigned short nonce_len, // IN - Nonce length in bytes.
+ BYTE plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len - mac_len.
+ WORD *plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len .
+ WORD mac_len, // IN - The length of the MAC that was calculated.
+ int *mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the authentication.
+ const BYTE key[], // IN - The AES key for decryption.
+ int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256.
+
+///////////////////
+// Test functions
+///////////////////
+int aes_test();
+int aes_ecb_test();
+int aes_cbc_test();
+int aes_ctr_test();
+int aes_ccm_test();
+
+#endif // AES_H
diff --git a/lib/crypto-algorithms/aes_test.c b/lib/crypto-algorithms/aes_test.c
new file mode 100644
index 0000000..d49726d
--- /dev/null
+++ b/lib/crypto-algorithms/aes_test.c
@@ -0,0 +1,276 @@
+/*********************************************************************
+* Filename: aes_test.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding AES
+ implementation. These tests do not encompass the full
+ range of available test vectors and are not sufficient
+ for FIPS-140 certification. However, if the tests pass
+ it is very, very likely that the code is correct and was
+ compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <memory.h>
+#include "aes.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void print_hex(BYTE str[], int len)
+{
+ int idx;
+
+ for(idx = 0; idx < len; idx++)
+ printf("%02x", str[idx]);
+}
+
+int aes_ecb_test()
+{
+ WORD key_schedule[60], idx;
+ BYTE enc_buf[128];
+ BYTE plaintext[2][16] = {
+ {0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a},
+ {0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51}
+ };
+ BYTE ciphertext[2][16] = {
+ {0xf3,0xee,0xd1,0xbd,0xb5,0xd2,0xa0,0x3c,0x06,0x4b,0x5a,0x7e,0x3d,0xb1,0x81,0xf8},
+ {0x59,0x1c,0xcb,0x10,0xd4,0x10,0xed,0x26,0xdc,0x5b,0xa7,0x4a,0x31,0x36,0x28,0x70}
+ };
+ BYTE key[1][32] = {
+ {0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}
+ };
+ int pass = 1;
+
+ // Raw ECB mode.
+ //printf("* ECB mode:\n");
+ aes_key_setup(key[0], key_schedule, 256);
+ //printf( "Key : ");
+ //print_hex(key[0], 32);
+
+ for(idx = 0; idx < 2; idx++) {
+ aes_encrypt(plaintext[idx], enc_buf, key_schedule, 256);
+ //printf("\nPlaintext : ");
+ //print_hex(plaintext[idx], 16);
+ //printf("\n-encrypted to: ");
+ //print_hex(enc_buf, 16);
+ pass = pass && !memcmp(enc_buf, ciphertext[idx], 16);
+
+ aes_decrypt(ciphertext[idx], enc_buf, key_schedule, 256);
+ //printf("\nCiphertext : ");
+ //print_hex(ciphertext[idx], 16);
+ //printf("\n-decrypted to: ");
+ //print_hex(enc_buf, 16);
+ pass = pass && !memcmp(enc_buf, plaintext[idx], 16);
+
+ //printf("\n\n");
+ }
+
+ return(pass);
+}
+
+int aes_cbc_test()
+{
+ WORD key_schedule[60];
+ BYTE enc_buf[128];
+ BYTE plaintext[1][32] = {
+ {0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51}
+ };
+ BYTE ciphertext[2][32] = {
+ {0xf5,0x8c,0x4c,0x04,0xd6,0xe5,0xf1,0xba,0x77,0x9e,0xab,0xfb,0x5f,0x7b,0xfb,0xd6,0x9c,0xfc,0x4e,0x96,0x7e,0xdb,0x80,0x8d,0x67,0x9f,0x77,0x7b,0xc6,0x70,0x2c,0x7d}
+ };
+ BYTE iv[1][16] = {
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}
+ };
+ BYTE key[1][32] = {
+ {0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}
+ };
+ int pass = 1;
+
+ //printf("* CBC mode:\n");
+ aes_key_setup(key[0], key_schedule, 256);
+
+ //printf( "Key : ");
+ //print_hex(key[0], 32);
+ //printf("\nIV : ");
+ //print_hex(iv[0], 16);
+
+ aes_encrypt_cbc(plaintext[0], 32, enc_buf, key_schedule, 256, iv[0]);
+ //printf("\nPlaintext : ");
+ //print_hex(plaintext[0], 32);
+ //printf("\n-encrypted to: ");
+ //print_hex(enc_buf, 32);
+ //printf("\nCiphertext : ");
+ //print_hex(ciphertext[0], 32);
+ pass = pass && !memcmp(enc_buf, ciphertext[0], 32);
+
+ //printf("\n\n");
+ return(pass);
+}
+
+int aes_ctr_test()
+{
+ WORD key_schedule[60];
+ BYTE enc_buf[128];
+ BYTE plaintext[1][32] = {
+ {0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51}
+ };
+ BYTE ciphertext[1][32] = {
+ {0x60,0x1e,0xc3,0x13,0x77,0x57,0x89,0xa5,0xb7,0xa7,0xf5,0x04,0xbb,0xf3,0xd2,0x28,0xf4,0x43,0xe3,0xca,0x4d,0x62,0xb5,0x9a,0xca,0x84,0xe9,0x90,0xca,0xca,0xf5,0xc5}
+ };
+ BYTE iv[1][16] = {
+ {0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff},
+ };
+ BYTE key[1][32] = {
+ {0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}
+ };
+ int pass = 1;
+
+ //printf("* CTR mode:\n");
+ aes_key_setup(key[0], key_schedule, 256);
+
+ //printf( "Key : ");
+ //print_hex(key[0], 32);
+ //printf("\nIV : ");
+ //print_hex(iv[0], 16);
+
+ aes_encrypt_ctr(plaintext[0], 32, enc_buf, key_schedule, 256, iv[0]);
+ //printf("\nPlaintext : ");
+ //print_hex(plaintext[0], 32);
+ //printf("\n-encrypted to: ");
+ //print_hex(enc_buf, 32);
+ pass = pass && !memcmp(enc_buf, ciphertext[0], 32);
+
+ aes_decrypt_ctr(ciphertext[0], 32, enc_buf, key_schedule, 256, iv[0]);
+ //printf("\nCiphertext : ");
+ //print_hex(ciphertext[0], 32);
+ //printf("\n-decrypted to: ");
+ //print_hex(enc_buf, 32);
+ pass = pass && !memcmp(enc_buf, plaintext[0], 32);
+
+ //printf("\n\n");
+ return(pass);
+}
+
+int aes_ccm_test()
+{
+ int mac_auth;
+ WORD enc_buf_len;
+ BYTE enc_buf[128];
+ BYTE plaintext[3][32] = {
+ {0x20,0x21,0x22,0x23},
+ {0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f},
+ {0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37}
+ };
+ BYTE assoc[3][32] = {
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13}
+ };
+ BYTE ciphertext[3][32 + 16] = {
+ {0x71,0x62,0x01,0x5b,0x4d,0xac,0x25,0x5d},
+ {0xd2,0xa1,0xf0,0xe0,0x51,0xea,0x5f,0x62,0x08,0x1a,0x77,0x92,0x07,0x3d,0x59,0x3d,0x1f,0xc6,0x4f,0xbf,0xac,0xcd},
+ {0xe3,0xb2,0x01,0xa9,0xf5,0xb7,0x1a,0x7a,0x9b,0x1c,0xea,0xec,0xcd,0x97,0xe7,0x0b,0x61,0x76,0xaa,0xd9,0xa4,0x42,0x8a,0xa5,0x48,0x43,0x92,0xfb,0xc1,0xb0,0x99,0x51}
+ };
+ BYTE iv[3][16] = {
+ {0x10,0x11,0x12,0x13,0x14,0x15,0x16},
+ {0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17},
+ {0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b}
+ };
+ BYTE key[1][32] = {
+ {0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}
+ };
+ int pass = 1;
+
+ //printf("* CCM mode:\n");
+ //printf("Key : ");
+ //print_hex(key[0], 16);
+
+ //print_hex(plaintext[0], 4);
+ //print_hex(assoc[0], 8);
+ //print_hex(ciphertext[0], 8);
+ //print_hex(iv[0], 7);
+ //print_hex(key[0], 16);
+
+ aes_encrypt_ccm(plaintext[0], 4, assoc[0], 8, iv[0], 7, enc_buf, &enc_buf_len, 4, key[0], 128);
+ //printf("\nNONCE : ");
+ //print_hex(iv[0], 7);
+ //printf("\nAssoc. Data : ");
+ //print_hex(assoc[0], 8);
+ //printf("\nPayload : ");
+ //print_hex(plaintext[0], 4);
+ //printf("\n-encrypted to: ");
+ //print_hex(enc_buf, enc_buf_len);
+ pass = pass && !memcmp(enc_buf, ciphertext[0], enc_buf_len);
+
+ aes_decrypt_ccm(ciphertext[0], 8, assoc[0], 8, iv[0], 7, enc_buf, &enc_buf_len, 4, &mac_auth, key[0], 128);
+ //printf("\n-Ciphertext : ");
+ //print_hex(ciphertext[0], 8);
+ //printf("\n-decrypted to: ");
+ //print_hex(enc_buf, enc_buf_len);
+ //printf("\nAuthenticated: %d ", mac_auth);
+ pass = pass && !memcmp(enc_buf, plaintext[0], enc_buf_len) && mac_auth;
+
+
+ aes_encrypt_ccm(plaintext[1], 16, assoc[1], 16, iv[1], 8, enc_buf, &enc_buf_len, 6, key[0], 128);
+ //printf("\n\nNONCE : ");
+ //print_hex(iv[1], 8);
+ //printf("\nAssoc. Data : ");
+ //print_hex(assoc[1], 16);
+ //printf("\nPayload : ");
+ //print_hex(plaintext[1], 16);
+ //printf("\n-encrypted to: ");
+ //print_hex(enc_buf, enc_buf_len);
+ pass = pass && !memcmp(enc_buf, ciphertext[1], enc_buf_len);
+
+ aes_decrypt_ccm(ciphertext[1], 22, assoc[1], 16, iv[1], 8, enc_buf, &enc_buf_len, 6, &mac_auth, key[0], 128);
+ //printf("\n-Ciphertext : ");
+ //print_hex(ciphertext[1], 22);
+ //printf("\n-decrypted to: ");
+ //print_hex(enc_buf, enc_buf_len);
+ //printf("\nAuthenticated: %d ", mac_auth);
+ pass = pass && !memcmp(enc_buf, plaintext[1], enc_buf_len) && mac_auth;
+
+
+ aes_encrypt_ccm(plaintext[2], 24, assoc[2], 20, iv[2], 12, enc_buf, &enc_buf_len, 8, key[0], 128);
+ //printf("\n\nNONCE : ");
+ //print_hex(iv[2], 12);
+ //printf("\nAssoc. Data : ");
+ //print_hex(assoc[2], 20);
+ //printf("\nPayload : ");
+ //print_hex(plaintext[2], 24);
+ //printf("\n-encrypted to: ");
+ //print_hex(enc_buf, enc_buf_len);
+ pass = pass && !memcmp(enc_buf, ciphertext[2], enc_buf_len);
+
+ aes_decrypt_ccm(ciphertext[2], 32, assoc[2], 20, iv[2], 12, enc_buf, &enc_buf_len, 8, &mac_auth, key[0], 128);
+ //printf("\n-Ciphertext : ");
+ //print_hex(ciphertext[2], 32);
+ //printf("\n-decrypted to: ");
+ //print_hex(enc_buf, enc_buf_len);
+ //printf("\nAuthenticated: %d ", mac_auth);
+ pass = pass && !memcmp(enc_buf, plaintext[2], enc_buf_len) && mac_auth;
+
+ //printf("\n\n");
+ return(pass);
+}
+
+int aes_test()
+{
+ int pass = 1;
+
+ pass = pass && aes_ecb_test();
+ pass = pass && aes_cbc_test();
+ pass = pass && aes_ctr_test();
+ pass = pass && aes_ccm_test();
+
+ return(pass);
+}
+
+int main(int argc, char *argv[])
+{
+ printf("AES Tests: %s\n", aes_test() ? "SUCCEEDED" : "FAILED");
+
+ return(0);
+}
diff --git a/lib/crypto-algorithms/arcfour.c b/lib/crypto-algorithms/arcfour.c
new file mode 100644
index 0000000..aa7544a
--- /dev/null
+++ b/lib/crypto-algorithms/arcfour.c
@@ -0,0 +1,45 @@
+/*********************************************************************
+* Filename: arcfour.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the ARCFOUR encryption algorithm.
+ Algorithm specification can be found here:
+ * http://en.wikipedia.org/wiki/RC4
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include "arcfour.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void arcfour_key_setup(BYTE state[], const BYTE key[], int len)
+{
+ int i, j;
+ BYTE t;
+
+ for (i = 0; i < 256; ++i)
+ state[i] = i;
+ for (i = 0, j = 0; i < 256; ++i) {
+ j = (j + state[i] + key[i % len]) % 256;
+ t = state[i];
+ state[i] = state[j];
+ state[j] = t;
+ }
+}
+
+void arcfour_generate_stream(BYTE state[], BYTE out[], size_t len)
+{
+ int i, j;
+ size_t idx;
+ BYTE t;
+
+ for (idx = 0, i = 0, j = 0; idx < len; ++idx) {
+ i = (i + 1) % 256;
+ j = (j + state[i]) % 256;
+ t = state[i];
+ state[i] = state[j];
+ state[j] = t;
+ out[idx] = state[(state[i] + state[j]) % 256];
+ }
+}
diff --git a/lib/crypto-algorithms/arcfour.h b/lib/crypto-algorithms/arcfour.h
new file mode 100644
index 0000000..f9f1e87
--- /dev/null
+++ b/lib/crypto-algorithms/arcfour.h
@@ -0,0 +1,30 @@
+/*********************************************************************
+* Filename: arcfour.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding ARCFOUR implementation.
+*********************************************************************/
+
+#ifndef ARCFOUR_H
+#define ARCFOUR_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+
+/*********************** FUNCTION DECLARATIONS **********************/
+// Input: state - the state used to generate the keystream
+// key - Key to use to initialize the state
+// len - length of key in bytes (valid lenth is 1 to 256)
+void arcfour_key_setup(BYTE state[], const BYTE key[], int len);
+
+// Pseudo-Random Generator Algorithm
+// Input: state - the state used to generate the keystream
+// out - Must be allocated to be of at least "len" length
+// len - number of bytes to generate
+void arcfour_generate_stream(BYTE state[], BYTE out[], size_t len);
+
+#endif // ARCFOUR_H
diff --git a/lib/crypto-algorithms/arcfour_test.c b/lib/crypto-algorithms/arcfour_test.c
new file mode 100644
index 0000000..985f8a7
--- /dev/null
+++ b/lib/crypto-algorithms/arcfour_test.c
@@ -0,0 +1,47 @@
+/*********************************************************************
+* Filename: arcfour_test.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding ARCFOUR
+ implementation. These tests do not encompass the full
+ range of available test vectors, however, if the tests
+ pass it is very, very likely that the code is correct
+ and was compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <memory.h>
+#include "arcfour.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+int rc4_test()
+{
+ BYTE state[256];
+ BYTE key[3][10] = {{"Key"}, {"Wiki"}, {"Secret"}};
+ BYTE stream[3][10] = {{0xEB,0x9F,0x77,0x81,0xB7,0x34,0xCA,0x72,0xA7,0x19},
+ {0x60,0x44,0xdb,0x6d,0x41,0xb7},
+ {0x04,0xd4,0x6b,0x05,0x3c,0xa8,0x7b,0x59}};
+ int stream_len[3] = {10,6,8};
+ BYTE buf[1024];
+ int idx;
+ int pass = 1;
+
+ // Only test the output stream. Note that the state can be reused.
+ for (idx = 0; idx < 3; idx++) {
+ arcfour_key_setup(state, key[idx], strlen(key[idx]));
+ arcfour_generate_stream(state, buf, stream_len[idx]);
+ pass = pass && !memcmp(stream[idx], buf, stream_len[idx]);
+ }
+
+ return(pass);
+}
+
+int main()
+{
+ printf("ARCFOUR tests: %s\n", rc4_test() ? "SUCCEEDED" : "FAILED");
+
+ return(0);
+}
diff --git a/lib/crypto-algorithms/base64.c b/lib/crypto-algorithms/base64.c
new file mode 100644
index 0000000..5e89808
--- /dev/null
+++ b/lib/crypto-algorithms/base64.c
@@ -0,0 +1,135 @@
+/*********************************************************************
+* Filename: base64.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the Base64 encoding algorithm.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include "base64.h"
+
+/****************************** MACROS ******************************/
+#define NEWLINE_INVL 76
+
+/**************************** VARIABLES *****************************/
+// Note: To change the charset to a URL encoding, replace the '+' and '/' with '*' and '-'
+static const BYTE charset[]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+BYTE revchar(char ch)
+{
+ if (ch >= 'A' && ch <= 'Z')
+ ch -= 'A';
+ else if (ch >= 'a' && ch <='z')
+ ch = ch - 'a' + 26;
+ else if (ch >= '0' && ch <='9')
+ ch = ch - '0' + 52;
+ else if (ch == '+')
+ ch = 62;
+ else if (ch == '/')
+ ch = 63;
+
+ return(ch);
+}
+
+size_t base64_encode(const BYTE in[], BYTE out[], size_t len, int newline_flag)
+{
+ size_t idx, idx2, blks, blk_ceiling, left_over, newline_count = 0;
+
+ blks = (len / 3);
+ left_over = len % 3;
+
+ if (out == NULL) {
+ idx2 = blks * 4 ;
+ if (left_over)
+ idx2 += 4;
+ if (newline_flag)
+ idx2 += len / 57; // (NEWLINE_INVL / 4) * 3 = 57. One newline per 57 input bytes.
+ }
+ else {
+ // Since 3 input bytes = 4 output bytes, determine out how many even sets of
+ // 3 bytes the input has.
+ blk_ceiling = blks * 3;
+ for (idx = 0, idx2 = 0; idx < blk_ceiling; idx += 3, idx2 += 4) {
+ out[idx2] = charset[in[idx] >> 2];
+ out[idx2 + 1] = charset[((in[idx] & 0x03) << 4) | (in[idx + 1] >> 4)];
+ out[idx2 + 2] = charset[((in[idx + 1] & 0x0f) << 2) | (in[idx + 2] >> 6)];
+ out[idx2 + 3] = charset[in[idx + 2] & 0x3F];
+ // The offical standard requires a newline every 76 characters.
+ // (Eg, first newline is character 77 of the output.)
+ if (((idx2 - newline_count + 4) % NEWLINE_INVL == 0) && newline_flag) {
+ out[idx2 + 4] = '\n';
+ idx2++;
+ newline_count++;
+ }
+ }
+
+ if (left_over == 1) {
+ out[idx2] = charset[in[idx] >> 2];
+ out[idx2 + 1] = charset[(in[idx] & 0x03) << 4];
+ out[idx2 + 2] = '=';
+ out[idx2 + 3] = '=';
+ idx2 += 4;
+ }
+ else if (left_over == 2) {
+ out[idx2] = charset[in[idx] >> 2];
+ out[idx2 + 1] = charset[((in[idx] & 0x03) << 4) | (in[idx + 1] >> 4)];
+ out[idx2 + 2] = charset[(in[idx + 1] & 0x0F) << 2];
+ out[idx2 + 3] = '=';
+ idx2 += 4;
+ }
+ }
+
+ return(idx2);
+}
+
+size_t base64_decode(const BYTE in[], BYTE out[], size_t len)
+{
+ BYTE ch;
+ size_t idx, idx2, blks, blk_ceiling, left_over;
+
+ if (in[len - 1] == '=')
+ len--;
+ if (in[len - 1] == '=')
+ len--;
+
+ blks = len / 4;
+ left_over = len % 4;
+
+ if (out == NULL) {
+ if (len >= 77 && in[NEWLINE_INVL] == '\n') // Verify that newlines where used.
+ len -= len / (NEWLINE_INVL + 1);
+ blks = len / 4;
+ left_over = len % 4;
+
+ idx = blks * 3;
+ if (left_over == 2)
+ idx ++;
+ else if (left_over == 3)
+ idx += 2;
+ }
+ else {
+ blk_ceiling = blks * 4;
+ for (idx = 0, idx2 = 0; idx2 < blk_ceiling; idx += 3, idx2 += 4) {
+ if (in[idx2] == '\n')
+ idx2++;
+ out[idx] = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
+ out[idx + 1] = (revchar(in[idx2 + 1]) << 4) | (revchar(in[idx2 + 2]) >> 2);
+ out[idx + 2] = (revchar(in[idx2 + 2]) << 6) | revchar(in[idx2 + 3]);
+ }
+
+ if (left_over == 2) {
+ out[idx] = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
+ idx++;
+ }
+ else if (left_over == 3) {
+ out[idx] = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
+ out[idx + 1] = (revchar(in[idx2 + 1]) << 4) | (revchar(in[idx2 + 2]) >> 2);
+ idx += 2;
+ }
+ }
+
+ return(idx);
+}
diff --git a/lib/crypto-algorithms/base64.h b/lib/crypto-algorithms/base64.h
new file mode 100644
index 0000000..e35c6c7
--- /dev/null
+++ b/lib/crypto-algorithms/base64.h
@@ -0,0 +1,27 @@
+/*********************************************************************
+* Filename: base64.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding Base64 implementation.
+*********************************************************************/
+
+#ifndef BASE64_H
+#define BASE64_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+
+/*********************** FUNCTION DECLARATIONS **********************/
+// Returns the size of the output. If called with out = NULL, will just return
+// the size of what the output would have been (without a terminating NULL).
+size_t base64_encode(const BYTE in[], BYTE out[], size_t len, int newline_flag);
+
+// Returns the size of the output. If called with out = NULL, will just return
+// the size of what the output would have been (without a terminating NULL).
+size_t base64_decode(const BYTE in[], BYTE out[], size_t len);
+
+#endif // BASE64_H
diff --git a/lib/crypto-algorithms/base64_test.c b/lib/crypto-algorithms/base64_test.c
new file mode 100644
index 0000000..c59cc98
--- /dev/null
+++ b/lib/crypto-algorithms/base64_test.c
@@ -0,0 +1,54 @@
+/*********************************************************************
+* Filename: blowfish_test.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding Base64
+ implementation. These tests do not encompass the full
+ range of available test vectors, however, if the tests
+ pass it is very, very likely that the code is correct
+ and was compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <memory.h>
+#include "base64.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+int base64_test()
+{
+ BYTE text[3][1024] = {{"fo"},
+ {"foobar"},
+ {"Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."}};
+ BYTE code[3][1024] = {{"Zm8="},
+ {"Zm9vYmFy"},
+ {"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\nIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\ndGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\ndWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\nZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="}};
+ BYTE buf[1024];
+ size_t buf_len;
+ int pass = 1;
+ int idx;
+
+ for (idx = 0; idx < 3; idx++) {
+ buf_len = base64_encode(text[idx], buf, strlen(text[idx]), 1);
+ pass = pass && ((buf_len == strlen(code[idx])) &&
+ (buf_len == base64_encode(text[idx], NULL, strlen(text[idx]), 1)));
+ pass = pass && !strcmp(code[idx], buf);
+
+ memset(buf, 0, sizeof(buf));
+ buf_len = base64_decode(code[idx], buf, strlen(code[idx]));
+ pass = pass && ((buf_len == strlen(text[idx])) &&
+ (buf_len == base64_decode(code[idx], NULL, strlen(code[idx]))));
+ pass = pass && !strcmp(text[idx], buf);
+ }
+
+ return(pass);
+}
+
+int main()
+{
+ printf("Base64 tests: %s\n", base64_test() ? "PASSED" : "FAILED");
+
+ return 0;
+}
diff --git a/lib/crypto-algorithms/blowfish.c b/lib/crypto-algorithms/blowfish.c
new file mode 100644
index 0000000..cea8f28
--- /dev/null
+++ b/lib/crypto-algorithms/blowfish.c
@@ -0,0 +1,269 @@
+/*********************************************************************
+* Filename: blowfish.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the Blowfish encryption algorithm.
+ Modes of operation (such as CBC) are not included.
+ Algorithm specification can be found here:
+ * http://www.schneier.com/blowfish.html
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include <memory.h>
+#include "blowfish.h"
+
+/****************************** MACROS ******************************/
+#define F(x,t) t = keystruct->s[0][(x) >> 24]; \
+ t += keystruct->s[1][((x) >> 16) & 0xff]; \
+ t ^= keystruct->s[2][((x) >> 8) & 0xff]; \
+ t += keystruct->s[3][(x) & 0xff];
+#define swap(r,l,t) t = l; l = r; r = t;
+#define ITERATION(l,r,t,pval) l ^= keystruct->p[pval]; F(l,t); r^= t; swap(r,l,t);
+
+/**************************** VARIABLES *****************************/
+static const WORD p_perm[18] = {
+ 0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,0x082EFA98,
+ 0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,0xC0AC29B7,0xC97C50DD,
+ 0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B
+};
+
+static const WORD s_perm[4][256] = { {
+ 0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96,0xBA7C9045,0xF12C7F99,
+ 0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16,0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,
+ 0x0D95748F,0x728EB658,0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013,
+ 0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E,0x6C9E0E8B,0xB01E8A3E,
+ 0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60,0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,
+ 0x55CA396A,0x2AAB10B6,0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A,
+ 0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C,0x7A325381,0x28958677,
+ 0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193,0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,
+ 0xEF845D5D,0xE98575B1,0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239,
+ 0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A,0x670C9C61,0xABD388F0,
+ 0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3,0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,
+ 0xA1F1651D,0x39AF0176,0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE,
+ 0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706,0x1BFEDF72,0x429B023D,
+ 0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B,0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,
+ 0xE3FE501A,0xB6794C3B,0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463,
+ 0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C,0xCC814544,0xAF5EBD09,
+ 0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3,0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,
+ 0x5579C0BD,0x1A60320A,0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8,
+ 0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760,0x53317B48,0x3E00DF82,
+ 0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB,0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,
+ 0x695B27B0,0xBBCA58C8,0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B,
+ 0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33,0x62FB1341,0xCEE4C6E8,
+ 0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4,0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,
+ 0xD08ED1D0,0xAFC725E0,0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C,
+ 0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777,0xEA752DFE,0x8B021FA1,
+ 0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299,0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,
+ 0x165FA266,0x80957705,0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF,
+ 0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E,0x226800BB,0x57B8E0AF,
+ 0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA,0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,
+ 0x83260376,0x6295CFA9,0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915,
+ 0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F,0xF296EC6B,0x2A0DD915,
+ 0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664,0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A
+},{
+ 0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D,0x9CEE60B8,0x8FEDB266,
+ 0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1,0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,
+ 0x3F54989A,0x5B429D65,0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1,
+ 0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9,0x3C971814,0x6B6A70A1,
+ 0x687F3584,0x52A0E286,0xB79C5305,0xAA500737,0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,
+ 0xB03ADA37,0xF0500C0D,0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD,
+ 0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC,0xC8B57634,0x9AF3DDA7,
+ 0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41,0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,
+ 0x4E548B38,0x4F6DB908,0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF,
+ 0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124,0x501ADDE6,0x9F84CD87,
+ 0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C,0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,
+ 0xEF1C1847,0x3215D908,0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD,
+ 0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B,0x3C11183B,0x5924A509,
+ 0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E,0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,
+ 0x771FE71C,0x4E3D06FA,0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A,
+ 0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D,0x1939260F,0x19C27960,
+ 0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66,0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,
+ 0xC332DDEF,0xBE6C5AA5,0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84,
+ 0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96,0x0334FE1E,0xAA0363CF,
+ 0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14,0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,
+ 0x648B1EAF,0x19BDF0CA,0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7,
+ 0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77,0x11ED935F,0x16681281,
+ 0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99,0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,
+ 0xCDB30AEB,0x532E3054,0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73,
+ 0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA,0xDB6C4F15,0xFACB4FD0,
+ 0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105,0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,
+ 0xCF62A1F2,0x5B8D2646,0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285,
+ 0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA,0x1DADF43E,0x233F7061,
+ 0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB,0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,
+ 0xA6078084,0x19F8509E,0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC,
+ 0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD,0x675FDA79,0xE3674340,
+ 0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20,0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7
+},{
+ 0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7,0xBCF46B2E,0xD4A20068,
+ 0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF,0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,
+ 0x4D95FC1D,0x96B591AF,0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504,
+ 0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4,0x0A2C86DA,0xE9B66DFB,
+ 0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE,0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,
+ 0xAACE1E7C,0xD3375FEC,0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B,
+ 0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332,0x6841E7F7,0xCA7820FB,
+ 0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527,0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,
+ 0x55A867BC,0xA1159A58,0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C,
+ 0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22,0x48C1133F,0xC70F86DC,
+ 0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17,0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,
+ 0x257B7834,0x602A9C60,0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115,
+ 0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99,0xDE720C8C,0x2DA2F728,
+ 0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0,0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,
+ 0x0A476341,0x992EFF74,0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D,
+ 0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3,0xB5390F92,0x690FED0B,
+ 0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3,0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,
+ 0x37392EB3,0xCC115979,0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C,
+ 0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA,0x3D25BDD8,0xE2E1C3C9,
+ 0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A,0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,
+ 0x9DBC8057,0xF0F7C086,0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC,
+ 0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24,0x55464299,0xBF582E61,
+ 0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2,0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,
+ 0x7AEB2661,0x8B1DDF84,0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C,
+ 0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09,0x662D09A1,0xC4324633,
+ 0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10,0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,
+ 0xDCB7DA83,0x573906FE,0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027,
+ 0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0,0x006058AA,0x30DC7D62,
+ 0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634,0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,
+ 0x6F05E409,0x4B7C0188,0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC,
+ 0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8,0xA28514D9,0x6C51133C,
+ 0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837,0xD79A3234,0x92638212,0x670EFA8E,0x406000E0
+},{
+ 0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742,0xD3822740,0x99BC9BBE,
+ 0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B,0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,
+ 0x5748AB2F,0xBC946E79,0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6,
+ 0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A,0x63EF8CE2,0x9A86EE22,
+ 0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4,0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,
+ 0x2826A2F9,0xA73A3AE1,0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59,
+ 0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797,0x2CF0B7D9,0x022B8B51,
+ 0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28,0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,
+ 0xE029AC71,0xE019A5E6,0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28,
+ 0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA,0x03A16125,0x0564F0BD,
+ 0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A,0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,
+ 0x7533D928,0xB155FDF5,0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F,
+ 0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE,0x5121CE64,0x774FBE32,
+ 0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680,0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,
+ 0xB39A460A,0x6445C0DD,0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB,
+ 0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB,0x8D6612AE,0xBF3C6F47,
+ 0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370,0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,
+ 0x4040CB08,0x4EB4E2CC,0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048,
+ 0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC,0xBB3A792B,0x344525BD,
+ 0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9,0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,
+ 0x1A908749,0xD44FBD9A,0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F,
+ 0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A,0x0F91FC71,0x9B941525,
+ 0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1,0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,
+ 0xE0EC6E0E,0x1698DB3B,0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E,
+ 0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E,0xE60B6F47,0x0FE3F11D,
+ 0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F,0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,
+ 0xF523F357,0xA6327623,0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC,
+ 0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A,0x45E1D006,0xC3F27B9A,
+ 0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6,0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,
+ 0x53113EC0,0x1640E3D3,0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060,
+ 0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C,0x01C36AE4,0xD6EBE1F9,
+ 0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F,0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6
+} };
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void blowfish_encrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct)
+{
+ WORD l,r,t; //,i;
+
+ l = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | (in[3]);
+ r = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | (in[7]);
+
+ ITERATION(l,r,t,0);
+ ITERATION(l,r,t,1);
+ ITERATION(l,r,t,2);
+ ITERATION(l,r,t,3);
+ ITERATION(l,r,t,4);
+ ITERATION(l,r,t,5);
+ ITERATION(l,r,t,6);
+ ITERATION(l,r,t,7);
+ ITERATION(l,r,t,8);
+ ITERATION(l,r,t,9);
+ ITERATION(l,r,t,10);
+ ITERATION(l,r,t,11);
+ ITERATION(l,r,t,12);
+ ITERATION(l,r,t,13);
+ ITERATION(l,r,t,14);
+ l ^= keystruct->p[15]; F(l,t); r^= t; //Last iteration has no swap()
+ r ^= keystruct->p[16];
+ l ^= keystruct->p[17];
+
+ out[0] = l >> 24;
+ out[1] = l >> 16;
+ out[2] = l >> 8;
+ out[3] = l;
+ out[4] = r >> 24;
+ out[5] = r >> 16;
+ out[6] = r >> 8;
+ out[7] = r;
+}
+
+void blowfish_decrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct)
+{
+ WORD l,r,t; //,i;
+
+ l = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | (in[3]);
+ r = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | (in[7]);
+
+ ITERATION(l,r,t,17);
+ ITERATION(l,r,t,16);
+ ITERATION(l,r,t,15);
+ ITERATION(l,r,t,14);
+ ITERATION(l,r,t,13);
+ ITERATION(l,r,t,12);
+ ITERATION(l,r,t,11);
+ ITERATION(l,r,t,10);
+ ITERATION(l,r,t,9);
+ ITERATION(l,r,t,8);
+ ITERATION(l,r,t,7);
+ ITERATION(l,r,t,6);
+ ITERATION(l,r,t,5);
+ ITERATION(l,r,t,4);
+ ITERATION(l,r,t,3);
+ l ^= keystruct->p[2]; F(l,t); r^= t; //Last iteration has no swap()
+ r ^= keystruct->p[1];
+ l ^= keystruct->p[0];
+
+ out[0] = l >> 24;
+ out[1] = l >> 16;
+ out[2] = l >> 8;
+ out[3] = l;
+ out[4] = r >> 24;
+ out[5] = r >> 16;
+ out[6] = r >> 8;
+ out[7] = r;
+}
+
+void blowfish_key_setup(const BYTE user_key[], BLOWFISH_KEY *keystruct, size_t len)
+{
+ BYTE block[8];
+ int idx,idx2;
+
+ // Copy over the constant init array vals (so the originals aren't destroyed).
+ memcpy(keystruct->p,p_perm,sizeof(WORD) * 18);
+ memcpy(keystruct->s,s_perm,sizeof(WORD) * 1024);
+
+ // Combine the key with the P box. Assume key is standard 448 bits (56 bytes) or less.
+ for (idx = 0, idx2 = 0; idx < 18; ++idx, idx2 += 4)
+ keystruct->p[idx] ^= (user_key[idx2 % len] << 24) | (user_key[(idx2+1) % len] << 16)
+ | (user_key[(idx2+2) % len] << 8) | (user_key[(idx2+3) % len]);
+ // Re-calculate the P box.
+ memset(block, 0, 8);
+ for (idx = 0; idx < 18; idx += 2) {
+ blowfish_encrypt(block,block,keystruct);
+ keystruct->p[idx] = (block[0] << 24) | (block[1] << 16) | (block[2] << 8) | block[3];
+ keystruct->p[idx+1]=(block[4] << 24) | (block[5] << 16) | (block[6] << 8) | block[7];
+ }
+ // Recalculate the S-boxes.
+ for (idx = 0; idx < 4; ++idx) {
+ for (idx2 = 0; idx2 < 256; idx2 += 2) {
+ blowfish_encrypt(block,block,keystruct);
+ keystruct->s[idx][idx2] = (block[0] << 24) | (block[1] << 16) |
+ (block[2] << 8) | block[3];
+ keystruct->s[idx][idx2+1] = (block[4] << 24) | (block[5] << 16) |
+ (block[6] << 8) | block[7];
+ }
+ }
+}
diff --git a/lib/crypto-algorithms/blowfish.h b/lib/crypto-algorithms/blowfish.h
new file mode 100644
index 0000000..d8e9d4a
--- /dev/null
+++ b/lib/crypto-algorithms/blowfish.h
@@ -0,0 +1,32 @@
+/*********************************************************************
+* Filename: blowfish.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding Blowfish implementation.
+*********************************************************************/
+
+#ifndef BLOWFISH_H
+#define BLOWFISH_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/****************************** MACROS ******************************/
+#define BLOWFISH_BLOCK_SIZE 8 // Blowfish operates on 8 bytes at a time
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
+
+typedef struct {
+ WORD p[18];
+ WORD s[4][256];
+} BLOWFISH_KEY;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void blowfish_key_setup(const BYTE user_key[], BLOWFISH_KEY *keystruct, size_t len);
+void blowfish_encrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct);
+void blowfish_decrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct);
+
+#endif // BLOWFISH_H
diff --git a/lib/crypto-algorithms/blowfish_test.c b/lib/crypto-algorithms/blowfish_test.c
new file mode 100644
index 0000000..0f0aa38
--- /dev/null
+++ b/lib/crypto-algorithms/blowfish_test.c
@@ -0,0 +1,68 @@
+/*********************************************************************
+* Filename: blowfish_test.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding Blowfish
+ implementation. These tests do not encompass the full
+ range of available test vectors, however, if the tests
+ pass it is very, very likely that the code is correct
+ and was compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <memory.h>
+#include "blowfish.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+int blowfish_test()
+{
+ BYTE key1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ BYTE key2[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
+ BYTE key3[24] = {0xF0,0xE1,0xD2,0xC3,0xB4,0xA5,0x96,0x87,
+ 0x78,0x69,0x5A,0x4B,0x3C,0x2D,0x1E,0x0F,
+ 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
+ BYTE p1[BLOWFISH_BLOCK_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ BYTE p2[BLOWFISH_BLOCK_SIZE] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
+ BYTE p3[BLOWFISH_BLOCK_SIZE] = {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10};
+
+ BYTE c1[BLOWFISH_BLOCK_SIZE] = {0x4e,0xf9,0x97,0x45,0x61,0x98,0xdd,0x78};
+ BYTE c2[BLOWFISH_BLOCK_SIZE] = {0x51,0x86,0x6f,0xd5,0xb8,0x5e,0xcb,0x8a};
+ BYTE c3[BLOWFISH_BLOCK_SIZE] = {0x05,0x04,0x4b,0x62,0xfa,0x52,0xd0,0x80};
+
+ BYTE enc_buf[BLOWFISH_BLOCK_SIZE];
+ BLOWFISH_KEY key;
+ int pass = 1;
+
+ // Test vector 1.
+ blowfish_key_setup(key1, &key, BLOWFISH_BLOCK_SIZE);
+ blowfish_encrypt(p1, enc_buf, &key);
+ pass = pass && !memcmp(c1, enc_buf, BLOWFISH_BLOCK_SIZE);
+ blowfish_decrypt(c1, enc_buf, &key);
+ pass = pass && !memcmp(p1, enc_buf, BLOWFISH_BLOCK_SIZE);
+
+ // Test vector 2.
+ blowfish_key_setup(key2, &key, BLOWFISH_BLOCK_SIZE);
+ blowfish_encrypt(p2, enc_buf, &key);
+ pass = pass && !memcmp(c2, enc_buf, BLOWFISH_BLOCK_SIZE);
+ blowfish_decrypt(c2, enc_buf, &key);
+ pass = pass && !memcmp(p2, enc_buf, BLOWFISH_BLOCK_SIZE);
+
+ // Test vector 3.
+ blowfish_key_setup(key3, &key, 24);
+ blowfish_encrypt(p3, enc_buf, &key);
+ pass = pass && !memcmp(c3, enc_buf, BLOWFISH_BLOCK_SIZE);
+ blowfish_decrypt(c3, enc_buf, &key);
+ pass = pass && !memcmp(p3, enc_buf, BLOWFISH_BLOCK_SIZE);
+
+ return(pass);
+}
+
+int main()
+{
+ printf("Blowfish tests: %s\n", blowfish_test() ? "SUCCEEDED" : "FAILED");
+
+ return(0);
+}
diff --git a/lib/crypto-algorithms/des.c b/lib/crypto-algorithms/des.c
new file mode 100644
index 0000000..d20db6f
--- /dev/null
+++ b/lib/crypto-algorithms/des.c
@@ -0,0 +1,269 @@
+/*********************************************************************
+* Filename: des.c
+* Author: Brad Conte (brad AT radconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the DES encryption algorithm.
+ Modes of operation (such as CBC) are not included.
+ The formal NIST algorithm specification can be found here:
+ * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include <memory.h>
+#include "des.h"
+
+/****************************** MACROS ******************************/
+// Obtain bit "b" from the left and shift it "c" places from the right
+#define BITNUM(a,b,c) (((a[(b)/8] >> (7 - (b%8))) & 0x01) << (c))
+#define BITNUMINTR(a,b,c) ((((a) >> (31 - (b))) & 0x00000001) << (c))
+#define BITNUMINTL(a,b,c) ((((a) << (b)) & 0x80000000) >> (c))
+
+// This macro converts a 6 bit block with the S-Box row defined as the first and last
+// bits to a 6 bit block with the row defined by the first two bits.
+#define SBOXBIT(a) (((a) & 0x20) | (((a) & 0x1f) >> 1) | (((a) & 0x01) << 4))
+
+/**************************** VARIABLES *****************************/
+static const BYTE sbox1[64] = {
+ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
+};
+static const BYTE sbox2[64] = {
+ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
+};
+static const BYTE sbox3[64] = {
+ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
+};
+static const BYTE sbox4[64] = {
+ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
+};
+static const BYTE sbox5[64] = {
+ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
+};
+static const BYTE sbox6[64] = {
+ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
+};
+static const BYTE sbox7[64] = {
+ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
+};
+static const BYTE sbox8[64] = {
+ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
+};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+// Initial (Inv)Permutation step
+void IP(WORD state[], const BYTE in[])
+{
+ state[0] = BITNUM(in,57,31) | BITNUM(in,49,30) | BITNUM(in,41,29) | BITNUM(in,33,28) |
+ BITNUM(in,25,27) | BITNUM(in,17,26) | BITNUM(in,9,25) | BITNUM(in,1,24) |
+ BITNUM(in,59,23) | BITNUM(in,51,22) | BITNUM(in,43,21) | BITNUM(in,35,20) |
+ BITNUM(in,27,19) | BITNUM(in,19,18) | BITNUM(in,11,17) | BITNUM(in,3,16) |
+ BITNUM(in,61,15) | BITNUM(in,53,14) | BITNUM(in,45,13) | BITNUM(in,37,12) |
+ BITNUM(in,29,11) | BITNUM(in,21,10) | BITNUM(in,13,9) | BITNUM(in,5,8) |
+ BITNUM(in,63,7) | BITNUM(in,55,6) | BITNUM(in,47,5) | BITNUM(in,39,4) |
+ BITNUM(in,31,3) | BITNUM(in,23,2) | BITNUM(in,15,1) | BITNUM(in,7,0);
+
+ state[1] = BITNUM(in,56,31) | BITNUM(in,48,30) | BITNUM(in,40,29) | BITNUM(in,32,28) |
+ BITNUM(in,24,27) | BITNUM(in,16,26) | BITNUM(in,8,25) | BITNUM(in,0,24) |
+ BITNUM(in,58,23) | BITNUM(in,50,22) | BITNUM(in,42,21) | BITNUM(in,34,20) |
+ BITNUM(in,26,19) | BITNUM(in,18,18) | BITNUM(in,10,17) | BITNUM(in,2,16) |
+ BITNUM(in,60,15) | BITNUM(in,52,14) | BITNUM(in,44,13) | BITNUM(in,36,12) |
+ BITNUM(in,28,11) | BITNUM(in,20,10) | BITNUM(in,12,9) | BITNUM(in,4,8) |
+ BITNUM(in,62,7) | BITNUM(in,54,6) | BITNUM(in,46,5) | BITNUM(in,38,4) |
+ BITNUM(in,30,3) | BITNUM(in,22,2) | BITNUM(in,14,1) | BITNUM(in,6,0);
+}
+
+void InvIP(WORD state[], BYTE in[])
+{
+ in[0] = BITNUMINTR(state[1],7,7) | BITNUMINTR(state[0],7,6) | BITNUMINTR(state[1],15,5) |
+ BITNUMINTR(state[0],15,4) | BITNUMINTR(state[1],23,3) | BITNUMINTR(state[0],23,2) |
+ BITNUMINTR(state[1],31,1) | BITNUMINTR(state[0],31,0);
+
+ in[1] = BITNUMINTR(state[1],6,7) | BITNUMINTR(state[0],6,6) | BITNUMINTR(state[1],14,5) |
+ BITNUMINTR(state[0],14,4) | BITNUMINTR(state[1],22,3) | BITNUMINTR(state[0],22,2) |
+ BITNUMINTR(state[1],30,1) | BITNUMINTR(state[0],30,0);
+
+ in[2] = BITNUMINTR(state[1],5,7) | BITNUMINTR(state[0],5,6) | BITNUMINTR(state[1],13,5) |
+ BITNUMINTR(state[0],13,4) | BITNUMINTR(state[1],21,3) | BITNUMINTR(state[0],21,2) |
+ BITNUMINTR(state[1],29,1) | BITNUMINTR(state[0],29,0);
+
+ in[3] = BITNUMINTR(state[1],4,7) | BITNUMINTR(state[0],4,6) | BITNUMINTR(state[1],12,5) |
+ BITNUMINTR(state[0],12,4) | BITNUMINTR(state[1],20,3) | BITNUMINTR(state[0],20,2) |
+ BITNUMINTR(state[1],28,1) | BITNUMINTR(state[0],28,0);
+
+ in[4] = BITNUMINTR(state[1],3,7) | BITNUMINTR(state[0],3,6) | BITNUMINTR(state[1],11,5) |
+ BITNUMINTR(state[0],11,4) | BITNUMINTR(state[1],19,3) | BITNUMINTR(state[0],19,2) |
+ BITNUMINTR(state[1],27,1) | BITNUMINTR(state[0],27,0);
+
+ in[5] = BITNUMINTR(state[1],2,7) | BITNUMINTR(state[0],2,6) | BITNUMINTR(state[1],10,5) |
+ BITNUMINTR(state[0],10,4) | BITNUMINTR(state[1],18,3) | BITNUMINTR(state[0],18,2) |
+ BITNUMINTR(state[1],26,1) | BITNUMINTR(state[0],26,0);
+
+ in[6] = BITNUMINTR(state[1],1,7) | BITNUMINTR(state[0],1,6) | BITNUMINTR(state[1],9,5) |
+ BITNUMINTR(state[0],9,4) | BITNUMINTR(state[1],17,3) | BITNUMINTR(state[0],17,2) |
+ BITNUMINTR(state[1],25,1) | BITNUMINTR(state[0],25,0);
+
+ in[7] = BITNUMINTR(state[1],0,7) | BITNUMINTR(state[0],0,6) | BITNUMINTR(state[1],8,5) |
+ BITNUMINTR(state[0],8,4) | BITNUMINTR(state[1],16,3) | BITNUMINTR(state[0],16,2) |
+ BITNUMINTR(state[1],24,1) | BITNUMINTR(state[0],24,0);
+}
+
+WORD f(WORD state, const BYTE key[])
+{
+ BYTE lrgstate[6]; //,i;
+ WORD t1,t2;
+
+ // Expantion Permutation
+ t1 = BITNUMINTL(state,31,0) | ((state & 0xf0000000) >> 1) | BITNUMINTL(state,4,5) |
+ BITNUMINTL(state,3,6) | ((state & 0x0f000000) >> 3) | BITNUMINTL(state,8,11) |
+ BITNUMINTL(state,7,12) | ((state & 0x00f00000) >> 5) | BITNUMINTL(state,12,17) |
+ BITNUMINTL(state,11,18) | ((state & 0x000f0000) >> 7) | BITNUMINTL(state,16,23);
+
+ t2 = BITNUMINTL(state,15,0) | ((state & 0x0000f000) << 15) | BITNUMINTL(state,20,5) |
+ BITNUMINTL(state,19,6) | ((state & 0x00000f00) << 13) | BITNUMINTL(state,24,11) |
+ BITNUMINTL(state,23,12) | ((state & 0x000000f0) << 11) | BITNUMINTL(state,28,17) |
+ BITNUMINTL(state,27,18) | ((state & 0x0000000f) << 9) | BITNUMINTL(state,0,23);
+
+ lrgstate[0] = (t1 >> 24) & 0x000000ff;
+ lrgstate[1] = (t1 >> 16) & 0x000000ff;
+ lrgstate[2] = (t1 >> 8) & 0x000000ff;
+ lrgstate[3] = (t2 >> 24) & 0x000000ff;
+ lrgstate[4] = (t2 >> 16) & 0x000000ff;
+ lrgstate[5] = (t2 >> 8) & 0x000000ff;
+
+ // Key XOR
+ lrgstate[0] ^= key[0];
+ lrgstate[1] ^= key[1];
+ lrgstate[2] ^= key[2];
+ lrgstate[3] ^= key[3];
+ lrgstate[4] ^= key[4];
+ lrgstate[5] ^= key[5];
+
+ // S-Box Permutation
+ state = (sbox1[SBOXBIT(lrgstate[0] >> 2)] << 28) |
+ (sbox2[SBOXBIT(((lrgstate[0] & 0x03) << 4) | (lrgstate[1] >> 4))] << 24) |
+ (sbox3[SBOXBIT(((lrgstate[1] & 0x0f) << 2) | (lrgstate[2] >> 6))] << 20) |
+ (sbox4[SBOXBIT(lrgstate[2] & 0x3f)] << 16) |
+ (sbox5[SBOXBIT(lrgstate[3] >> 2)] << 12) |
+ (sbox6[SBOXBIT(((lrgstate[3] & 0x03) << 4) | (lrgstate[4] >> 4))] << 8) |
+ (sbox7[SBOXBIT(((lrgstate[4] & 0x0f) << 2) | (lrgstate[5] >> 6))] << 4) |
+ sbox8[SBOXBIT(lrgstate[5] & 0x3f)];
+
+ // P-Box Permutation
+ state = BITNUMINTL(state,15,0) | BITNUMINTL(state,6,1) | BITNUMINTL(state,19,2) |
+ BITNUMINTL(state,20,3) | BITNUMINTL(state,28,4) | BITNUMINTL(state,11,5) |
+ BITNUMINTL(state,27,6) | BITNUMINTL(state,16,7) | BITNUMINTL(state,0,8) |
+ BITNUMINTL(state,14,9) | BITNUMINTL(state,22,10) | BITNUMINTL(state,25,11) |
+ BITNUMINTL(state,4,12) | BITNUMINTL(state,17,13) | BITNUMINTL(state,30,14) |
+ BITNUMINTL(state,9,15) | BITNUMINTL(state,1,16) | BITNUMINTL(state,7,17) |
+ BITNUMINTL(state,23,18) | BITNUMINTL(state,13,19) | BITNUMINTL(state,31,20) |
+ BITNUMINTL(state,26,21) | BITNUMINTL(state,2,22) | BITNUMINTL(state,8,23) |
+ BITNUMINTL(state,18,24) | BITNUMINTL(state,12,25) | BITNUMINTL(state,29,26) |
+ BITNUMINTL(state,5,27) | BITNUMINTL(state,21,28) | BITNUMINTL(state,10,29) |
+ BITNUMINTL(state,3,30) | BITNUMINTL(state,24,31);
+
+ // Return the final state value
+ return(state);
+}
+
+void des_key_setup(const BYTE key[], BYTE schedule[][6], DES_MODE mode)
+{
+ WORD i, j, to_gen, C, D;
+ const WORD key_rnd_shift[16] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
+ const WORD key_perm_c[28] = {56,48,40,32,24,16,8,0,57,49,41,33,25,17,
+ 9,1,58,50,42,34,26,18,10,2,59,51,43,35};
+ const WORD key_perm_d[28] = {62,54,46,38,30,22,14,6,61,53,45,37,29,21,
+ 13,5,60,52,44,36,28,20,12,4,27,19,11,3};
+ const WORD key_compression[48] = {13,16,10,23,0,4,2,27,14,5,20,9,
+ 22,18,11,3,25,7,15,6,26,19,12,1,
+ 40,51,30,36,46,54,29,39,50,44,32,47,
+ 43,48,38,55,33,52,45,41,49,35,28,31};
+
+ // Permutated Choice #1 (copy the key in, ignoring parity bits).
+ for (i = 0, j = 31, C = 0; i < 28; ++i, --j)
+ C |= BITNUM(key,key_perm_c[i],j);
+ for (i = 0, j = 31, D = 0; i < 28; ++i, --j)
+ D |= BITNUM(key,key_perm_d[i],j);
+
+ // Generate the 16 subkeys.
+ for (i = 0; i < 16; ++i) {
+ C = ((C << key_rnd_shift[i]) | (C >> (28-key_rnd_shift[i]))) & 0xfffffff0;
+ D = ((D << key_rnd_shift[i]) | (D >> (28-key_rnd_shift[i]))) & 0xfffffff0;
+
+ // Decryption subkeys are reverse order of encryption subkeys so
+ // generate them in reverse if the key schedule is for decryption useage.
+ if (mode == DES_DECRYPT)
+ to_gen = 15 - i;
+ else /*(if mode == DES_ENCRYPT)*/
+ to_gen = i;
+ // Initialize the array
+ for (j = 0; j < 6; ++j)
+ schedule[to_gen][j] = 0;
+ for (j = 0; j < 24; ++j)
+ schedule[to_gen][j/8] |= BITNUMINTR(C,key_compression[j],7 - (j%8));
+ for ( ; j < 48; ++j)
+ schedule[to_gen][j/8] |= BITNUMINTR(D,key_compression[j] - 28,7 - (j%8));
+ }
+}
+
+void des_crypt(const BYTE in[], BYTE out[], const BYTE key[][6])
+{
+ WORD state[2],idx,t;
+
+ IP(state,in);
+
+ for (idx=0; idx < 15; ++idx) {
+ t = state[1];
+ state[1] = f(state[1],key[idx]) ^ state[0];
+ state[0] = t;
+ }
+ // Perform the final loop manually as it doesn't switch sides
+ state[0] = f(state[1],key[15]) ^ state[0];
+
+ InvIP(state,out);
+}
+
+void three_des_key_setup(const BYTE key[], BYTE schedule[][16][6], DES_MODE mode)
+{
+ if (mode == DES_ENCRYPT) {
+ des_key_setup(&key[0],schedule[0],mode);
+ des_key_setup(&key[8],schedule[1],!mode);
+ des_key_setup(&key[16],schedule[2],mode);
+ }
+ else /*if (mode == DES_DECRYPT*/ {
+ des_key_setup(&key[16],schedule[0],mode);
+ des_key_setup(&key[8],schedule[1],!mode);
+ des_key_setup(&key[0],schedule[2],mode);
+ }
+}
+
+void three_des_crypt(const BYTE in[], BYTE out[], const BYTE key[][16][6])
+{
+ des_crypt(in,out,key[0]);
+ des_crypt(out,out,key[1]);
+ des_crypt(out,out,key[2]);
+}
diff --git a/lib/crypto-algorithms/des.h b/lib/crypto-algorithms/des.h
new file mode 100644
index 0000000..1503772
--- /dev/null
+++ b/lib/crypto-algorithms/des.h
@@ -0,0 +1,37 @@
+/*********************************************************************
+* Filename: des.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding DES implementation.
+ Note that encryption and decryption are defined by how
+ the key setup is performed, the actual en/de-cryption is
+ performed by the same function.
+*********************************************************************/
+
+#ifndef DES_H
+#define DESH
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/****************************** MACROS ******************************/
+#define DES_BLOCK_SIZE 8 // DES operates on 8 bytes at a time
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
+
+typedef enum {
+ DES_ENCRYPT,
+ DES_DECRYPT
+} DES_MODE;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void des_key_setup(const BYTE key[], BYTE schedule[][6], DES_MODE mode);
+void des_crypt(const BYTE in[], BYTE out[], const BYTE key[][6]);
+
+void three_des_key_setup(const BYTE key[], BYTE schedule[][16][6], DES_MODE mode);
+void three_des_crypt(const BYTE in[], BYTE out[], const BYTE key[][16][6]);
+
+#endif // DES_H
diff --git a/lib/crypto-algorithms/des_test.c b/lib/crypto-algorithms/des_test.c
new file mode 100644
index 0000000..3e46134
--- /dev/null
+++ b/lib/crypto-algorithms/des_test.c
@@ -0,0 +1,83 @@
+/*********************************************************************
+* Filename: des_test.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding DES
+ implementation. These tests do not encompass the full
+ range of available test vectors, however, if the tests
+ pass it is very, very likely that the code is correct
+ and was compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <memory.h>
+#include "des.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+int des_test()
+{
+ BYTE pt1[DES_BLOCK_SIZE] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xE7};
+ BYTE pt2[DES_BLOCK_SIZE] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};
+ BYTE pt3[DES_BLOCK_SIZE] = {0x54,0x68,0x65,0x20,0x71,0x75,0x66,0x63};
+ BYTE ct1[DES_BLOCK_SIZE] = {0xc9,0x57,0x44,0x25,0x6a,0x5e,0xd3,0x1d};
+ BYTE ct2[DES_BLOCK_SIZE] = {0x85,0xe8,0x13,0x54,0x0f,0x0a,0xb4,0x05};
+ BYTE ct3[DES_BLOCK_SIZE] = {0xc9,0x57,0x44,0x25,0x6a,0x5e,0xd3,0x1d};
+ BYTE ct4[DES_BLOCK_SIZE] = {0xA8,0x26,0xFD,0x8C,0xE5,0x3B,0x85,0x5F};
+ BYTE key1[DES_BLOCK_SIZE] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};
+ BYTE key2[DES_BLOCK_SIZE] = {0x13,0x34,0x57,0x79,0x9B,0xBC,0xDF,0xF1};
+ BYTE three_key1[DES_BLOCK_SIZE * 3] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
+ 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
+ 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};
+ BYTE three_key2[DES_BLOCK_SIZE * 3] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
+ 0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,0x01,
+ 0x45,0x67,0x89,0xAB,0xCD,0xEF,0x01,0x23};
+
+ BYTE schedule[16][6];
+ BYTE three_schedule[3][16][6];
+ BYTE buf[DES_BLOCK_SIZE];
+ int pass = 1;
+
+ des_key_setup(key1, schedule, DES_ENCRYPT);
+ des_crypt(pt1, buf, schedule);
+ pass = pass && !memcmp(ct1, buf, DES_BLOCK_SIZE);
+
+ des_key_setup(key1, schedule, DES_DECRYPT);
+ des_crypt(ct1, buf, schedule);
+ pass = pass && !memcmp(pt1, buf, DES_BLOCK_SIZE);
+
+ des_key_setup(key2, schedule, DES_ENCRYPT);
+ des_crypt(pt2, buf, schedule);
+ pass = pass && !memcmp(ct2, buf, DES_BLOCK_SIZE);
+
+ des_key_setup(key2, schedule, DES_DECRYPT);
+ des_crypt(ct2, buf, schedule);
+ pass = pass && !memcmp(pt2, buf, DES_BLOCK_SIZE);
+
+ three_des_key_setup(three_key1, three_schedule, DES_ENCRYPT);
+ three_des_crypt(pt1, buf, three_schedule);
+ pass = pass && !memcmp(ct3, buf, DES_BLOCK_SIZE);
+
+ three_des_key_setup(three_key1, three_schedule, DES_DECRYPT);
+ three_des_crypt(ct3, buf, three_schedule);
+ pass = pass && !memcmp(pt1, buf, DES_BLOCK_SIZE);
+
+ three_des_key_setup(three_key2, three_schedule, DES_ENCRYPT);
+ three_des_crypt(pt3, buf, three_schedule);
+ pass = pass && !memcmp(ct4, buf, DES_BLOCK_SIZE);
+
+ three_des_key_setup(three_key2, three_schedule, DES_DECRYPT);
+ three_des_crypt(ct4, buf, three_schedule);
+ pass = pass && !memcmp(pt3, buf, DES_BLOCK_SIZE);
+
+ return(pass);
+}
+
+int main()
+{
+ printf("DES test: %s\n", des_test() ? "SUCCEEDED" : "FAILED");
+
+ return(0);
+}
diff --git a/lib/crypto-algorithms/md2.c b/lib/crypto-algorithms/md2.c
new file mode 100644
index 0000000..de6bb6b
--- /dev/null
+++ b/lib/crypto-algorithms/md2.c
@@ -0,0 +1,104 @@
+/*********************************************************************
+* Filename: md2.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the MD2 hashing algorithm.
+ Algorithm specification can be found here:
+ * http://tools.ietf.org/html/rfc1319 .
+ Input is little endian byte order.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include <memory.h>
+#include "md2.h"
+
+/**************************** VARIABLES *****************************/
+static const BYTE s[256] = {
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void md2_transform(MD2_CTX *ctx, BYTE data[])
+{
+ int j,k,t;
+
+ //memcpy(&ctx->state[16], data);
+ for (j=0; j < 16; ++j) {
+ ctx->state[j + 16] = data[j];
+ ctx->state[j + 32] = (ctx->state[j+16] ^ ctx->state[j]);
+ }
+
+ t = 0;
+ for (j = 0; j < 18; ++j) {
+ for (k = 0; k < 48; ++k) {
+ ctx->state[k] ^= s[t];
+ t = ctx->state[k];
+ }
+ t = (t+j) & 0xFF;
+ }
+
+ t = ctx->checksum[15];
+ for (j=0; j < 16; ++j) {
+ ctx->checksum[j] ^= s[data[j] ^ t];
+ t = ctx->checksum[j];
+ }
+}
+
+void md2_init(MD2_CTX *ctx)
+{
+ int i;
+
+ for (i=0; i < 48; ++i)
+ ctx->state[i] = 0;
+ for (i=0; i < 16; ++i)
+ ctx->checksum[i] = 0;
+ ctx->len = 0;
+}
+
+void md2_update(MD2_CTX *ctx, const BYTE data[], size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i) {
+ ctx->data[ctx->len] = data[i];
+ ctx->len++;
+ if (ctx->len == MD2_BLOCK_SIZE) {
+ md2_transform(ctx, ctx->data);
+ ctx->len = 0;
+ }
+ }
+}
+
+void md2_final(MD2_CTX *ctx, BYTE hash[])
+{
+ int to_pad;
+
+ to_pad = MD2_BLOCK_SIZE - ctx->len;
+
+ while (ctx->len < MD2_BLOCK_SIZE)
+ ctx->data[ctx->len++] = to_pad;
+
+ md2_transform(ctx, ctx->data);
+ md2_transform(ctx, ctx->checksum);
+
+ memcpy(hash, ctx->state, MD2_BLOCK_SIZE);
+}
diff --git a/lib/crypto-algorithms/md2.h b/lib/crypto-algorithms/md2.h
new file mode 100644
index 0000000..97706af
--- /dev/null
+++ b/lib/crypto-algorithms/md2.h
@@ -0,0 +1,33 @@
+/*********************************************************************
+* Filename: md2.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding MD2 implementation.
+*********************************************************************/
+
+#ifndef MD2_H
+#define MD2_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/****************************** MACROS ******************************/
+#define MD2_BLOCK_SIZE 16
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+
+typedef struct {
+ BYTE data[16];
+ BYTE state[48];
+ BYTE checksum[16];
+ int len;
+} MD2_CTX;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void md2_init(MD2_CTX *ctx);
+void md2_update(MD2_CTX *ctx, const BYTE data[], size_t len);
+void md2_final(MD2_CTX *ctx, BYTE hash[]); // size of hash must be MD2_BLOCK_SIZE
+
+#endif // MD2_H
diff --git a/lib/crypto-algorithms/md2_test.c b/lib/crypto-algorithms/md2_test.c
new file mode 100644
index 0000000..883f20a
--- /dev/null
+++ b/lib/crypto-algorithms/md2_test.c
@@ -0,0 +1,58 @@
+/*********************************************************************
+* Filename: md2_test.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding MD2
+ implementation. These tests do not encompass the full
+ range of available test vectors, however, if the tests
+ pass it is very, very likely that the code is correct
+ and was compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include "md2.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+int md2_test()
+{
+ BYTE text1[] = {"abc"};
+ BYTE text2[] = {"abcdefghijklmnopqrstuvwxyz"};
+ BYTE text3_1[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"};
+ BYTE text3_2[] = {"fghijklmnopqrstuvwxyz0123456789"};
+ BYTE hash1[MD2_BLOCK_SIZE] = {0xda,0x85,0x3b,0x0d,0x3f,0x88,0xd9,0x9b,0x30,0x28,0x3a,0x69,0xe6,0xde,0xd6,0xbb};
+ BYTE hash2[MD2_BLOCK_SIZE] = {0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b};
+ BYTE hash3[MD2_BLOCK_SIZE] = {0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd};
+ BYTE buf[16];
+ MD2_CTX ctx;
+ int pass = 1;
+
+ md2_init(&ctx);
+ md2_update(&ctx, text1, strlen(text1));
+ md2_final(&ctx, buf);
+ pass = pass && !memcmp(hash1, buf, MD2_BLOCK_SIZE);
+
+ // Note that the MD2 object can be re-used.
+ md2_init(&ctx);
+ md2_update(&ctx, text2, strlen(text2));
+ md2_final(&ctx, buf);
+ pass = pass && !memcmp(hash2, buf, MD2_BLOCK_SIZE);
+
+ // Note that the data is added in two chunks.
+ md2_init(&ctx);
+ md2_update(&ctx, text3_1, strlen(text3_1));
+ md2_update(&ctx, text3_2, strlen(text3_2));
+ md2_final(&ctx, buf);
+ pass = pass && !memcmp(hash3, buf, MD2_BLOCK_SIZE);
+
+ return(pass);
+}
+
+int main()
+{
+ printf("MD2 tests: %s\n", md2_test() ? "SUCCEEDED" : "FAILED");
+}
diff --git a/lib/crypto-algorithms/md5.c b/lib/crypto-algorithms/md5.c
new file mode 100644
index 0000000..cdba052
--- /dev/null
+++ b/lib/crypto-algorithms/md5.c
@@ -0,0 +1,189 @@
+/*********************************************************************
+* Filename: md5.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the MD5 hashing algorithm.
+ Algorithm specification can be found here:
+ * http://tools.ietf.org/html/rfc1321
+ This implementation uses little endian byte order.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include <memory.h>
+#include "md5.h"
+
+/****************************** MACROS ******************************/
+#define ROTLEFT(a,b) ((a << b) | (a >> (32-b)))
+
+#define F(x,y,z) ((x & y) | (~x & z))
+#define G(x,y,z) ((x & z) | (y & ~z))
+#define H(x,y,z) (x ^ y ^ z)
+#define I(x,y,z) (y ^ (x | ~z))
+
+#define FF(a,b,c,d,m,s,t) { a += F(b,c,d) + m + t; \
+ a = b + ROTLEFT(a,s); }
+#define GG(a,b,c,d,m,s,t) { a += G(b,c,d) + m + t; \
+ a = b + ROTLEFT(a,s); }
+#define HH(a,b,c,d,m,s,t) { a += H(b,c,d) + m + t; \
+ a = b + ROTLEFT(a,s); }
+#define II(a,b,c,d,m,s,t) { a += I(b,c,d) + m + t; \
+ a = b + ROTLEFT(a,s); }
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void md5_transform(MD5_CTX *ctx, const BYTE data[])
+{
+ WORD a, b, c, d, m[16], i, j;
+
+ // MD5 specifies big endian byte order, but this implementation assumes a little
+ // endian byte order CPU. Reverse all the bytes upon input, and re-reverse them
+ // on output (in md5_final()).
+ for (i = 0, j = 0; i < 16; ++i, j += 4)
+ m[i] = (data[j]) + (data[j + 1] << 8) + (data[j + 2] << 16) + (data[j + 3] << 24);
+
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+
+ FF(a,b,c,d,m[0], 7,0xd76aa478);
+ FF(d,a,b,c,m[1], 12,0xe8c7b756);
+ FF(c,d,a,b,m[2], 17,0x242070db);
+ FF(b,c,d,a,m[3], 22,0xc1bdceee);
+ FF(a,b,c,d,m[4], 7,0xf57c0faf);
+ FF(d,a,b,c,m[5], 12,0x4787c62a);
+ FF(c,d,a,b,m[6], 17,0xa8304613);
+ FF(b,c,d,a,m[7], 22,0xfd469501);
+ FF(a,b,c,d,m[8], 7,0x698098d8);
+ FF(d,a,b,c,m[9], 12,0x8b44f7af);
+ FF(c,d,a,b,m[10],17,0xffff5bb1);
+ FF(b,c,d,a,m[11],22,0x895cd7be);
+ FF(a,b,c,d,m[12], 7,0x6b901122);
+ FF(d,a,b,c,m[13],12,0xfd987193);
+ FF(c,d,a,b,m[14],17,0xa679438e);
+ FF(b,c,d,a,m[15],22,0x49b40821);
+
+ GG(a,b,c,d,m[1], 5,0xf61e2562);
+ GG(d,a,b,c,m[6], 9,0xc040b340);
+ GG(c,d,a,b,m[11],14,0x265e5a51);
+ GG(b,c,d,a,m[0], 20,0xe9b6c7aa);
+ GG(a,b,c,d,m[5], 5,0xd62f105d);
+ GG(d,a,b,c,m[10], 9,0x02441453);
+ GG(c,d,a,b,m[15],14,0xd8a1e681);
+ GG(b,c,d,a,m[4], 20,0xe7d3fbc8);
+ GG(a,b,c,d,m[9], 5,0x21e1cde6);
+ GG(d,a,b,c,m[14], 9,0xc33707d6);
+ GG(c,d,a,b,m[3], 14,0xf4d50d87);
+ GG(b,c,d,a,m[8], 20,0x455a14ed);
+ GG(a,b,c,d,m[13], 5,0xa9e3e905);
+ GG(d,a,b,c,m[2], 9,0xfcefa3f8);
+ GG(c,d,a,b,m[7], 14,0x676f02d9);
+ GG(b,c,d,a,m[12],20,0x8d2a4c8a);
+
+ HH(a,b,c,d,m[5], 4,0xfffa3942);
+ HH(d,a,b,c,m[8], 11,0x8771f681);
+ HH(c,d,a,b,m[11],16,0x6d9d6122);
+ HH(b,c,d,a,m[14],23,0xfde5380c);
+ HH(a,b,c,d,m[1], 4,0xa4beea44);
+ HH(d,a,b,c,m[4], 11,0x4bdecfa9);
+ HH(c,d,a,b,m[7], 16,0xf6bb4b60);
+ HH(b,c,d,a,m[10],23,0xbebfbc70);
+ HH(a,b,c,d,m[13], 4,0x289b7ec6);
+ HH(d,a,b,c,m[0], 11,0xeaa127fa);
+ HH(c,d,a,b,m[3], 16,0xd4ef3085);
+ HH(b,c,d,a,m[6], 23,0x04881d05);
+ HH(a,b,c,d,m[9], 4,0xd9d4d039);
+ HH(d,a,b,c,m[12],11,0xe6db99e5);
+ HH(c,d,a,b,m[15],16,0x1fa27cf8);
+ HH(b,c,d,a,m[2], 23,0xc4ac5665);
+
+ II(a,b,c,d,m[0], 6,0xf4292244);
+ II(d,a,b,c,m[7], 10,0x432aff97);
+ II(c,d,a,b,m[14],15,0xab9423a7);
+ II(b,c,d,a,m[5], 21,0xfc93a039);
+ II(a,b,c,d,m[12], 6,0x655b59c3);
+ II(d,a,b,c,m[3], 10,0x8f0ccc92);
+ II(c,d,a,b,m[10],15,0xffeff47d);
+ II(b,c,d,a,m[1], 21,0x85845dd1);
+ II(a,b,c,d,m[8], 6,0x6fa87e4f);
+ II(d,a,b,c,m[15],10,0xfe2ce6e0);
+ II(c,d,a,b,m[6], 15,0xa3014314);
+ II(b,c,d,a,m[13],21,0x4e0811a1);
+ II(a,b,c,d,m[4], 6,0xf7537e82);
+ II(d,a,b,c,m[11],10,0xbd3af235);
+ II(c,d,a,b,m[2], 15,0x2ad7d2bb);
+ II(b,c,d,a,m[9], 21,0xeb86d391);
+
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+}
+
+void md5_init(MD5_CTX *ctx)
+{
+ ctx->datalen = 0;
+ ctx->bitlen = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+}
+
+void md5_update(MD5_CTX *ctx, const BYTE data[], size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i) {
+ ctx->data[ctx->datalen] = data[i];
+ ctx->datalen++;
+ if (ctx->datalen == 64) {
+ md5_transform(ctx, ctx->data);
+ ctx->bitlen += 512;
+ ctx->datalen = 0;
+ }
+ }
+}
+
+void md5_final(MD5_CTX *ctx, BYTE hash[])
+{
+ size_t i;
+
+ i = ctx->datalen;
+
+ // Pad whatever data is left in the buffer.
+ if (ctx->datalen < 56) {
+ ctx->data[i++] = 0x80;
+ while (i < 56)
+ ctx->data[i++] = 0x00;
+ }
+ else if (ctx->datalen >= 56) {
+ ctx->data[i++] = 0x80;
+ while (i < 64)
+ ctx->data[i++] = 0x00;
+ md5_transform(ctx, ctx->data);
+ memset(ctx->data, 0, 56);
+ }
+
+ // Append to the padding the total message's length in bits and transform.
+ ctx->bitlen += ctx->datalen * 8;
+ ctx->data[56] = ctx->bitlen;
+ ctx->data[57] = ctx->bitlen >> 8;
+ ctx->data[58] = ctx->bitlen >> 16;
+ ctx->data[59] = ctx->bitlen >> 24;
+ ctx->data[60] = ctx->bitlen >> 32;
+ ctx->data[61] = ctx->bitlen >> 40;
+ ctx->data[62] = ctx->bitlen >> 48;
+ ctx->data[63] = ctx->bitlen >> 56;
+ md5_transform(ctx, ctx->data);
+
+ // Since this implementation uses little endian byte ordering and MD uses big endian,
+ // reverse all the bytes when copying the final state to the output hash.
+ for (i = 0; i < 4; ++i) {
+ hash[i] = (ctx->state[0] >> (i * 8)) & 0x000000ff;
+ hash[i + 4] = (ctx->state[1] >> (i * 8)) & 0x000000ff;
+ hash[i + 8] = (ctx->state[2] >> (i * 8)) & 0x000000ff;
+ hash[i + 12] = (ctx->state[3] >> (i * 8)) & 0x000000ff;
+ }
+}
diff --git a/lib/crypto-algorithms/md5.h b/lib/crypto-algorithms/md5.h
new file mode 100644
index 0000000..1370387
--- /dev/null
+++ b/lib/crypto-algorithms/md5.h
@@ -0,0 +1,34 @@
+/*********************************************************************
+* Filename: md5.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding MD5 implementation.
+*********************************************************************/
+
+#ifndef MD5_H
+#define MD5_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/****************************** MACROS ******************************/
+#define MD5_BLOCK_SIZE 16 // MD5 outputs a 16 byte digest
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
+
+typedef struct {
+ BYTE data[64];
+ WORD datalen;
+ unsigned long long bitlen;
+ WORD state[4];
+} MD5_CTX;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void md5_init(MD5_CTX *ctx);
+void md5_update(MD5_CTX *ctx, const BYTE data[], size_t len);
+void md5_final(MD5_CTX *ctx, BYTE hash[]);
+
+#endif // MD5_H
diff --git a/lib/crypto-algorithms/md5_test.c b/lib/crypto-algorithms/md5_test.c
new file mode 100644
index 0000000..e945c8b
--- /dev/null
+++ b/lib/crypto-algorithms/md5_test.c
@@ -0,0 +1,60 @@
+/*********************************************************************
+* Filename: md5_test.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding MD5
+ implementation. These tests do not encompass the full
+ range of available test vectors, however, if the tests
+ pass it is very, very likely that the code is correct
+ and was compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <memory.h>
+#include <string.h>
+#include "md5.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+int md5_test()
+{
+ BYTE text1[] = {""};
+ BYTE text2[] = {"abc"};
+ BYTE text3_1[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"};
+ BYTE text3_2[] = {"fghijklmnopqrstuvwxyz0123456789"};
+ BYTE hash1[MD5_BLOCK_SIZE] = {0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04,0xe9,0x80,0x09,0x98,0xec,0xf8,0x42,0x7e};
+ BYTE hash2[MD5_BLOCK_SIZE] = {0x90,0x01,0x50,0x98,0x3c,0xd2,0x4f,0xb0,0xd6,0x96,0x3f,0x7d,0x28,0xe1,0x7f,0x72};
+ BYTE hash3[MD5_BLOCK_SIZE] = {0xd1,0x74,0xab,0x98,0xd2,0x77,0xd9,0xf5,0xa5,0x61,0x1c,0x2c,0x9f,0x41,0x9d,0x9f};
+ BYTE buf[16];
+ MD5_CTX ctx;
+ int pass = 1;
+
+ md5_init(&ctx);
+ md5_update(&ctx, text1, strlen(text1));
+ md5_final(&ctx, buf);
+ pass = pass && !memcmp(hash1, buf, MD5_BLOCK_SIZE);
+
+ // Note the MD5 object can be reused.
+ md5_init(&ctx);
+ md5_update(&ctx, text2, strlen(text2));
+ md5_final(&ctx, buf);
+ pass = pass && !memcmp(hash2, buf, MD5_BLOCK_SIZE);
+
+ // Note the data is being added in two chunks.
+ md5_init(&ctx);
+ md5_update(&ctx, text3_1, strlen(text3_1));
+ md5_update(&ctx, text3_2, strlen(text3_2));
+ md5_final(&ctx, buf);
+ pass = pass && !memcmp(hash3, buf, MD5_BLOCK_SIZE);
+
+ return(pass);
+}
+
+int main()
+{
+ printf("MD5 tests: %s\n", md5_test() ? "SUCCEEDED" : "FAILED");
+
+ return(0);
+}
diff --git a/lib/crypto-algorithms/rot-13.c b/lib/crypto-algorithms/rot-13.c
new file mode 100644
index 0000000..0ab8497
--- /dev/null
+++ b/lib/crypto-algorithms/rot-13.c
@@ -0,0 +1,35 @@
+/*********************************************************************
+* Filename: rot-13.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the ROT-13 encryption algorithm.
+ Algorithm specification can be found here:
+ *
+ This implementation uses little endian byte order.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <string.h>
+#include "rot-13.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void rot13(char str[])
+{
+ int case_type, idx, len;
+
+ for (idx = 0, len = strlen(str); idx < len; idx++) {
+ // Only process alphabetic characters.
+ if (str[idx] < 'A' || (str[idx] > 'Z' && str[idx] < 'a') || str[idx] > 'z')
+ continue;
+ // Determine if the char is upper or lower case.
+ if (str[idx] >= 'a')
+ case_type = 'a';
+ else
+ case_type = 'A';
+ // Rotate the char's value, ensuring it doesn't accidentally "fall off" the end.
+ str[idx] = (str[idx] + 13) % (case_type + 26);
+ if (str[idx] < 26)
+ str[idx] += case_type;
+ }
+}
diff --git a/lib/crypto-algorithms/rot-13.h b/lib/crypto-algorithms/rot-13.h
new file mode 100644
index 0000000..4c581c3
--- /dev/null
+++ b/lib/crypto-algorithms/rot-13.h
@@ -0,0 +1,20 @@
+/*********************************************************************
+* Filename: rot-13.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding ROT-13 implementation.
+*********************************************************************/
+
+#ifndef ROT13_H
+#define ROT13_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/*********************** FUNCTION DECLARATIONS **********************/
+// Performs IN PLACE rotation of the input. Assumes input is NULL terminated.
+// Preserves each charcter's case. Ignores non alphabetic characters.
+void rot13(char str[]);
+
+#endif // ROT13_H
diff --git a/lib/crypto-algorithms/rot-13_test.c b/lib/crypto-algorithms/rot-13_test.c
new file mode 100644
index 0000000..a6fd01d
--- /dev/null
+++ b/lib/crypto-algorithms/rot-13_test.c
@@ -0,0 +1,44 @@
+/*********************************************************************
+* Filename: rot-13_test.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding ROT-13
+ implementation. These tests do not encompass the full
+ range of available test vectors, however, if the tests
+ pass it is very, very likely that the code is correct
+ and was compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <string.h>
+#include "rot-13.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+int rot13_test()
+{
+ char text[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"};
+ char code[] = {"NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"};
+ char buf[1024];
+ int pass = 1;
+
+ // To encode, just apply ROT-13.
+ strcpy(buf, text);
+ rot13(buf);
+ pass = pass && !strcmp(code, buf);
+
+ // To decode, just re-apply ROT-13.
+ rot13(buf);
+ pass = pass && !strcmp(text, buf);
+
+ return(pass);
+}
+
+int main()
+{
+ printf("ROT-13 tests: %s\n", rot13_test() ? "SUCCEEDED" : "FAILED");
+
+ return(0);
+}
diff --git a/lib/crypto-algorithms/sha1.c b/lib/crypto-algorithms/sha1.c
new file mode 100644
index 0000000..2f9622d
--- /dev/null
+++ b/lib/crypto-algorithms/sha1.c
@@ -0,0 +1,149 @@
+/*********************************************************************
+* Filename: sha1.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the SHA1 hashing algorithm.
+ Algorithm specification can be found here:
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
+ This implementation uses little endian byte order.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include <memory.h>
+#include "sha1.h"
+
+/****************************** MACROS ******************************/
+#define ROTLEFT(a, b) ((a << b) | (a >> (32 - b)))
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void sha1_transform(SHA1_CTX *ctx, const BYTE data[])
+{
+ WORD a, b, c, d, e, i, j, t, m[80];
+
+ for (i = 0, j = 0; i < 16; ++i, j += 4)
+ m[i] = (data[j] << 24) + (data[j + 1] << 16) + (data[j + 2] << 8) + (data[j + 3]);
+ for ( ; i < 80; ++i) {
+ m[i] = (m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]);
+ m[i] = (m[i] << 1) | (m[i] >> 31);
+ }
+
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+ e = ctx->state[4];
+
+ for (i = 0; i < 20; ++i) {
+ t = ROTLEFT(a, 5) + ((b & c) ^ (~b & d)) + e + ctx->k[0] + m[i];
+ e = d;
+ d = c;
+ c = ROTLEFT(b, 30);
+ b = a;
+ a = t;
+ }
+ for ( ; i < 40; ++i) {
+ t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[1] + m[i];
+ e = d;
+ d = c;
+ c = ROTLEFT(b, 30);
+ b = a;
+ a = t;
+ }
+ for ( ; i < 60; ++i) {
+ t = ROTLEFT(a, 5) + ((b & c) ^ (b & d) ^ (c & d)) + e + ctx->k[2] + m[i];
+ e = d;
+ d = c;
+ c = ROTLEFT(b, 30);
+ b = a;
+ a = t;
+ }
+ for ( ; i < 80; ++i) {
+ t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[3] + m[i];
+ e = d;
+ d = c;
+ c = ROTLEFT(b, 30);
+ b = a;
+ a = t;
+ }
+
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+ ctx->state[4] += e;
+}
+
+void sha1_init(SHA1_CTX *ctx)
+{
+ ctx->datalen = 0;
+ ctx->bitlen = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xc3d2e1f0;
+ ctx->k[0] = 0x5a827999;
+ ctx->k[1] = 0x6ed9eba1;
+ ctx->k[2] = 0x8f1bbcdc;
+ ctx->k[3] = 0xca62c1d6;
+}
+
+void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i) {
+ ctx->data[ctx->datalen] = data[i];
+ ctx->datalen++;
+ if (ctx->datalen == 64) {
+ sha1_transform(ctx, ctx->data);
+ ctx->bitlen += 512;
+ ctx->datalen = 0;
+ }
+ }
+}
+
+void sha1_final(SHA1_CTX *ctx, BYTE hash[])
+{
+ WORD i;
+
+ i = ctx->datalen;
+
+ // Pad whatever data is left in the buffer.
+ if (ctx->datalen < 56) {
+ ctx->data[i++] = 0x80;
+ while (i < 56)
+ ctx->data[i++] = 0x00;
+ }
+ else {
+ ctx->data[i++] = 0x80;
+ while (i < 64)
+ ctx->data[i++] = 0x00;
+ sha1_transform(ctx, ctx->data);
+ memset(ctx->data, 0, 56);
+ }
+
+ // Append to the padding the total message's length in bits and transform.
+ ctx->bitlen += ctx->datalen * 8;
+ ctx->data[63] = ctx->bitlen;
+ ctx->data[62] = ctx->bitlen >> 8;
+ ctx->data[61] = ctx->bitlen >> 16;
+ ctx->data[60] = ctx->bitlen >> 24;
+ ctx->data[59] = ctx->bitlen >> 32;
+ ctx->data[58] = ctx->bitlen >> 40;
+ ctx->data[57] = ctx->bitlen >> 48;
+ ctx->data[56] = ctx->bitlen >> 56;
+ sha1_transform(ctx, ctx->data);
+
+ // Since this implementation uses little endian byte ordering and MD uses big endian,
+ // reverse all the bytes when copying the final state to the output hash.
+ for (i = 0; i < 4; ++i) {
+ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
+ }
+}
diff --git a/lib/crypto-algorithms/sha1.h b/lib/crypto-algorithms/sha1.h
new file mode 100644
index 0000000..f32bb7c
--- /dev/null
+++ b/lib/crypto-algorithms/sha1.h
@@ -0,0 +1,35 @@
+/*********************************************************************
+* Filename: sha1.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding SHA1 implementation.
+*********************************************************************/
+
+#ifndef SHA1_H
+#define SHA1_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/****************************** MACROS ******************************/
+#define SHA1_BLOCK_SIZE 20 // SHA1 outputs a 20 byte digest
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
+
+typedef struct {
+ BYTE data[64];
+ WORD datalen;
+ unsigned long long bitlen;
+ WORD state[5];
+ WORD k[4];
+} SHA1_CTX;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void sha1_init(SHA1_CTX *ctx);
+void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len);
+void sha1_final(SHA1_CTX *ctx, BYTE hash[]);
+
+#endif // SHA1_H
diff --git a/lib/crypto-algorithms/sha1_test.c b/lib/crypto-algorithms/sha1_test.c
new file mode 100644
index 0000000..6c78f7d
--- /dev/null
+++ b/lib/crypto-algorithms/sha1_test.c
@@ -0,0 +1,58 @@
+/*********************************************************************
+* Filename: sha1_test.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding SHA1
+ implementation. These tests do not encompass the full
+ range of available test vectors, however, if the tests
+ pass it is very, very likely that the code is correct
+ and was compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <memory.h>
+#include <string.h>
+#include "sha1.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+int sha1_test()
+{
+ BYTE text1[] = {"abc"};
+ BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
+ BYTE text3[] = {"aaaaaaaaaa"};
+ BYTE hash1[SHA1_BLOCK_SIZE] = {0xa9,0x99,0x3e,0x36,0x47,0x06,0x81,0x6a,0xba,0x3e,0x25,0x71,0x78,0x50,0xc2,0x6c,0x9c,0xd0,0xd8,0x9d};
+ BYTE hash2[SHA1_BLOCK_SIZE] = {0x84,0x98,0x3e,0x44,0x1c,0x3b,0xd2,0x6e,0xba,0xae,0x4a,0xa1,0xf9,0x51,0x29,0xe5,0xe5,0x46,0x70,0xf1};
+ BYTE hash3[SHA1_BLOCK_SIZE] = {0x34,0xaa,0x97,0x3c,0xd4,0xc4,0xda,0xa4,0xf6,0x1e,0xeb,0x2b,0xdb,0xad,0x27,0x31,0x65,0x34,0x01,0x6f};
+ BYTE buf[SHA1_BLOCK_SIZE];
+ int idx;
+ SHA1_CTX ctx;
+ int pass = 1;
+
+ sha1_init(&ctx);
+ sha1_update(&ctx, text1, strlen(text1));
+ sha1_final(&ctx, buf);
+ pass = pass && !memcmp(hash1, buf, SHA1_BLOCK_SIZE);
+
+ sha1_init(&ctx);
+ sha1_update(&ctx, text2, strlen(text2));
+ sha1_final(&ctx, buf);
+ pass = pass && !memcmp(hash2, buf, SHA1_BLOCK_SIZE);
+
+ sha1_init(&ctx);
+ for (idx = 0; idx < 100000; ++idx)
+ sha1_update(&ctx, text3, strlen(text3));
+ sha1_final(&ctx, buf);
+ pass = pass && !memcmp(hash3, buf, SHA1_BLOCK_SIZE);
+
+ return(pass);
+}
+
+int main()
+{
+ printf("SHA1 tests: %s\n", sha1_test() ? "SUCCEEDED" : "FAILED");
+
+ return(0);
+}
diff --git a/lib/crypto-algorithms/sha256.c b/lib/crypto-algorithms/sha256.c
new file mode 100644
index 0000000..eb9c5c0
--- /dev/null
+++ b/lib/crypto-algorithms/sha256.c
@@ -0,0 +1,158 @@
+/*********************************************************************
+* Filename: sha256.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the SHA-256 hashing algorithm.
+ SHA-256 is one of the three algorithms in the SHA2
+ specification. The others, SHA-384 and SHA-512, are not
+ offered in this implementation.
+ Algorithm specification can be found here:
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
+ This implementation uses little endian byte order.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include <memory.h>
+#include "sha256.h"
+
+/****************************** MACROS ******************************/
+#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
+
+#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
+#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
+#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
+#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
+#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
+
+/**************************** VARIABLES *****************************/
+static const WORD k[64] = {
+ 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+ 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+ 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+ 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+ 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+ 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+ 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+ 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
+{
+ WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
+
+ for (i = 0, j = 0; i < 16; ++i, j += 4)
+ m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
+ for ( ; i < 64; ++i)
+ m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
+
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+ e = ctx->state[4];
+ f = ctx->state[5];
+ g = ctx->state[6];
+ h = ctx->state[7];
+
+ for (i = 0; i < 64; ++i) {
+ t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
+ t2 = EP0(a) + MAJ(a,b,c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+ ctx->state[4] += e;
+ ctx->state[5] += f;
+ ctx->state[6] += g;
+ ctx->state[7] += h;
+}
+
+void sha256_init(SHA256_CTX *ctx)
+{
+ ctx->datalen = 0;
+ ctx->bitlen = 0;
+ ctx->state[0] = 0x6a09e667;
+ ctx->state[1] = 0xbb67ae85;
+ ctx->state[2] = 0x3c6ef372;
+ ctx->state[3] = 0xa54ff53a;
+ ctx->state[4] = 0x510e527f;
+ ctx->state[5] = 0x9b05688c;
+ ctx->state[6] = 0x1f83d9ab;
+ ctx->state[7] = 0x5be0cd19;
+}
+
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
+{
+ WORD i;
+
+ for (i = 0; i < len; ++i) {
+ ctx->data[ctx->datalen] = data[i];
+ ctx->datalen++;
+ if (ctx->datalen == 64) {
+ sha256_transform(ctx, ctx->data);
+ ctx->bitlen += 512;
+ ctx->datalen = 0;
+ }
+ }
+}
+
+void sha256_final(SHA256_CTX *ctx, BYTE hash[])
+{
+ WORD i;
+
+ i = ctx->datalen;
+
+ // Pad whatever data is left in the buffer.
+ if (ctx->datalen < 56) {
+ ctx->data[i++] = 0x80;
+ while (i < 56)
+ ctx->data[i++] = 0x00;
+ }
+ else {
+ ctx->data[i++] = 0x80;
+ while (i < 64)
+ ctx->data[i++] = 0x00;
+ sha256_transform(ctx, ctx->data);
+ memset(ctx->data, 0, 56);
+ }
+
+ // Append to the padding the total message's length in bits and transform.
+ ctx->bitlen += ctx->datalen * 8;
+ ctx->data[63] = ctx->bitlen;
+ ctx->data[62] = ctx->bitlen >> 8;
+ ctx->data[61] = ctx->bitlen >> 16;
+ ctx->data[60] = ctx->bitlen >> 24;
+ ctx->data[59] = ctx->bitlen >> 32;
+ ctx->data[58] = ctx->bitlen >> 40;
+ ctx->data[57] = ctx->bitlen >> 48;
+ ctx->data[56] = ctx->bitlen >> 56;
+ sha256_transform(ctx, ctx->data);
+
+ // Since this implementation uses little endian byte ordering and SHA uses big endian,
+ // reverse all the bytes when copying the final state to the output hash.
+ for (i = 0; i < 4; ++i) {
+ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
+ }
+}
diff --git a/lib/crypto-algorithms/sha256.h b/lib/crypto-algorithms/sha256.h
new file mode 100644
index 0000000..7123a30
--- /dev/null
+++ b/lib/crypto-algorithms/sha256.h
@@ -0,0 +1,34 @@
+/*********************************************************************
+* Filename: sha256.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding SHA1 implementation.
+*********************************************************************/
+
+#ifndef SHA256_H
+#define SHA256_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/****************************** MACROS ******************************/
+#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
+
+typedef struct {
+ BYTE data[64];
+ WORD datalen;
+ unsigned long long bitlen;
+ WORD state[8];
+} SHA256_CTX;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void sha256_init(SHA256_CTX *ctx);
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
+void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
+
+#endif // SHA256_H
diff --git a/lib/crypto-algorithms/sha256_test.c b/lib/crypto-algorithms/sha256_test.c
new file mode 100644
index 0000000..6951c51
--- /dev/null
+++ b/lib/crypto-algorithms/sha256_test.c
@@ -0,0 +1,61 @@
+/*********************************************************************
+* Filename: sha256.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Performs known-answer tests on the corresponding SHA1
+ implementation. These tests do not encompass the full
+ range of available test vectors, however, if the tests
+ pass it is very, very likely that the code is correct
+ and was compiled properly. This code also serves as
+ example usage of the functions.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdio.h>
+#include <memory.h>
+#include <string.h>
+#include "sha256.h"
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+int sha256_test()
+{
+ BYTE text1[] = {"abc"};
+ BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
+ BYTE text3[] = {"aaaaaaaaaa"};
+ BYTE hash1[SHA256_BLOCK_SIZE] = {0xba,0x78,0x16,0xbf,0x8f,0x01,0xcf,0xea,0x41,0x41,0x40,0xde,0x5d,0xae,0x22,0x23,
+ 0xb0,0x03,0x61,0xa3,0x96,0x17,0x7a,0x9c,0xb4,0x10,0xff,0x61,0xf2,0x00,0x15,0xad};
+ BYTE hash2[SHA256_BLOCK_SIZE] = {0x24,0x8d,0x6a,0x61,0xd2,0x06,0x38,0xb8,0xe5,0xc0,0x26,0x93,0x0c,0x3e,0x60,0x39,
+ 0xa3,0x3c,0xe4,0x59,0x64,0xff,0x21,0x67,0xf6,0xec,0xed,0xd4,0x19,0xdb,0x06,0xc1};
+ BYTE hash3[SHA256_BLOCK_SIZE] = {0xcd,0xc7,0x6e,0x5c,0x99,0x14,0xfb,0x92,0x81,0xa1,0xc7,0xe2,0x84,0xd7,0x3e,0x67,
+ 0xf1,0x80,0x9a,0x48,0xa4,0x97,0x20,0x0e,0x04,0x6d,0x39,0xcc,0xc7,0x11,0x2c,0xd0};
+ BYTE buf[SHA256_BLOCK_SIZE];
+ SHA256_CTX ctx;
+ int idx;
+ int pass = 1;
+
+ sha256_init(&ctx);
+ sha256_update(&ctx, text1, strlen(text1));
+ sha256_final(&ctx, buf);
+ pass = pass && !memcmp(hash1, buf, SHA256_BLOCK_SIZE);
+
+ sha256_init(&ctx);
+ sha256_update(&ctx, text2, strlen(text2));
+ sha256_final(&ctx, buf);
+ pass = pass && !memcmp(hash2, buf, SHA256_BLOCK_SIZE);
+
+ sha256_init(&ctx);
+ for (idx = 0; idx < 100000; ++idx)
+ sha256_update(&ctx, text3, strlen(text3));
+ sha256_final(&ctx, buf);
+ pass = pass && !memcmp(hash3, buf, SHA256_BLOCK_SIZE);
+
+ return(pass);
+}
+
+int main()
+{
+ printf("SHA-256 tests: %s\n", sha256_test() ? "SUCCEEDED" : "FAILEd");
+
+ return(0);
+}
diff --git a/lib/curve25519-donna/.gitignore b/lib/curve25519-donna/.gitignore
new file mode 100644
index 0000000..ccabede
--- /dev/null
+++ b/lib/curve25519-donna/.gitignore
@@ -0,0 +1,12 @@
+/curve25519-donna-c64.a
+/curve25519-donna.a
+/test-curve25519-donna
+/speed-curve25519-donna
+/test-curve25519-donna-c64
+/speed-curve25519-donna-c64
+/test-sc-curve25519-donna-c64
+/build
+*.o
+*.pyc
+/dist
+/MANIFEST
diff --git a/lib/curve25519-donna/LICENSE.md b/lib/curve25519-donna/LICENSE.md
new file mode 100644
index 0000000..33a3240
--- /dev/null
+++ b/lib/curve25519-donna/LICENSE.md
@@ -0,0 +1,46 @@
+Copyright 2008, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+* Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+curve25519-donna: Curve25519 elliptic curve, public key function
+
+http://code.google.com/p/curve25519-donna/
+
+Adam Langley <agl@imperialviolet.org>
+
+Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
+
+More information about curve25519 can be found here
+ http://cr.yp.to/ecdh.html
+
+djb's sample implementation of curve25519 is written in a special assembly
+language called qhasm and uses the floating point registers.
+
+This is, almost, a clean room reimplementation from the curve25519 paper. It
+uses many of the tricks described therein. Only the crecip function is taken
+from the sample implementation.
diff --git a/lib/curve25519-donna/Makefile b/lib/curve25519-donna/Makefile
new file mode 100644
index 0000000..e31fcca
--- /dev/null
+++ b/lib/curve25519-donna/Makefile
@@ -0,0 +1,56 @@
+CFLAGS=-Wmissing-prototypes -Wdeclaration-after-statement -O2 -Wall
+CFLAGS_32=-m32
+
+targets: curve25519-donna.a curve25519-donna-c64.a
+
+test: test-donna test-donna-c64
+
+clean:
+ rm -f *.o *.a *.pp test-curve25519-donna test-curve25519-donna-c64 speed-curve25519-donna speed-curve25519-donna-c64 test-noncanon-curve25519-donna test-noncanon-curve25519-donna-c64
+
+curve25519-donna.a: curve25519-donna.o
+ ar -rc curve25519-donna.a curve25519-donna.o
+ ranlib curve25519-donna.a
+
+curve25519-donna.o: curve25519-donna.c
+ gcc -c curve25519-donna.c $(CFLAGS) $(CFLAGS_32)
+
+curve25519-donna-c64.a: curve25519-donna-c64.o
+ ar -rc curve25519-donna-c64.a curve25519-donna-c64.o
+ ranlib curve25519-donna-c64.a
+
+curve25519-donna-c64.o: curve25519-donna-c64.c
+ gcc -c curve25519-donna-c64.c $(CFLAGS)
+
+test-donna: test-curve25519-donna
+ ./test-curve25519-donna | head -123456 | tail -1
+
+test-donna-c64: test-curve25519-donna-c64
+ ./test-curve25519-donna-c64 | head -123456 | tail -1
+
+test-curve25519-donna: test-curve25519.c curve25519-donna.a
+ gcc -o test-curve25519-donna test-curve25519.c curve25519-donna.a $(CFLAGS) $(CFLAGS_32)
+
+test-curve25519-donna-c64: test-curve25519.c curve25519-donna-c64.a
+ gcc -o test-curve25519-donna-c64 test-curve25519.c curve25519-donna-c64.a $(CFLAGS)
+
+speed-curve25519-donna: speed-curve25519.c curve25519-donna.a
+ gcc -o speed-curve25519-donna speed-curve25519.c curve25519-donna.a $(CFLAGS) $(CFLAGS_32)
+
+speed-curve25519-donna-c64: speed-curve25519.c curve25519-donna-c64.a
+ gcc -o speed-curve25519-donna-c64 speed-curve25519.c curve25519-donna-c64.a $(CFLAGS)
+
+test-sc-curve25519-donna-c64: test-sc-curve25519.c curve25519-donna-c64.a
+ gcc -o test-sc-curve25519-donna-c64 -O test-sc-curve25519.c curve25519-donna-c64.a test-sc-curve25519.s $(CFLAGS)
+
+test-noncanon-donna: test-noncanon-curve25519-donna
+ ./test-noncanon-curve25519-donna
+
+test-noncanon-donna-c64: test-noncanon-curve25519-donna-c64
+ ./test-noncanon-curve25519-donna-c64
+
+test-noncanon-curve25519-donna: test-noncanon.c curve25519-donna.a
+ gcc -o test-noncanon-curve25519-donna test-noncanon.c curve25519-donna.a $(CFLAGS) $(CFLAGS_32)
+
+test-noncanon-curve25519-donna-c64: test-noncanon.c curve25519-donna-c64.a
+ gcc -o test-noncanon-curve25519-donna-c64 test-noncanon.c curve25519-donna-c64.a $(CFLAGS)
diff --git a/lib/curve25519-donna/README b/lib/curve25519-donna/README
new file mode 100644
index 0000000..9adf9be
--- /dev/null
+++ b/lib/curve25519-donna/README
@@ -0,0 +1,40 @@
+See http://code.google.com/p/curve25519-donna/ for details.
+
+BUILDING:
+
+If you run `make`, two .a archives will be built, similar to djb's curve25519
+code. Alternatively, read on:
+
+The C implementation is contained within curve25519-donna.c. It has no external
+dependancies and is BSD licenced. You can copy/include/link it directly in with
+your program. Recommended C flags: -O2
+
+The x86-64 bit implementation is contained within curve25519-donna-x86-64.c and
+curve25519-donna-x86-64.s. Build like this:
+
+% cpp curve25519-donna-x86-64.s > curve25519-donna-x86-64.s.pp
+% as -o curve25519-donna-x86-64.s.o curve25519-donna-x86-64.s.pp
+% gcc -O2 -c curve25519-donna-x86-64.c
+
+Then the two .o files can be linked in
+
+USAGE:
+
+The usage is exactly the same as djb's code (as described at
+http://cr.yp.to/ecdh.html) expect that the function is called curve25519_donna.
+
+In short,
+
+To generate a private key just generate 32 random bytes.
+
+To generate the public key, just do:
+
+ static const uint8_t basepoint[32] = {9};
+ curve25519_donna(mypublic, mysecret, basepoint);
+
+To generate an agreed key do:
+
+ uint8_t shared_key[32];
+ curve25519_donna(shared_key, mysecret, theirpublic);
+
+And hash the shared_key with a cryptographic hash function before using.
diff --git a/lib/curve25519-donna/contrib/Curve25519Donna.c b/lib/curve25519-donna/contrib/Curve25519Donna.c
new file mode 100644
index 0000000..71b816c
--- /dev/null
+++ b/lib/curve25519-donna/contrib/Curve25519Donna.c
@@ -0,0 +1,118 @@
+/*
+ James Robson
+ Public domain.
+*/
+
+#include "Curve25519Donna.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void curve25519_donna(unsigned char *output, const unsigned char *a,
+ const unsigned char *b);
+
+unsigned char*
+as_unsigned_char_array(JNIEnv* env, jbyteArray array, int* len);
+
+jbyteArray as_byte_array(JNIEnv* env, unsigned char* buf, int len);
+
+
+jbyteArray as_byte_array(JNIEnv* env, unsigned char* buf, int len) {
+ jbyteArray array = (*env)->NewByteArray(env, len);
+ (*env)->SetByteArrayRegion(env, array, 0, len, (jbyte*)buf);
+
+ //int i;
+ //for (i = 0;i < len;++i) printf("%02x",(unsigned int) buf[i]); printf(" ");
+ //printf("\n");
+
+ return array;
+}
+
+unsigned char*
+as_unsigned_char_array(JNIEnv* env, jbyteArray array, int* len) {
+
+ *len = (*env)->GetArrayLength(env, array);
+ unsigned char* buf = (unsigned char*)calloc(*len+1, sizeof(char));
+ (*env)->GetByteArrayRegion (env, array, 0, *len, (jbyte*)buf);
+ return buf;
+
+}
+
+JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_curve25519Donna
+ (JNIEnv *env, jobject obj, jbyteArray a, jbyteArray b) {
+
+ unsigned char o[32] = {0};
+ int l1, l2;
+ unsigned char* a1 = as_unsigned_char_array(env, a, &l1);
+ unsigned char* b1 = as_unsigned_char_array(env, b, &l2);
+
+ if ( !(l1 == 32 && l2 == 32) ) {
+ fprintf(stderr, "Error, must be length 32");
+ return NULL;
+ }
+
+
+ curve25519_donna(o, (const unsigned char*)a1, (const unsigned char*)b1);
+
+ free(a1);
+ free(b1);
+
+ return as_byte_array(env, (unsigned char*)o, 32);
+}
+
+JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makePrivate
+ (JNIEnv *env, jobject obj, jbyteArray secret) {
+
+ int len;
+ unsigned char* k = as_unsigned_char_array(env, secret, &len);
+
+ if (len != 32) {
+ fprintf(stderr, "Error, must be length 32");
+ return NULL;
+ }
+
+ k[0] &= 248;
+ k[31] &= 127;
+ k[31] |= 64;
+ return as_byte_array(env, k, 32);
+}
+
+JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_getPublic
+ (JNIEnv *env, jobject obj, jbyteArray privkey) {
+
+ int len;
+ unsigned char* private = as_unsigned_char_array(env, privkey, &len);
+
+ if (len != 32) {
+ fprintf(stderr, "Error, must be length 32");
+ return NULL;
+ }
+
+ unsigned char pubkey[32];
+ unsigned char basepoint[32] = {9};
+
+ curve25519_donna(pubkey, private, basepoint);
+ return as_byte_array(env, (unsigned char*)pubkey, 32);
+}
+
+JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makeSharedSecret
+ (JNIEnv *env, jobject obj, jbyteArray privkey, jbyteArray their_pubkey) {
+
+ unsigned char shared_secret[32];
+
+ int l1, l2;
+ unsigned char* private = as_unsigned_char_array(env, privkey, &l1);
+ unsigned char* pubkey = as_unsigned_char_array(env, their_pubkey, &l2);
+
+ if ( !(l1 == 32 && l2 == 32) ) {
+ fprintf(stderr, "Error, must be length 32");
+ return NULL;
+ }
+
+ curve25519_donna(shared_secret, private, pubkey);
+ return as_byte_array(env, (unsigned char*)shared_secret, 32);
+}
+
+JNIEXPORT void JNICALL Java_Curve25519Donna_helowrld
+ (JNIEnv *env, jobject obj) {
+ printf("helowrld\n");
+}
diff --git a/lib/curve25519-donna/contrib/Curve25519Donna.h b/lib/curve25519-donna/contrib/Curve25519Donna.h
new file mode 100644
index 0000000..3cd4ca0
--- /dev/null
+++ b/lib/curve25519-donna/contrib/Curve25519Donna.h
@@ -0,0 +1,53 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class Curve25519Donna */
+
+#ifndef _Included_Curve25519Donna
+#define _Included_Curve25519Donna
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: Curve25519Donna
+ * Method: curve25519Donna
+ * Signature: ([B[B)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_curve25519Donna
+ (JNIEnv *, jobject, jbyteArray, jbyteArray);
+
+/*
+ * Class: Curve25519Donna
+ * Method: makePrivate
+ * Signature: ([B)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makePrivate
+ (JNIEnv *, jobject, jbyteArray);
+
+/*
+ * Class: Curve25519Donna
+ * Method: getPublic
+ * Signature: ([B)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_getPublic
+ (JNIEnv *, jobject, jbyteArray);
+
+/*
+ * Class: Curve25519Donna
+ * Method: makeSharedSecret
+ * Signature: ([B[B)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makeSharedSecret
+ (JNIEnv *, jobject, jbyteArray, jbyteArray);
+
+/*
+ * Class: Curve25519Donna
+ * Method: helowrld
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_Curve25519Donna_helowrld
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/lib/curve25519-donna/contrib/Curve25519Donna.java b/lib/curve25519-donna/contrib/Curve25519Donna.java
new file mode 100644
index 0000000..e28cb53
--- /dev/null
+++ b/lib/curve25519-donna/contrib/Curve25519Donna.java
@@ -0,0 +1,77 @@
+/*
+ James Robson
+ Public domain.
+*/
+
+public class Curve25519Donna {
+
+ final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
+
+ public static String bytesToHex(byte[] bytes) {
+ char[] hexChars = new char[bytes.length * 2];
+ int v;
+ for ( int j = 0; j < bytes.length; j++ ) {
+ v = bytes[j] & 0xFF;
+ hexChars[j * 2] = hexArray[v >>> 4];
+ hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
+ public native byte[] curve25519Donna(byte[] a, byte[] b);
+ public native byte[] makePrivate(byte[] secret);
+ public native byte[] getPublic(byte[] privkey);
+ public native byte[] makeSharedSecret(byte[] privkey, byte[] theirPubKey);
+ public native void helowrld();
+
+ // Uncomment if your Java is 32-bit:
+ //static { System.loadLibrary("Curve25519Donna"); }
+
+ // Otherwise, load this 64-bit .jnilib:
+ static { System.loadLibrary("Curve25519Donna_64"); }
+
+ /*
+ To give the old tires a kick (OSX):
+ java -cp `pwd` Curve25519Donna
+ */
+ public static void main (String[] args) {
+
+ Curve25519Donna c = new Curve25519Donna();
+
+ // These should be 32 bytes long
+ byte[] user1Secret = "abcdefghijklmnopqrstuvwxyz123456".getBytes();
+ byte[] user2Secret = "654321zyxwvutsrqponmlkjihgfedcba".getBytes();
+
+
+ // You can use the curve function directly...
+
+ //byte[] o = c.curve25519Donna(a, b);
+ //System.out.println("o = " + bytesToHex(o));
+
+
+ // ... but it's not really necessary. Just use the following
+ // convenience methods:
+
+ byte[] privKey = c.makePrivate(user1Secret);
+ byte[] pubKey = c.getPublic(privKey);
+
+ byte[] privKey2 = c.makePrivate(user2Secret);
+ byte[] pubKey2 = c.getPublic(privKey2);
+
+ System.out.println("'user1' privKey = " + bytesToHex(privKey));
+ System.out.println("'user1' pubKey = " + bytesToHex(pubKey));
+ System.out.println("===================================================");
+
+ System.out.println("'user2' privKey = " + bytesToHex(privKey2));
+ System.out.println("'user2' pubKey = " + bytesToHex(pubKey2));
+ System.out.println("===================================================");
+
+
+ byte[] ss1 = c.makeSharedSecret(privKey, pubKey2);
+ System.out.println("'user1' computes shared secret: " + bytesToHex(ss1));
+
+ byte[] ss2 = c.makeSharedSecret(privKey2, pubKey);
+ System.out.println("'user2' computes shared secret: " + bytesToHex(ss2));
+
+ }
+}
diff --git a/lib/curve25519-donna/contrib/make-snippets b/lib/curve25519-donna/contrib/make-snippets
new file mode 100644
index 0000000..4568721
--- /dev/null
+++ b/lib/curve25519-donna/contrib/make-snippets
@@ -0,0 +1,68 @@
+CFLAGS=-Wmissing-prototypes -Wdeclaration-after-statement -O2 -Wall
+CC=clang
+
+
+targets: curve25519-donna.a curve25519-donna-c64.a
+
+test: test-donna test-donna-c64
+
+
+clean:
+ rm -f java-src/*.class java-src/*.jnilib *.dylib *.o *.a *.pp test-curve25519-donna test-curve25519-donna-c64 speed-curve25519-donna speed-curve25519-donna-c64
+
+curve25519-donna.a: curve25519-donna.o
+ ar -rc curve25519-donna.a curve25519-donna.o
+ ranlib curve25519-donna.a
+
+
+##### OSX dynamic library (32- & 64-bit)
+
+curve25519donna.dylib: curve25519-donna.a curve25519-donna-c64.a
+ $(CC) -m32 -fpic -shared -Wl,-all_load curve25519-donna.a -Wl,-all_load -o libcurve25519donna.dylib
+ $(CC) -fpic -shared -Wl,-all_load curve25519-donna-c64.a -Wl,-all_load -o libcurve25519donna_64.dylib
+
+##### OSX/Java section hence
+
+# Java JNI - compiled for OSX (32- & 64-bit)
+Curve25519Donna.class:
+ cd java-src; javah -jni Curve25519Donna; cd ..
+ cd java-src; javac Curve25519Donna.java; cd ..
+
+Curve25519Donna.jnilib: curve25519-donna.a curve25519-donna-c64.a Curve25519Donna.class
+ @echo "Building 32-bit..."
+ clang -o java-src/libCurve25519Donna.jnilib $(CFLAGS) -lc -shared -m32 -I /System/Library/Frameworks/JavaVM.framework/Headers curve25519-donna.o java-src/Curve25519Donna.c
+ @echo "Building 64-bit..."
+ clang -o java-src/libCurve25519Donna_64.jnilib $(CFLAGS) -lc -shared -I /System/Library/Frameworks/JavaVM.framework/Headers curve25519-donna-c64.o java-src/Curve25519Donna.c
+
+##### OSX/Java section end
+
+curve25519-donna.o: curve25519-donna.c
+ $(CC) -c curve25519-donna.c $(CFLAGS) -m32
+
+curve25519-donna-c64.a: curve25519-donna-c64.o
+ ar -rc curve25519-donna-c64.a curve25519-donna-c64.o
+ ranlib curve25519-donna-c64.a
+
+curve25519-donna-c64.o: curve25519-donna-c64.c
+ $(CC) -c curve25519-donna-c64.c $(CFLAGS)
+
+test-donna: test-curve25519-donna
+ ./test-curve25519-donna | head -123456 | tail -1
+
+test-donna-c64: test-curve25519-donna-c64
+ ./test-curve25519-donna-c64 | head -123456 | tail -1
+
+test-curve25519-donna: test-curve25519.c curve25519-donna.a
+ $(CC) -o test-curve25519-donna test-curve25519.c curve25519-donna.a $(CFLAGS) -m32
+
+test-curve25519-donna-c64: test-curve25519.c curve25519-donna-c64.a
+ $(CC) -o test-curve25519-donna-c64 test-curve25519.c curve25519-donna-c64.a $(CFLAGS)
+
+speed-curve25519-donna: speed-curve25519.c curve25519-donna.a
+ $(CC) -o speed-curve25519-donna speed-curve25519.c curve25519-donna.a $(CFLAGS) -m32
+
+speed-curve25519-donna-c64: speed-curve25519.c curve25519-donna-c64.a
+ $(CC) -o speed-curve25519-donna-c64 speed-curve25519.c curve25519-donna-c64.a $(CFLAGS)
+
+test-sc-curve25519-donna-c64: test-sc-curve25519.c curve25519-donna-c64.a
+ $(CC) -o test-sc-curve25519-donna-c64 -O test-sc-curve25519.c curve25519-donna-c64.a test-sc-curve25519.s $(CFLAGS)
diff --git a/lib/curve25519-donna/curve25519-donna-c64.c b/lib/curve25519-donna/curve25519-donna-c64.c
new file mode 100644
index 0000000..9ebd8a1
--- /dev/null
+++ b/lib/curve25519-donna/curve25519-donna-c64.c
@@ -0,0 +1,449 @@
+/* Copyright 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Code released into the public domain.
+ *
+ * curve25519-donna: Curve25519 elliptic curve, public key function
+ *
+ * http://code.google.com/p/curve25519-donna/
+ *
+ * Adam Langley <agl@imperialviolet.org>
+ *
+ * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
+ *
+ * More information about curve25519 can be found here
+ * http://cr.yp.to/ecdh.html
+ *
+ * djb's sample implementation of curve25519 is written in a special assembly
+ * language called qhasm and uses the floating point registers.
+ *
+ * This is, almost, a clean room reimplementation from the curve25519 paper. It
+ * uses many of the tricks described therein. Only the crecip function is taken
+ * from the sample implementation.
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+typedef uint8_t u8;
+typedef uint64_t limb;
+typedef limb felem[5];
+// This is a special gcc mode for 128-bit integers. It's implemented on 64-bit
+// platforms only as far as I know.
+typedef unsigned uint128_t __attribute__((mode(TI)));
+
+#undef force_inline
+#define force_inline __attribute__((always_inline))
+
+/* Sum two numbers: output += in */
+static inline void force_inline
+fsum(limb *output, const limb *in) {
+ output[0] += in[0];
+ output[1] += in[1];
+ output[2] += in[2];
+ output[3] += in[3];
+ output[4] += in[4];
+}
+
+/* Find the difference of two numbers: output = in - output
+ * (note the order of the arguments!)
+ *
+ * Assumes that out[i] < 2**52
+ * On return, out[i] < 2**55
+ */
+static inline void force_inline
+fdifference_backwards(felem out, const felem in) {
+ /* 152 is 19 << 3 */
+ static const limb two54m152 = (((limb)1) << 54) - 152;
+ static const limb two54m8 = (((limb)1) << 54) - 8;
+
+ out[0] = in[0] + two54m152 - out[0];
+ out[1] = in[1] + two54m8 - out[1];
+ out[2] = in[2] + two54m8 - out[2];
+ out[3] = in[3] + two54m8 - out[3];
+ out[4] = in[4] + two54m8 - out[4];
+}
+
+/* Multiply a number by a scalar: output = in * scalar */
+static inline void force_inline
+fscalar_product(felem output, const felem in, const limb scalar) {
+ uint128_t a;
+
+ a = ((uint128_t) in[0]) * scalar;
+ output[0] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[1]) * scalar + ((limb) (a >> 51));
+ output[1] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[2]) * scalar + ((limb) (a >> 51));
+ output[2] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[3]) * scalar + ((limb) (a >> 51));
+ output[3] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[4]) * scalar + ((limb) (a >> 51));
+ output[4] = ((limb)a) & 0x7ffffffffffff;
+
+ output[0] += (a >> 51) * 19;
+}
+
+/* Multiply two numbers: output = in2 * in
+ *
+ * output must be distinct to both inputs. The inputs are reduced coefficient
+ * form, the output is not.
+ *
+ * Assumes that in[i] < 2**55 and likewise for in2.
+ * On return, output[i] < 2**52
+ */
+static inline void force_inline
+fmul(felem output, const felem in2, const felem in) {
+ uint128_t t[5];
+ limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c;
+
+ r0 = in[0];
+ r1 = in[1];
+ r2 = in[2];
+ r3 = in[3];
+ r4 = in[4];
+
+ s0 = in2[0];
+ s1 = in2[1];
+ s2 = in2[2];
+ s3 = in2[3];
+ s4 = in2[4];
+
+ t[0] = ((uint128_t) r0) * s0;
+ t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0;
+ t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1;
+ t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1;
+ t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2;
+
+ r4 *= 19;
+ r1 *= 19;
+ r2 *= 19;
+ r3 *= 19;
+
+ t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2;
+ t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3;
+ t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4;
+ t[3] += ((uint128_t) r4) * s4;
+
+ r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51);
+ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51);
+ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51);
+ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51);
+ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51);
+ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff;
+ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff;
+ r2 += c;
+
+ output[0] = r0;
+ output[1] = r1;
+ output[2] = r2;
+ output[3] = r3;
+ output[4] = r4;
+}
+
+static inline void force_inline
+fsquare_times(felem output, const felem in, limb count) {
+ uint128_t t[5];
+ limb r0,r1,r2,r3,r4,c;
+ limb d0,d1,d2,d4,d419;
+
+ r0 = in[0];
+ r1 = in[1];
+ r2 = in[2];
+ r3 = in[3];
+ r4 = in[4];
+
+ do {
+ d0 = r0 * 2;
+ d1 = r1 * 2;
+ d2 = r2 * 2 * 19;
+ d419 = r4 * 19;
+ d4 = d419 * 2;
+
+ t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 ));
+ t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19));
+ t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 ));
+ t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 ));
+ t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 ));
+
+ r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51);
+ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51);
+ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51);
+ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51);
+ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51);
+ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff;
+ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff;
+ r2 += c;
+ } while(--count);
+
+ output[0] = r0;
+ output[1] = r1;
+ output[2] = r2;
+ output[3] = r3;
+ output[4] = r4;
+}
+
+/* Load a little-endian 64-bit number */
+static limb
+load_limb(const u8 *in) {
+ return
+ ((limb)in[0]) |
+ (((limb)in[1]) << 8) |
+ (((limb)in[2]) << 16) |
+ (((limb)in[3]) << 24) |
+ (((limb)in[4]) << 32) |
+ (((limb)in[5]) << 40) |
+ (((limb)in[6]) << 48) |
+ (((limb)in[7]) << 56);
+}
+
+static void
+store_limb(u8 *out, limb in) {
+ out[0] = in & 0xff;
+ out[1] = (in >> 8) & 0xff;
+ out[2] = (in >> 16) & 0xff;
+ out[3] = (in >> 24) & 0xff;
+ out[4] = (in >> 32) & 0xff;
+ out[5] = (in >> 40) & 0xff;
+ out[6] = (in >> 48) & 0xff;
+ out[7] = (in >> 56) & 0xff;
+}
+
+/* Take a little-endian, 32-byte number and expand it into polynomial form */
+static void
+fexpand(limb *output, const u8 *in) {
+ output[0] = load_limb(in) & 0x7ffffffffffff;
+ output[1] = (load_limb(in+6) >> 3) & 0x7ffffffffffff;
+ output[2] = (load_limb(in+12) >> 6) & 0x7ffffffffffff;
+ output[3] = (load_limb(in+19) >> 1) & 0x7ffffffffffff;
+ output[4] = (load_limb(in+24) >> 12) & 0x7ffffffffffff;
+}
+
+/* Take a fully reduced polynomial form number and contract it into a
+ * little-endian, 32-byte array
+ */
+static void
+fcontract(u8 *output, const felem input) {
+ uint128_t t[5];
+
+ t[0] = input[0];
+ t[1] = input[1];
+ t[2] = input[2];
+ t[3] = input[3];
+ t[4] = input[4];
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
+
+ /* now t is between 0 and 2^255-1, properly carried. */
+ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */
+
+ t[0] += 19;
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
+
+ /* now between 19 and 2^255-1 in both cases, and offset by 19. */
+
+ t[0] += 0x8000000000000 - 19;
+ t[1] += 0x8000000000000 - 1;
+ t[2] += 0x8000000000000 - 1;
+ t[3] += 0x8000000000000 - 1;
+ t[4] += 0x8000000000000 - 1;
+
+ /* now between 2^255 and 2^256-20, and offset by 2^255. */
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[4] &= 0x7ffffffffffff;
+
+ store_limb(output, t[0] | (t[1] << 51));
+ store_limb(output+8, (t[1] >> 13) | (t[2] << 38));
+ store_limb(output+16, (t[2] >> 26) | (t[3] << 25));
+ store_limb(output+24, (t[3] >> 39) | (t[4] << 12));
+}
+
+/* Input: Q, Q', Q-Q'
+ * Output: 2Q, Q+Q'
+ *
+ * x2 z3: long form
+ * x3 z3: long form
+ * x z: short form, destroyed
+ * xprime zprime: short form, destroyed
+ * qmqp: short form, preserved
+ */
+static void
+fmonty(limb *x2, limb *z2, /* output 2Q */
+ limb *x3, limb *z3, /* output Q + Q' */
+ limb *x, limb *z, /* input Q */
+ limb *xprime, limb *zprime, /* input Q' */
+ const limb *qmqp /* input Q - Q' */) {
+ limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5],
+ zzprime[5], zzzprime[5];
+
+ memcpy(origx, x, 5 * sizeof(limb));
+ fsum(x, z);
+ fdifference_backwards(z, origx); // does x - z
+
+ memcpy(origxprime, xprime, sizeof(limb) * 5);
+ fsum(xprime, zprime);
+ fdifference_backwards(zprime, origxprime);
+ fmul(xxprime, xprime, z);
+ fmul(zzprime, x, zprime);
+ memcpy(origxprime, xxprime, sizeof(limb) * 5);
+ fsum(xxprime, zzprime);
+ fdifference_backwards(zzprime, origxprime);
+ fsquare_times(x3, xxprime, 1);
+ fsquare_times(zzzprime, zzprime, 1);
+ fmul(z3, zzzprime, qmqp);
+
+ fsquare_times(xx, x, 1);
+ fsquare_times(zz, z, 1);
+ fmul(x2, xx, zz);
+ fdifference_backwards(zz, xx); // does zz = xx - zz
+ fscalar_product(zzz, zz, 121665);
+ fsum(zzz, xx);
+ fmul(z2, zz, zzz);
+}
+
+// -----------------------------------------------------------------------------
+// Maybe swap the contents of two limb arrays (@a and @b), each @len elements
+// long. Perform the swap iff @swap is non-zero.
+//
+// This function performs the swap without leaking any side-channel
+// information.
+// -----------------------------------------------------------------------------
+static void
+swap_conditional(limb a[5], limb b[5], limb iswap) {
+ unsigned i;
+ const limb swap = -iswap;
+
+ for (i = 0; i < 5; ++i) {
+ const limb x = swap & (a[i] ^ b[i]);
+ a[i] ^= x;
+ b[i] ^= x;
+ }
+}
+
+/* Calculates nQ where Q is the x-coordinate of a point on the curve
+ *
+ * resultx/resultz: the x coordinate of the resulting curve point (short form)
+ * n: a little endian, 32-byte number
+ * q: a point of the curve (short form)
+ */
+static void
+cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
+ limb a[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0};
+ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
+ limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1};
+ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
+
+ unsigned i, j;
+
+ memcpy(nqpqx, q, sizeof(limb) * 5);
+
+ for (i = 0; i < 32; ++i) {
+ u8 byte = n[31 - i];
+ for (j = 0; j < 8; ++j) {
+ const limb bit = byte >> 7;
+
+ swap_conditional(nqx, nqpqx, bit);
+ swap_conditional(nqz, nqpqz, bit);
+ fmonty(nqx2, nqz2,
+ nqpqx2, nqpqz2,
+ nqx, nqz,
+ nqpqx, nqpqz,
+ q);
+ swap_conditional(nqx2, nqpqx2, bit);
+ swap_conditional(nqz2, nqpqz2, bit);
+
+ t = nqx;
+ nqx = nqx2;
+ nqx2 = t;
+ t = nqz;
+ nqz = nqz2;
+ nqz2 = t;
+ t = nqpqx;
+ nqpqx = nqpqx2;
+ nqpqx2 = t;
+ t = nqpqz;
+ nqpqz = nqpqz2;
+ nqpqz2 = t;
+
+ byte <<= 1;
+ }
+ }
+
+ memcpy(resultx, nqx, sizeof(limb) * 5);
+ memcpy(resultz, nqz, sizeof(limb) * 5);
+}
+
+
+// -----------------------------------------------------------------------------
+// Shamelessly copied from djb's code, tightened a little
+// -----------------------------------------------------------------------------
+static void
+crecip(felem out, const felem z) {
+ felem a,t0,b,c;
+
+ /* 2 */ fsquare_times(a, z, 1); // a = 2
+ /* 8 */ fsquare_times(t0, a, 2);
+ /* 9 */ fmul(b, t0, z); // b = 9
+ /* 11 */ fmul(a, b, a); // a = 11
+ /* 22 */ fsquare_times(t0, a, 1);
+ /* 2^5 - 2^0 = 31 */ fmul(b, t0, b);
+ /* 2^10 - 2^5 */ fsquare_times(t0, b, 5);
+ /* 2^10 - 2^0 */ fmul(b, t0, b);
+ /* 2^20 - 2^10 */ fsquare_times(t0, b, 10);
+ /* 2^20 - 2^0 */ fmul(c, t0, b);
+ /* 2^40 - 2^20 */ fsquare_times(t0, c, 20);
+ /* 2^40 - 2^0 */ fmul(t0, t0, c);
+ /* 2^50 - 2^10 */ fsquare_times(t0, t0, 10);
+ /* 2^50 - 2^0 */ fmul(b, t0, b);
+ /* 2^100 - 2^50 */ fsquare_times(t0, b, 50);
+ /* 2^100 - 2^0 */ fmul(c, t0, b);
+ /* 2^200 - 2^100 */ fsquare_times(t0, c, 100);
+ /* 2^200 - 2^0 */ fmul(t0, t0, c);
+ /* 2^250 - 2^50 */ fsquare_times(t0, t0, 50);
+ /* 2^250 - 2^0 */ fmul(t0, t0, b);
+ /* 2^255 - 2^5 */ fsquare_times(t0, t0, 5);
+ /* 2^255 - 21 */ fmul(out, t0, a);
+}
+
+int curve25519_donna(u8 *, const u8 *, const u8 *);
+
+int
+curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
+ limb bp[5], x[5], z[5], zmone[5];
+ uint8_t e[32];
+ int i;
+
+ for (i = 0;i < 32;++i) e[i] = secret[i];
+ e[0] &= 248;
+ e[31] &= 127;
+ e[31] |= 64;
+
+ fexpand(bp, basepoint);
+ cmult(x, z, e, bp);
+ crecip(zmone, z);
+ fmul(z, x, zmone);
+ fcontract(mypublic, z);
+ return 0;
+}
diff --git a/lib/curve25519-donna/curve25519-donna.c b/lib/curve25519-donna/curve25519-donna.c
new file mode 100644
index 0000000..ed15d6c
--- /dev/null
+++ b/lib/curve25519-donna/curve25519-donna.c
@@ -0,0 +1,860 @@
+/* Copyright 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * curve25519-donna: Curve25519 elliptic curve, public key function
+ *
+ * http://code.google.com/p/curve25519-donna/
+ *
+ * Adam Langley <agl@imperialviolet.org>
+ *
+ * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
+ *
+ * More information about curve25519 can be found here
+ * http://cr.yp.to/ecdh.html
+ *
+ * djb's sample implementation of curve25519 is written in a special assembly
+ * language called qhasm and uses the floating point registers.
+ *
+ * This is, almost, a clean room reimplementation from the curve25519 paper. It
+ * uses many of the tricks described therein. Only the crecip function is taken
+ * from the sample implementation. */
+
+#include <string.h>
+#include <stdint.h>
+
+#ifdef _MSC_VER
+#define inline __inline
+#endif
+
+typedef uint8_t u8;
+typedef int32_t s32;
+typedef int64_t limb;
+
+/* Field element representation:
+ *
+ * Field elements are written as an array of signed, 64-bit limbs, least
+ * significant first. The value of the field element is:
+ * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
+ *
+ * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */
+
+/* Sum two numbers: output += in */
+static void fsum(limb *output, const limb *in) {
+ unsigned i;
+ for (i = 0; i < 10; i += 2) {
+ output[0+i] = output[0+i] + in[0+i];
+ output[1+i] = output[1+i] + in[1+i];
+ }
+}
+
+/* Find the difference of two numbers: output = in - output
+ * (note the order of the arguments!). */
+static void fdifference(limb *output, const limb *in) {
+ unsigned i;
+ for (i = 0; i < 10; ++i) {
+ output[i] = in[i] - output[i];
+ }
+}
+
+/* Multiply a number by a scalar: output = in * scalar */
+static void fscalar_product(limb *output, const limb *in, const limb scalar) {
+ unsigned i;
+ for (i = 0; i < 10; ++i) {
+ output[i] = in[i] * scalar;
+ }
+}
+
+/* Multiply two numbers: output = in2 * in
+ *
+ * output must be distinct to both inputs. The inputs are reduced coefficient
+ * form, the output is not.
+ *
+ * output[x] <= 14 * the largest product of the input limbs. */
+static void fproduct(limb *output, const limb *in2, const limb *in) {
+ output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
+ output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[0]);
+ output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[0]);
+ output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[0]);
+ output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
+ 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[1])) +
+ ((limb) ((s32) in2[0])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[0]);
+ output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[0]);
+ output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[1])) +
+ ((limb) ((s32) in2[2])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[0]);
+ output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[0]);
+ output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
+ 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[1])) +
+ ((limb) ((s32) in2[2])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[0]);
+ output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[0]);
+ output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[1])) +
+ ((limb) ((s32) in2[4])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[2]);
+ output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[2]);
+ output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
+ 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[3])) +
+ ((limb) ((s32) in2[4])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[4]);
+ output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[4]);
+ output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[5])) +
+ ((limb) ((s32) in2[6])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[6]);
+ output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[6]);
+ output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
+ 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[7]));
+ output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[8]);
+ output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
+}
+
+/* Reduce a long form to a short form by taking the input mod 2^255 - 19.
+ *
+ * On entry: |output[i]| < 14*2^54
+ * On exit: |output[0..8]| < 280*2^54 */
+static void freduce_degree(limb *output) {
+ /* Each of these shifts and adds ends up multiplying the value by 19.
+ *
+ * For output[0..8], the absolute entry value is < 14*2^54 and we add, at
+ * most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */
+ output[8] += output[18] << 4;
+ output[8] += output[18] << 1;
+ output[8] += output[18];
+ output[7] += output[17] << 4;
+ output[7] += output[17] << 1;
+ output[7] += output[17];
+ output[6] += output[16] << 4;
+ output[6] += output[16] << 1;
+ output[6] += output[16];
+ output[5] += output[15] << 4;
+ output[5] += output[15] << 1;
+ output[5] += output[15];
+ output[4] += output[14] << 4;
+ output[4] += output[14] << 1;
+ output[4] += output[14];
+ output[3] += output[13] << 4;
+ output[3] += output[13] << 1;
+ output[3] += output[13];
+ output[2] += output[12] << 4;
+ output[2] += output[12] << 1;
+ output[2] += output[12];
+ output[1] += output[11] << 4;
+ output[1] += output[11] << 1;
+ output[1] += output[11];
+ output[0] += output[10] << 4;
+ output[0] += output[10] << 1;
+ output[0] += output[10];
+}
+
+#if (-1 & 3) != 3
+#error "This code only works on a two's complement system"
+#endif
+
+/* return v / 2^26, using only shifts and adds.
+ *
+ * On entry: v can take any value. */
+static inline limb
+div_by_2_26(const limb v)
+{
+ /* High word of v; no shift needed. */
+ const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
+ /* Set to all 1s if v was negative; else set to 0s. */
+ const int32_t sign = ((int32_t) highword) >> 31;
+ /* Set to 0x3ffffff if v was negative; else set to 0. */
+ const int32_t roundoff = ((uint32_t) sign) >> 6;
+ /* Should return v / (1<<26) */
+ return (v + roundoff) >> 26;
+}
+
+/* return v / (2^25), using only shifts and adds.
+ *
+ * On entry: v can take any value. */
+static inline limb
+div_by_2_25(const limb v)
+{
+ /* High word of v; no shift needed*/
+ const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
+ /* Set to all 1s if v was negative; else set to 0s. */
+ const int32_t sign = ((int32_t) highword) >> 31;
+ /* Set to 0x1ffffff if v was negative; else set to 0. */
+ const int32_t roundoff = ((uint32_t) sign) >> 7;
+ /* Should return v / (1<<25) */
+ return (v + roundoff) >> 25;
+}
+
+/* Reduce all coefficients of the short form input so that |x| < 2^26.
+ *
+ * On entry: |output[i]| < 280*2^54 */
+static void freduce_coefficients(limb *output) {
+ unsigned i;
+
+ output[10] = 0;
+
+ for (i = 0; i < 10; i += 2) {
+ limb over = div_by_2_26(output[i]);
+ /* The entry condition (that |output[i]| < 280*2^54) means that over is, at
+ * most, 280*2^28 in the first iteration of this loop. This is added to the
+ * next limb and we can approximate the resulting bound of that limb by
+ * 281*2^54. */
+ output[i] -= over << 26;
+ output[i+1] += over;
+
+ /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| <
+ * 281*2^29. When this is added to the next limb, the resulting bound can
+ * be approximated as 281*2^54.
+ *
+ * For subsequent iterations of the loop, 281*2^54 remains a conservative
+ * bound and no overflow occurs. */
+ over = div_by_2_25(output[i+1]);
+ output[i+1] -= over << 25;
+ output[i+2] += over;
+ }
+ /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */
+ output[0] += output[10] << 4;
+ output[0] += output[10] << 1;
+ output[0] += output[10];
+
+ output[10] = 0;
+
+ /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29
+ * So |over| will be no more than 2^16. */
+ {
+ limb over = div_by_2_26(output[0]);
+ output[0] -= over << 26;
+ output[1] += over;
+ }
+
+ /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The
+ * bound on |output[1]| is sufficient to meet our needs. */
+}
+
+/* A helpful wrapper around fproduct: output = in * in2.
+ *
+ * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27.
+ *
+ * output must be distinct to both inputs. The output is reduced degree
+ * (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */
+static void
+fmul(limb *output, const limb *in, const limb *in2) {
+ limb t[19];
+ fproduct(t, in, in2);
+ /* |t[i]| < 14*2^54 */
+ freduce_degree(t);
+ freduce_coefficients(t);
+ /* |t[i]| < 2^26 */
+ memcpy(output, t, sizeof(limb) * 10);
+}
+
+/* Square a number: output = in**2
+ *
+ * output must be distinct from the input. The inputs are reduced coefficient
+ * form, the output is not.
+ *
+ * output[x] <= 14 * the largest product of the input limbs. */
+static void fsquare_inner(limb *output, const limb *in) {
+ output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
+ output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
+ output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
+ ((limb) ((s32) in[0])) * ((s32) in[2]));
+ output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
+ ((limb) ((s32) in[0])) * ((s32) in[3]));
+ output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
+ 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
+ 2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
+ output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
+ ((limb) ((s32) in[1])) * ((s32) in[4]) +
+ ((limb) ((s32) in[0])) * ((s32) in[5]));
+ output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
+ ((limb) ((s32) in[2])) * ((s32) in[4]) +
+ ((limb) ((s32) in[0])) * ((s32) in[6]) +
+ 2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
+ output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
+ ((limb) ((s32) in[2])) * ((s32) in[5]) +
+ ((limb) ((s32) in[1])) * ((s32) in[6]) +
+ ((limb) ((s32) in[0])) * ((s32) in[7]));
+ output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
+ 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
+ ((limb) ((s32) in[0])) * ((s32) in[8]) +
+ 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
+ ((limb) ((s32) in[3])) * ((s32) in[5])));
+ output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
+ ((limb) ((s32) in[3])) * ((s32) in[6]) +
+ ((limb) ((s32) in[2])) * ((s32) in[7]) +
+ ((limb) ((s32) in[1])) * ((s32) in[8]) +
+ ((limb) ((s32) in[0])) * ((s32) in[9]));
+ output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
+ ((limb) ((s32) in[4])) * ((s32) in[6]) +
+ ((limb) ((s32) in[2])) * ((s32) in[8]) +
+ 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
+ ((limb) ((s32) in[1])) * ((s32) in[9])));
+ output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
+ ((limb) ((s32) in[4])) * ((s32) in[7]) +
+ ((limb) ((s32) in[3])) * ((s32) in[8]) +
+ ((limb) ((s32) in[2])) * ((s32) in[9]));
+ output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
+ 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
+ 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
+ ((limb) ((s32) in[3])) * ((s32) in[9])));
+ output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
+ ((limb) ((s32) in[5])) * ((s32) in[8]) +
+ ((limb) ((s32) in[4])) * ((s32) in[9]));
+ output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
+ ((limb) ((s32) in[6])) * ((s32) in[8]) +
+ 2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
+ output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
+ ((limb) ((s32) in[6])) * ((s32) in[9]));
+ output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
+ 4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
+ output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
+ output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
+}
+
+/* fsquare sets output = in^2.
+ *
+ * On entry: The |in| argument is in reduced coefficients form and |in[i]| <
+ * 2^27.
+ *
+ * On exit: The |output| argument is in reduced coefficients form (indeed, one
+ * need only provide storage for 10 limbs) and |out[i]| < 2^26. */
+static void
+fsquare(limb *output, const limb *in) {
+ limb t[19];
+ fsquare_inner(t, in);
+ /* |t[i]| < 14*2^54 because the largest product of two limbs will be <
+ * 2^(27+27) and fsquare_inner adds together, at most, 14 of those
+ * products. */
+ freduce_degree(t);
+ freduce_coefficients(t);
+ /* |t[i]| < 2^26 */
+ memcpy(output, t, sizeof(limb) * 10);
+}
+
+/* Take a little-endian, 32-byte number and expand it into polynomial form */
+static void
+fexpand(limb *output, const u8 *input) {
+#define F(n,start,shift,mask) \
+ output[n] = ((((limb) input[start + 0]) | \
+ ((limb) input[start + 1]) << 8 | \
+ ((limb) input[start + 2]) << 16 | \
+ ((limb) input[start + 3]) << 24) >> shift) & mask;
+ F(0, 0, 0, 0x3ffffff);
+ F(1, 3, 2, 0x1ffffff);
+ F(2, 6, 3, 0x3ffffff);
+ F(3, 9, 5, 0x1ffffff);
+ F(4, 12, 6, 0x3ffffff);
+ F(5, 16, 0, 0x1ffffff);
+ F(6, 19, 1, 0x3ffffff);
+ F(7, 22, 3, 0x1ffffff);
+ F(8, 25, 4, 0x3ffffff);
+ F(9, 28, 6, 0x1ffffff);
+#undef F
+}
+
+#if (-32 >> 1) != -16
+#error "This code only works when >> does sign-extension on negative numbers"
+#endif
+
+/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */
+static s32 s32_eq(s32 a, s32 b) {
+ a = ~(a ^ b);
+ a &= a << 16;
+ a &= a << 8;
+ a &= a << 4;
+ a &= a << 2;
+ a &= a << 1;
+ return a >> 31;
+}
+
+/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are
+ * both non-negative. */
+static s32 s32_gte(s32 a, s32 b) {
+ a -= b;
+ /* a >= 0 iff a >= b. */
+ return ~(a >> 31);
+}
+
+/* Take a fully reduced polynomial form number and contract it into a
+ * little-endian, 32-byte array.
+ *
+ * On entry: |input_limbs[i]| < 2^26 */
+static void
+fcontract(u8 *output, limb *input_limbs) {
+ int i;
+ int j;
+ s32 input[10];
+ s32 mask;
+
+ /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */
+ for (i = 0; i < 10; i++) {
+ input[i] = input_limbs[i];
+ }
+
+ for (j = 0; j < 2; ++j) {
+ for (i = 0; i < 9; ++i) {
+ if ((i & 1) == 1) {
+ /* This calculation is a time-invariant way to make input[i]
+ * non-negative by borrowing from the next-larger limb. */
+ const s32 mask = input[i] >> 31;
+ const s32 carry = -((input[i] & mask) >> 25);
+ input[i] = input[i] + (carry << 25);
+ input[i+1] = input[i+1] - carry;
+ } else {
+ const s32 mask = input[i] >> 31;
+ const s32 carry = -((input[i] & mask) >> 26);
+ input[i] = input[i] + (carry << 26);
+ input[i+1] = input[i+1] - carry;
+ }
+ }
+
+ /* There's no greater limb for input[9] to borrow from, but we can multiply
+ * by 19 and borrow from input[0], which is valid mod 2^255-19. */
+ {
+ const s32 mask = input[9] >> 31;
+ const s32 carry = -((input[9] & mask) >> 25);
+ input[9] = input[9] + (carry << 25);
+ input[0] = input[0] - (carry * 19);
+ }
+
+ /* After the first iteration, input[1..9] are non-negative and fit within
+ * 25 or 26 bits, depending on position. However, input[0] may be
+ * negative. */
+ }
+
+ /* The first borrow-propagation pass above ended with every limb
+ except (possibly) input[0] non-negative.
+
+ If input[0] was negative after the first pass, then it was because of a
+ carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most,
+ one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19.
+
+ In the second pass, each limb is decreased by at most one. Thus the second
+ borrow-propagation pass could only have wrapped around to decrease
+ input[0] again if the first pass left input[0] negative *and* input[1]
+ through input[9] were all zero. In that case, input[1] is now 2^25 - 1,
+ and this last borrow-propagation step will leave input[1] non-negative. */
+ {
+ const s32 mask = input[0] >> 31;
+ const s32 carry = -((input[0] & mask) >> 26);
+ input[0] = input[0] + (carry << 26);
+ input[1] = input[1] - carry;
+ }
+
+ /* All input[i] are now non-negative. However, there might be values between
+ * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */
+ for (j = 0; j < 2; j++) {
+ for (i = 0; i < 9; i++) {
+ if ((i & 1) == 1) {
+ const s32 carry = input[i] >> 25;
+ input[i] &= 0x1ffffff;
+ input[i+1] += carry;
+ } else {
+ const s32 carry = input[i] >> 26;
+ input[i] &= 0x3ffffff;
+ input[i+1] += carry;
+ }
+ }
+
+ {
+ const s32 carry = input[9] >> 25;
+ input[9] &= 0x1ffffff;
+ input[0] += 19*carry;
+ }
+ }
+
+ /* If the first carry-chain pass, just above, ended up with a carry from
+ * input[9], and that caused input[0] to be out-of-bounds, then input[0] was
+ * < 2^26 + 2*19, because the carry was, at most, two.
+ *
+ * If the second pass carried from input[9] again then input[0] is < 2*19 and
+ * the input[9] -> input[0] carry didn't push input[0] out of bounds. */
+
+ /* It still remains the case that input might be between 2^255-19 and 2^255.
+ * In this case, input[1..9] must take their maximum value and input[0] must
+ * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */
+ mask = s32_gte(input[0], 0x3ffffed);
+ for (i = 1; i < 10; i++) {
+ if ((i & 1) == 1) {
+ mask &= s32_eq(input[i], 0x1ffffff);
+ } else {
+ mask &= s32_eq(input[i], 0x3ffffff);
+ }
+ }
+
+ /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus
+ * this conditionally subtracts 2^255-19. */
+ input[0] -= mask & 0x3ffffed;
+
+ for (i = 1; i < 10; i++) {
+ if ((i & 1) == 1) {
+ input[i] -= mask & 0x1ffffff;
+ } else {
+ input[i] -= mask & 0x3ffffff;
+ }
+ }
+
+ input[1] <<= 2;
+ input[2] <<= 3;
+ input[3] <<= 5;
+ input[4] <<= 6;
+ input[6] <<= 1;
+ input[7] <<= 3;
+ input[8] <<= 4;
+ input[9] <<= 6;
+#define F(i, s) \
+ output[s+0] |= input[i] & 0xff; \
+ output[s+1] = (input[i] >> 8) & 0xff; \
+ output[s+2] = (input[i] >> 16) & 0xff; \
+ output[s+3] = (input[i] >> 24) & 0xff;
+ output[0] = 0;
+ output[16] = 0;
+ F(0,0);
+ F(1,3);
+ F(2,6);
+ F(3,9);
+ F(4,12);
+ F(5,16);
+ F(6,19);
+ F(7,22);
+ F(8,25);
+ F(9,28);
+#undef F
+}
+
+/* Input: Q, Q', Q-Q'
+ * Output: 2Q, Q+Q'
+ *
+ * x2 z3: long form
+ * x3 z3: long form
+ * x z: short form, destroyed
+ * xprime zprime: short form, destroyed
+ * qmqp: short form, preserved
+ *
+ * On entry and exit, the absolute value of the limbs of all inputs and outputs
+ * are < 2^26. */
+static void fmonty(limb *x2, limb *z2, /* output 2Q */
+ limb *x3, limb *z3, /* output Q + Q' */
+ limb *x, limb *z, /* input Q */
+ limb *xprime, limb *zprime, /* input Q' */
+ const limb *qmqp /* input Q - Q' */) {
+ limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
+ zzprime[19], zzzprime[19], xxxprime[19];
+
+ memcpy(origx, x, 10 * sizeof(limb));
+ fsum(x, z);
+ /* |x[i]| < 2^27 */
+ fdifference(z, origx); /* does x - z */
+ /* |z[i]| < 2^27 */
+
+ memcpy(origxprime, xprime, sizeof(limb) * 10);
+ fsum(xprime, zprime);
+ /* |xprime[i]| < 2^27 */
+ fdifference(zprime, origxprime);
+ /* |zprime[i]| < 2^27 */
+ fproduct(xxprime, xprime, z);
+ /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be <
+ * 2^(27+27) and fproduct adds together, at most, 14 of those products.
+ * (Approximating that to 2^58 doesn't work out.) */
+ fproduct(zzprime, x, zprime);
+ /* |zzprime[i]| < 14*2^54 */
+ freduce_degree(xxprime);
+ freduce_coefficients(xxprime);
+ /* |xxprime[i]| < 2^26 */
+ freduce_degree(zzprime);
+ freduce_coefficients(zzprime);
+ /* |zzprime[i]| < 2^26 */
+ memcpy(origxprime, xxprime, sizeof(limb) * 10);
+ fsum(xxprime, zzprime);
+ /* |xxprime[i]| < 2^27 */
+ fdifference(zzprime, origxprime);
+ /* |zzprime[i]| < 2^27 */
+ fsquare(xxxprime, xxprime);
+ /* |xxxprime[i]| < 2^26 */
+ fsquare(zzzprime, zzprime);
+ /* |zzzprime[i]| < 2^26 */
+ fproduct(zzprime, zzzprime, qmqp);
+ /* |zzprime[i]| < 14*2^52 */
+ freduce_degree(zzprime);
+ freduce_coefficients(zzprime);
+ /* |zzprime[i]| < 2^26 */
+ memcpy(x3, xxxprime, sizeof(limb) * 10);
+ memcpy(z3, zzprime, sizeof(limb) * 10);
+
+ fsquare(xx, x);
+ /* |xx[i]| < 2^26 */
+ fsquare(zz, z);
+ /* |zz[i]| < 2^26 */
+ fproduct(x2, xx, zz);
+ /* |x2[i]| < 14*2^52 */
+ freduce_degree(x2);
+ freduce_coefficients(x2);
+ /* |x2[i]| < 2^26 */
+ fdifference(zz, xx); // does zz = xx - zz
+ /* |zz[i]| < 2^27 */
+ memset(zzz + 10, 0, sizeof(limb) * 9);
+ fscalar_product(zzz, zz, 121665);
+ /* |zzz[i]| < 2^(27+17) */
+ /* No need to call freduce_degree here:
+ fscalar_product doesn't increase the degree of its input. */
+ freduce_coefficients(zzz);
+ /* |zzz[i]| < 2^26 */
+ fsum(zzz, xx);
+ /* |zzz[i]| < 2^27 */
+ fproduct(z2, zz, zzz);
+ /* |z2[i]| < 14*2^(26+27) */
+ freduce_degree(z2);
+ freduce_coefficients(z2);
+ /* |z2|i| < 2^26 */
+}
+
+/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
+ * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
+ * side-channel attacks.
+ *
+ * NOTE that this function requires that 'iswap' be 1 or 0; other values give
+ * wrong results. Also, the two limb arrays must be in reduced-coefficient,
+ * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
+ * and all all values in a[0..9],b[0..9] must have magnitude less than
+ * INT32_MAX. */
+static void
+swap_conditional(limb a[19], limb b[19], limb iswap) {
+ unsigned i;
+ const s32 swap = (s32) -iswap;
+
+ for (i = 0; i < 10; ++i) {
+ const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
+ a[i] = ((s32)a[i]) ^ x;
+ b[i] = ((s32)b[i]) ^ x;
+ }
+}
+
+/* Calculates nQ where Q is the x-coordinate of a point on the curve
+ *
+ * resultx/resultz: the x coordinate of the resulting curve point (short form)
+ * n: a little endian, 32-byte number
+ * q: a point of the curve (short form) */
+static void
+cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
+ limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
+ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
+ limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
+ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
+
+ unsigned i, j;
+
+ memcpy(nqpqx, q, sizeof(limb) * 10);
+
+ for (i = 0; i < 32; ++i) {
+ u8 byte = n[31 - i];
+ for (j = 0; j < 8; ++j) {
+ const limb bit = byte >> 7;
+
+ swap_conditional(nqx, nqpqx, bit);
+ swap_conditional(nqz, nqpqz, bit);
+ fmonty(nqx2, nqz2,
+ nqpqx2, nqpqz2,
+ nqx, nqz,
+ nqpqx, nqpqz,
+ q);
+ swap_conditional(nqx2, nqpqx2, bit);
+ swap_conditional(nqz2, nqpqz2, bit);
+
+ t = nqx;
+ nqx = nqx2;
+ nqx2 = t;
+ t = nqz;
+ nqz = nqz2;
+ nqz2 = t;
+ t = nqpqx;
+ nqpqx = nqpqx2;
+ nqpqx2 = t;
+ t = nqpqz;
+ nqpqz = nqpqz2;
+ nqpqz2 = t;
+
+ byte <<= 1;
+ }
+ }
+
+ memcpy(resultx, nqx, sizeof(limb) * 10);
+ memcpy(resultz, nqz, sizeof(limb) * 10);
+}
+
+// -----------------------------------------------------------------------------
+// Shamelessly copied from djb's code
+// -----------------------------------------------------------------------------
+static void
+crecip(limb *out, const limb *z) {
+ limb z2[10];
+ limb z9[10];
+ limb z11[10];
+ limb z2_5_0[10];
+ limb z2_10_0[10];
+ limb z2_20_0[10];
+ limb z2_50_0[10];
+ limb z2_100_0[10];
+ limb t0[10];
+ limb t1[10];
+ int i;
+
+ /* 2 */ fsquare(z2,z);
+ /* 4 */ fsquare(t1,z2);
+ /* 8 */ fsquare(t0,t1);
+ /* 9 */ fmul(z9,t0,z);
+ /* 11 */ fmul(z11,z9,z2);
+ /* 22 */ fsquare(t0,z11);
+ /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
+
+ /* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
+ /* 2^7 - 2^2 */ fsquare(t1,t0);
+ /* 2^8 - 2^3 */ fsquare(t0,t1);
+ /* 2^9 - 2^4 */ fsquare(t1,t0);
+ /* 2^10 - 2^5 */ fsquare(t0,t1);
+ /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
+
+ /* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
+ /* 2^12 - 2^2 */ fsquare(t1,t0);
+ /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
+ /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
+
+ /* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
+ /* 2^22 - 2^2 */ fsquare(t1,t0);
+ /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
+ /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
+
+ /* 2^41 - 2^1 */ fsquare(t1,t0);
+ /* 2^42 - 2^2 */ fsquare(t0,t1);
+ /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
+ /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
+
+ /* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
+ /* 2^52 - 2^2 */ fsquare(t1,t0);
+ /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
+ /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
+
+ /* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
+ /* 2^102 - 2^2 */ fsquare(t0,t1);
+ /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
+ /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
+
+ /* 2^201 - 2^1 */ fsquare(t0,t1);
+ /* 2^202 - 2^2 */ fsquare(t1,t0);
+ /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
+ /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
+
+ /* 2^251 - 2^1 */ fsquare(t1,t0);
+ /* 2^252 - 2^2 */ fsquare(t0,t1);
+ /* 2^253 - 2^3 */ fsquare(t1,t0);
+ /* 2^254 - 2^4 */ fsquare(t0,t1);
+ /* 2^255 - 2^5 */ fsquare(t1,t0);
+ /* 2^255 - 21 */ fmul(out,t1,z11);
+}
+
+int
+curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
+ limb bp[10], x[10], z[11], zmone[10];
+ uint8_t e[32];
+ int i;
+
+ for (i = 0; i < 32; ++i) e[i] = secret[i];
+ e[0] &= 248;
+ e[31] &= 127;
+ e[31] |= 64;
+
+ fexpand(bp, basepoint);
+ cmult(x, z, e, bp);
+ crecip(zmone, z);
+ fmul(z, x, zmone);
+ fcontract(mypublic, z);
+ return 0;
+}
diff --git a/lib/curve25519-donna/curve25519-donna.podspec b/lib/curve25519-donna/curve25519-donna.podspec
new file mode 100644
index 0000000..0f2f31a
--- /dev/null
+++ b/lib/curve25519-donna/curve25519-donna.podspec
@@ -0,0 +1,13 @@
+Pod::Spec.new do |s|
+ s.name = "curve25519-donna"
+ s.version = "1.2.1"
+ s.summary = "Implementations of a fast elliptic-curve, Diffie-Hellman primitive"
+ s.description = <<-DESC
+ Curve25519 is a state-of-the-art Diffie-Hellman function suitable for a wide variety of applications.
+ DESC
+ s.homepage = "http://code.google.com/p/curve25519-donna"
+ s.license = 'BSD 3-Clause'
+ s.author = 'Dan Bernstein'
+ s.source = { :git => "https://github.com/agl/curve25519-donna.git", :tag => "1.2.1" }
+ s.source_files = 'curve25519-donna.c'
+end
diff --git a/lib/curve25519-donna/python-src/curve25519/__init__.py b/lib/curve25519-donna/python-src/curve25519/__init__.py
new file mode 100644
index 0000000..873ff57
--- /dev/null
+++ b/lib/curve25519-donna/python-src/curve25519/__init__.py
@@ -0,0 +1,4 @@
+
+from .keys import Private, Public
+
+hush_pyflakes = [Private, Public]; del hush_pyflakes
diff --git a/lib/curve25519-donna/python-src/curve25519/curve25519module.c b/lib/curve25519-donna/python-src/curve25519/curve25519module.c
new file mode 100644
index 0000000..e309ec0
--- /dev/null
+++ b/lib/curve25519-donna/python-src/curve25519/curve25519module.c
@@ -0,0 +1,105 @@
+/* tell python that PyArg_ParseTuple(t#) means Py_ssize_t, not int */
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#if (PY_VERSION_HEX < 0x02050000)
+ typedef int Py_ssize_t;
+#endif
+
+/* This is required for compatibility with Python 2. */
+#if PY_MAJOR_VERSION >= 3
+ #include <bytesobject.h>
+ #define y "y"
+#else
+ #define PyBytes_FromStringAndSize PyString_FromStringAndSize
+ #define y "t"
+#endif
+
+int curve25519_donna(char *mypublic,
+ const char *secret, const char *basepoint);
+
+static PyObject *
+pycurve25519_makeprivate(PyObject *self, PyObject *args)
+{
+ char *in1;
+ Py_ssize_t in1len;
+ if (!PyArg_ParseTuple(args, y"#:clamp", &in1, &in1len))
+ return NULL;
+ if (in1len != 32) {
+ PyErr_SetString(PyExc_ValueError, "input must be 32-byte string");
+ return NULL;
+ }
+ in1[0] &= 248;
+ in1[31] &= 127;
+ in1[31] |= 64;
+ return PyBytes_FromStringAndSize((char *)in1, 32);
+}
+
+static PyObject *
+pycurve25519_makepublic(PyObject *self, PyObject *args)
+{
+ const char *private;
+ char mypublic[32];
+ char basepoint[32] = {9};
+ Py_ssize_t privatelen;
+ if (!PyArg_ParseTuple(args, y"#:makepublic", &private, &privatelen))
+ return NULL;
+ if (privatelen != 32) {
+ PyErr_SetString(PyExc_ValueError, "input must be 32-byte string");
+ return NULL;
+ }
+ curve25519_donna(mypublic, private, basepoint);
+ return PyBytes_FromStringAndSize((char *)mypublic, 32);
+}
+
+static PyObject *
+pycurve25519_makeshared(PyObject *self, PyObject *args)
+{
+ const char *myprivate, *theirpublic;
+ char shared_key[32];
+ Py_ssize_t myprivatelen, theirpubliclen;
+ if (!PyArg_ParseTuple(args, y"#"y"#:generate",
+ &myprivate, &myprivatelen, &theirpublic, &theirpubliclen))
+ return NULL;
+ if (myprivatelen != 32) {
+ PyErr_SetString(PyExc_ValueError, "input must be 32-byte string");
+ return NULL;
+ }
+ if (theirpubliclen != 32) {
+ PyErr_SetString(PyExc_ValueError, "input must be 32-byte string");
+ return NULL;
+ }
+ curve25519_donna(shared_key, myprivate, theirpublic);
+ return PyBytes_FromStringAndSize((char *)shared_key, 32);
+}
+
+
+static PyMethodDef
+curve25519_functions[] = {
+ {"make_private", pycurve25519_makeprivate, METH_VARARGS, "data->private"},
+ {"make_public", pycurve25519_makepublic, METH_VARARGS, "private->public"},
+ {"make_shared", pycurve25519_makeshared, METH_VARARGS, "private+public->shared"},
+ {NULL, NULL, 0, NULL},
+};
+
+#if PY_MAJOR_VERSION >= 3
+ static struct PyModuleDef
+ curve25519_module = {
+ PyModuleDef_HEAD_INIT,
+ "_curve25519",
+ NULL,
+ NULL,
+ curve25519_functions,
+ };
+
+ PyObject *
+ PyInit__curve25519(void)
+ {
+ return PyModule_Create(&curve25519_module);
+ }
+#else
+ PyMODINIT_FUNC
+ init_curve25519(void)
+ {
+ (void)Py_InitModule("_curve25519", curve25519_functions);
+ }
+#endif \ No newline at end of file
diff --git a/lib/curve25519-donna/python-src/curve25519/keys.py b/lib/curve25519-donna/python-src/curve25519/keys.py
new file mode 100644
index 0000000..e131dac
--- /dev/null
+++ b/lib/curve25519-donna/python-src/curve25519/keys.py
@@ -0,0 +1,46 @@
+from . import _curve25519
+from hashlib import sha256
+import os
+
+# the curve25519 functions are really simple, and could be used without an
+# OOP layer, but it's a bit too easy to accidentally swap the private and
+# public keys that way.
+
+def _hash_shared(shared):
+ return sha256(b"curve25519-shared:"+shared).digest()
+
+class Private:
+ def __init__(self, secret=None, seed=None):
+ if secret is None:
+ if seed is None:
+ secret = os.urandom(32)
+ else:
+ secret = sha256(b"curve25519-private:"+seed).digest()
+ else:
+ assert seed is None, "provide secret, seed, or neither, not both"
+ if not isinstance(secret, bytes) or len(secret) != 32:
+ raise TypeError("secret= must be 32-byte string")
+ self.private = _curve25519.make_private(secret)
+
+ def serialize(self):
+ return self.private
+
+ def get_public(self):
+ return Public(_curve25519.make_public(self.private))
+
+ def get_shared_key(self, public, hashfunc=None):
+ if not isinstance(public, Public):
+ raise ValueError("'public' must be an instance of Public")
+ if hashfunc is None:
+ hashfunc = _hash_shared
+ shared = _curve25519.make_shared(self.private, public.public)
+ return hashfunc(shared)
+
+class Public:
+ def __init__(self, public):
+ assert isinstance(public, bytes)
+ assert len(public) == 32
+ self.public = public
+
+ def serialize(self):
+ return self.public
diff --git a/lib/curve25519-donna/python-src/curve25519/test/__init__.py b/lib/curve25519-donna/python-src/curve25519/test/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/curve25519-donna/python-src/curve25519/test/__init__.py
diff --git a/lib/curve25519-donna/python-src/curve25519/test/test_curve25519.py b/lib/curve25519-donna/python-src/curve25519/test/test_curve25519.py
new file mode 100755
index 0000000..2ecbd47
--- /dev/null
+++ b/lib/curve25519-donna/python-src/curve25519/test/test_curve25519.py
@@ -0,0 +1,99 @@
+#! /usr/bin/python
+
+import unittest
+
+from curve25519 import Private, Public
+from hashlib import sha1, sha256
+from binascii import hexlify
+
+class Basic(unittest.TestCase):
+ def test_basic(self):
+ secret1 = b"abcdefghijklmnopqrstuvwxyz123456"
+ self.assertEqual(len(secret1), 32)
+
+ secret2 = b"654321zyxwvutsrqponmlkjihgfedcba"
+ self.assertEqual(len(secret2), 32)
+ priv1 = Private(secret=secret1)
+ pub1 = priv1.get_public()
+ priv2 = Private(secret=secret2)
+ pub2 = priv2.get_public()
+ shared12 = priv1.get_shared_key(pub2)
+ e = b"b0818125eab42a8ac1af5e8b9b9c15ed2605c2bbe9675de89e5e6e7f442b9598"
+ self.assertEqual(hexlify(shared12), e)
+ shared21 = priv2.get_shared_key(pub1)
+ self.assertEqual(shared12, shared21)
+
+ pub2a = Public(pub2.serialize())
+ shared12a = priv1.get_shared_key(pub2a)
+ self.assertEqual(hexlify(shared12a), e)
+
+ def test_errors(self):
+ priv1 = Private()
+ self.assertRaises(ValueError, priv1.get_shared_key, priv1)
+
+ def test_seed(self):
+ # use 32-byte secret
+ self.assertRaises(TypeError, Private, secret=123)
+ self.assertRaises(TypeError, Private, secret=b"too short")
+ secret1 = b"abcdefghijklmnopqrstuvwxyz123456"
+ assert len(secret1) == 32
+ priv1 = Private(secret=secret1)
+ priv1a = Private(secret=secret1)
+ priv1b = Private(priv1.serialize())
+ self.assertEqual(priv1.serialize(), priv1a.serialize())
+ self.assertEqual(priv1.serialize(), priv1b.serialize())
+ e = b"6062636465666768696a6b6c6d6e6f707172737475767778797a313233343576"
+ self.assertEqual(hexlify(priv1.serialize()), e)
+
+ # the private key is a clamped form of the secret, so they won't
+ # quite be the same
+ p = Private(secret=b"\x00"*32)
+ self.assertEqual(hexlify(p.serialize()), b"00"*31+b"40")
+ p = Private(secret=b"\xff"*32)
+ self.assertEqual(hexlify(p.serialize()), b"f8"+b"ff"*30+b"7f")
+
+ # use arbitrary-length seed
+ self.assertRaises(TypeError, Private, seed=123)
+ priv1 = Private(seed=b"abc")
+ priv1a = Private(seed=b"abc")
+ priv1b = Private(priv1.serialize())
+ self.assertEqual(priv1.serialize(), priv1a.serialize())
+ self.assertEqual(priv1.serialize(), priv1b.serialize())
+ self.assertRaises(AssertionError, Private, seed=b"abc", secret=b"no")
+
+ priv1 = Private(seed=b"abc")
+ priv1a = Private(priv1.serialize())
+ self.assertEqual(priv1.serialize(), priv1a.serialize())
+ self.assertRaises(AssertionError, Private, seed=b"abc", secret=b"no")
+
+ # use built-in os.urandom
+ priv2 = Private()
+ priv2a = Private(priv2.private)
+ self.assertEqual(priv2.serialize(), priv2a.serialize())
+
+ # attempt to use both secret= and seed=, not allowed
+ self.assertRaises(AssertionError, Private, seed=b"abc", secret=b"no")
+
+ def test_hashfunc(self):
+ priv1 = Private(seed=b"abc")
+ priv2 = Private(seed=b"def")
+ shared_sha256 = priv1.get_shared_key(priv2.get_public())
+ e = b"da959ffe77ebeb4757fe5ba310e28ede425ae0d0ff5ec9c884e2d08f311cf5e5"
+ self.assertEqual(hexlify(shared_sha256), e)
+
+ # confirm the hash function remains what we think it is
+ def myhash(shared_key):
+ return sha256(b"curve25519-shared:"+shared_key).digest()
+ shared_myhash = priv1.get_shared_key(priv2.get_public(), myhash)
+ self.assertEqual(hexlify(shared_myhash), e)
+
+ def hexhash(shared_key):
+ return sha1(shared_key).hexdigest().encode()
+ shared_hexhash = priv1.get_shared_key(priv2.get_public(), hexhash)
+ self.assertEqual(shared_hexhash,
+ b"80eec98222c8edc4324fb9477a3c775ce7c6c93a")
+
+
+if __name__ == "__main__":
+ unittest.main()
+
diff --git a/lib/curve25519-donna/python-src/curve25519/test/test_speed.py b/lib/curve25519-donna/python-src/curve25519/test/test_speed.py
new file mode 100755
index 0000000..87952fa
--- /dev/null
+++ b/lib/curve25519-donna/python-src/curve25519/test/test_speed.py
@@ -0,0 +1,46 @@
+#! /usr/bin/python
+
+from time import time
+from curve25519 import Private
+
+count = 10000
+elapsed_get_public = 0.0
+elapsed_get_shared = 0.0
+
+def abbreviate_time(data):
+ # 1.23s, 790ms, 132us
+ if data is None:
+ return ""
+ s = float(data)
+ if s >= 10:
+ #return abbreviate.abbreviate_time(data)
+ return "%d" % s
+ if s >= 1.0:
+ return "%.2fs" % s
+ if s >= 0.01:
+ return "%dms" % (1000*s)
+ if s >= 0.001:
+ return "%.1fms" % (1000*s)
+ if s >= 0.000001:
+ return "%.1fus" % (1000000*s)
+ return "%dns" % (1000000000*s)
+
+def nohash(key): return key
+
+for i in range(count):
+ p = Private()
+ start = time()
+ pub = p.get_public()
+ elapsed_get_public += time() - start
+ pub2 = Private().get_public()
+ start = time()
+ shared = p.get_shared_key(pub2) #, hashfunc=nohash)
+ elapsed_get_shared += time() - start
+
+print("get_public: %s" % abbreviate_time(elapsed_get_public / count))
+print("get_shared: %s" % abbreviate_time(elapsed_get_shared / count))
+
+# these take about 560us-570us each (with the default compiler settings, -Os)
+# on my laptop, same with -O2
+# of which the python overhead is about 5us
+# and the get_shared_key() hash step adds about 5us
diff --git a/lib/curve25519-donna/setup.py b/lib/curve25519-donna/setup.py
new file mode 100755
index 0000000..dc1b8eb
--- /dev/null
+++ b/lib/curve25519-donna/setup.py
@@ -0,0 +1,38 @@
+#! /usr/bin/python
+
+from subprocess import Popen, PIPE
+from distutils.core import setup, Extension
+
+version = Popen(["git", "describe", "--tags"], stdout=PIPE).communicate()[0]\
+ .strip().decode("utf8")
+
+ext_modules = [Extension("curve25519._curve25519",
+ ["python-src/curve25519/curve25519module.c",
+ "curve25519-donna.c"],
+ )]
+
+short_description="Python wrapper for the Curve25519 cryptographic library"
+long_description="""\
+Curve25519 is a fast elliptic-curve key-agreement protocol, in which two
+parties Alice and Bob each generate a (public,private) keypair, exchange
+public keys, and can then compute the same shared key. Specifically, Alice
+computes F(Aprivate, Bpublic), Bob computes F(Bprivate, Apublic), and both
+get the same value (and nobody else can guess that shared value, even if they
+know Apublic and Bpublic).
+
+This is a Python wrapper for the portable 'curve25519-donna' implementation
+of this algorithm, written by Adam Langley, hosted at
+http://code.google.com/p/curve25519-donna/
+"""
+
+setup(name="curve25519-donna",
+ version=version,
+ description=short_description,
+ long_description=long_description,
+ author="Brian Warner",
+ author_email="warner-pycurve25519-donna@lothar.com",
+ license="BSD",
+ packages=["curve25519", "curve25519.test"],
+ package_dir={"curve25519": "python-src/curve25519"},
+ ext_modules=ext_modules,
+ )
diff --git a/lib/curve25519-donna/speed-curve25519.c b/lib/curve25519-donna/speed-curve25519.c
new file mode 100644
index 0000000..d945d48
--- /dev/null
+++ b/lib/curve25519-donna/speed-curve25519.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdint.h>
+
+typedef uint8_t u8;
+
+extern void curve25519_donna(u8 *output, const u8 *secret, const u8 *bp);
+
+static uint64_t
+time_now() {
+ struct timeval tv;
+ uint64_t ret;
+
+ gettimeofday(&tv, NULL);
+ ret = tv.tv_sec;
+ ret *= 1000000;
+ ret += tv.tv_usec;
+
+ return ret;
+}
+
+int
+main() {
+ static const unsigned char basepoint[32] = {9};
+ unsigned char mysecret[32], mypublic[32];
+ unsigned i;
+ uint64_t start, end;
+
+ memset(mysecret, 42, 32);
+ mysecret[0] &= 248;
+ mysecret[31] &= 127;
+ mysecret[31] |= 64;
+
+ // Load the caches
+ for (i = 0; i < 1000; ++i) {
+ curve25519_donna(mypublic, mysecret, basepoint);
+ }
+
+ start = time_now();
+ for (i = 0; i < 30000; ++i) {
+ curve25519_donna(mypublic, mysecret, basepoint);
+ }
+ end = time_now();
+
+ printf("%luus\n", (unsigned long) ((end - start) / 30000));
+
+ return 0;
+}
diff --git a/lib/curve25519-donna/test-curve25519.c b/lib/curve25519-donna/test-curve25519.c
new file mode 100644
index 0000000..591d871
--- /dev/null
+++ b/lib/curve25519-donna/test-curve25519.c
@@ -0,0 +1,54 @@
+/*
+test-curve25519 version 20050915
+D. J. Bernstein
+Public domain.
+
+Tiny modifications by agl
+*/
+
+#include <stdio.h>
+
+extern void curve25519_donna(unsigned char *output, const unsigned char *a,
+ const unsigned char *b);
+void doit(unsigned char *ek,unsigned char *e,unsigned char *k);
+
+void doit(unsigned char *ek,unsigned char *e,unsigned char *k)
+{
+ int i;
+
+ for (i = 0;i < 32;++i) printf("%02x",(unsigned int) e[i]); printf(" ");
+ for (i = 0;i < 32;++i) printf("%02x",(unsigned int) k[i]); printf(" ");
+ curve25519_donna(ek,e,k);
+ for (i = 0;i < 32;++i) printf("%02x",(unsigned int) ek[i]); printf("\n");
+}
+
+unsigned char e1k[32];
+unsigned char e2k[32];
+unsigned char e1e2k[32];
+unsigned char e2e1k[32];
+unsigned char e1[32] = {3};
+unsigned char e2[32] = {5};
+unsigned char k[32] = {9};
+
+int
+main()
+{
+ int loop;
+ int i;
+
+ for (loop = 0;loop < 10000;++loop) {
+ doit(e1k,e1,k);
+ doit(e2e1k,e2,e1k);
+ doit(e2k,e2,k);
+ doit(e1e2k,e1,e2k);
+ for (i = 0;i < 32;++i) if (e1e2k[i] != e2e1k[i]) {
+ printf("fail\n");
+ return 1;
+ }
+ for (i = 0;i < 32;++i) e1[i] ^= e2k[i];
+ for (i = 0;i < 32;++i) e2[i] ^= e1k[i];
+ for (i = 0;i < 32;++i) k[i] ^= e1e2k[i];
+ }
+
+ return 0;
+}
diff --git a/lib/curve25519-donna/test-noncanon.c b/lib/curve25519-donna/test-noncanon.c
new file mode 100644
index 0000000..6de4e8d
--- /dev/null
+++ b/lib/curve25519-donna/test-noncanon.c
@@ -0,0 +1,39 @@
+/* This file can be used to test whether the code handles non-canonical curve
+ * points (i.e. points with the 256th bit set) in the same way as the reference
+ * implementation. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+extern void curve25519_donna(unsigned char *output, const unsigned char *a,
+ const unsigned char *b);
+int
+main()
+{
+ static const uint8_t point1[32] = {
+ 0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ };
+ static const uint8_t point2[32] = {
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ };
+ static const uint8_t scalar[32] = { 1 };
+ uint8_t out1[32], out2[32];
+
+ curve25519_donna(out1, scalar, point1);
+ curve25519_donna(out2, scalar, point2);
+
+ if (0 == memcmp(out1, out2, sizeof(out1))) {
+ fprintf(stderr, "Top bit not ignored.\n");
+ return 1;
+ }
+
+ fprintf(stderr, "Top bit correctly ignored.\n");
+ return 0;
+}
diff --git a/lib/curve25519-donna/test-sc-curve25519.c b/lib/curve25519-donna/test-sc-curve25519.c
new file mode 100644
index 0000000..14a7e3c
--- /dev/null
+++ b/lib/curve25519-donna/test-sc-curve25519.c
@@ -0,0 +1,72 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <math.h>
+
+extern void curve25519_donna(uint8_t *, const uint8_t *, const uint8_t *);
+extern uint64_t tsc_read();
+
+int
+main(int argc, char **argv) {
+ uint8_t private_key[32], public[32], peer1[32], peer2[32], output[32];
+ static const uint8_t basepoint[32] = {9};
+ unsigned i;
+ uint64_t sum = 0, sum_squares = 0, skipped = 0, mean;
+ static const unsigned count = 200000;
+
+ memset(private_key, 42, sizeof(private_key));
+
+ private_key[0] &= 248;
+ private_key[31] &= 127;
+ private_key[31] |= 64;
+
+ curve25519_donna(public, private_key, basepoint);
+ memset(peer1, 0, sizeof(peer1));
+ memset(peer2, 255, sizeof(peer2));
+
+ for (i = 0; i < count; ++i) {
+ const uint64_t start = tsc_read();
+ curve25519_donna(output, peer1, public);
+ const uint64_t end = tsc_read();
+ const uint64_t delta = end - start;
+ if (delta > 650000) {
+ // something terrible happened (task switch etc)
+ skipped++;
+ continue;
+ }
+ sum += delta;
+ sum_squares += (delta * delta);
+ }
+
+ mean = sum / ((uint64_t) count);
+ printf("all 0: mean:%lu sd:%f skipped:%lu\n",
+ mean,
+ sqrt((double)(sum_squares/((uint64_t) count) - mean*mean)),
+ skipped);
+
+ sum = sum_squares = skipped = 0;
+
+ for (i = 0; i < count; ++i) {
+ const uint64_t start = tsc_read();
+ curve25519_donna(output, peer2, public);
+ const uint64_t end = tsc_read();
+ const uint64_t delta = end - start;
+ if (delta > 650000) {
+ // something terrible happened (task switch etc)
+ skipped++;
+ continue;
+ }
+ sum += delta;
+ sum_squares += (delta * delta);
+ }
+
+ mean = sum / ((uint64_t) count);
+ printf("all 1: mean:%lu sd:%f skipped:%lu\n",
+ mean,
+ sqrt((double)(sum_squares/((uint64_t) count) - mean*mean)),
+ skipped);
+
+ return 0;
+}
diff --git a/lib/curve25519-donna/test-sc-curve25519.s b/lib/curve25519-donna/test-sc-curve25519.s
new file mode 100644
index 0000000..1da4f68
--- /dev/null
+++ b/lib/curve25519-donna/test-sc-curve25519.s
@@ -0,0 +1,8 @@
+.text
+.globl tsc_read
+
+tsc_read:
+rdtsc
+shl $32,%rdx
+or %rdx,%rax
+ret
diff --git a/ed25519_32.dll b/lib/ed25519/ed25519_32.dll
index ac15a95..ac15a95 100644
--- a/ed25519_32.dll
+++ b/lib/ed25519/ed25519_32.dll
Binary files differ
diff --git a/ed25519_64.dll b/lib/ed25519/ed25519_64.dll
index f50647c..f50647c 100644
--- a/ed25519_64.dll
+++ b/lib/ed25519/ed25519_64.dll
Binary files differ
diff --git a/readme.md b/lib/ed25519/readme.md
index 676a631..676a631 100644
--- a/readme.md
+++ b/lib/ed25519/readme.md
diff --git a/src/add_scalar.c b/lib/ed25519/src/add_scalar.c
index a4f2a55..a4f2a55 100644
--- a/src/add_scalar.c
+++ b/lib/ed25519/src/add_scalar.c
diff --git a/src/ed25519.h b/lib/ed25519/src/ed25519.h
index 8924659..8924659 100644
--- a/src/ed25519.h
+++ b/lib/ed25519/src/ed25519.h
diff --git a/src/fe.c b/lib/ed25519/src/fe.c
index 448e3e9..448e3e9 100644
--- a/src/fe.c
+++ b/lib/ed25519/src/fe.c
diff --git a/src/fe.h b/lib/ed25519/src/fe.h
index b4b62d2..b4b62d2 100644
--- a/src/fe.h
+++ b/lib/ed25519/src/fe.h
diff --git a/src/fixedint.h b/lib/ed25519/src/fixedint.h
index 1a8745b..1a8745b 100644
--- a/src/fixedint.h
+++ b/lib/ed25519/src/fixedint.h
diff --git a/src/ge.c b/lib/ed25519/src/ge.c
index 3c342b1..3c342b1 100644
--- a/src/ge.c
+++ b/lib/ed25519/src/ge.c
diff --git a/src/ge.h b/lib/ed25519/src/ge.h
index 17fde2d..17fde2d 100644
--- a/src/ge.h
+++ b/lib/ed25519/src/ge.h
diff --git a/src/key_exchange.c b/lib/ed25519/src/key_exchange.c
index abd75da..abd75da 100644
--- a/src/key_exchange.c
+++ b/lib/ed25519/src/key_exchange.c
diff --git a/src/keypair.c b/lib/ed25519/src/keypair.c
index dc1b8ec..dc1b8ec 100644
--- a/src/keypair.c
+++ b/lib/ed25519/src/keypair.c
diff --git a/src/precomp_data.h b/lib/ed25519/src/precomp_data.h
index 776b84f..776b84f 100644
--- a/src/precomp_data.h
+++ b/lib/ed25519/src/precomp_data.h
diff --git a/src/sc.c b/lib/ed25519/src/sc.c
index ca5bad2..ca5bad2 100644
--- a/src/sc.c
+++ b/lib/ed25519/src/sc.c
diff --git a/src/sc.h b/lib/ed25519/src/sc.h
index 8fa727e..8fa727e 100644
--- a/src/sc.h
+++ b/lib/ed25519/src/sc.h
diff --git a/src/seed.c b/lib/ed25519/src/seed.c
index 25e5182..25e5182 100644
--- a/src/seed.c
+++ b/lib/ed25519/src/seed.c
diff --git a/src/sha512.c b/lib/ed25519/src/sha512.c
index cb8ae71..cb8ae71 100644
--- a/src/sha512.c
+++ b/lib/ed25519/src/sha512.c
diff --git a/src/sha512.h b/lib/ed25519/src/sha512.h
index e56b00e..e56b00e 100644
--- a/src/sha512.h
+++ b/lib/ed25519/src/sha512.h
diff --git a/src/sign.c b/lib/ed25519/src/sign.c
index 199a839..199a839 100644
--- a/src/sign.c
+++ b/lib/ed25519/src/sign.c
diff --git a/src/verify.c b/lib/ed25519/src/verify.c
index 32f988e..32f988e 100644
--- a/src/verify.c
+++ b/lib/ed25519/src/verify.c
diff --git a/test.c b/lib/ed25519/test.c
index e2159a9..e2159a9 100644
--- a/test.c
+++ b/lib/ed25519/test.c
diff --git a/src/axolotl.cpp b/src/axolotl.cpp
new file mode 100644
index 0000000..0f0d226
--- /dev/null
+++ b/src/axolotl.cpp
@@ -0,0 +1,439 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "axolotl/axolotl.hh"
+#include "axolotl/message.hh"
+#include "axolotl/memory.hh"
+
+#include <cstring>
+
+namespace {
+
+std::uint8_t PROTOCOL_VERSION = 3;
+std::size_t MAC_LENGTH = 8;
+std::size_t KEY_LENGTH = axolotl::Curve25519PublicKey::LENGTH;
+std::uint8_t MESSAGE_KEY_SEED[1] = {0x01};
+std::uint8_t CHAIN_KEY_SEED[1] = {0x02};
+std::size_t MAX_MESSAGE_GAP = 2000;
+
+void create_chain_key(
+ axolotl::SharedKey const & root_key,
+ axolotl::Curve25519KeyPair const & our_key,
+ axolotl::Curve25519PublicKey const & their_key,
+ axolotl::KdfInfo const & info,
+ axolotl::SharedKey & new_root_key,
+ axolotl::ChainKey & new_chain_key
+) {
+ axolotl::SharedKey secret;
+ axolotl::curve25519_shared_secret(our_key, their_key, secret);
+ std::uint8_t derived_secrets[64];
+ axolotl::hkdf_sha256(
+ secret, sizeof(secret),
+ root_key, sizeof(root_key),
+ info.ratchet_info, info.ratchet_info_length,
+ derived_secrets, sizeof(derived_secrets)
+ );
+ std::memcpy(new_root_key, derived_secrets, 32);
+ std::memcpy(new_chain_key.key, derived_secrets + 32, 32);
+ new_chain_key.index = 0;
+ axolotl::unset(derived_secrets);
+ axolotl::unset(secret);
+}
+
+
+void advance_chain_key(
+ axolotl::ChainKey const & chain_key,
+ axolotl::ChainKey & new_chain_key
+) {
+ axolotl::hmac_sha256(
+ chain_key.key, sizeof(chain_key.key),
+ CHAIN_KEY_SEED, sizeof(CHAIN_KEY_SEED),
+ new_chain_key.key
+ );
+ new_chain_key.index = chain_key.index + 1;
+}
+
+
+void create_message_keys(
+ axolotl::ChainKey const & chain_key,
+ axolotl::KdfInfo const & info,
+ axolotl::MessageKey & message_key
+) {
+ axolotl::SharedKey secret;
+ axolotl::hmac_sha256(
+ chain_key.key, sizeof(chain_key.key),
+ MESSAGE_KEY_SEED, sizeof(MESSAGE_KEY_SEED),
+ secret
+ );
+ std::uint8_t derived_secrets[80];
+ axolotl::hkdf_sha256(
+ secret, sizeof(secret),
+ NULL, 0,
+ info.message_info, info.message_info_length,
+ derived_secrets, sizeof(derived_secrets)
+ );
+ std::memcpy(message_key.cipher_key.key, derived_secrets, 32);
+ std::memcpy(message_key.mac_key, derived_secrets + 32, 32);
+ std::memcpy(message_key.iv.iv, derived_secrets + 64, 16);
+ message_key.index = chain_key.index;
+ axolotl::unset(derived_secrets);
+ axolotl::unset(secret);
+}
+
+
+bool verify_mac(
+ axolotl::MessageKey const & message_key,
+ std::uint8_t const * input,
+ axolotl::MessageReader const & reader
+) {
+ std::uint8_t mac[axolotl::HMAC_SHA256_OUTPUT_LENGTH];
+ axolotl::hmac_sha256(
+ message_key.mac_key, sizeof(message_key.mac_key),
+ input, reader.body_length,
+ mac
+ );
+
+ bool result = std::memcmp(mac, reader.mac, MAC_LENGTH) == 0;
+ axolotl::unset(mac);
+ return result;
+}
+
+
+bool verify_mac_for_existing_chain(
+ axolotl::Session const & session,
+ axolotl::ChainKey const & chain,
+ std::uint8_t const * input,
+ axolotl::MessageReader const & reader
+) {
+ if (reader.counter < chain.index) {
+ return false;
+ }
+
+ /* Limit the number of hashes we're prepared to compute */
+ if (reader.counter - chain.index > MAX_MESSAGE_GAP) {
+ return false;
+ }
+
+ axolotl::ChainKey new_chain = chain;
+
+ while (new_chain.index < reader.counter) {
+ advance_chain_key(new_chain, new_chain);
+ }
+
+ axolotl::MessageKey message_key;
+ create_message_keys(new_chain, session.kdf_info, message_key);
+
+ bool result = verify_mac(message_key, input, reader);
+ axolotl::unset(new_chain);
+ return result;
+}
+
+
+bool verify_mac_for_new_chain(
+ axolotl::Session const & session,
+ std::uint8_t const * input,
+ axolotl::MessageReader const & reader
+) {
+ axolotl::SharedKey new_root_key;
+ axolotl::ReceiverChain new_chain;
+
+ /* They shouldn't move to a new chain until we've sent them a message
+ * acknowledging the last one */
+ if (session.sender_chain.empty()) {
+ return false;
+ }
+
+ /* Limit the number of hashes we're prepared to compute */
+ if (reader.counter > MAX_MESSAGE_GAP) {
+ return false;
+ }
+ std::memcpy(
+ new_chain.ratchet_key.public_key, reader.ratchet_key, KEY_LENGTH
+ );
+
+ create_chain_key(
+ session.root_key, session.sender_chain[0].ratchet_key,
+ new_chain.ratchet_key, session.kdf_info,
+ new_root_key, new_chain.chain_key
+ );
+
+ bool result = verify_mac_for_existing_chain(
+ session, new_chain.chain_key, input, reader
+ );
+ axolotl::unset(new_root_key);
+ axolotl::unset(new_chain);
+ return result;
+}
+
+} // namespace
+
+
+axolotl::Session::Session(
+ axolotl::KdfInfo const & kdf_info
+) : kdf_info(kdf_info), last_error(axolotl::ErrorCode::SUCCESS) {
+}
+
+
+void axolotl::Session::initialise_as_bob(
+ std::uint8_t const * shared_secret, std::size_t shared_secret_length,
+ axolotl::Curve25519PublicKey const & their_ratchet_key
+) {
+ std::uint8_t derived_secrets[64];
+ axolotl::hkdf_sha256(
+ shared_secret, shared_secret_length,
+ NULL, 0,
+ kdf_info.root_info, kdf_info.root_info_length,
+ derived_secrets, sizeof(derived_secrets)
+ );
+ receiver_chains.insert();
+ std::memcpy(root_key, derived_secrets, 32);
+ std::memcpy(receiver_chains[0].chain_key.key, derived_secrets + 32, 32);
+ receiver_chains[0].ratchet_key = their_ratchet_key;
+ axolotl::unset(derived_secrets);
+}
+
+
+void axolotl::Session::initialise_as_alice(
+ std::uint8_t const * shared_secret, std::size_t shared_secret_length,
+ axolotl::Curve25519KeyPair const & our_ratchet_key
+) {
+ std::uint8_t derived_secrets[64];
+ axolotl::hkdf_sha256(
+ shared_secret, shared_secret_length,
+ NULL, 0,
+ kdf_info.root_info, kdf_info.root_info_length,
+ derived_secrets, sizeof(derived_secrets)
+ );
+ sender_chain.insert();
+ std::memcpy(root_key, derived_secrets, 32);
+ std::memcpy(sender_chain[0].chain_key.key, derived_secrets + 32, 32);
+ sender_chain[0].ratchet_key = our_ratchet_key;
+ axolotl::unset(derived_secrets);
+}
+
+
+std::size_t axolotl::Session::encrypt_max_output_length(
+ std::size_t plaintext_length
+) {
+ std::size_t counter = 0;
+ if (!sender_chain.empty()) {
+ counter = sender_chain[0].chain_key.index;
+ }
+ std::size_t padded = axolotl::aes_encrypt_cbc_length(plaintext_length);
+ return axolotl::encode_message_length(
+ counter, KEY_LENGTH, padded, MAC_LENGTH
+ );
+}
+
+
+std::size_t axolotl::Session::encrypt_random_length() {
+ return sender_chain.empty() ? KEY_LENGTH : 0;
+}
+
+
+std::size_t axolotl::Session::encrypt(
+ std::uint8_t const * plaintext, std::size_t plaintext_length,
+ std::uint8_t const * random, std::size_t random_length,
+ std::uint8_t * output, std::size_t max_output_length
+) {
+ if (random_length < encrypt_random_length()) {
+ last_error = axolotl::ErrorCode::NOT_ENOUGH_RANDOM;
+ return std::size_t(-1);
+ }
+ if (max_output_length < encrypt_max_output_length(plaintext_length)) {
+ last_error = axolotl::ErrorCode::OUTPUT_BUFFER_TOO_SMALL;
+ return std::size_t(-1);
+ }
+
+ if (sender_chain.empty()) {
+ sender_chain.insert();
+ axolotl::generate_key(random, sender_chain[0].ratchet_key);
+ create_chain_key(
+ root_key,
+ sender_chain[0].ratchet_key,
+ receiver_chains[0].ratchet_key,
+ kdf_info,
+ root_key, sender_chain[0].chain_key
+ );
+ }
+
+ MessageKey keys;
+ create_message_keys(sender_chain[0].chain_key, kdf_info, keys);
+ advance_chain_key(sender_chain[0].chain_key, sender_chain[0].chain_key);
+
+ std::size_t padded = axolotl::aes_encrypt_cbc_length(plaintext_length);
+ std::uint32_t counter = keys.index;
+ const Curve25519PublicKey &ratchet_key = sender_chain[0].ratchet_key;
+
+ axolotl::MessageWriter writer(axolotl::encode_message(
+ PROTOCOL_VERSION, counter, KEY_LENGTH, padded, output
+ ));
+
+ std::memcpy(writer.ratchet_key, ratchet_key.public_key, KEY_LENGTH);
+
+ axolotl::aes_encrypt_cbc(
+ keys.cipher_key, keys.iv,
+ plaintext, plaintext_length,
+ writer.ciphertext
+ );
+
+ std::uint8_t mac[axolotl::HMAC_SHA256_OUTPUT_LENGTH];
+ axolotl::hmac_sha256(
+ keys.mac_key, sizeof(keys.mac_key),
+ output, writer.body_length,
+ mac
+ );
+ std::memcpy(writer.mac, mac, MAC_LENGTH);
+
+ axolotl::unset(keys);
+ return writer.body_length + MAC_LENGTH;
+}
+
+
+std::size_t axolotl::Session::decrypt_max_plaintext_length(
+ std::size_t input_length
+) {
+ return input_length;
+}
+
+
+std::size_t axolotl::Session::decrypt(
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * plaintext, std::size_t max_plaintext_length
+) {
+ if (max_plaintext_length < decrypt_max_plaintext_length(input_length)) {
+ last_error = axolotl::ErrorCode::OUTPUT_BUFFER_TOO_SMALL;
+ return std::size_t(-1);
+ }
+
+ axolotl::MessageReader reader(axolotl::decode_message(
+ input, input_length, MAC_LENGTH
+ ));
+
+ if (reader.version != PROTOCOL_VERSION) {
+ last_error = axolotl::ErrorCode::BAD_MESSAGE_VERSION;
+ return std::size_t(-1);
+ }
+
+ if (reader.body_length == 0 || reader.ratchet_key_length != KEY_LENGTH) {
+ last_error = axolotl::ErrorCode::BAD_MESSAGE_FORMAT;
+ return std::size_t(-1);
+ }
+
+ ReceiverChain * chain = NULL;
+ for (axolotl::ReceiverChain & receiver_chain : receiver_chains) {
+ if (0 == std::memcmp(
+ receiver_chain.ratchet_key.public_key, reader.ratchet_key,
+ KEY_LENGTH
+ )) {
+ chain = &receiver_chain;
+ break;
+ }
+ }
+
+ if (!chain) {
+ if (!verify_mac_for_new_chain(*this, input, reader)) {
+ last_error = axolotl::ErrorCode::BAD_MESSAGE_MAC;
+ return std::size_t(-1);
+ }
+ } else {
+ if (chain->chain_key.index > reader.counter) {
+ /* Chain already advanced beyond the key for this message
+ * Check if the message keys are in the skipped key list. */
+ for (axolotl::SkippedMessageKey & skipped : skipped_message_keys) {
+ if (reader.counter == skipped.message_key.index
+ && 0 == std::memcmp(
+ skipped.ratchet_key.public_key, reader.ratchet_key,
+ KEY_LENGTH
+ )
+ ) {
+ /* Found the key for this message. Check the MAC. */
+ if (!verify_mac(skipped.message_key, input, reader)) {
+ last_error = axolotl::ErrorCode::BAD_MESSAGE_MAC;
+ return std::size_t(-1);
+ }
+
+ std::size_t result = axolotl::aes_decrypt_cbc(
+ skipped.message_key.cipher_key,
+ skipped.message_key.iv,
+ reader.ciphertext, reader.ciphertext_length,
+ plaintext
+ );
+
+ if (result == std::size_t(-1)) {
+ last_error = axolotl::ErrorCode::BAD_MESSAGE_MAC;
+ return result;
+ }
+
+ /* Remove the key from the skipped keys now that we've
+ * decoded the message it corresponds to. */
+ axolotl::unset(skipped);
+ skipped_message_keys.erase(&skipped);
+ return result;
+ }
+ }
+ /* No matching keys for the message, fail with bad mac */
+ last_error = axolotl::ErrorCode::BAD_MESSAGE_MAC;
+ return std::size_t(-1);
+ } else if (!verify_mac_for_existing_chain(
+ *this, chain->chain_key, input, reader
+ )) {
+ last_error = axolotl::ErrorCode::BAD_MESSAGE_MAC;
+ return std::size_t(-1);
+ }
+ }
+
+ if (!chain) {
+ /* They have started using a new empheral ratchet key.
+ * We need to derive a new set of chain keys.
+ * We can discard our previous empheral ratchet key.
+ * We will generate a new key when we send the next message. */
+ chain = receiver_chains.insert();
+ std::memcpy(
+ chain->ratchet_key.public_key, reader.ratchet_key, KEY_LENGTH
+ );
+ create_chain_key(
+ root_key, sender_chain[0].ratchet_key, chain->ratchet_key,
+ kdf_info, root_key, chain->chain_key
+ );
+ axolotl::unset(sender_chain[0]);
+ sender_chain.erase(sender_chain.begin());
+ }
+
+ while (chain->chain_key.index < reader.counter) {
+ axolotl::SkippedMessageKey & key = *skipped_message_keys.insert();
+ create_message_keys(chain->chain_key, kdf_info, key.message_key);
+ key.ratchet_key = chain->ratchet_key;
+ advance_chain_key(chain->chain_key, chain->chain_key);
+ }
+
+ axolotl::MessageKey message_key;
+ create_message_keys(chain->chain_key, kdf_info, message_key);
+ std::size_t result = axolotl::aes_decrypt_cbc(
+ message_key.cipher_key,
+ message_key.iv,
+ reader.ciphertext, reader.ciphertext_length,
+ plaintext
+ );
+ axolotl::unset(message_key);
+
+ advance_chain_key(chain->chain_key, chain->chain_key);
+
+ if (result == std::size_t(-1)) {
+ last_error = axolotl::ErrorCode::BAD_MESSAGE_MAC;
+ return std::size_t(-1);
+ } else {
+ return result;
+ }
+}
diff --git a/src/crypto.cpp b/src/crypto.cpp
new file mode 100644
index 0000000..57f31cd
--- /dev/null
+++ b/src/crypto.cpp
@@ -0,0 +1,256 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "axolotl/crypto.hh"
+#include "axolotl/memory.hh"
+
+#include <cstring>
+
+extern "C" {
+
+int curve25519_donna(
+ uint8_t * output,
+ const uint8_t * secret,
+ const uint8_t * basepoint
+);
+
+#include "crypto-algorithms/aes.h"
+#include "crypto-algorithms/sha256.h"
+
+}
+
+
+namespace {
+
+static const std::uint8_t CURVE25519_BASEPOINT[32] = {9};
+static const std::size_t AES_BLOCK_LENGTH = 16;
+static const std::size_t SHA256_HASH_LENGTH = 32;
+static const std::size_t SHA256_BLOCK_LENGTH = 64;
+static const std::uint8_t HKDF_DEFAULT_SALT[32] = {};
+
+
+template<std::size_t block_size>
+inline static void xor_block(
+ std::uint8_t * block,
+ std::uint8_t const * input
+) {
+ for (std::size_t i = 0; i < block_size; ++i) {
+ block[i] ^= input[i];
+ }
+}
+
+
+inline static void hmac_sha256_key(
+ std::uint8_t const * input_key, std::size_t input_key_length,
+ std::uint8_t * hmac_key
+) {
+ std::memset(hmac_key, 0, SHA256_BLOCK_LENGTH);
+ if (input_key_length > SHA256_BLOCK_LENGTH) {
+ ::SHA256_CTX context;
+ ::sha256_init(&context);
+ ::sha256_update(&context, input_key, input_key_length);
+ ::sha256_final(&context, hmac_key);
+ } else {
+ std::memcpy(hmac_key, input_key, input_key_length);
+ }
+}
+
+
+inline void hmac_sha256_init(
+ ::SHA256_CTX * context,
+ std::uint8_t const * hmac_key
+) {
+ std::uint8_t i_pad[SHA256_BLOCK_LENGTH];
+ std::memcpy(i_pad, hmac_key, SHA256_BLOCK_LENGTH);
+ for (std::size_t i = 0; i < SHA256_BLOCK_LENGTH; ++i) {
+ i_pad[i] ^= 0x36;
+ }
+ ::sha256_init(context);
+ ::sha256_update(context, i_pad, SHA256_BLOCK_LENGTH);
+ axolotl::unset(i_pad);
+}
+
+
+inline void hmac_sha256_final(
+ ::SHA256_CTX * context,
+ std::uint8_t const * hmac_key,
+ std::uint8_t * output
+) {
+ std::uint8_t o_pad[SHA256_BLOCK_LENGTH + SHA256_HASH_LENGTH];
+ std::memcpy(o_pad, hmac_key, SHA256_BLOCK_LENGTH);
+ for (std::size_t i = 0; i < SHA256_BLOCK_LENGTH; ++i) {
+ o_pad[i] ^= 0x5C;
+ }
+ ::sha256_final(context, o_pad + SHA256_BLOCK_LENGTH);
+ ::SHA256_CTX final_context;
+ ::sha256_init(&final_context);
+ ::sha256_update(&final_context, o_pad, sizeof(o_pad));
+ ::sha256_final(&final_context, output);
+ axolotl::unset(final_context);
+ axolotl::unset(o_pad);
+}
+
+} // namespace
+
+
+void axolotl::generate_key(
+ std::uint8_t const * random_32_bytes,
+ axolotl::Curve25519KeyPair & key_pair
+) {
+ std::memcpy(key_pair.private_key, random_32_bytes, 32);
+ ::curve25519_donna(
+ key_pair.public_key, key_pair.private_key, CURVE25519_BASEPOINT
+ );
+}
+
+
+void axolotl::curve25519_shared_secret(
+ axolotl::Curve25519KeyPair const & our_key,
+ axolotl::Curve25519PublicKey const & their_key,
+ std::uint8_t * output
+) {
+ ::curve25519_donna(output, our_key.private_key, their_key.public_key);
+}
+
+
+std::size_t axolotl::aes_encrypt_cbc_length(
+ std::size_t input_length
+) {
+ return input_length + AES_BLOCK_LENGTH - input_length % AES_BLOCK_LENGTH;
+}
+
+
+void axolotl::aes_encrypt_cbc(
+ axolotl::Aes256Key const & key,
+ axolotl::Aes256Iv const & iv,
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * output
+) {
+ std::uint32_t key_schedule[60];
+ ::aes_key_setup(key.key, key_schedule, 256);
+ std::uint8_t input_block[AES_BLOCK_LENGTH];
+ std::memcpy(input_block, iv.iv, AES_BLOCK_LENGTH);
+ while (input_length >= AES_BLOCK_LENGTH) {
+ xor_block<AES_BLOCK_LENGTH>(input_block, input);
+ ::aes_encrypt(input_block, output, key_schedule, 256);
+ std::memcpy(input_block, output, AES_BLOCK_LENGTH);
+ input += AES_BLOCK_LENGTH;
+ output += AES_BLOCK_LENGTH;
+ input_length -= AES_BLOCK_LENGTH;
+ }
+ std::size_t i = 0;
+ for (; i < input_length; ++i) {
+ input_block[i] ^= input[i];
+ }
+ for (; i < AES_BLOCK_LENGTH; ++i) {
+ input_block[i] ^= AES_BLOCK_LENGTH - input_length;
+ }
+ ::aes_encrypt(input_block, output, key_schedule, 256);
+ axolotl::unset(key_schedule);
+ axolotl::unset(input_block);
+}
+
+
+std::size_t axolotl::aes_decrypt_cbc(
+ axolotl::Aes256Key const & key,
+ axolotl::Aes256Iv const & iv,
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * output
+) {
+ std::uint32_t key_schedule[60];
+ ::aes_key_setup(key.key, key_schedule, 256);
+ for (std::size_t i = 0; i < input_length; i += AES_BLOCK_LENGTH) {
+ ::aes_decrypt(&input[i], &output[i], key_schedule, 256);
+ if (i == 0) {
+ xor_block<AES_BLOCK_LENGTH>(&output[i], iv.iv);
+ } else {
+ xor_block<AES_BLOCK_LENGTH>(&output[i], &input[i - AES_BLOCK_LENGTH]);
+ }
+ }
+ axolotl::unset(key_schedule);
+ std::size_t padding = output[input_length - 1];
+ return (padding > input_length) ? std::size_t(-1) : (input_length - padding);
+}
+
+
+void axolotl::sha256(
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * output
+) {
+ ::SHA256_CTX context;
+ ::sha256_init(&context);
+ ::sha256_update(&context, input, input_length);
+ ::sha256_final(&context, output);
+ axolotl::unset(context);
+}
+
+void axolotl::hmac_sha256(
+ std::uint8_t const * key, std::size_t key_length,
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t * output
+) {
+ std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
+ ::SHA256_CTX context;
+ hmac_sha256_key(key, key_length, hmac_key);
+ hmac_sha256_init(&context, hmac_key);
+ ::sha256_update(&context, input, input_length);
+ hmac_sha256_final(&context, hmac_key, output);
+ axolotl::unset(hmac_key);
+ axolotl::unset(context);
+}
+
+
+void axolotl::hkdf_sha256(
+ std::uint8_t const * input, std::size_t input_length,
+ std::uint8_t const * salt, std::size_t salt_length,
+ std::uint8_t const * info, std::size_t info_length,
+ std::uint8_t * output, std::size_t output_length
+) {
+ ::SHA256_CTX context;
+ std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
+ std::uint8_t step_result[SHA256_HASH_LENGTH];
+ std::size_t bytes_remaining = output_length;
+ std::uint8_t iteration = 1;
+ if (!salt) {
+ salt = HKDF_DEFAULT_SALT;
+ salt_length = sizeof(HKDF_DEFAULT_SALT);
+ }
+ /* Expand */
+ hmac_sha256_key(salt, salt_length, hmac_key);
+ hmac_sha256_init(&context, hmac_key);
+ ::sha256_update(&context, input, input_length);
+ hmac_sha256_final(&context, hmac_key, step_result);
+ hmac_sha256_key(step_result, SHA256_HASH_LENGTH, hmac_key);
+
+ /* Extract */
+ hmac_sha256_init(&context, hmac_key);
+ ::sha256_update(&context, info, info_length);
+ ::sha256_update(&context, &iteration, 1);
+ hmac_sha256_final(&context, hmac_key, step_result);
+ while (bytes_remaining > SHA256_HASH_LENGTH) {
+ std::memcpy(output, step_result, SHA256_HASH_LENGTH);
+ output += SHA256_HASH_LENGTH;
+ bytes_remaining -= SHA256_HASH_LENGTH;
+ iteration ++;
+ hmac_sha256_init(&context, hmac_key);
+ ::sha256_update(&context, step_result, SHA256_HASH_LENGTH);
+ ::sha256_update(&context, info, info_length);
+ ::sha256_update(&context, &iteration, 1);
+ hmac_sha256_final(&context, hmac_key, step_result);
+ }
+ std::memcpy(output, step_result, bytes_remaining);
+ axolotl::unset(context);
+ axolotl::unset(hmac_key);
+ axolotl::unset(step_result);
+}
diff --git a/src/libs.cpp b/src/libs.cpp
new file mode 100644
index 0000000..61bb86c
--- /dev/null
+++ b/src/libs.cpp
@@ -0,0 +1,19 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+extern "C" {
+#include "crypto-algorithms/sha256.c"
+#include "crypto-algorithms/aes.c"
+#include "curve25519-donna/curve25519-donna.c"
+}
diff --git a/src/memory.cpp b/src/memory.cpp
new file mode 100644
index 0000000..14c95dd
--- /dev/null
+++ b/src/memory.cpp
@@ -0,0 +1,11 @@
+#include "axolotl/memory.hh"
+
+void axolotl::unset(
+ volatile void * buffer, std::size_t buffer_length
+) {
+ volatile char * pos = reinterpret_cast<volatile char *>(buffer);
+ volatile char * end = pos + buffer_length;
+ while (pos != end) {
+ *(pos++) = 0;
+ }
+}
diff --git a/src/message.cpp b/src/message.cpp
new file mode 100644
index 0000000..289faa3
--- /dev/null
+++ b/src/message.cpp
@@ -0,0 +1,184 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "axolotl/message.hh"
+
+namespace {
+
+template<typename T>
+std::size_t varint_length(
+ T value
+) {
+ std::size_t result = 1;
+ while (value > 128U) {
+ ++result;
+ value >>= 7;
+ }
+ return result;
+}
+
+
+template<typename T>
+std::uint8_t * varint_encode(
+ std::uint8_t * output,
+ T value
+) {
+ while (value > 128U) {
+ *(output++) = (0x7F & value) | 0x80;
+ }
+ (*output++) = value;
+ return output;
+}
+
+
+template<typename T>
+T varint_decode(
+ std::uint8_t const * varint_start,
+ std::uint8_t const * varint_end
+) {
+ T value = 0;
+ do {
+ value <<= 7;
+ value |= 0x7F & *(--varint_end);
+ } while (varint_end != varint_start);
+ return value;
+}
+
+
+std::uint8_t const * varint_skip(
+ std::uint8_t const * input,
+ std::uint8_t const * input_end
+) {
+ while (input != input_end) {
+ std::uint8_t tmp = *(input++);
+ if ((tmp & 0x80) == 0) {
+ return input;
+ }
+ }
+ return input;
+}
+
+
+std::size_t varstring_length(
+ std::size_t string_length
+) {
+ return varint_length(string_length) + string_length;
+}
+
+static std::size_t const VERSION_LENGTH = 1;
+static std::uint8_t const RATCHET_KEY_TAG = 012;
+static std::uint8_t const COUNTER_TAG = 020;
+static std::uint8_t const CIPHERTEXT_TAG = 042;
+
+} // namespace
+
+
+std::size_t axolotl::encode_message_length(
+ std::uint32_t counter,
+ std::size_t ratchet_key_length,
+ std::size_t ciphertext_length,
+ std::size_t mac_length
+) {
+ std::size_t length = VERSION_LENGTH;
+ length += 1 + varstring_length(ratchet_key_length);
+ length += 1 + varint_length(counter);
+ length += 1 + varstring_length(ciphertext_length);
+ return length + mac_length;
+}
+
+
+axolotl::MessageWriter axolotl::encode_message(
+ std::uint8_t version,
+ std::uint32_t counter,
+ std::size_t ratchet_key_length,
+ std::size_t ciphertext_length,
+ std::uint8_t * output
+) {
+ axolotl::MessageWriter result;
+ std::uint8_t * pos = output;
+ *(pos++) = version;
+ *(pos++) = COUNTER_TAG;
+ pos = varint_encode(pos, counter);
+ *(pos++) = RATCHET_KEY_TAG;
+ pos = varint_encode(pos, ratchet_key_length);
+ result.ratchet_key = pos;
+ pos += ratchet_key_length;
+ *(pos++) = CIPHERTEXT_TAG;
+ pos = varint_encode(pos, ciphertext_length);
+ result.ciphertext = pos;
+ pos += ciphertext_length;
+ result.body_length = pos - output;
+ result.mac = pos;
+ return result;
+}
+
+
+axolotl::MessageReader axolotl::decode_message(
+ std::uint8_t const * input, std::size_t input_length,
+ std::size_t mac_length
+) {
+ axolotl::MessageReader result;
+ result.body_length = 0;
+ std::uint8_t const * pos = input;
+ std::uint8_t const * end = input + input_length - mac_length;
+ std::uint8_t flags = 0;
+ result.mac = end;
+ if (pos == end) return result;
+ result.version = *(pos++);
+ while (pos != end) {
+ uint8_t tag = *(pos);
+ if (tag == COUNTER_TAG) {
+ ++pos;
+ std::uint8_t const * counter_start = pos;
+ pos = varint_skip(pos, end);
+ result.counter = varint_decode<std::uint32_t>(counter_start, pos);
+ flags |= 1;
+ } else if (tag == RATCHET_KEY_TAG) {
+ ++pos;
+ std::uint8_t const * len_start = pos;
+ pos = varint_skip(pos, end);
+ std::size_t len = varint_decode<std::size_t>(len_start, pos);
+ if (len > end - pos) return result;
+ result.ratchet_key_length = len;
+ result.ratchet_key = pos;
+ pos += len;
+ flags |= 2;
+ } else if (tag == CIPHERTEXT_TAG) {
+ ++pos;
+ std::uint8_t const * len_start = pos;
+ pos = varint_skip(pos, end);
+ std::size_t len = varint_decode<std::size_t>(len_start, pos);
+ if (len > end - pos) return result;
+ result.ciphertext_length = len;
+ result.ciphertext = pos;
+ pos += len;
+ flags |= 4;
+ } else if (tag & 0x7 == 0) {
+ pos = varint_skip(pos, end);
+ pos = varint_skip(pos, end);
+ } else if (tag & 0x7 == 2) {
+ std::uint8_t const * len_start = pos;
+ pos = varint_skip(pos, end);
+ std::size_t len = varint_decode<std::size_t>(len_start, pos);
+ if (len > end - pos) return result;
+ pos += len;
+ } else {
+ return result;
+ }
+ }
+ if (flags == 0x7) {
+ result.body_length = end - input;
+ }
+ return result;
+}
diff --git a/test.py b/test.py
new file mode 100755
index 0000000..336591c
--- /dev/null
+++ b/test.py
@@ -0,0 +1,32 @@
+#! /usr/bin/python
+# Copyright 2015 OpenMarket Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import subprocess
+import glob
+import os
+
+if not os.path.exists("build"):
+ os.mkdir("build")
+
+test_files = glob.glob("tests/test_*.cpp")
+source_files = glob.glob("src/*.cpp")
+
+compile_args = "g++ -Itests/include -Iinclude -Ilib --std=c++11".split()
+compile_args += source_files
+
+for test_file in test_files:
+ exe_file = "build/" + test_file[:4]
+ subprocess.check_call(compile_args + [test_file, "-o", exe_file])
+ subprocess.check_call([exe_file])
diff --git a/tests/include/unittest.hh b/tests/include/unittest.hh
new file mode 100644
index 0000000..437ea77
--- /dev/null
+++ b/tests/include/unittest.hh
@@ -0,0 +1,84 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstring>
+#include <iostream>
+#include <iomanip>
+#include <cstdlib>
+
+
+std::ostream & print_hex(
+ std::ostream & os,
+ std::uint8_t const * data,
+ std::size_t length
+) {
+ for (std::size_t i = 0; i < length; i++) {
+ os << std::setw(2) << std::setfill('0') << std::right
+ << std::hex << (int) data[i];
+ }
+ return os;
+}
+
+
+char const * TEST_CASE;
+
+
+template<typename T>
+void assert_equals(
+ const char *file,
+ unsigned line,
+ const char *expected_expr,
+ const char *actual_expr,
+ T const & expected,
+ T const & actual
+) {
+ if (expected != actual) {
+ std::cout << "FAILED: " << TEST_CASE << std::endl;
+ std::cout << file << ":" << line << std::endl;
+ std::cout << expected_expr << " == " << actual_expr << std::endl;
+ std::cout << "Expected: " << expected << std::endl;
+ std::cout << "Actual: " << actual << std::endl;
+ std::exit(1);
+ }
+}
+
+
+void assert_equals(
+ const char *file,
+ unsigned line,
+ const char *expected_expr,
+ const char *actual_expr,
+ std::uint8_t const * expected,
+ std::uint8_t const * actual,
+ std::size_t length
+) {
+ if (std::memcmp(expected, actual, length)) {
+ std::cout << "FAILED: " << TEST_CASE << std::endl;
+ std::cout << file << ":" << line << std::endl;
+ std::cout << expected_expr << " == " << actual_expr << std::endl;
+ print_hex(std::cout << "Expected: ", expected, length) << std::endl;
+ print_hex(std::cout << "Actual: ", actual, length) << std::endl;
+ std::exit(1);
+ }
+}
+
+#define assert_equals(expected, actual, ...) assert_equals( \
+ __FILE__, __LINE__, #expected, #actual, expected, actual, ##__VA_ARGS__ \
+)
+
+class TestCase {
+public:
+ TestCase(const char *name) { TEST_CASE = name; }
+ ~TestCase() { std::cout << "PASSED: " << TEST_CASE << std::endl; }
+};
diff --git a/tests/test_axolotl.cpp b/tests/test_axolotl.cpp
new file mode 100644
index 0000000..f268f2a
--- /dev/null
+++ b/tests/test_axolotl.cpp
@@ -0,0 +1,174 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "axolotl/axolotl.hh"
+#include "unittest.hh"
+
+
+int main() {
+
+std::uint8_t root_info[] = "Axolotl";
+std::uint8_t ratchet_info[] = "AxolotlRatchet";
+std::uint8_t message_info[] = "AxolotlMessageKeys";
+
+axolotl::KdfInfo kdf_info = {
+ root_info, sizeof(root_info) - 1,
+ ratchet_info, sizeof(ratchet_info - 1),
+ message_info, sizeof(ratchet_info - 1)
+};
+
+std::uint8_t random_bytes[] = "0123456789ABDEF0123456789ABCDEF";
+axolotl::Curve25519KeyPair bob_key;
+axolotl::generate_key(random_bytes, bob_key);
+
+std::uint8_t shared_secret[] = "A secret";
+
+{ /* Send/Receive test case */
+TestCase test_case("Axolotl Send/Receive");
+
+axolotl::Session alice(kdf_info);
+axolotl::Session bob(kdf_info);
+
+alice.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, bob_key);
+bob.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, bob_key);
+
+std::uint8_t plaintext[] = "Message";
+std::size_t plaintext_length = sizeof(plaintext) - 1;
+
+std::size_t message_length, random_length, output_length;
+std::size_t encrypt_length, decrypt_length;
+{
+ /* Bob sends Alice a message */
+ message_length = bob.encrypt_max_output_length(plaintext_length);
+ random_length = bob.encrypt_random_length();
+ assert_equals(std::size_t(0), random_length);
+ output_length = alice.decrypt_max_plaintext_length(message_length);
+
+ std::uint8_t message[message_length];
+ std::uint8_t output[output_length];
+
+ encrypt_length = bob.encrypt(
+ plaintext, plaintext_length,
+ NULL, 0,
+ message, message_length
+ );
+ assert_equals(message_length, encrypt_length);
+
+ decrypt_length = alice.decrypt(
+ message, message_length,
+ output, output_length
+ );
+ assert_equals(plaintext_length, decrypt_length);
+ assert_equals(plaintext, output, decrypt_length);
+}
+
+
+{
+ /* Alice sends Bob a message */
+ message_length = alice.encrypt_max_output_length(plaintext_length);
+ random_length = alice.encrypt_random_length();
+ assert_equals(std::size_t(32), random_length);
+ output_length = bob.decrypt_max_plaintext_length(message_length);
+
+ std::uint8_t message[message_length];
+ std::uint8_t output[output_length];
+ std::uint8_t random[] = "This is a random 32 byte string.";
+
+ encrypt_length = alice.encrypt(
+ plaintext, plaintext_length,
+ random, 32,
+ message, message_length
+ );
+ assert_equals(message_length, encrypt_length);
+
+ decrypt_length = bob.decrypt(
+ message, message_length,
+ output, output_length
+ );
+ assert_equals(plaintext_length, decrypt_length);
+ assert_equals(plaintext, output, decrypt_length);
+}
+
+} /* Send/receive message test case */
+
+{ /* Out of order test case */
+
+TestCase test_case("Axolotl Out of Order");
+
+axolotl::Session alice(kdf_info);
+axolotl::Session bob(kdf_info);
+
+alice.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, bob_key);
+bob.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, bob_key);
+
+std::uint8_t plaintext_1[] = "First Message";
+std::size_t plaintext_1_length = sizeof(plaintext_1) - 1;
+
+std::uint8_t plaintext_2[] = "Second Messsage. A bit longer than the first.";
+std::size_t plaintext_2_length = sizeof(plaintext_2) - 1;
+
+std::size_t message_1_length, message_2_length, random_length, output_length;
+std::size_t encrypt_length, decrypt_length;
+
+{
+ /* Alice sends Bob two messages and they arrive out of order */
+ message_1_length = alice.encrypt_max_output_length(plaintext_1_length);
+ random_length = alice.encrypt_random_length();
+ assert_equals(std::size_t(32), random_length);
+
+ std::uint8_t message_1[message_1_length];
+ std::uint8_t random[] = "This is a random 32 byte string.";
+ encrypt_length = alice.encrypt(
+ plaintext_1, plaintext_1_length,
+ random, 32,
+ message_1, message_1_length
+ );
+ assert_equals(message_1_length, encrypt_length);
+
+ message_2_length = alice.encrypt_max_output_length(plaintext_2_length);
+ random_length = alice.encrypt_random_length();
+ assert_equals(std::size_t(0), random_length);
+
+ std::uint8_t message_2[message_2_length];
+ encrypt_length = alice.encrypt(
+ plaintext_2, plaintext_2_length,
+ NULL, 0,
+ message_2, message_2_length
+ );
+ assert_equals(message_2_length, encrypt_length);
+
+ output_length = bob.decrypt_max_plaintext_length(message_2_length);
+ std::uint8_t output_1[output_length];
+ decrypt_length = bob.decrypt(
+ message_2, message_2_length,
+ output_1, output_length
+ );
+ assert_equals(plaintext_2_length, decrypt_length);
+ assert_equals(plaintext_2, output_1, decrypt_length);
+
+ output_length = bob.decrypt_max_plaintext_length(message_1_length);
+ std::uint8_t output_2[output_length];
+ decrypt_length = bob.decrypt(
+ message_1, message_1_length,
+ output_2, output_length
+ );
+
+ assert_equals(plaintext_1_length, decrypt_length);
+ assert_equals(plaintext_1, output_2, decrypt_length);
+}
+
+} /* Out of order test case */
+
+
+}
diff --git a/tests/test_crypto.cpp b/tests/test_crypto.cpp
new file mode 100644
index 0000000..1c068c4
--- /dev/null
+++ b/tests/test_crypto.cpp
@@ -0,0 +1,218 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "axolotl/crypto.hh"
+
+#include "unittest.hh"
+
+int main() {
+
+
+{ /* Curve25529 Test Case 1 */
+
+TestCase test_case("Curve25529 Test Case 1");
+
+std::uint8_t alice_private[32] = {
+ 0x77, 0x07, 0x6D, 0x0A, 0x73, 0x18, 0xA5, 0x7D,
+ 0x3C, 0x16, 0xC1, 0x72, 0x51, 0xB2, 0x66, 0x45,
+ 0xDF, 0x4C, 0x2F, 0x87, 0xEB, 0xC0, 0x99, 0x2A,
+ 0xB1, 0x77, 0xFB, 0xA5, 0x1D, 0xB9, 0x2C, 0x2A
+};
+
+std::uint8_t alice_public[32] = {
+ 0x85, 0x20, 0xF0, 0x09, 0x89, 0x30, 0xA7, 0x54,
+ 0x74, 0x8B, 0x7D, 0xDC, 0xB4, 0x3E, 0xF7, 0x5A,
+ 0x0D, 0xBF, 0x3A, 0x0D, 0x26, 0x38, 0x1A, 0xF4,
+ 0xEB, 0xA4, 0xA9, 0x8E, 0xAA, 0x9B, 0x4E, 0x6A
+};
+
+std::uint8_t bob_private[32] = {
+ 0x5D, 0xAB, 0x08, 0x7E, 0x62, 0x4A, 0x8A, 0x4B,
+ 0x79, 0xE1, 0x7F, 0x8B, 0x83, 0x80, 0x0E, 0xE6,
+ 0x6F, 0x3B, 0xB1, 0x29, 0x26, 0x18, 0xB6, 0xFD,
+ 0x1C, 0x2F, 0x8B, 0x27, 0xFF, 0x88, 0xE0, 0xEB
+};
+
+std::uint8_t bob_public[32] = {
+ 0xDE, 0x9E, 0xDB, 0x7D, 0x7B, 0x7D, 0xC1, 0xB4,
+ 0xD3, 0x5B, 0x61, 0xC2, 0xEC, 0xE4, 0x35, 0x37,
+ 0x3F, 0x83, 0x43, 0xC8, 0x5B, 0x78, 0x67, 0x4D,
+ 0xAD, 0xFC, 0x7E, 0x14, 0x6F, 0x88, 0x2B, 0x4F
+};
+
+std::uint8_t expected_agreement[32] = {
+ 0x4A, 0x5D, 0x9D, 0x5B, 0xA4, 0xCE, 0x2D, 0xE1,
+ 0x72, 0x8E, 0x3B, 0xF4, 0x80, 0x35, 0x0F, 0x25,
+ 0xE0, 0x7E, 0x21, 0xC9, 0x47, 0xD1, 0x9E, 0x33,
+ 0x76, 0xF0, 0x9B, 0x3C, 0x1E, 0x16, 0x17, 0x42
+};
+
+axolotl::Curve25519KeyPair alice_pair;
+axolotl::generate_key(alice_private, alice_pair);
+
+assert_equals(alice_private, alice_pair.private_key, 32);
+assert_equals(alice_public, alice_pair.public_key, 32);
+
+axolotl::Curve25519KeyPair bob_pair;
+axolotl::generate_key(bob_private, bob_pair);
+
+assert_equals(bob_private, bob_pair.private_key, 32);
+assert_equals(bob_public, bob_pair.public_key, 32);
+
+std::uint8_t actual_agreement[axolotl::CURVE25519_SHARED_SECRET_LENGTH] = {};
+
+axolotl::curve25519_shared_secret(alice_pair, bob_pair, actual_agreement);
+
+assert_equals(expected_agreement, actual_agreement, 32);
+
+axolotl::curve25519_shared_secret(bob_pair, alice_pair, actual_agreement);
+
+assert_equals(expected_agreement, actual_agreement, 32);
+
+} /* Curve25529 Test Case 1 */
+
+
+{ /* AES Test Case 1 */
+
+TestCase test_case("AES Test Case 1");
+
+axolotl::Aes256Key key = {};
+axolotl::Aes256Iv iv = {};
+std::uint8_t input[16] = {};
+
+std::uint8_t expected[32] = {
+ 0xDC, 0x95, 0xC0, 0x78, 0xA2, 0x40, 0x89, 0x89,
+ 0xAD, 0x48, 0xA2, 0x14, 0x92, 0x84, 0x20, 0x87,
+ 0xF3, 0xC0, 0x03, 0xDD, 0xC4, 0xA7, 0xB8, 0xA9,
+ 0x4B, 0xAE, 0xDF, 0xFC, 0x3D, 0x21, 0x4C, 0x38
+};
+
+std::size_t length = axolotl::aes_encrypt_cbc_length(sizeof(input));
+assert_equals(std::size_t(32), length);
+
+
+std::uint8_t actual[32] = {};
+
+axolotl::aes_encrypt_cbc(key, iv, input, sizeof(input), actual);
+assert_equals(expected, actual, 32);
+
+length = axolotl::aes_decrypt_cbc(key, iv, expected, sizeof(expected), actual);
+assert_equals(std::size_t(16), length);
+assert_equals(input, actual, length);
+
+} /* AES Test Case 1 */
+
+
+{ /* SHA 256 Test Case 1 */
+
+TestCase test_case("SHA 256 Test Case 1");
+
+std::uint8_t input[0] = {};
+
+std::uint8_t expected[32] = {
+ 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14,
+ 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
+ 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C,
+ 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55
+};
+
+std::uint8_t actual[32];
+
+axolotl::sha256(input, sizeof(input), actual);
+
+assert_equals(expected, actual, 32);
+
+} /* SHA 256 Test Case 1 */
+
+{ /* HMAC Test Case 1 */
+
+TestCase test_case("HMAC Test Case 1");
+
+std::uint8_t input[0] = {};
+
+std::uint8_t expected[32] = {
+ 0xb6, 0x13, 0x67, 0x9a, 0x08, 0x14, 0xd9, 0xec,
+ 0x77, 0x2f, 0x95, 0xd7, 0x78, 0xc3, 0x5f, 0xc5,
+ 0xff, 0x16, 0x97, 0xc4, 0x93, 0x71, 0x56, 0x53,
+ 0xc6, 0xc7, 0x12, 0x14, 0x42, 0x92, 0xc5, 0xad
+};
+
+std::uint8_t actual[32];
+
+axolotl::hmac_sha256(input, sizeof(input), input, sizeof(input), actual);
+
+assert_equals(expected, actual, 32);
+
+} /* HMAC Test Case 1 */
+
+{ /* HDKF Test Case 1 */
+
+TestCase test_case("HDKF Test Case 1");
+
+std::uint8_t input[22] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+};
+
+std::uint8_t salt[13] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c
+};
+
+std::uint8_t info[10] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9
+};
+
+std::uint8_t hmac_expected_output[32] = {
+ 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
+ 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
+ 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
+ 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5,
+};
+
+std::uint8_t hmac_actual_output[32] = {};
+
+axolotl::hmac_sha256(
+ salt, sizeof(salt),
+ input, sizeof(input),
+ hmac_actual_output
+);
+
+assert_equals(hmac_expected_output, hmac_actual_output, 32);
+
+std::uint8_t hkdf_expected_output[42] = {
+ 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
+ 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
+ 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
+ 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
+ 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
+ 0x58, 0x65
+};
+
+std::uint8_t hkdf_actual_output[42] = {};
+
+axolotl::hkdf_sha256(
+ input, sizeof(input),
+ salt, sizeof(salt),
+ info, sizeof(info),
+ hkdf_actual_output, sizeof(hkdf_actual_output)
+);
+
+assert_equals(hkdf_expected_output, hkdf_actual_output, 42);
+
+} /* HDKF Test Case 1 */
+
+}
diff --git a/tests/test_list.cpp b/tests/test_list.cpp
new file mode 100644
index 0000000..2cf23dc
--- /dev/null
+++ b/tests/test_list.cpp
@@ -0,0 +1,70 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "axolotl/list.hh"
+#include "unittest.hh"
+
+int main() {
+
+{ /** List insert test **/
+
+TestCase test_case("List insert");
+
+axolotl::List<int, 4> test_list;
+
+assert_equals(std::size_t(0), test_list.size());
+
+for (int i = 0; i < 4; ++i) {
+ test_list.insert(test_list.end(), i);
+}
+
+assert_equals(std::size_t(4), test_list.size());
+
+int i = 0;
+for (auto item : test_list) {
+ assert_equals(i++, item);
+}
+
+assert_equals(4, i);
+
+test_list.insert(test_list.end(), 4);
+
+assert_equals(4, test_list[3]);
+
+} /** List insert test **/
+
+{ /** List erase test **/
+TestCase test_case("List erase");
+
+axolotl::List<int, 4> test_list;
+assert_equals(std::size_t(0), test_list.size());
+
+for (int i = 0; i < 4; ++i) {
+ test_list.insert(test_list.end(), i);
+}
+assert_equals(std::size_t(4), test_list.size());
+
+test_list.erase(test_list.begin());
+assert_equals(std::size_t(3), test_list.size());
+
+int i = 0;
+for (auto item : test_list) {
+ assert_equals(i + 1, item);
+ ++i;
+}
+assert_equals(3, i);
+
+}
+
+}
diff --git a/tests/test_message.cpp b/tests/test_message.cpp
new file mode 100644
index 0000000..ca36ff5
--- /dev/null
+++ b/tests/test_message.cpp
@@ -0,0 +1,65 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "axolotl/message.hh"
+#include "unittest.hh"
+
+int main() {
+
+std::uint8_t message1[36] = "\x03\n\nratchetkey\x10\x01\"\nciphertexthmacsha2";
+std::uint8_t message2[36] = "\x03\x10\x01\n\nratchetkey\"\nciphertexthmacsha2";
+std::uint8_t ratchetkey[11] = "ratchetkey";
+std::uint8_t ciphertext[11] = "ciphertext";
+std::uint8_t hmacsha2[9] = "hmacsha2";
+
+{ /* Message decode test */
+
+TestCase test_case("Message decode test");
+
+axolotl::MessageReader reader(axolotl::decode_message(message1, 35, 8));
+
+assert_equals(std::size_t(27), reader.body_length);
+assert_equals(std::uint8_t(3), reader.version);
+assert_equals(std::uint32_t(1), reader.counter);
+assert_equals(std::size_t(10), reader.ratchet_key_length);
+assert_equals(std::size_t(10), reader.ciphertext_length);
+
+assert_equals(ratchetkey, reader.ratchet_key, 10);
+assert_equals(ciphertext, reader.ciphertext, 10);
+assert_equals(hmacsha2, reader.mac, 8);
+
+
+} /* Message decode test */
+
+{ /* Message encode test */
+
+TestCase test_case("Message encode test");
+
+std::size_t length = axolotl::encode_message_length(1, 10, 10, 8);
+assert_equals(std::size_t(35), length);
+
+std::uint8_t output[length];
+
+axolotl::MessageWriter writer(axolotl::encode_message(3, 1, 10, 10, output));
+assert_equals(std::size_t(27), writer.body_length);
+
+std::memcpy(writer.ratchet_key, ratchetkey, 10);
+std::memcpy(writer.ciphertext, ciphertext, 10);
+std::memcpy(writer.mac, hmacsha2, 8);
+
+assert_equals(message2, output, 35);
+
+} /* Message encode test */
+
+}