NaCl/Windows

From Qontrol.nl Wiki
Jump to: navigation, search

To use NaCl cryptography on Windows, there are two options:

  1. Use a C#/.Net port
  2. Compile the original NaCl code on Windows

A native compile of the original sourcecode will usually give the best results in terms of speed and resemblance to the original library. To make compiling NaCl on windows somewhat less painful, I've written a shellscript that extracts/creates all files needed, including a VS.Net/VisualC++.Net 9 project file.

Note that currently the build script does not support any platform specific optimized implementations of the cryptographic primitives. As a result, performance is usually comparable to or worse than the performance of the C#/.Net code.

The script currently compiles all reference implementations, but only exports a limited set. If anything you need is not exported, this is easy to change by editing the .def file.

The output of this script may also be useful to build the NaCl code for other previously unsupported platforms. It creates a file names sources.lst, which lists all the C source code files to compile. Don't forget to add the (generated) includes directory to the include path.

#!/bin/sh -e
top="`pwd`/build/windows"
include="$top/include"
source="$top/source"

export LANG=C

rm -rf "$top"
mkdir -p "$top"
mkdir -p "$include"
mkdir -p "$source"

cp "randombytes/devurandom.h" "$include/randombytes.h"
(
	echo "#include <windows.h>"
	echo "#include <Wincrypt.h>"
	echo "#pragma comment(lib, \"crypt32.lib\")"
	echo "void randombytes(unsigned char * a,unsigned long long c) {"
	echo "HCRYPTPROV hProvider = 0;"
	echo "while (1) {"
	echo "if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { Sleep(1); continue; }"
	echo "if (!CryptGenRandom(hProvider, (DWORD)c, (BYTE*)a)) { CryptReleaseContext(hProvider, 0); Sleep(1); continue; }"
	echo "CryptReleaseContext(hProvider, 0);"
	echo "break;"
	echo "}"
	echo "}"
) > "$source/randombytes.c"
echo "source/randombytes.c" > "$top/sources.lst"

macros=`cat MACROS`
prototypesc=`cat PROTOTYPES.c`
prototypescpp=`cat PROTOTYPES.cpp`
cat OPERATIONS | while read o
do
	[ -d "$o" ] || continue
	ls "$o" | sort | while read p
	do
		[ -d "$o/$p" ] || continue
		[ -f "$o/$p/used" ] || continue
		op="${o}_${p}"
		doth="$o/$p/ref/api.h"
		implementationdir=`dirname $doth`
		opi=`echo "$implementationdir" | tr ./- ___`
		language=c
		echo "$op"
		(
			to="${source}/${op}"
			mkdir -p "$to"
			cd "$implementationdir"
			cfiles=`ls | grep '\.c$' || :`
			sfiles=`ls | grep '\.[sS]$' || :`
			(
				echo "#ifndef ${o}_H"
				echo "#define ${o}_H"
				echo ""
				echo "#include \"${op}.h\""
				echo ""
				echo "$macros" | egrep "${o}"'$|'"${o}"'\(|'"${o}"'_' | sed "s/$o/$op/" | while read mop
				do
					echo "#define ${mop} ${mop}" | sed "s/$op/$o/"
				done
				echo "#define ${o}_PRIMITIVE \"${p}\""
				echo "#define ${o}_IMPLEMENTATION ${op}_IMPLEMENTATION"
				echo "#define ${o}_VERSION ${op}_VERSION"
				echo ""
				echo "#endif"
			) > "${to}/${o}.h"
			(
				echo "#ifndef ${op}_H"
				echo "#define ${op}_H"
				echo ""
				sed 's/[ 	]CRYPTO_/ '"${opi}"'_/g' < api.h
				echo '#ifdef __cplusplus'
				echo '#include <string>'
				echo "$prototypescpp" | egrep "${o}"'$|'"${o}"'\(|'"${o}"'_' | sed "s/$o/$opi/"
				echo 'extern "C" {'
				echo '#endif'
				echo "$prototypesc" | egrep "${o}"'$|'"${o}"'\(|'"${o}"'_' | sed "s/$o/$opi/"
				echo '#ifdef __cplusplus'
				echo '}'
				echo '#endif'
				echo ""
				echo "$macros" | egrep "${o}"'$|'"${o}"'\(|'"${o}"'_' | sed "s/$o/$opi/" | while read mopi
				do
					echo "#define ${mopi} ${mopi}" | sed "s/$opi/$op/"
				done
				echo "#define ${op}_IMPLEMENTATION \"${implementationdir}\""
				echo "#ifndef ${opi}_VERSION"
				echo "#define ${opi}_VERSION \"-\""
				echo "#endif"
				echo "#define ${op}_VERSION ${opi}_VERSION"
				echo ""
				echo "#endif"
			) > "${to}/${op}.h"

			for f in $cfiles $sfiles
			do
				echo "${op}_${f}"
				cp "$f" "${to}/${op}_${f}"
				echo "source/${op}/${op}_${f}" >> "$top/sources.lst"
			done

			cp -p "${to}/$op.h" "$include/$op.h"

			[ -f "../selected" ]  || continue
			cp -p "${to}/$o.h" "$include/$o.h"
		)
	done
done

(
	echo "LIBRARY	\"nacl\""
	echo "EXPORTS"
	echo "	crypto_box_curve25519xsalsa20poly1305_ref"
	echo "	crypto_box_curve25519xsalsa20poly1305_ref_open"
	echo "	crypto_box_curve25519xsalsa20poly1305_ref_keypair"
	echo "	crypto_box_curve25519xsalsa20poly1305_ref_beforenm"
	echo "	crypto_box_curve25519xsalsa20poly1305_ref_afternm"
	echo "	crypto_box_curve25519xsalsa20poly1305_ref_open_afternm"
) > "$top/nacl.def"

(
	echo "<?xml version='1.0' encoding='Windows-1252'?>"
	echo "<VisualStudioProject ProjectType='Visual C++' Version='9,00' Name='nacl' RootNamespace='NaCl'>"
	echo "<Platforms><Platform Name='Win32' /></Platforms>"
	echo "<ToolFiles></ToolFiles>"
	echo "<Configurations>"
	echo "<Configuration Name='Release|Win32'"
	echo "OutputDirectory='\$(ProjectDir)\$(ConfigurationName)' IntermediateDirectory='\$(ConfigurationName)'"
	echo "ConfigurationType='2' CharacterSet='2' WholeProgramOptimization='1'>"
	echo "<Tool Name='VCCLCompilerTool' AdditionalIncludeDirectories='include\\' />"
	echo "<Tool Name='VCLinkerTool' ModuleDefinitionFile='nacl.def' />"
	echo "</Configuration>"
	echo "</Configurations>"
	echo "<References></References>"
	echo "<Files>"
	echo "<Filter Name='Source Files' Filter='cpp;c;s'>"
	sed "s_/_\\\\_g" "$top/sources.lst" | sed "s_^\\(.*\\)\$_<File RelativePath='\\1' />_"
	echo "</Filter>"
	echo "<File RelativePath='nacl.def' />"
	echo "</Files>"
	echo "<Globals></Globals>"
	echo "</VisualStudioProject>"
) > "$top/nacl.vcproj"

rm "$top/sources.lst"