Tuesday, March 31, 2015

Compiling and using PyNaCl on Windows 7

Step-by-step how to compile PyNaCl Python package on win32.

Python 2.7.x for Windows - download it from here.
libsodium-1.0.2-msvc - download precompiled binaries from here.
Microsoft Visual C++ Compiler for Python 2.7 - you can download MS C++ compiler for Pyhton from here.

This guide is based on https://github.com/pyca/pynacl/issues/100 and and is a focused reiteration of it.

Python for Windows is compiled with MSVC and because of that it is not possible to compile extensions with MinGW/MSYS. The main problem is with CFFI (Common Foreign Function Interface) and most probably if you succeed with compiling, the lib will not work (will hang if trying to use its functions)

1. Download and install Python for Windows

2. Download and install Microsoft Visual C++ Compiler for Python 2.7 

3. Install python setuptools (needed for MSVC++ Python) with pip:
C:> pip install setuptools
4. Download libsodium latest release with -msvc at the end. Unzip it in C:\work\libsodium-1.0.2-msvc
5. Go to C:\work\libsodium-1.0.2-msvc\Win32\Release\v120\dynamic and rename libsodium.lib to sodium.lib. On 64bit Windows use this dir: C:\work\libsodium-1.0.2-msvc\x64\Release\v120\dynamic

6. Download PyNaCl source and unzip it to C:\work\PyNaCl-0.3.0

7. Start the MSVC++ Python shell: Start -> All Programs -> Microsoft Visual C++ Compiler Package for Python 2.7 -> Visual C++ 2008 32-bit Command Prompt

8. Set these 3 variables in cmd prompt:
set INCLUDE=%INCLUDE%C:\work\libsodium-1.0.2-msvc\include
set LIB=%LIB%C:\work\libsodium-1.0.2-msvc\Win32\Release\v120\dynamic

on 64bit Windows change:
set LIB=%LIB%C:\work\libsodium-1.0.2-msvc\Win32\Release\v120\dynamic
set LIB=%LIB%C:\work\libsodium-1.0.2-msvc\x64\Release\v120\dynamic
9. Probably you will need these two files when compiling:
Download and copy them to: C:\work\libsodium-1.0.2-msvc\include

10. Start the building process:
C:\>cd C:\work\PyNaCl-0.3.0
C:\work\PyNaCl-0.3.0>python setup.py build
11. If everything is ok, then install it:
C:\work\PyNaCl-0.3.0>python setup.py install
12. Finally, copy the original libsodium.dll in PyNaCl install dir:
C:>copy C:\work\libsodium-1.0.2-msvc\Win32\Release\v120\dynamic\libsodium.dll C:\Python27\Lib\site-packages\PyNaCl-0.3.0-py2.7-win32.egg\nacl\_lib
Here is a test program (from doc examples https://pynacl.readthedocs.org/en/latest/public/) slightly modified:
import nacl.utils
nacl.public import PrivateKey, Box

skbob = PrivateKey.generate()
pkbob = skbob.public_key  
skalice = PrivateKey.generate()
pkalice = skalice.public_key 
bob_box = Box(skbob, pkalice)
message = b"Kill all humans"
nonce = nacl.utils.random(Box.NONCE_SIZE)

encrypted = bob_box.encrypt(message, nonce)
print "Encrypted Message:", encrypted
alice_box = Box(skalice, pkbob)

plaintext = alice_box.decrypt(encrypted)
print "Plaintext Message:", plaintext

If it works, you should see something like:
C:\work>python nacltest.py
Encrypted Message: ₧╫fαIé├l(α▀W¬½♥↔≈‼╟  üRδD≈é☻'^∞v√oòΣls╣8,ƒ   ↓ü↓╓+ô╓è╣=§╣
Plaintext Message: Kill all humans