2018-05-10 17:50:30 +02:00

134 lines
5.4 KiB
Python

"""
This file is part of Python Salsa20
a Python bridge to the libsodium C [X]Salsa20 library
Released under The BSD 3-Clause License
Copyright (c) 2013 Keybase
Python module and ctypes bindings
"""
import imp
import sys
from ctypes import (cdll,
c_char_p, c_int, c_uint64,
create_string_buffer)
_salsa20 = cdll.LoadLibrary(imp.find_module('_salsa20')[1])
_stream_salsa20 = _salsa20.exp_stream_salsa20
_stream_salsa20.argtypes = [ c_char_p, # unsigned char * c
c_uint64, # unsigned long long clen
c_char_p, # const unsigned char * n
c_char_p # const unsigned char * k
]
_stream_salsa20.restype = c_int
_stream_salsa20_xor = _salsa20.exp_stream_salsa20_xor
_stream_salsa20_xor.argtypes = [ c_char_p, # unsigned char * c
c_char_p, # const unsigned char *m
c_uint64, # unsigned long long mlen
c_char_p, # const unsigned char * n
c_char_p # const unsigned char * k
]
_stream_salsa20_xor.restype = c_int
_stream_xsalsa20 = _salsa20.exp_stream_xsalsa20
_stream_xsalsa20.argtypes = [ c_char_p, # unsigned char * c
c_uint64, # unsigned long long clen
c_char_p, # const unsigned char * n
c_char_p # const unsigned char * k
]
_stream_xsalsa20.restype = c_int
_stream_xsalsa20_xor = _salsa20.exp_stream_xsalsa20_xor
_stream_xsalsa20_xor.argtypes = [ c_char_p, # unsigned char * c
c_char_p, # const unsigned char *m
c_uint64, # unsigned long long mlen
c_char_p, # const unsigned char * n
c_char_p # const unsigned char * k
]
_stream_xsalsa20_xor.restype = c_int
IS_PY2 = sys.version_info < (3, 0, 0, 'final', 0)
def _ensure_bytes(data):
if (IS_PY2 and not isinstance(data, str)) or (not IS_PY2 and not isinstance(data, bytes)):
raise TypeError('can not encrypt/decrypt unicode objects')
def Salsa20_keystream(length, nonce, key):
_ensure_bytes(nonce)
_ensure_bytes(key)
if not len(key) == 32: raise ValueError('invalid key length')
if not len(nonce) == 8: raise ValueError('invalid nonce length')
if not length > 0: raise ValueError('invalid length')
outbuf = create_string_buffer(length)
_stream_salsa20(outbuf, length, nonce, key)
return outbuf.raw
def Salsa20_xor(message, nonce, key):
_ensure_bytes(nonce)
_ensure_bytes(key)
_ensure_bytes(message)
if not len(key) == 32: raise ValueError('invalid key length')
if not len(nonce) == 8: raise ValueError('invalid nonce length')
if not len(message) > 0: raise ValueError('invalid message length')
outbuf = create_string_buffer(len(message))
_stream_salsa20_xor(outbuf, message, len(message), nonce, key)
return outbuf.raw
def XSalsa20_keystream(length, nonce, key):
_ensure_bytes(nonce)
_ensure_bytes(key)
if not len(key) == 32: raise ValueError('invalid key length')
if not len(nonce) == 24: raise ValueError('invalid nonce length')
if not length > 0: raise ValueError('invalid length')
outbuf = create_string_buffer(length)
_stream_xsalsa20(outbuf, length, nonce, key)
return outbuf.raw
def XSalsa20_xor(message, nonce, key):
_ensure_bytes(nonce)
_ensure_bytes(key)
_ensure_bytes(message)
if not len(key) == 32: raise ValueError('invalid key length')
if not len(nonce) == 24: raise ValueError('invalid nonce length')
if not len(message) > 0: raise ValueError('invalid message length')
outbuf = create_string_buffer(len(message))
_stream_xsalsa20_xor(outbuf, message, len(message), nonce, key)
return outbuf.raw
def self_test():
import binascii, hashlib
key = binascii.unhexlify('1b27556473e985d462cd51197a9a46c76009549eac6474f206c4ee0844f68389')
nonce = binascii.unhexlify('69696ee955b62b73cd62bda875fc73d68219e0036b7a0b37')
output = XSalsa20_keystream(4194304, nonce, key)
assert hashlib.sha256(output).hexdigest() == '662b9d0e3463029156069b12f918691a98f7dfb2ca0393c96bbfc6b1fbd630a2'
message = binascii.unhexlify('0000000000000000000000000000000000000000000000000000000000000000be075fc53c81f2d5cf141316ebeb0c7b5228c52a4c62cbd44b66849b64244ffce5ecbaaf33bd751a1ac728d45e6c61296cdc3c01233561f41db66cce314adb310e3be8250c46f06dceea3a7fa1348057e2f6556ad6b1318a024a838f21af1fde048977eb48f59ffd4924ca1c60902e52f0a089bc76897040e082f937763848645e0705')
output = XSalsa20_xor(message, nonce, key)
assert output[32:] == binascii.unhexlify('8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186ac0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5')
key = binascii.unhexlify('dc908dda0b9344a953629b733820778880f3ceb421bb61b91cbd4c3e66256ce4')
nonce = binascii.unhexlify('8219e0036b7a0b37')
output = Salsa20_keystream(4194304, nonce, key)
assert hashlib.sha256(output).hexdigest() == '662b9d0e3463029156069b12f918691a98f7dfb2ca0393c96bbfc6b1fbd630a2'
self_test()