From c8b79bf686113c3418d8d65ff0a1920da2b409bc Mon Sep 17 00:00:00 2001 From: Micah Anderson Date: Thu, 14 Nov 2013 16:35:32 -0500 Subject: initial commit --- PKG-INFO | 139 ++++++ README.rst | 121 +++++ debian/changelog | 29 ++ debian/compat | 1 + debian/control | 20 + debian/copyright | 43 ++ debian/python-scrypt.lintian-overrides | 4 + debian/rules | 6 + debian/source/format | 1 + scrypt-1.1.6/config.h | 99 ++++ scrypt-1.1.6/lib/crypto/crypto_aesctr.c | 124 +++++ scrypt-1.1.6/lib/crypto/crypto_aesctr.h | 59 +++ scrypt-1.1.6/lib/crypto/crypto_scrypt-nosse.c | 345 ++++++++++++++ scrypt-1.1.6/lib/crypto/crypto_scrypt.h | 46 ++ scrypt-1.1.6/lib/crypto/sha256.c | 412 ++++++++++++++++ scrypt-1.1.6/lib/crypto/sha256.h | 62 +++ scrypt-1.1.6/lib/scryptenc/scryptenc.c | 633 +++++++++++++++++++++++++ scrypt-1.1.6/lib/scryptenc/scryptenc.h | 112 +++++ scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.c | 192 ++++++++ scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.h | 39 ++ scrypt-1.1.6/lib/util/memlimit.c | 343 ++++++++++++++ scrypt-1.1.6/lib/util/memlimit.h | 42 ++ scrypt-1.1.6/lib/util/readpass.h | 45 ++ scrypt-1.1.6/lib/util/sysendian.h | 140 ++++++ scrypt-1.1.6/lib/util/warn.c | 75 +++ scrypt-1.1.6/lib/util/warn.h | 13 + scrypt-1.1.6/scrypt_platform.h | 12 + scrypt.py | 224 +++++++++ setup.py | 105 ++++ src/scrypt.c | 74 +++ tests/__init__.py | 0 tests/ciphertexts.csv | 6 + tests/hashvectors.csv | 5 + tests/test_scrypt.py | 285 +++++++++++ tests/test_scrypt_py2x.py | 51 ++ tests/test_scrypt_py3x.py | 56 +++ 36 files changed, 3963 insertions(+) create mode 100644 PKG-INFO create mode 100644 README.rst create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/python-scrypt.lintian-overrides create mode 100755 debian/rules create mode 100644 debian/source/format create mode 100644 scrypt-1.1.6/config.h create mode 100644 scrypt-1.1.6/lib/crypto/crypto_aesctr.c create mode 100644 scrypt-1.1.6/lib/crypto/crypto_aesctr.h create mode 100644 scrypt-1.1.6/lib/crypto/crypto_scrypt-nosse.c create mode 100644 scrypt-1.1.6/lib/crypto/crypto_scrypt.h create mode 100644 scrypt-1.1.6/lib/crypto/sha256.c create mode 100644 scrypt-1.1.6/lib/crypto/sha256.h create mode 100644 scrypt-1.1.6/lib/scryptenc/scryptenc.c create mode 100644 scrypt-1.1.6/lib/scryptenc/scryptenc.h create mode 100644 scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.c create mode 100644 scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.h create mode 100644 scrypt-1.1.6/lib/util/memlimit.c create mode 100644 scrypt-1.1.6/lib/util/memlimit.h create mode 100644 scrypt-1.1.6/lib/util/readpass.h create mode 100644 scrypt-1.1.6/lib/util/sysendian.h create mode 100644 scrypt-1.1.6/lib/util/warn.c create mode 100644 scrypt-1.1.6/lib/util/warn.h create mode 100644 scrypt-1.1.6/scrypt_platform.h create mode 100644 scrypt.py create mode 100644 setup.py create mode 100644 src/scrypt.c create mode 100644 tests/__init__.py create mode 100644 tests/ciphertexts.csv create mode 100644 tests/hashvectors.csv create mode 100644 tests/test_scrypt.py create mode 100644 tests/test_scrypt_py2x.py create mode 100644 tests/test_scrypt_py3x.py diff --git a/PKG-INFO b/PKG-INFO new file mode 100644 index 0000000..6d65038 --- /dev/null +++ b/PKG-INFO @@ -0,0 +1,139 @@ +Metadata-Version: 1.0 +Name: scrypt +Version: 0.6.1 +Summary: Bindings for the scrypt key derivation function library +Home-page: http://bitbucket.org/mhallin/py-scrypt +Author: Magnus Hallin +Author-email: mhallin@gmail.com +License: 2-clause BSD +Description: ========================= + Python scrypt_ bindings + ========================= + + This is a set of Python_ bindings for the scrypt_ key derivation + function. + + Scrypt is useful when encrypting password as it is possible to specify + a *minimum* amount of time to use when encrypting and decrypting. If, + for example, a password takes 0.05 seconds to verify, a user won't + notice the slight delay when signing in, but doing a brute force + search of several billion passwords will take a considerable amount of + time. This is in contrast to more traditional hash functions such as + MD5 or the SHA family which can be implemented extremely fast on cheap + hardware. + + Installation + ============ + + You can install py-scrypt from this repository if you want the latest + but possibly non-compiling version:: + + $ hg clone http://bitbucket.org/mhallin/py-scrypt + $ cd py-scrypt + $ python setup.py build + + Become superuser (or use virtualenv): + # python setup.py install + + Run tests after install: + $ python setup.py test + + Or you can install the latest release from PyPi:: + + $ pip install scrypt + + If you want py-scrypt for your Python 3 environment, just run the + above commands with your Python 3 interpreter. Py-scrypt supports both + Python 2 and 3. + + From version 0.6.0 (not available on PyPi yet), py-scrypt supports + PyPy as well. + + Usage + ===== + + Fore encryption/decryption, the library exports two functions + ``encrypt`` and ``decrypt``:: + + >>> import scrypt + >>> data = scrypt.encrypt('a secret message', 'password', maxtime=0.1) # This will take at least 0.1 seconds + >>> data[:20] + 'scrypt\x00\r\x00\x00\x00\x08\x00\x00\x00\x01RX9H' + >>> scrypt.decrypt(data, 'password', maxtime=0.1) # This will also take at least 0.1 seconds + 'a secret message' + >>> scrypt.decrypt(data, 'password', maxtime=0.05) # scrypt won't be able to decrypt this data fast enough + Traceback (most recent call last): + File "", line 1, in + scrypt.error: decrypting file would take too long + >>> scrypt.decrypt(data, 'wrong password', maxtime=0.1) # scrypt will throw an exception if the password is incorrect + Traceback (most recent call last): + File "", line 1, in + scrypt.error: password is incorrect + + From these, one can make a simple password verifier using the following + functions:: + + def randstr(length): + return ''.join(chr(random.randint(0,255)) for i in range(length)) + + def hash_password(password, maxtime=0.5, datalength=64): + return scrypt.encrypt(randstr(datalength), password, maxtime=maxtime) + + def verify_password(hashed_password, guessed_password, maxtime=0.5): + try: + scrypt.decrypt(hashed_password, guessed_password, maxtime) + return True + except scrypt.error: + return False + + + But, if you want output that is deterministic and constant in size, + you can use the ``hash`` function:: + + >>> import scrypt + >>> h1 = scrypt.hash('password', 'random salt') + >>> len(h1) # The hash will be 64 bytes by default, but is overridable. + 64 + >>> h1[:10] + '\xfe\x87\xf3hS\tUo\xcd\xc8' + >>> h2 = scrypt.hash('password', 'random salt') + >>> h1 == h2 # The hash function is deterministic + True + + + Acknowledgements + ================ + + Scrypt_ was created by Colin Percival and is licensed as 2-clause BSD. + Since scrypt does not normally build as a shared library, I have included + the source for the currently latest version of the library in this + repository. When a new version arrives, I will update these sources. + + `Kelvin Wong`_ on Bitbucket provided changes to make the library + available on Mac OS X 10.6 and earlier, as well as changes to make the + library work more like the command-line version of scrypt by + default. Kelvin also contributed with the unit tests, lots of cross + platform testing and work on the ``hash`` function. + + Burstaholic_ on Bitbucket provided the necessary changes to make + the library build on Windows. + + License + ======= + + This library is licensed under the same license as scrypt; 2-clause BSD. + + .. _scrypt: http://www.tarsnap.com/scrypt.html + .. _Python: http://python.org + .. _Burstaholic: https://bitbucket.org/Burstaholic + .. _Kelvin Wong: https://bitbucket.org/kelvinwong_ca + +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Security :: Cryptography +Classifier: Topic :: Software Development :: Libraries diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..f567b6c --- /dev/null +++ b/README.rst @@ -0,0 +1,121 @@ +========================= + Python scrypt_ bindings +========================= + +This is a set of Python_ bindings for the scrypt_ key derivation +function. + +Scrypt is useful when encrypting password as it is possible to specify +a *minimum* amount of time to use when encrypting and decrypting. If, +for example, a password takes 0.05 seconds to verify, a user won't +notice the slight delay when signing in, but doing a brute force +search of several billion passwords will take a considerable amount of +time. This is in contrast to more traditional hash functions such as +MD5 or the SHA family which can be implemented extremely fast on cheap +hardware. + +Installation +============ + +You can install py-scrypt from this repository if you want the latest +but possibly non-compiling version:: + + $ hg clone http://bitbucket.org/mhallin/py-scrypt + $ cd py-scrypt + $ python setup.py build + + Become superuser (or use virtualenv): + # python setup.py install + + Run tests after install: + $ python setup.py test + +Or you can install the latest release from PyPi:: + + $ pip install scrypt + +If you want py-scrypt for your Python 3 environment, just run the +above commands with your Python 3 interpreter. Py-scrypt supports both +Python 2 and 3. + +From version 0.6.0 (not available on PyPi yet), py-scrypt supports +PyPy as well. + +Usage +===== + +Fore encryption/decryption, the library exports two functions +``encrypt`` and ``decrypt``:: + + >>> import scrypt + >>> data = scrypt.encrypt('a secret message', 'password', maxtime=0.1) # This will take at least 0.1 seconds + >>> data[:20] + 'scrypt\x00\r\x00\x00\x00\x08\x00\x00\x00\x01RX9H' + >>> scrypt.decrypt(data, 'password', maxtime=0.1) # This will also take at least 0.1 seconds + 'a secret message' + >>> scrypt.decrypt(data, 'password', maxtime=0.05) # scrypt won't be able to decrypt this data fast enough + Traceback (most recent call last): + File "", line 1, in + scrypt.error: decrypting file would take too long + >>> scrypt.decrypt(data, 'wrong password', maxtime=0.1) # scrypt will throw an exception if the password is incorrect + Traceback (most recent call last): + File "", line 1, in + scrypt.error: password is incorrect + +From these, one can make a simple password verifier using the following +functions:: + + def randstr(length): + return ''.join(chr(random.randint(0,255)) for i in range(length)) + + def hash_password(password, maxtime=0.5, datalength=64): + return scrypt.encrypt(randstr(datalength), password, maxtime=maxtime) + + def verify_password(hashed_password, guessed_password, maxtime=0.5): + try: + scrypt.decrypt(hashed_password, guessed_password, maxtime) + return True + except scrypt.error: + return False + + +But, if you want output that is deterministic and constant in size, +you can use the ``hash`` function:: + + >>> import scrypt + >>> h1 = scrypt.hash('password', 'random salt') + >>> len(h1) # The hash will be 64 bytes by default, but is overridable. + 64 + >>> h1[:10] + '\xfe\x87\xf3hS\tUo\xcd\xc8' + >>> h2 = scrypt.hash('password', 'random salt') + >>> h1 == h2 # The hash function is deterministic + True + + +Acknowledgements +================ + +Scrypt_ was created by Colin Percival and is licensed as 2-clause BSD. +Since scrypt does not normally build as a shared library, I have included +the source for the currently latest version of the library in this +repository. When a new version arrives, I will update these sources. + +`Kelvin Wong`_ on Bitbucket provided changes to make the library +available on Mac OS X 10.6 and earlier, as well as changes to make the +library work more like the command-line version of scrypt by +default. Kelvin also contributed with the unit tests, lots of cross +platform testing and work on the ``hash`` function. + +Burstaholic_ on Bitbucket provided the necessary changes to make +the library build on Windows. + +License +======= + +This library is licensed under the same license as scrypt; 2-clause BSD. + +.. _scrypt: http://www.tarsnap.com/scrypt.html +.. _Python: http://python.org +.. _Burstaholic: https://bitbucket.org/Burstaholic +.. _Kelvin Wong: https://bitbucket.org/kelvinwong_ca diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..38d89fb --- /dev/null +++ b/debian/changelog @@ -0,0 +1,29 @@ +python-scrypt (0.6.1-5) unstable; urgency=low + + * Remove dependency on libscrypt0, it requires porting + + -- Micah Anderson Thu, 22 Aug 2013 16:01:24 -0400 + +python-scrypt (0.6.1-4) unstable; urgency=low + + * Update debian/copyright to fix missing DEP5 field + + -- Micah Anderson Tue, 13 Aug 2013 09:37:16 -0400 + +python-scrypt (0.6.1-3) unstable; urgency=low + + * Fix typo in libscrypt0 package dependency + + -- Micah Anderson Sat, 10 Aug 2013 21:39:40 +0200 + +python-scrypt (0.6.1-2) unstable; urgency=low + + * Add missing license information for embedded scrypt + + -- Micah Anderson Thu, 04 Jul 2013 12:03:29 -0400 + +python-scrypt (0.6.1-1) unstable; urgency=low + + * Initial package (Closes: #710464) + + -- Micah Anderson Thu, 30 May 2013 15:30:06 -0400 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..efa6172 --- /dev/null +++ b/debian/control @@ -0,0 +1,20 @@ +Source: python-scrypt +Maintainer: Micah Anderson +Section: python +Priority: optional +Build-Depends: python-all-dev (>= 2.6.6-3), debhelper (>= 9) +Standards-Version: 3.9.4 + +Package: python-scrypt +Architecture: any +Depends: ${misc:Depends}, ${python:Depends}, ${shlibs:Depends} +Description: Python bindings for the scrypt key derivation function library + This is a set of Python bindings for the scrypt key derivation function. + . + Scrypt is useful when encrypting password as it is possible to specify a + minimum amount of time to use when encrypting and decrypting. If, for + example, a password takes 0.05 seconds to verify, a user won't notice the + slight delay when signing in, but doing a brute force search of several + billion passwords will take a considerable amount of time. This is in + contrast to more traditional hash functions such as MD5 or the SHA family + which can be implemented extremely fast on cheap hardware. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..4af456c --- /dev/null +++ b/debian/copyright @@ -0,0 +1,43 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: scrypt +Upstream-Contact: mhallin@gmail.com +Source: + +Files: * +Copyright: Copyright (C) 2010 Magnus Hallin +License: BSD-2-Clause + +License: BSD-2-Clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. 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. + . + THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. + +Files: scrypt-1.1.6/* +Copyright: Copyright 2005,2007-2009 Colin Percival +License: BSD-2-Clause + +Files: debian/* +Copyright: Copyright 2013 Micah Anderson +License: GPL-3+ + +License: GPL-3+ + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/debian/python-scrypt.lintian-overrides b/debian/python-scrypt.lintian-overrides new file mode 100644 index 0000000..472a1d6 --- /dev/null +++ b/debian/python-scrypt.lintian-overrides @@ -0,0 +1,4 @@ +# Only the debian packaging is covered by the GPL, the rest is a 2-clause BSD +# tell lintian to not complain: +python-scrypt: possible-gpl-code-linked-with-openssl + diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..bcebae9 --- /dev/null +++ b/debian/rules @@ -0,0 +1,6 @@ +#!/usr/bin/make -f + +%: + dh $@ --with python2 --buildsystem=python_distutils + + diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/scrypt-1.1.6/config.h b/scrypt-1.1.6/config.h new file mode 100644 index 0000000..f1e6fd6 --- /dev/null +++ b/scrypt-1.1.6/config.h @@ -0,0 +1,99 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define to 1 if you have the declaration of `be64enc', and to 0 if you + don't. */ +#define HAVE_DECL_BE64ENC 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERR_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `rt' library (-lrt). */ +/* #undef HAVE_LIBRT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `posix_memalign' function. */ +/* #undef HAVE_POSIX_MEMALIGN */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if the system has the type `struct sysinfo'. */ +/* #undef HAVE_STRUCT_SYSINFO */ + +/* Define to 1 if `mem_unit' is member of `struct sysinfo'. */ +/* #undef HAVE_STRUCT_SYSINFO_MEM_UNIT */ + +/* Define to 1 if `totalram' is member of `struct sysinfo'. */ +/* #undef HAVE_STRUCT_SYSINFO_TOTALRAM */ + +/* Define to 1 if the OS has a hw.usermem sysctl */ +/* #undef HAVE_SYSCTL_HW_USERMEM */ + +/* Define to 1 if you have the `sysinfo' function. */ +/* #undef HAVE_SYSINFO */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSINFO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "scrypt" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "scrypt" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "scrypt 1.1.6" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "scrypt" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.1.6" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.1.6" + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ diff --git a/scrypt-1.1.6/lib/crypto/crypto_aesctr.c b/scrypt-1.1.6/lib/crypto/crypto_aesctr.c new file mode 100644 index 0000000..00db8f0 --- /dev/null +++ b/scrypt-1.1.6/lib/crypto/crypto_aesctr.c @@ -0,0 +1,124 @@ +/*- + * Copyright 2007-2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#include +#include + +#include + +#include "sysendian.h" + +#include "crypto_aesctr.h" + +struct crypto_aesctr { + AES_KEY * key; + uint64_t nonce; + uint64_t bytectr; + uint8_t buf[16]; +}; + +/** + * crypto_aesctr_init(key, nonce): + * Prepare to encrypt/decrypt data with AES in CTR mode, using the provided + * expanded key and nonce. The key provided must remain valid for the + * lifetime of the stream. + */ +struct crypto_aesctr * +crypto_aesctr_init(AES_KEY * key, uint64_t nonce) +{ + struct crypto_aesctr * stream; + + /* Allocate memory. */ + if ((stream = malloc(sizeof(struct crypto_aesctr))) == NULL) + goto err0; + + /* Initialize values. */ + stream->key = key; + stream->nonce = nonce; + stream->bytectr = 0; + + /* Success! */ + return (stream); + +err0: + /* Failure! */ + return (NULL); +} + +/** + * crypto_aesctr_stream(stream, inbuf, outbuf, buflen): + * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with + * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers + * ${inbuf} and ${outbuf} overlap, they must be identical. + */ +void +crypto_aesctr_stream(struct crypto_aesctr * stream, const uint8_t * inbuf, + uint8_t * outbuf, size_t buflen) +{ + uint8_t pblk[16]; + size_t pos; + int bytemod; + + for (pos = 0; pos < buflen; pos++) { + /* How far through the buffer are we? */ + bytemod = stream->bytectr % 16; + + /* Generate a block of cipherstream if needed. */ + if (bytemod == 0) { + be64enc(pblk, stream->nonce); + be64enc(pblk + 8, stream->bytectr / 16); + AES_encrypt(pblk, stream->buf, stream->key); + } + + /* Encrypt a byte. */ + outbuf[pos] = inbuf[pos] ^ stream->buf[bytemod]; + + /* Move to the next byte of cipherstream. */ + stream->bytectr += 1; + } +} + +/** + * crypto_aesctr_free(stream): + * Free the provided stream object. + */ +void +crypto_aesctr_free(struct crypto_aesctr * stream) +{ + int i; + + /* Zero potentially sensitive information. */ + for (i = 0; i < 16; i++) + stream->buf[i] = 0; + stream->bytectr = stream->nonce = 0; + + /* Free the stream. */ + free(stream); +} diff --git a/scrypt-1.1.6/lib/crypto/crypto_aesctr.h b/scrypt-1.1.6/lib/crypto/crypto_aesctr.h new file mode 100644 index 0000000..b50398f --- /dev/null +++ b/scrypt-1.1.6/lib/crypto/crypto_aesctr.h @@ -0,0 +1,59 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _CRYPTO_AESCTR_H_ +#define _CRYPTO_AESCTR_H_ + +#include + +#include + +/** + * crypto_aesctr_init(key, nonce): + * Prepare to encrypt/decrypt data with AES in CTR mode, using the provided + * expanded key and nonce. The key provided must remain valid for the + * lifetime of the stream. + */ +struct crypto_aesctr * crypto_aesctr_init(AES_KEY *, uint64_t); + +/** + * crypto_aesctr_stream(stream, inbuf, outbuf, buflen): + * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with + * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers + * ${inbuf} and ${outbuf} overlap, they must be identical. + */ +void crypto_aesctr_stream(struct crypto_aesctr *, const uint8_t *, + uint8_t *, size_t); + +/** + * crypto_aesctr_free(stream): + * Free the provided stream object. + */ +void crypto_aesctr_free(struct crypto_aesctr *); + +#endif /* !_CRYPTO_AESCTR_H_ */ diff --git a/scrypt-1.1.6/lib/crypto/crypto_scrypt-nosse.c b/scrypt-1.1.6/lib/crypto/crypto_scrypt-nosse.c new file mode 100644 index 0000000..a253379 --- /dev/null +++ b/scrypt-1.1.6/lib/crypto/crypto_scrypt-nosse.c @@ -0,0 +1,345 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#include + +#ifndef _WIN32 +#include +#endif + +#include +#include +#include +#include + +#include "sha256.h" +#include "sysendian.h" + +#include "crypto_scrypt.h" + +static void blkcpy(void *, void *, size_t); +static void blkxor(void *, void *, size_t); +static void salsa20_8(uint32_t[16]); +static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t); +static uint64_t integerify(void *, size_t); +static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *); + +static void +blkcpy(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] ^= S[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + uint32_t x[16]; + size_t i; + + blkcpy(x, B, 64); + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 16], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16 + 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8 + r * 16], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(void * B, size_t r) +{ + uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY) +{ + uint32_t * X = XY; + uint32_t * Y = &XY[32 * r]; + uint32_t * Z = &XY[64 * r]; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) + X[k] = le32dec(&B[4 * k]); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (32 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) + le32enc(&B[4 * k], X[k]); +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + void * B0, * V0, * XY0; + uint8_t * B; + uint32_t * V; + uint32_t * XY; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (((N & (N - 1)) != 0) || (N == 0)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ +#ifdef _WIN32 +#undef HAVE_POSIX_MEMALIGN +#endif + +#ifdef HAVE_POSIX_MEMALIGN + if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) + goto err0; + B = (uint8_t *)(B0); + if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) + goto err1; + XY = (uint32_t *)(XY0); +#ifndef MAP_ANON + if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) + goto err2; + V = (uint32_t *)(V0); +#endif +#else + if ((B0 = malloc(128 * r * p + 63)) == NULL) + goto err0; + B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); + if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) + goto err1; + XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); +#ifndef MAP_ANON + if ((V0 = malloc(128 * r * N + 63)) == NULL) + goto err2; + V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); +#endif +#endif +#ifdef MAP_ANON + if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + goto err2; + V = (uint32_t *)(V0); +#endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_scrypt_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_scrypt_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); + + /* Free memory. */ +#ifdef MAP_ANON + if (munmap(V0, 128 * r * N)) + goto err2; +#else + free(V0); +#endif + free(XY0); + free(B0); + + /* Success! */ + return (0); + +err2: + free(XY0); +err1: + free(B0); +err0: + /* Failure! */ + return (-1); +} diff --git a/scrypt-1.1.6/lib/crypto/crypto_scrypt.h b/scrypt-1.1.6/lib/crypto/crypto_scrypt.h new file mode 100644 index 0000000..f72e1f4 --- /dev/null +++ b/scrypt-1.1.6/lib/crypto/crypto_scrypt.h @@ -0,0 +1,46 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _CRYPTO_SCRYPT_H_ +#define _CRYPTO_SCRYPT_H_ + +#include + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int crypto_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, + uint32_t, uint32_t, uint8_t *, size_t); + +#endif /* !_CRYPTO_SCRYPT_H_ */ diff --git a/scrypt-1.1.6/lib/crypto/sha256.c b/scrypt-1.1.6/lib/crypto/sha256.c new file mode 100644 index 0000000..2812cf5 --- /dev/null +++ b/scrypt-1.1.6/lib/crypto/sha256.c @@ -0,0 +1,412 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ +#include "scrypt_platform.h" + +#include + +#include +#include + +#include "sysendian.h" + +#include "sha256.h" + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 4. + */ +static void +be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + be32enc(dst + i * 4, src[i]); +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +static void +be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + dst[i] = be32dec(src + i * 4); +} + +/* Elementary functions used by scrypt_SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* scrypt_SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +/* + * scrypt_SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +scrypt_SHA256_Transform(uint32_t * state, const unsigned char block[64]) +{ + uint32_t W[64]; + uint32_t S[8]; + uint32_t t0, t1; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) + state[i] += S[i]; + + /* Clean the stack. */ + memset(W, 0, 256); + memset(S, 0, 32); + t0 = t1 = 0; +} + +static unsigned char PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +scrypt_SHA256_Pad(scrypt_SHA256_CTX * ctx) +{ + unsigned char len[8]; + uint32_t r, plen; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be32enc_vect(len, ctx->count, 8); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ + r = (ctx->count[1] >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + scrypt_SHA256_Update(ctx, PAD, (size_t)plen); + + /* Add the terminating bit-count */ + scrypt_SHA256_Update(ctx, len, 8); +} + +/* SHA-256 initialization. Begins a SHA-256 operation. */ +void +scrypt_SHA256_Init(scrypt_SHA256_CTX * ctx) +{ + + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + 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; +} + +/* Add bytes into the hash */ +void +scrypt_SHA256_Update(scrypt_SHA256_CTX * ctx, const void *in, size_t len) +{ + uint32_t bitlen[2]; + uint32_t r; + const unsigned char *src = in; + + /* Number of bytes left in the buffer from previous updates */ + r = (ctx->count[1] >> 3) & 0x3f; + + /* Convert the length into a number of bits */ + bitlen[1] = ((uint32_t)len) << 3; + bitlen[0] = (uint32_t)(len >> 29); + + /* Update number of bits */ + if ((ctx->count[1] += bitlen[1]) < bitlen[1]) + ctx->count[0]++; + ctx->count[0] += bitlen[0]; + + /* Handle the case where we don't need to perform any transforms */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block */ + memcpy(&ctx->buf[r], src, 64 - r); + scrypt_SHA256_Transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks */ + while (len >= 64) { + scrypt_SHA256_Transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* + * SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +void +scrypt_SHA256_Final(unsigned char digest[32], scrypt_SHA256_CTX * ctx) +{ + + /* Add padding */ + scrypt_SHA256_Pad(ctx); + + /* Write the hash */ + be32enc_vect(digest, ctx->state, 32); + + /* Clear the context state */ + memset((void *)ctx, 0, sizeof(*ctx)); +} + +/* Initialize an HMAC-scrypt_SHA256 operation with the given key. */ +void +HMAC_scrypt_SHA256_Init(HMAC_scrypt_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char * K = _K; + size_t i; + + /* If Klen > 64, the key is really scrypt_SHA256(K). */ + if (Klen > 64) { + scrypt_SHA256_Init(&ctx->ictx); + scrypt_SHA256_Update(&ctx->ictx, K, Klen); + scrypt_SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner scrypt_SHA256 operation is scrypt_SHA256(K xor [block of 0x36] || data). */ + scrypt_SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + scrypt_SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer scrypt_SHA256 operation is scrypt_SHA256(K xor [block of 0x5c] || hash). */ + scrypt_SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + scrypt_SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-scrypt_SHA256 operation. */ +void +HMAC_scrypt_SHA256_Update(HMAC_scrypt_SHA256_CTX * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner scrypt_SHA256 operation. */ + scrypt_SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-scrypt_SHA256 operation. */ +void +HMAC_scrypt_SHA256_Final(unsigned char digest[32], HMAC_scrypt_SHA256_CTX * ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner scrypt_SHA256 operation. */ + scrypt_SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer scrypt_SHA256 operation. */ + scrypt_SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer scrypt_SHA256 operation. */ + scrypt_SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_scrypt_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-scrypt_SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_scrypt_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_scrypt_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + HMAC_scrypt_SHA256_Init(&PShctx, passwd, passwdlen); + HMAC_scrypt_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_scrypt_SHA256_CTX)); + HMAC_scrypt_SHA256_Update(&hctx, ivec, 4); + HMAC_scrypt_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_scrypt_SHA256_Init(&hctx, passwd, passwdlen); + HMAC_scrypt_SHA256_Update(&hctx, U, 32); + HMAC_scrypt_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_scrypt_SHA256_CTX)); +} diff --git a/scrypt-1.1.6/lib/crypto/sha256.h b/scrypt-1.1.6/lib/crypto/sha256.h new file mode 100644 index 0000000..74ab0fd --- /dev/null +++ b/scrypt-1.1.6/lib/crypto/sha256.h @@ -0,0 +1,62 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $ + */ + +#ifndef _scrypt_SHA256_H_ +#define _scrypt_SHA256_H_ + +#include + +#include + +typedef struct scrypt_SHA256Context { + uint32_t state[8]; + uint32_t count[2]; + unsigned char buf[64]; +} scrypt_SHA256_CTX; + +typedef struct HMAC_scrypt_SHA256Context { + scrypt_SHA256_CTX ictx; + scrypt_SHA256_CTX octx; +} HMAC_scrypt_SHA256_CTX; + +void scrypt_SHA256_Init(scrypt_SHA256_CTX *); +void scrypt_SHA256_Update(scrypt_SHA256_CTX *, const void *, size_t); +void scrypt_SHA256_Final(unsigned char [32], scrypt_SHA256_CTX *); +void HMAC_scrypt_SHA256_Init(HMAC_scrypt_SHA256_CTX *, const void *, size_t); +void HMAC_scrypt_SHA256_Update(HMAC_scrypt_SHA256_CTX *, const void *, size_t); +void HMAC_scrypt_SHA256_Final(unsigned char [32], HMAC_scrypt_SHA256_CTX *); + +/** + * PBKDF2_scrypt_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-scrypt_SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_scrypt_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_scrypt_SHA256_H_ */ diff --git a/scrypt-1.1.6/lib/scryptenc/scryptenc.c b/scrypt-1.1.6/lib/scryptenc/scryptenc.c new file mode 100644 index 0000000..c16a82c --- /dev/null +++ b/scrypt-1.1.6/lib/scryptenc/scryptenc.c @@ -0,0 +1,633 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "crypto_aesctr.h" +#include "crypto_scrypt.h" +#include "memlimit.h" +#include "scryptenc_cpuperf.h" +#include "sha256.h" +#include "sysendian.h" + +#include "scryptenc.h" + +#ifdef _WIN32 +#include +#include +#endif + +#define ENCBLOCK 65536 + +static int pickparams(size_t, double, double, + int *, uint32_t *, uint32_t *); +static int checkparams(size_t, double, double, int, uint32_t, uint32_t); +static int getsalt(uint8_t[32]); + +static int +pickparams(size_t maxmem, double maxmemfrac, double maxtime, + int * logN, uint32_t * r, uint32_t * p) +{ + size_t memlimit; + double opps; + double opslimit; + double maxN, maxrp; + int rc; + + /* Figure out how much memory to use. */ + if (memtouse(maxmem, maxmemfrac, &memlimit)) + return (1); + + /* Figure out how fast the CPU is. */ + if ((rc = scryptenc_cpuperf(&opps)) != 0) + return (rc); + opslimit = opps * maxtime; + + /* Allow a minimum of 2^15 salsa20/8 cores. */ + if (opslimit < 32768) + opslimit = 32768; + + /* Fix r = 8 for now. */ + *r = 8; + + /* + * The memory limit requires that 128Nr <= memlimit, while the CPU + * limit requires that 4Nrp <= opslimit. If opslimit < memlimit/32, + * opslimit imposes the stronger limit on N. + */ +#ifdef DEBUG + fprintf(stderr, "Requiring 128Nr <= %u, 4Nrp <= %f\n", + memlimit, opslimit); +#endif + if (opslimit < memlimit/32) { + /* Set p = 1 and choose N based on the CPU limit. */ + *p = 1; + maxN = opslimit / (*r * 4); + for (*logN = 1; *logN < 63; *logN += 1) { + if ((uint64_t)(1) << *logN > maxN / 2) + break; + } + } else { + /* Set N based on the memory limit. */ + maxN = memlimit / (*r * 128); + for (*logN = 1; *logN < 63; *logN += 1) { + if ((uint64_t)(1) << *logN > maxN / 2) + break; + } + + /* Choose p based on the CPU limit. */ + maxrp = (opslimit / 4) / ((uint64_t)(1) << *logN); + if (maxrp > 0x3fffffff) + maxrp = 0x3fffffff; + *p = (uint32_t)(maxrp) / *r; + } + +#ifdef DEBUG + fprintf(stderr, "N = %u r = %d p = %d\n", + (size_t)(1) << *logN, (int)(*r), (int)(*p)); +#endif + + /* Success! */ + return (0); +} + +static int +checkparams(size_t maxmem, double maxmemfrac, double maxtime, + int logN, uint32_t r, uint32_t p) +{ + size_t memlimit; + double opps; + double opslimit; + uint64_t N; + int rc; + + /* Figure out the maximum amount of memory we can use. */ + if (memtouse(maxmem, maxmemfrac, &memlimit)) + return (1); + + /* Figure out how fast the CPU is. */ + if ((rc = scryptenc_cpuperf(&opps)) != 0) + return (rc); + opslimit = opps * maxtime; + + /* Sanity-check values. */ + if ((logN < 1) || (logN > 63)) + return (7); + if ((uint64_t)(r) * (uint64_t)(p) >= 0x40000000) + return (7); + + /* Check limits. */ + N = (uint64_t)(1) << logN; + if ((memlimit / N) / r < 128) + return (9); + if ((opslimit / N) / (r * p) < 4) + return (10); + + /* Success! */ + return (0); +} + +static int +getsalt(uint8_t salt[32]) +{ + int fd; + ssize_t lenread; + uint8_t * buf = salt; + size_t buflen = 32; + +#ifndef _WIN32 + /* Open /dev/urandom. */ + if ((fd = open("/dev/urandom", O_RDONLY)) == -1) + goto err0; + + /* Read bytes until we have filled the buffer. */ + while (buflen > 0) { + if ((lenread = read(fd, buf, buflen)) == -1) + goto err1; + + /* The random device should never EOF. */ + if (lenread == 0) + goto err1; + + /* We're partly done. */ + buf += lenread; + buflen -= lenread; + } + + /* Close the device. */ + while (close(fd) == -1) { + if (errno != EINTR) + goto err0; + } + + /* Success! */ + return (0); + +err1: + close(fd); +err0: + /* Failure! */ + return (4); +#else + HCRYPTPROV context; + DWORD error; + + if(CryptAcquireContext(&context, NULL, NULL, PROV_RSA_AES, 0) == NTE_BAD_KEYSET) + { + if(!CryptAcquireContext(&context, NULL, NULL, PROV_RSA_AES, CRYPT_NEWKEYSET)) + { + error = GetLastError(); + printf("%x", error); + return (14); + } + } + + if(CryptGenRandom(context, 32, buf)) + { + buf += 32; + return (0); + } + else{return(15);} +#endif +} + +static int +scryptenc_setup(uint8_t header[96], uint8_t dk[64], + const uint8_t * passwd, size_t passwdlen, + size_t maxmem, double maxmemfrac, double maxtime) +{ + uint8_t salt[32]; + uint8_t hbuf[32]; + int logN; + uint64_t N; + uint32_t r; + uint32_t p; + scrypt_SHA256_CTX ctx; + uint8_t * key_hmac = &dk[32]; + HMAC_scrypt_SHA256_CTX hctx; + int rc; + + /* Pick values for N, r, p. */ + if ((rc = pickparams(maxmem, maxmemfrac, maxtime, + &logN, &r, &p)) != 0) + return (rc); + N = (uint64_t)(1) << logN; + + /* Get some salt. */ + if ((rc = getsalt(salt)) != 0) + return (rc); + + /* Generate the derived keys. */ + if (crypto_scrypt(passwd, passwdlen, salt, 32, N, r, p, dk, 64)) + return (3); + + /* Construct the file header. */ + memcpy(header, "scrypt", 6); + header[6] = 0; + header[7] = logN; + be32enc(&header[8], r); + be32enc(&header[12], p); + memcpy(&header[16], salt, 32); + + /* Add header checksum. */ + scrypt_SHA256_Init(&ctx); + scrypt_SHA256_Update(&ctx, header, 48); + scrypt_SHA256_Final(hbuf, &ctx); + memcpy(&header[48], hbuf, 16); + + /* Add header signature (used for verifying password). */ + HMAC_scrypt_SHA256_Init(&hctx, key_hmac, 32); + HMAC_scrypt_SHA256_Update(&hctx, header, 64); + HMAC_scrypt_SHA256_Final(hbuf, &hctx); + memcpy(&header[64], hbuf, 32); + + /* Success! */ + return (0); +} + +static int +scryptdec_setup(const uint8_t header[96], uint8_t dk[64], + const uint8_t * passwd, size_t passwdlen, + size_t maxmem, double maxmemfrac, double maxtime) +{ + uint8_t salt[32]; + uint8_t hbuf[32]; + int logN; + uint32_t r; + uint32_t p; + uint64_t N; + scrypt_SHA256_CTX ctx; + uint8_t * key_hmac = &dk[32]; + HMAC_scrypt_SHA256_CTX hctx; + int rc; + + /* Parse N, r, p, salt. */ + logN = header[7]; + r = be32dec(&header[8]); + p = be32dec(&header[12]); + memcpy(salt, &header[16], 32); + + /* Verify header checksum. */ + scrypt_SHA256_Init(&ctx); + scrypt_SHA256_Update(&ctx, header, 48); + scrypt_SHA256_Final(hbuf, &ctx); + if (memcmp(&header[48], hbuf, 16)) + return (7); + + /* + * Check whether the provided parameters are valid and whether the + * key derivation function can be computed within the allowed memory + * and CPU time. + */ + if ((rc = checkparams(maxmem, maxmemfrac, maxtime, logN, r, p)) != 0) + return (rc); + + /* Compute the derived keys. */ + N = (uint64_t)(1) << logN; + if (crypto_scrypt(passwd, passwdlen, salt, 32, N, r, p, dk, 64)) + return (3); + + /* Check header signature (i.e., verify password). */ + HMAC_scrypt_SHA256_Init(&hctx, key_hmac, 32); + HMAC_scrypt_SHA256_Update(&hctx, header, 64); + HMAC_scrypt_SHA256_Final(hbuf, &hctx); + if (memcmp(hbuf, &header[64], 32)) + return (11); + + /* Success! */ + return (0); +} + +/** + * scryptenc_buf(inbuf, inbuflen, outbuf, passwd, passwdlen, + * maxmem, maxmemfrac, maxtime): + * Encrypt inbuflen bytes from inbuf, writing the resulting inbuflen + 128 + * bytes to outbuf. + */ +int +scryptenc_buf(const uint8_t * inbuf, size_t inbuflen, uint8_t * outbuf, + const uint8_t * passwd, size_t passwdlen, + size_t maxmem, double maxmemfrac, double maxtime) +{ + uint8_t dk[64]; + uint8_t hbuf[32]; + uint8_t header[96]; + uint8_t * key_enc = dk; + uint8_t * key_hmac = &dk[32]; + int rc; + HMAC_scrypt_SHA256_CTX hctx; + AES_KEY key_enc_exp; + struct crypto_aesctr * AES; + + /* Generate the header and derived key. */ + if ((rc = scryptenc_setup(header, dk, passwd, passwdlen, + maxmem, maxmemfrac, maxtime)) != 0) + return (rc); + + /* Copy header into output buffer. */ + memcpy(outbuf, header, 96); + + /* Encrypt data. */ + if (AES_set_encrypt_key(key_enc, 256, &key_enc_exp)) + return (5); + if ((AES = crypto_aesctr_init(&key_enc_exp, 0)) == NULL) + return (6); + crypto_aesctr_stream(AES, inbuf, &outbuf[96], inbuflen); + crypto_aesctr_free(AES); + + /* Add signature. */ + HMAC_scrypt_SHA256_Init(&hctx, key_hmac, 32); + HMAC_scrypt_SHA256_Update(&hctx, outbuf, 96 + inbuflen); + HMAC_scrypt_SHA256_Final(hbuf, &hctx); + memcpy(&outbuf[96 + inbuflen], hbuf, 32); + + /* Zero sensitive data. */ + memset(dk, 0, 64); + memset(&key_enc_exp, 0, sizeof(AES_KEY)); + + /* Success! */ + return (0); +} + +/** + * scryptdec_buf(inbuf, inbuflen, outbuf, outlen, passwd, passwdlen, + * maxmem, maxmemfrac, maxtime): + * Decrypt inbuflen bytes fro inbuf, writing the result into outbuf and the + * decrypted data length to outlen. The allocated length of outbuf must + * be at least inbuflen. + */ +int +scryptdec_buf(const uint8_t * inbuf, size_t inbuflen, uint8_t * outbuf, + size_t * outlen, const uint8_t * passwd, size_t passwdlen, + size_t maxmem, double maxmemfrac, double maxtime) +{ + uint8_t hbuf[32]; + uint8_t dk[64]; + uint8_t * key_enc = dk; + uint8_t * key_hmac = &dk[32]; + int rc; + HMAC_scrypt_SHA256_CTX hctx; + AES_KEY key_enc_exp; + struct crypto_aesctr * AES; + + /* + * All versions of the scrypt format will start with "scrypt" and + * have at least 7 bytes of header. + */ + if ((inbuflen < 7) || (memcmp(inbuf, "scrypt", 6) != 0)) + return (7); + + /* Check the format. */ + if (inbuf[6] != 0) + return (8); + + /* We must have at least 128 bytes. */ + if (inbuflen < 128) + return (7); + + /* Parse the header and generate derived keys. */ + if ((rc = scryptdec_setup(inbuf, dk, passwd, passwdlen, + maxmem, maxmemfrac, maxtime)) != 0) + return (rc); + + /* Decrypt data. */ + if (AES_set_encrypt_key(key_enc, 256, &key_enc_exp)) + return (5); + if ((AES = crypto_aesctr_init(&key_enc_exp, 0)) == NULL) + return (6); + crypto_aesctr_stream(AES, &inbuf[96], outbuf, inbuflen - 128); + crypto_aesctr_free(AES); + *outlen = inbuflen - 128; + + /* Verify signature. */ + HMAC_scrypt_SHA256_Init(&hctx, key_hmac, 32); + HMAC_scrypt_SHA256_Update(&hctx, inbuf, inbuflen - 32); + HMAC_scrypt_SHA256_Final(hbuf, &hctx); + if (memcmp(hbuf, &inbuf[inbuflen - 32], 32)) + return (7); + + /* Zero sensitive data. */ + memset(dk, 0, 64); + memset(&key_enc_exp, 0, sizeof(AES_KEY)); + + /* Success! */ + return (0); +} + +/** + * scryptenc_file(infile, outfile, passwd, passwdlen, + * maxmem, maxmemfrac, maxtime): + * Read a stream from infile and encrypt it, writing the resulting stream to + * outfile. + */ +int +scryptenc_file(FILE * infile, FILE * outfile, + const uint8_t * passwd, size_t passwdlen, + size_t maxmem, double maxmemfrac, double maxtime) +{ + uint8_t buf[ENCBLOCK]; + uint8_t dk[64]; + uint8_t hbuf[32]; + uint8_t header[96]; + uint8_t * key_enc = dk; + uint8_t * key_hmac = &dk[32]; + size_t readlen; + HMAC_scrypt_SHA256_CTX hctx; + AES_KEY key_enc_exp; + struct crypto_aesctr * AES; + int rc; + + /* Generate the header and derived key. */ + if ((rc = scryptenc_setup(header, dk, passwd, passwdlen, + maxmem, maxmemfrac, maxtime)) != 0) + return (rc); + + /* Hash and write the header. */ + HMAC_scrypt_SHA256_Init(&hctx, key_hmac, 32); + HMAC_scrypt_SHA256_Update(&hctx, header, 96); + if (fwrite(header, 96, 1, outfile) != 1) + return (12); + + /* + * Read blocks of data, encrypt them, and write them out; hash the + * data as it is produced. + */ + if (AES_set_encrypt_key(key_enc, 256, &key_enc_exp)) + return (5); + if ((AES = crypto_aesctr_init(&key_enc_exp, 0)) == NULL) + return (6); + do { + if ((readlen = fread(buf, 1, ENCBLOCK, infile)) == 0) + break; + crypto_aesctr_stream(AES, buf, buf, readlen); + HMAC_scrypt_SHA256_Update(&hctx, buf, readlen); + if (fwrite(buf, 1, readlen, outfile) < readlen) + return (12); + } while (1); + crypto_aesctr_free(AES); + + /* Did we exit the loop due to a read error? */ + if (ferror(infile)) + return (13); + + /* Compute the final HMAC and output it. */ + HMAC_scrypt_SHA256_Final(hbuf, &hctx); + if (fwrite(hbuf, 32, 1, outfile) != 1) + return (12); + + /* Zero sensitive data. */ + memset(dk, 0, 64); + memset(&key_enc_exp, 0, sizeof(AES_KEY)); + + /* Success! */ + return (0); +} + +/** + * scryptdec_file(infile, outfile, passwd, passwdlen, + * maxmem, maxmemfrac, maxtime): + * Read a stream from infile and decrypt it, writing the resulting stream to + * outfile. + */ +int +scryptdec_file(FILE * infile, FILE * outfile, + const uint8_t * passwd, size_t passwdlen, + size_t maxmem, double maxmemfrac, double maxtime) +{ + uint8_t buf[ENCBLOCK + 32]; + uint8_t header[96]; + uint8_t hbuf[32]; + uint8_t dk[64]; + uint8_t * key_enc = dk; + uint8_t * key_hmac = &dk[32]; + size_t buflen = 0; + size_t readlen; + HMAC_scrypt_SHA256_CTX hctx; + AES_KEY key_enc_exp; + struct crypto_aesctr * AES; + int rc; + + /* + * Read the first 7 bytes of the file; all future version of scrypt + * are guaranteed to have at least 7 bytes of header. + */ + if (fread(header, 7, 1, infile) < 1) { + if (ferror(infile)) + return (13); + else + return (7); + } + + /* Do we have the right magic? */ + if (memcmp(header, "scrypt", 6)) + return (7); + if (header[6] != 0) + return (8); + + /* + * Read another 89 bytes of the file; version 0 of the srypt file + * format has a 96-byte header. + */ + if (fread(&header[7], 89, 1, infile) < 1) { + if (ferror(infile)) + return (13); + else + return (7); + } + + /* Parse the header and generate derived keys. */ + if ((rc = scryptdec_setup(header, dk, passwd, passwdlen, + maxmem, maxmemfrac, maxtime)) != 0) + return (rc); + + /* Start hashing with the header. */ + HMAC_scrypt_SHA256_Init(&hctx, key_hmac, 32); + HMAC_scrypt_SHA256_Update(&hctx, header, 96); + + /* + * We don't know how long the encrypted data block is (we can't know, + * since data can be streamed into 'scrypt enc') so we need to read + * data and decrypt all of it except the final 32 bytes, then check + * if that final 32 bytes is the correct signature. + */ + if (AES_set_encrypt_key(key_enc, 256, &key_enc_exp)) + return (5); + if ((AES = crypto_aesctr_init(&key_enc_exp, 0)) == NULL) + return (6); + do { + /* Read data until we have more than 32 bytes of it. */ + if ((readlen = fread(&buf[buflen], 1, + ENCBLOCK + 32 - buflen, infile)) == 0) + break; + buflen += readlen; + if (buflen <= 32) + continue; + + /* + * Decrypt, hash, and output everything except the last 32 + * bytes out of what we have in our buffer. + */ + HMAC_scrypt_SHA256_Update(&hctx, buf, buflen - 32); + crypto_aesctr_stream(AES, buf, buf, buflen - 32); + if (fwrite(buf, 1, buflen - 32, outfile) < buflen - 32) + return (12); + + /* Move the last 32 bytes to the start of the buffer. */ + memmove(buf, &buf[buflen - 32], 32); + buflen = 32; + } while (1); + crypto_aesctr_free(AES); + + /* Did we exit the loop due to a read error? */ + if (ferror(infile)) + return (13); + + /* Did we read enough data that we *might* have a valid signature? */ + if (buflen < 32) + return (7); + + /* Verify signature. */ + HMAC_scrypt_SHA256_Final(hbuf, &hctx); + if (memcmp(hbuf, buf, 32)) + return (7); + + /* Zero sensitive data. */ + memset(dk, 0, 64); + memset(&key_enc_exp, 0, sizeof(AES_KEY)); + + return (0); +} diff --git a/scrypt-1.1.6/lib/scryptenc/scryptenc.h b/scrypt-1.1.6/lib/scryptenc/scryptenc.h new file mode 100644 index 0000000..7dc3dd3 --- /dev/null +++ b/scrypt-1.1.6/lib/scryptenc/scryptenc.h @@ -0,0 +1,112 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _SCRYPTENC_H_ +#define _SCRYPTENC_H_ + +#include +#include + +/** + * The parameters maxmem, maxmemfrac, and maxtime used by all of these + * functions are defined as follows: + * maxmem - maximum number of bytes of storage to use for V array (which is + * by far the largest consumer of memory). If this value is set to 0, no + * maximum will be enforced; any other value less than 1 MiB will be + * treated as 1 MiB. + * maxmemfrac - maximum fraction of available storage to use for the V array, + * where "available storage" is defined as the minimum out of the + * RLIMIT_AS, RLIMIT_DATA. and RLIMIT_RSS resource limits (if any are + * set). If this value is set to 0 or more than 0.5 it will be treated + * as 0.5; and this value will never cause a limit of less than 1 MiB to + * be enforced. + * maxtime - maximum amount of CPU time to spend computing the derived keys, + * in seconds. This limit is only approximately enforced; the CPU + * performance is estimated and parameter limits are chosen accordingly. + * For the encryption functions, the parameters to the scrypt key derivation + * function are chosen to make the key as strong as possible subject to the + * specified limits; for the decryption functions, the parameters used are + * compared to the computed limits and an error is returned if decrypting + * the data would take too much memory or CPU time. + */ +/** + * Return codes from scrypt(enc|dec)_(buf|file): + * 0 success + * 1 getrlimit or sysctl(hw.usermem) failed + * 2 clock_getres or clock_gettime failed + * 3 error computing derived key + * 4 could not read salt from /dev/urandom + * 5 error in OpenSSL + * 6 malloc failed + * 7 data is not a valid scrypt-encrypted block + * 8 unrecognized scrypt format + * 9 decrypting file would take too much memory + * 10 decrypting file would take too long + * 11 password is incorrect + * 12 error writing output file + * 13 error reading input file + */ + +/** + * scryptenc_buf(inbuf, inbuflen, outbuf, passwd, passwdlen, + * maxmem, maxmemfrac, maxtime): + * Encrypt inbuflen bytes from inbuf, writing the resulting inbuflen + 128 + * bytes to outbuf. + */ +int scryptenc_buf(const uint8_t *, size_t, uint8_t *, + const uint8_t *, size_t, size_t, double, double); + +/** + * scryptdec_buf(inbuf, inbuflen, outbuf, outlen, passwd, passwdlen, + * maxmem, maxmemfrac, maxtime): + * Decrypt inbuflen bytes from inbuf, writing the result into outbuf and the + * decrypted data length to outlen. The allocated length of outbuf must + * be at least inbuflen. + */ +int scryptdec_buf(const uint8_t *, size_t, uint8_t *, size_t *, + const uint8_t *, size_t, size_t, double, double); + +/** + * scryptenc_file(infile, outfile, passwd, passwdlen, + * maxmem, maxmemfrac, maxtime): + * Read a stream from infile and encrypt it, writing the resulting stream to + * outfile. + */ +int scryptenc_file(FILE *, FILE *, const uint8_t *, size_t, + size_t, double, double); + +/** + * scryptdec_file(infile, outfile, passwd, passwdlen, + * maxmem, maxmemfrac, maxtime): + * Read a stream from infile and decrypt it, writing the resulting stream to + * outfile. + */ +int scryptdec_file(FILE *, FILE *, const uint8_t *, size_t, + size_t, double, double); + +#endif /* !_SCRYPTENC_H_ */ diff --git a/scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.c b/scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.c new file mode 100644 index 0000000..14d0d0a --- /dev/null +++ b/scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.c @@ -0,0 +1,192 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#include + +#include +#include +#include + +#include "crypto_scrypt.h" + +#include "scryptenc_cpuperf.h" + +#ifdef _WIN32 +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif + +#ifdef HAVE_CLOCK_GETTIME + +static clock_t clocktouse; + +static int +getclockres(double * resd) +{ + struct timespec res; + + /* + * Try clocks in order of preference until we find one which works. + * (We assume that if clock_getres works, clock_gettime will, too.) + * The use of if/else/if/else/if/else rather than if/elif/elif/else + * is ugly but legal, and allows us to #ifdef things appropriately. + */ +#ifdef CLOCK_VIRTUAL + if (clock_getres(CLOCK_VIRTUAL, &res) == 0) + clocktouse = CLOCK_VIRTUAL; + else +#endif +#ifdef CLOCK_MONOTONIC + if (clock_getres(CLOCK_MONOTONIC, &res) == 0) + clocktouse = CLOCK_MONOTONIC; + else +#endif + if (clock_getres(CLOCK_REALTIME, &res) == 0) + clocktouse = CLOCK_REALTIME; + else + return (-1); + + /* Convert clock resolution to a double. */ + *resd = res.tv_sec + res.tv_nsec * 0.000000001; + + return (0); +} + +static int +getclocktime(struct timespec * ts) +{ + + if (clock_gettime(clocktouse, ts)) + return (-1); + + return (0); +} + +#else +static int +getclockres(double * resd) +{ + + *resd = 1.0 / CLOCKS_PER_SEC; + + return (0); +} + +static int +getclocktime(struct timespec * ts) +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL)) + return (-1); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + + return (0); +} +#endif + +static int +getclockdiff(struct timespec * st, double * diffd) +{ + struct timespec en; + + if (getclocktime(&en)) + return (1); + *diffd = (en.tv_nsec - st->tv_nsec) * 0.000000001 + + (en.tv_sec - st->tv_sec); + + return (0); +} + +/** + * scryptenc_cpuperf(opps): + * Estimate the number of salsa20/8 cores which can be executed per second, + * and return the value via opps. + */ +int +scryptenc_cpuperf(double * opps) +{ + struct timespec st; + double resd, diffd; + uint64_t i = 0; + + /* Get the clock resolution. */ + if (getclockres(&resd)) + return (2); + +#ifdef DEBUG + fprintf(stderr, "Clock resolution is %f\n", resd); +#endif + + /* Loop until the clock ticks. */ + if (getclocktime(&st)) + return (2); + do { + /* Do an scrypt. */ + if (crypto_scrypt(NULL, 0, NULL, 0, 16, 1, 1, NULL, 0)) + return (3); + + /* Has the clock ticked? */ + if (getclockdiff(&st, &diffd)) + return (2); + if (diffd > 0) + break; + } while (1); + + /* Could how many scryps we can do before the next tick. */ + if (getclocktime(&st)) + return (2); + do { + /* Do an scrypt. */ + if (crypto_scrypt(NULL, 0, NULL, 0, 128, 1, 1, NULL, 0)) + return (3); + + /* We invoked the salsa20/8 core 512 times. */ + i += 512; + + /* Check if we have looped for long enough. */ + if (getclockdiff(&st, &diffd)) + return (2); + if (diffd > resd) + break; + } while (1); + +#ifdef DEBUG + fprintf(stderr, "%u salsa20/8 cores performed in %f seconds\n", + (uintmax_t)i, diffd); +#endif + + /* We can do approximately i salsa20/8 cores per diffd seconds. */ + *opps = i / diffd; + return (0); +} diff --git a/scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.h b/scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.h new file mode 100644 index 0000000..e236fff --- /dev/null +++ b/scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.h @@ -0,0 +1,39 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _SCRYPTENC_CPUPERF_H_ +#define _SCRYPTENC_CPUPERF_H_ + +/** + * scryptenc_cpuperf(opps): + * Estimate the number of salsa20/8 cores which can be executed per second, + * and return the value via opps. + */ +int scryptenc_cpuperf(double *); + +#endif /* !_SCRYPTENC_CPUPERF_H_ */ diff --git a/scrypt-1.1.6/lib/util/memlimit.c b/scrypt-1.1.6/lib/util/memlimit.c new file mode 100644 index 0000000..6268163 --- /dev/null +++ b/scrypt-1.1.6/lib/util/memlimit.c @@ -0,0 +1,343 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#include + +#ifndef _WIN32 +#include +#endif + +#ifdef _WIN32 +#define _WIN32_WINNT 0x0502 +#include +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYSCTL_HW_USERMEM +#include +#endif +#ifdef HAVE_SYS_SYSINFO_H +#include +#endif + +#include +#include +#include +#include + +#ifdef DEBUG +#include +#endif + +#include "memlimit.h" + +#ifdef HAVE_SYSCTL_HW_USERMEM +static int +memlimit_sysctl_hw_usermem(size_t * memlimit) +{ + int mib[2]; + uint8_t usermembuf[8]; + size_t usermemlen = 8; + uint64_t usermem; + + /* Ask the kernel how much RAM we have. */ + mib[0] = CTL_HW; + mib[1] = HW_USERMEM; + if (sysctl(mib, 2, usermembuf, &usermemlen, NULL, 0)) + return (1); + + /* + * Parse as either a uint64_t or a uint32_t based on the length of + * output the kernel reports having copied out. It appears that all + * systems providing a sysctl interface for reading integers copy + * them out as system-endian values, so we don't need to worry about + * parsing them. + */ + if (usermemlen == sizeof(uint64_t)) + usermem = *(uint64_t *)usermembuf; + else if (usermemlen == sizeof(uint32_t)) + usermem = *(uint32_t *)usermembuf; + else + return (1); + + /* Return the sysctl value, but clamp to SIZE_MAX if necessary. */ +#if UINT64_MAX > SIZE_MAX + if (usermem > SIZE_MAX) + *memlimit = SIZE_MAX; + else + *memlimit = usermem; +#else + *memlimit = usermem; +#endif + + /* Success! */ + return (0); +} +#endif + +/* If we don't HAVE_STRUCT_SYSINFO, we can't use sysinfo. */ +#ifndef HAVE_STRUCT_SYSINFO +#undef HAVE_SYSINFO +#endif + +/* If we don't HAVE_STRUCT_SYSINFO_TOTALRAM, we can't use sysinfo. */ +#ifndef HAVE_STRUCT_SYSINFO_TOTALRAM +#undef HAVE_SYSINFO +#endif + +#ifdef HAVE_SYSINFO +static int +memlimit_sysinfo(size_t * memlimit) +{ + struct sysinfo info; + uint64_t totalmem; + + /* Get information from the kernel. */ + if (sysinfo(&info)) + return (1); + totalmem = info.totalram; + + /* If we're on a modern kernel, adjust based on mem_unit. */ +#ifdef HAVE_STRUCT_SYSINFO_MEM_UNIT + totalmem = totalmem * info.mem_unit; +#endif + + /* Return the value, but clamp to SIZE_MAX if necessary. */ +#if UINT64_MAX > SIZE_MAX + if (totalmem > SIZE_MAX) + *memlimit = SIZE_MAX; + else + *memlimit = totalmem; +#else + *memlimit = totalmem; +#endif + + /* Success! */ + return (0); +} +#endif /* HAVE_SYSINFO */ + +#ifndef _WIN32 +static int +memlimit_rlimit(size_t * memlimit) +{ + struct rlimit rl; + uint64_t memrlimit; + + /* Find the least of... */ + memrlimit = (uint64_t)(-1); + + /* ... RLIMIT_AS... */ +#ifdef RLIMIT_AS + if (getrlimit(RLIMIT_AS, &rl)) + return (1); + if ((rl.rlim_cur != RLIM_INFINITY) && + ((uint64_t)rl.rlim_cur < memrlimit)) + memrlimit = rl.rlim_cur; +#endif + + /* ... RLIMIT_DATA... */ + if (getrlimit(RLIMIT_DATA, &rl)) + return (1); + if ((rl.rlim_cur != RLIM_INFINITY) && + ((uint64_t)rl.rlim_cur < memrlimit)) + memrlimit = rl.rlim_cur; + + /* ... and RLIMIT_RSS. */ +#ifdef RLIMIT_RSS + if (getrlimit(RLIMIT_RSS, &rl)) + return (1); + if ((rl.rlim_cur != RLIM_INFINITY) && + ((uint64_t)rl.rlim_cur < memrlimit)) + memrlimit = rl.rlim_cur; +#endif + + /* Return the value, but clamp to SIZE_MAX if necessary. */ +#if UINT64_MAX > SIZE_MAX + if (memrlimit > SIZE_MAX) + *memlimit = SIZE_MAX; + else + *memlimit = memrlimit; +#else + *memlimit = memrlimit; +#endif + + /* Success! */ + return (0); +} +#endif + +#ifdef _SC_PHYS_PAGES + +/* Some systems define _SC_PAGESIZE instead of _SC_PAGE_SIZE. */ +#ifndef _SC_PAGE_SIZE +#define _SC_PAGE_SIZE _SC_PAGESIZE +#endif + +static int +memlimit_sysconf(size_t * memlimit) +{ + long pagesize; + long physpages; + uint64_t totalmem; + + /* Set errno to 0 in order to distinguish "no limit" from "error". */ + errno = 0; + + /* Read the two limits. */ + if (((pagesize = sysconf(_SC_PAGE_SIZE)) == -1) || + ((physpages = sysconf(_SC_PHYS_PAGES)) == -1)) { + /* Did an error occur? */ + if (errno != 0) + return (1); + + /* If not, there is no limit. */ + totalmem = (uint64_t)(-1); + } else { + /* Compute the limit. */ + totalmem = (uint64_t)(pagesize) * (uint64_t)(physpages); + } + + /* Return the value, but clamp to SIZE_MAX if necessary. */ +#if UINT64_MAX > SIZE_MAX + if (totalmem > SIZE_MAX) + *memlimit = SIZE_MAX; + else + *memlimit = totalmem; +#else + *memlimit = totalmem; +#endif + + /* Success! */ + return (0); +} +#endif + +#ifdef _WIN32 +static int +memlimit_windows(size_t * memlimit) +{ + MEMORYSTATUSEX state; + state.dwLength = sizeof(state); + + if(!GlobalMemoryStatusEx (&state)) + return (1); + + + *memlimit = state.ullTotalPhys; + return (0); + +} +#endif + +int +memtouse(size_t maxmem, double maxmemfrac, size_t * memlimit) +{ + size_t sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit; + size_t sysconf_memlimit; + size_t memlimit_min; + size_t memavail; + size_t windows_memlimit; + + /* Get memory limits. */ +#ifdef HAVE_SYSCTL_HW_USERMEM + if (memlimit_sysctl_hw_usermem(&sysctl_memlimit)) + return (1); +#else + sysctl_memlimit = (size_t)(-1); +#endif +#ifdef HAVE_SYSINFO + if (memlimit_sysinfo(&sysinfo_memlimit)) + return (1); +#else + sysinfo_memlimit = (size_t)(-1); +#endif +#ifndef _WIN32 + if (memlimit_rlimit(&rlimit_memlimit)) + return (1); +#else + rlimit_memlimit=(size_t)(-1); +#endif +#ifdef _SC_PHYS_PAGES + if (memlimit_sysconf(&sysconf_memlimit)) + return (1); +#else + sysconf_memlimit = (size_t)(-1); +#endif +#ifdef _WIN32 + if (memlimit_windows(&windows_memlimit)) + return (1); +#else + windows_memlimit=(size_t)(-1); +#endif + +#ifdef DEBUG + fprintf(stderr, "Memory limits are %u %u %u %u %u\n", + sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit, + sysconf_memlimit, windows_memlimit); +#endif + + /* Find the smallest of them. */ + memlimit_min = (size_t)(-1); + if (memlimit_min > sysctl_memlimit) + memlimit_min = sysctl_memlimit; + if (memlimit_min > sysinfo_memlimit) + memlimit_min = sysinfo_memlimit; + if (memlimit_min > rlimit_memlimit) + memlimit_min = rlimit_memlimit; + if (memlimit_min > sysconf_memlimit) + memlimit_min = sysconf_memlimit; + if (memlimit_min > windows_memlimit) + memlimit_min = windows_memlimit; + + /* Only use the specified fraction of the available memory. */ + if ((maxmemfrac > 0.5) || (maxmemfrac == 0.0)) + maxmemfrac = 0.5; + memavail = maxmemfrac * memlimit_min; + + /* Don't use more than the specified maximum. */ + if ((maxmem > 0) && (memavail > maxmem)) + memavail = maxmem; + + /* But always allow at least 1 MiB. */ + if (memavail < 1048576) + memavail = 1048576; + +#ifdef DEBUG + fprintf(stderr, "Allowing up to %u memory to be used\n", memavail); +#endif + + /* Return limit via the provided pointer. */ + *memlimit = memavail; + return (0); +} diff --git a/scrypt-1.1.6/lib/util/memlimit.h b/scrypt-1.1.6/lib/util/memlimit.h new file mode 100644 index 0000000..d3b4891 --- /dev/null +++ b/scrypt-1.1.6/lib/util/memlimit.h @@ -0,0 +1,42 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _MEMLIMIT_H_ +#define _MEMLIMIT_H_ + +#include + +/** + * memtouse(maxmem, maxmemfrac, memlimit): + * Examine the system and return via memlimit the amount of RAM which should + * be used -- the specified fraction of the available RAM, but no more than + * maxmem, and no less than 1MiB. + */ +int memtouse(size_t, double, size_t *); + +#endif /* !_MEMLIMIT_H_ */ diff --git a/scrypt-1.1.6/lib/util/readpass.h b/scrypt-1.1.6/lib/util/readpass.h new file mode 100644 index 0000000..da57278 --- /dev/null +++ b/scrypt-1.1.6/lib/util/readpass.h @@ -0,0 +1,45 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _READPASS_H_ +#define _READPASS_H_ + +/** + * tarsnap_getpass(passwd, prompt, confirmprompt, devtty) + * If ${devtty} is non-zero, read a password from /dev/tty if possible; if + * not, read from stdin. If reading from a tty (either /dev/tty or stdin), + * disable echo and prompt the user by printing ${prompt} to stderr. If + * ${confirmprompt} is non-NULL, read a second password (prompting if a + * terminal is being used) and repeat until the user enters the same password + * twice. Return the password as a malloced NUL-terminated string via + * ${passwd}. The obscure name is to avoid namespace collisions due to the + * getpass / readpass / readpassphrase / etc. functions in various libraries. + */ +int tarsnap_readpass(char **, const char *, const char *, int); + +#endif /* !_READPASS_H_ */ diff --git a/scrypt-1.1.6/lib/util/sysendian.h b/scrypt-1.1.6/lib/util/sysendian.h new file mode 100644 index 0000000..62ef31a --- /dev/null +++ b/scrypt-1.1.6/lib/util/sysendian.h @@ -0,0 +1,140 @@ +/*- + * Copyright 2007-2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _SYSENDIAN_H_ +#define _SYSENDIAN_H_ + +#include "scrypt_platform.h" + +/* If we don't have be64enc, the we have isn't usable. */ +#if !HAVE_DECL_BE64ENC +#undef HAVE_SYS_ENDIAN_H +#endif + +#ifdef HAVE_SYS_ENDIAN_H + +#include + +#else + +#include + +static inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static inline uint64_t +be64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); +} + +static inline void +be64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + +static inline uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static inline uint64_t +le64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + + ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + + ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + + ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); +} + +static inline void +le64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; + p[4] = (x >> 32) & 0xff; + p[5] = (x >> 40) & 0xff; + p[6] = (x >> 48) & 0xff; + p[7] = (x >> 56) & 0xff; +} +#endif /* !HAVE_SYS_ENDIAN_H */ + +#endif /* !_SYSENDIAN_H_ */ diff --git a/scrypt-1.1.6/lib/util/warn.c b/scrypt-1.1.6/lib/util/warn.c new file mode 100644 index 0000000..504f935 --- /dev/null +++ b/scrypt-1.1.6/lib/util/warn.c @@ -0,0 +1,75 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#ifdef HAVE_ERR_H +/* + * Everything is provided through err.h and the associated library, so we + * don't need to do anything here. + */ +#else +#include +#include +#include +#include + +#include "warn.h" + +const char * warn_progname = "(null)"; + +void +warn(const char * fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "%s", warn_progname); + if (fmt != NULL) { + fprintf(stderr, ": "); + vfprintf(stderr, fmt, ap); + } + fprintf(stderr, ": %s\n", strerror(errno)); + va_end(ap); +} + +void +warnx(const char * fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "%s", warn_progname); + if (fmt != NULL) { + fprintf(stderr, ": "); + vfprintf(stderr, fmt, ap); + } + fprintf(stderr, "\n"); + va_end(ap); +} +#endif diff --git a/scrypt-1.1.6/lib/util/warn.h b/scrypt-1.1.6/lib/util/warn.h new file mode 100644 index 0000000..262d24b --- /dev/null +++ b/scrypt-1.1.6/lib/util/warn.h @@ -0,0 +1,13 @@ +#ifndef _WARN_H_ +#define _WARN_H_ + +#ifdef HAVE_ERR_H +#include +#else +#define NEED_WARN_PROGNAME +const char * warn_progname; +void warn(const char *, ...); +void warnx(const char *, ...); +#endif + +#endif /* !_WARN_H_ */ diff --git a/scrypt-1.1.6/scrypt_platform.h b/scrypt-1.1.6/scrypt_platform.h new file mode 100644 index 0000000..5cec236 --- /dev/null +++ b/scrypt-1.1.6/scrypt_platform.h @@ -0,0 +1,12 @@ +#ifndef _SCRYPT_PLATFORM_H_ +#define _SCRYPT_PLATFORM_H_ + +#if defined(CONFIG_H_FILE) +#include CONFIG_H_FILE +#elif defined(HAVE_CONFIG_H) +#include "config.h" +#else +#error Need either CONFIG_H_FILE or HAVE_CONFIG_H defined. +#endif + +#endif /* !_SCRYPT_PLATFORM_H_ */ diff --git a/scrypt.py b/scrypt.py new file mode 100644 index 0000000..d504400 --- /dev/null +++ b/scrypt.py @@ -0,0 +1,224 @@ +import imp +import os +import sys + +from ctypes import (cdll, + POINTER, pointer, + c_char_p, + c_size_t, c_double, c_int, c_uint64, c_uint32, + create_string_buffer) + +_scrypt = cdll.LoadLibrary(imp.find_module('_scrypt')[1]) + +_scryptenc_buf = _scrypt.exp_scryptenc_buf +_scryptenc_buf.argtypes = [c_char_p, # const uint_t *inbuf + c_size_t, # size_t inbuflen + c_char_p, # uint8_t *outbuf + c_char_p, # const uint8_t *passwd + c_size_t, # size_t passwdlen + c_size_t, # size_t maxmem + c_double, # double maxmemfrac + c_double, # double maxtime + ] +_scryptenc_buf.restype = c_int + +_scryptdec_buf = _scrypt.exp_scryptdec_buf +_scryptdec_buf.argtypes = [c_char_p, # const uint8_t *inbuf + c_size_t, # size_t inbuflen + c_char_p, # uint8_t *outbuf + POINTER(c_size_t), # size_t *outlen + c_char_p, # const uint8_t *passwd + c_size_t, # size_t passwdlen + c_size_t, # size_t maxmem + c_double, # double maxmemfrac + c_double, # double maxtime + ] +_scryptdec_buf.restype = c_int + +_crypto_scrypt = _scrypt.exp_crypto_scrypt +_crypto_scrypt.argtypes = [c_char_p, # const uint8_t *passwd + c_size_t, # size_t passwdlen + c_char_p, # const uint8_t *salt + c_size_t, # size_t saltlen + c_uint64, # uint64_t N + c_uint32, # uint32_t r + c_uint32, # uint32_t p + c_char_p, # uint8_t *buf + c_size_t, # size_t buflen + ] +_crypto_scrypt.restype = c_int + +ERROR_MESSAGES = ['success', + 'getrlimit or sysctl(hw.usermem) failed', + 'clock_getres or clock_gettime failed', + 'error computing derived key', + 'could not read salt from /dev/urandom', + 'error in OpenSSL', + 'malloc failed', + 'data is not a valid scrypt-encrypted block', + 'unrecognized scrypt format', + 'decrypting file would take too much memory', + 'decrypting file would take too long', + 'password is incorrect', + 'error writing output file', + 'error reading input file'] + +MAXMEM_DEFAULT = 0 +MAXMEMFRAC_DEFAULT = 0.5 +MAXTIME_DEFAULT = 300.0 +MAXTIME_DEFAULT_ENC = 5.0 + +IS_PY2 = sys.version_info < (3, 0, 0, 'final', 0) + + +class error(Exception): + def __init__(self, scrypt_code): + if isinstance(scrypt_code, int): + self._scrypt_code = scrypt_code + super(error, self).__init__(ERROR_MESSAGES[scrypt_code]) + else: + self._scrypt_code = -1 + super(error, self).__init__(scrypt_code) + + +def _ensure_bytes(data): + if IS_PY2 and isinstance(data, unicode): + raise TypeError('can not encrypt/decrypt unicode objects') + + if not IS_PY2 and isinstance(data, str): + return bytes(data, 'utf-8') + + return data + + +def encrypt(input, password, + maxtime=MAXTIME_DEFAULT_ENC, + maxmem=MAXMEM_DEFAULT, + maxmemfrac=MAXMEMFRAC_DEFAULT): + """ + Encrypt a string using a password. The resulting data will have len = + len(input) + 128. + + Notes for Python 2: + - `input` and `password` must be str instances + - The result will be a str instance + + Notes for Python 3: + - `input` and `password` can be both str and bytes. If they are str + instances, they will be encoded with utf-8 + - The result will be a bytes instance + + Exceptions raised: + - TypeError on invalid input + - scrypt.error if encryption failed + + For more information on the `maxtime`, `maxmem`, and `maxmemfrac` + parameters, see the scrypt documentation. + """ + + input = _ensure_bytes(input) + password = _ensure_bytes(password) + + outbuf = create_string_buffer(len(input) + 128) + result = _scryptenc_buf(input, len(input), + outbuf, + password, len(password), + maxmem, maxmemfrac, maxtime) + if result: + raise error(result) + + return outbuf.raw + + +def decrypt(input, password, + maxtime=MAXTIME_DEFAULT, + maxmem=MAXMEM_DEFAULT, + maxmemfrac=MAXMEMFRAC_DEFAULT, + encoding='utf-8'): + """ + Decrypt a string using a password. + + Notes for Python 2: + - `input` and `password` must be str instances + - The result will be a str instance + - The encoding parameter is ignored + + Notes for Python 3: + - `input` and `password` can be both str and bytes. If they are str + instances, they wil be encoded with utf-8. `input` *should* + really be a bytes instance, since that's what `encrypt` returns. + - The result will be a str instance encoded with `encoding`. + If encoding=None, the result will be a bytes instance. + + Exceptions raised: + - TypeError on invalid input + - scrypt.error if decryption failed + + For more information on the `maxtime`, `maxmem`, and `maxmemfrac` + parameters, see the scrypt documentation. + """ + + outbuf = create_string_buffer(len(input)) + outbuflen = pointer(c_size_t(0)) + + input = _ensure_bytes(input) + password = _ensure_bytes(password) + + result = _scryptdec_buf(input, len(input), + outbuf, outbuflen, + password, len(password), + maxmem, maxmemfrac, maxtime) + + if result: + raise error(result) + + out_bytes = outbuf.raw[:outbuflen.contents.value] + + if IS_PY2 or encoding is None: + return out_bytes + + return str(out_bytes, encoding) + + +def hash(password, salt, N=1 << 14, r=8, p=1, buflen=64): + """ + Compute scrypt(password, salt, N, r, p, buflen). + + The parameters r, p, and buflen must satisfy r * p < 2^30 and + buflen <= (2^32 - 1) * 32. The parameter N must be a power of 2 + greater than 1. N, r and p must all be positive. + + Notes for Python 2: + - `password` and `salt` must be str instances + - The result will be a str instance + + Notes for Python 3: + - `password` and `salt` can be both str and bytes. If they are str + instances, they wil be encoded with utf-8. + - The result will be a bytes instance + + Exceptions raised: + - TypeError on invalid input + - scrypt.error if scrypt failed + """ + + outbuf = create_string_buffer(buflen) + + password = _ensure_bytes(password) + salt = _ensure_bytes(salt) + + if r * p >= (1 << 30) or N <= 1 or (N & (N - 1)) != 0 or p < 1 or r < 1: + raise error('hash parameters are wrong (r*p should be < 2**30, and N should be a power of two > 1)') + + result = _crypto_scrypt(password, len(password), + salt, len(salt), + N, r, p, + outbuf, buflen) + + if result: + raise error('could not compute hash') + + return outbuf.raw + + +__all__ = ['error', 'encrypt', 'decrypt', 'hash'] diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..0190808 --- /dev/null +++ b/setup.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +from distutils.core import setup, Extension, Command + +import sys +import platform + +includes = [] +library_dirs = [] +cmdclasses = dict() +CFLAGS = [] + + +class Tester(Command): + """Runs unit tests""" + + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + if ((sys.version_info > (3, 2, 0, 'final', 0)) or + (sys.version_info > (2, 7, 0, 'final', 0) and sys.version_info < (3, 0, 0, 'final', 0))): + from unittest import TextTestRunner, defaultTestLoader + else: + try: + from unittest2 import TextTestRunner, defaultTestLoader + except ImportError: + print("Please install unittest2 to run the test suite") + exit(-1) + from tests import test_scrypt, test_scrypt_py2x, test_scrypt_py3x + suite = defaultTestLoader.loadTestsFromModule(test_scrypt) + suite.addTests(defaultTestLoader.loadTestsFromModule(test_scrypt_py2x)) + suite.addTests(defaultTestLoader.loadTestsFromModule(test_scrypt_py3x)) + runner = TextTestRunner() + result = runner.run(suite) + +cmdclasses['test'] = Tester + +if sys.platform.startswith('linux'): + define_macros = [('HAVE_CLOCK_GETTIME', '1'), + ('HAVE_LIBRT', '1'), + ('HAVE_POSIX_MEMALIGN', '1'), + ('HAVE_STRUCT_SYSINFO', '1'), + ('HAVE_STRUCT_SYSINFO_MEM_UNIT', '1'), + ('HAVE_STRUCT_SYSINFO_TOTALRAM', '1'), + ('HAVE_SYSINFO', '1'), + ('HAVE_SYS_SYSINFO_H', '1'), + ('_FILE_OFFSET_BITS', '64')] + libraries = ['crypto', 'rt'] + CFLAGS.append('-O2') +elif sys.platform.startswith('win32'): + define_macros = [] + library_dirs = ['c:\OpenSSL-Win32\lib\MinGW'] + libraries = ['eay32'] + includes = ['c:\OpenSSL-Win32\include'] +elif sys.platform.startswith('darwin') and platform.mac_ver()[0] < '10.6': + define_macros = [('HAVE_SYSCTL_HW_USERMEM', '1')] + libraries = ['crypto'] +else: + define_macros = [('HAVE_POSIX_MEMALIGN', '1'), + ('HAVE_SYSCTL_HW_USERMEM', '1')] + libraries = ['crypto'] + +scrypt_module = Extension('_scrypt', + sources=['src/scrypt.c', + 'scrypt-1.1.6/lib/crypto/crypto_aesctr.c', + 'scrypt-1.1.6/lib/crypto/crypto_scrypt-nosse.c', + 'scrypt-1.1.6/lib/crypto/sha256.c', + 'scrypt-1.1.6/lib/scryptenc/scryptenc.c', + 'scrypt-1.1.6/lib/scryptenc/scryptenc_cpuperf.c', + 'scrypt-1.1.6/lib/util/memlimit.c', + 'scrypt-1.1.6/lib/util/warn.c'], + include_dirs=['scrypt-1.1.6', + 'scrypt-1.1.6/lib', + 'scrypt-1.1.6/lib/scryptenc', + 'scrypt-1.1.6/lib/crypto', + 'scrypt-1.1.6/lib/util'] + includes, + define_macros=[('HAVE_CONFIG_H', None)] + define_macros, + extra_compile_args=CFLAGS, + library_dirs=library_dirs, + libraries=libraries) + +setup(name='scrypt', + version='0.6.1', + description='Bindings for the scrypt key derivation function library', + author='Magnus Hallin', + author_email='mhallin@gmail.com', + url='http://bitbucket.org/mhallin/py-scrypt', + py_modules=['scrypt'], + ext_modules=[scrypt_module], + classifiers=['Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Topic :: Security :: Cryptography', + 'Topic :: Software Development :: Libraries'], + license='2-clause BSD', + long_description=open('README.rst').read(), + cmdclass=cmdclasses) diff --git a/src/scrypt.c b/src/scrypt.c new file mode 100644 index 0000000..69d6816 --- /dev/null +++ b/src/scrypt.c @@ -0,0 +1,74 @@ +/*- + * Copyright 2010 Magnus Hallin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include + +#include "scryptenc.h" +#include "crypto_scrypt.h" + +#if !defined(DL_EXPORT) + +#if defined(HAVE_DECLSPEC_DLL) +#define DL_EXPORT(type) __declspec(dllexport) type +#else +#define DL_EXPORT(type) type +#endif + +#endif + + +/* Exported trampolines */ +DL_EXPORT(int) exp_scryptenc_buf(const uint8_t *inbuf, size_t inbuflen, + uint8_t *outbuf, + const uint8_t *passwd, size_t passwdlen, + size_t maxmem, double maxmemfrac, double maxtime) { + return scryptenc_buf(inbuf, inbuflen, outbuf, passwd, passwdlen, + maxmem, maxmemfrac, maxtime); +} + +DL_EXPORT(int) exp_scryptdec_buf(const uint8_t *inbuf, size_t inbuflen, + uint8_t *outbuf, size_t *outbuflen, + const uint8_t *passwd, size_t passwdlen, + size_t maxmem, double maxmemfrac, double maxtime) { + return scryptdec_buf(inbuf, inbuflen, outbuf, outbuflen, passwd, passwdlen, + maxmem, maxmemfrac, maxtime); +} + +DL_EXPORT(int) exp_crypto_scrypt(const uint8_t *passwd, size_t passwdlen, + const uint8_t *salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, + uint8_t *buf, size_t buflen) { + return crypto_scrypt(passwd, passwdlen, salt, saltlen, + N, r, p, buf, buflen); +} + +/* + We need a stub init_scrypt function so the module will link as a proper module. + + Do not import _scrypt from python; it will not work since _scrypt is not a *real* module +*/ +PyMODINIT_FUNC init_scrypt(void) { } +PyMODINIT_FUNC PyInit__scrypt(void) { } diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/ciphertexts.csv b/tests/ciphertexts.csv new file mode 100644 index 0000000..7594dd4 --- /dev/null +++ b/tests/ciphertexts.csv @@ -0,0 +1,6 @@ +input,password,maxtime,maxmem,maxmemfrac,ciphertext +message,password,0.01,0,0.0625,736372797074000a00000008000000019f6d3fe5e9423a12d330e35089befdfbb476c7d4faea91492a2561f942c1599701aba424220218b9f81812df06d7cf2a281fd0fdbc7c9d978c335bf5209b1062ee2e49993c4d3a37d347ad6bf0eaecc2fe579a6f320b0acf475882c222c0ba34a7ac5379bedc82358bb3f736ea31d4b824e8bc95c75579 +message,password,5.0000,0.0000,0.1250,736372797074000a00000008000000cb974d55992fea307caa3593205c8851cd56b3ddfd241ee7b1c075cfd2e2f871dddcee71b6bc2b6b075caa1699ea58ce32e9fcd802b18069828201692380574e23e84c2d39d6a951c9c2401dea1a0fa44195b01fca9332f7aac223c84251c69a28037788e09cf297a003a62e2e7c5b6f039e3c1d21fa5da6 +message,password,0.5000,0.0000,0.0625,736372797074000a00000008000000141429bb22aef840e1dde29564dada8f2a77fc2855fe8c9e27e5bf5df4a0eec330344e8471bf83e2466a28acc9d1813a3e50e64697fb8e9c7c17954950f16a5b78fe114d8b147c5936802fe52b17f83e6da9de884257f2a938aa37c2e92b1c33cd9afd0f5e91baba29be4b1c0709bd2a31a4c52394f9b0d4 +message,password,0.5000,0.0000,0.1250,736372797074000a0000000800000014e9baa49b57b2e5b561df54121d870532714f063f295c15ca48e32b677e8e11126ab8da24683951749a19eede36ea3768cb01e8eda6c0f570db7051e07e99d2d687ce28f96aa2e6afa8a0a8c5d902c847e041e14435a22d873c4e676f7a7f5ab9107171b583d02724c056707640931a3c160b9e0ef87bae +message,password,0.5000,10485760.0000,0.1250,736372797074000a0000000800000014e53c55cd89b6e2de639c1621d92e79212e5f4fc793387435486427eb8adeb192382b5b6397f98ac66fa528a13cba01bd611082369fe1e2244a01ba8329ff6fcaa2db5e87fb75683ae6fc636d873c2e004a0209b947c7b8e805174d65ec0ac2cb597baadae6cf092c33a5096590860b51570faa89e39bf0 \ No newline at end of file diff --git a/tests/hashvectors.csv b/tests/hashvectors.csv new file mode 100644 index 0000000..bcf6b40 --- /dev/null +++ b/tests/hashvectors.csv @@ -0,0 +1,5 @@ +password,salt,n,r,p,hexhash +,,16,1,1,77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906 +password,NaCl,1024,8,16,fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640 +pleaseletmein,SodiumChloride,16384,8,1,7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887 +pleaseletmein,SodiumChloride,32768,16,4,cbc397a9b5f5a53048c5b9f039ee1246d9532c8089fb346a4ab47cd0701febf18652b1ee042e070d1b6c631c43fd05ececd5b165ee1c2ffc1a2e98406fc2cd52 \ No newline at end of file diff --git a/tests/test_scrypt.py b/tests/test_scrypt.py new file mode 100644 index 0000000..4c5a207 --- /dev/null +++ b/tests/test_scrypt.py @@ -0,0 +1,285 @@ +# -*- coding: utf-8 -*- + +from os import urandom +from os.path import dirname, abspath, sep +from sys import version_info +from csv import reader +from binascii import a2b_hex, b2a_hex +import base64 +import json + +if ((version_info > (3, 2, 0, 'final', 0)) or + (version_info > (2, 7, 0, 'final', 0) and version_info < (3, 0, 0, 'final', 0))): + import unittest as testm +else: + try: + import unittest2 as testm + except ImportError: + print("Please install unittest2 to run the test suite") + exit(-1) + +import scrypt + + +class TestScrypt(testm.TestCase): + + def setUp(self): + self.input = "message" + self.password = "password" + self.longinput = str(urandom(100000)) + self.five_minutes = 300.0 + self.five_seconds = 5.0 + self.one_byte = 1 # in Bytes + self.one_megabyte = 1024 * 1024 # in Bytes + self.ten_megabytes = 10 * self.one_megabyte + base_dir = dirname(abspath(__file__)) + sep + cvf = open(base_dir + "ciphertexts.csv", "r") + ciphertxt_reader = reader(cvf, dialect="excel") + self.ciphertexts = [] + for row in ciphertxt_reader: + self.ciphertexts.append(row) + cvf.close() + self.ciphertext = a2b_hex(bytes(self.ciphertexts[1][5].encode('ascii'))) + + def test_encrypt_decrypt(self): + """Test encrypt for simple encryption and decryption""" + s = scrypt.encrypt(self.input, self.password, 0.1) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt(self): + """Test encrypt takes input and password strings as + positional arguments and produces ciphertext""" + s = scrypt.encrypt(self.input, self.password) + self.assertEqual(len(s), 128 + len(self.input)) + + def test_encrypt_input_and_password_as_keywords(self): + """Test encrypt for input and password accepted as keywords""" + s = scrypt.encrypt(password=self.password, input=self.input) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt_missing_input_keyword_argument(self): + """Test encrypt raises TypeError if keyword argument missing input""" + self.assertRaises(TypeError, lambda: scrypt.encrypt(password=self.password)) + + def test_encrypt_missing_password_positional_argument(self): + """Test encrypt raises TypeError if second positional argument missing + (password)""" + self.assertRaises(TypeError, lambda: scrypt.encrypt(self.input)) + + def test_encrypt_missing_both_required_positional_arguments(self): + """Test encrypt raises TypeError if both positional arguments missing + (input and password)""" + self.assertRaises(TypeError, lambda: scrypt.encrypt()) + + def test_encrypt_maxtime_positional(self): + """Test encrypt maxtime accepts maxtime at position 3""" + s = scrypt.encrypt(self.input, self.password, 0.01) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt_maxtime_key(self): + """Test encrypt maxtime accepts maxtime as keyword argument""" + s = scrypt.encrypt(self.input, self.password, maxtime=0.01) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt_maxmem_positional(self): + """Test encrypt maxmem accepts 4th positional argument and exactly + (1 megabyte) of storage to use for V array""" + s = scrypt.encrypt(self.input, self.password, 0.01, self.one_megabyte) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt_maxmem_undersized(self): + """Test encrypt maxmem accepts (< 1 megabyte) of storage to use for V array""" + s = scrypt.encrypt(self.input, self.password, 0.01, self.one_byte) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt_maxmem_in_normal_range(self): + """Test encrypt maxmem accepts (> 1 megabyte) of storage to use for V array""" + s = scrypt.encrypt(self.input, + self.password, + 0.01, + self.ten_megabytes) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt_maxmem_keyword_argument(self): + """Test encrypt maxmem accepts exactly (1 megabyte) of storage to use for + V array""" + s = scrypt.encrypt(self.input, + self.password, + maxmem=self.one_megabyte, + maxtime=0.01) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt_maxmemfrac_positional(self): + """Test encrypt maxmemfrac accepts 5th positional argument of 1/16 total + memory for V array""" + s = scrypt.encrypt(self.input, self.password, 0.01, 0, 0.0625) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt_maxmemfrac_keyword_argument(self): + """Test encrypt maxmemfrac accepts keyword argument of 1/16 total memory for + V array""" + s = scrypt.encrypt(self.input, self.password, maxmemfrac=0.0625, + maxtime=0.01) + m = scrypt.decrypt(s, self.password) + self.assertEqual(m, self.input) + + def test_encrypt_long_input(self): + """Test encrypt accepts long input for encryption""" + s = scrypt.encrypt(self.longinput, self.password, 0.1) + self.assertEqual(len(s), 128 + len(self.longinput)) + + def test_encrypt_raises_error_on_invalid_keyword(self): + """Test encrypt raises TypeError if invalid keyword used in argument""" + self.assertRaises(TypeError, lambda: scrypt.encrypt(self.input, + self.password, nonsense="Raise error")) + + def test_decrypt_from_csv_ciphertexts(self): + """Test decrypt function with precalculated combinations""" + for row in self.ciphertexts[1:]: + h = scrypt.decrypt(a2b_hex(bytes(row[5].encode('ascii'))), row[1]) + self.assertEqual(bytes(h.encode("ascii")), row[0].encode("ascii")) + + def test_decrypt_maxtime_positional(self): + """Test decrypt function accepts third positional argument""" + m = scrypt.decrypt(self.ciphertext, self.password, self.five_seconds) + self.assertEqual(m, self.input) + + def test_decrypt_maxtime_keyword_argument(self): + """Test decrypt function accepts maxtime keyword argument""" + m = scrypt.decrypt(maxtime=1.0, input=self.ciphertext, password=self.password) + self.assertEqual(m, self.input) + + def test_decrypt_maxmem_positional(self): + """Test decrypt function accepts fourth positional argument""" + m = scrypt.decrypt(self.ciphertext, self.password, self.five_minutes, self.ten_megabytes) + self.assertEqual(m, self.input) + + def test_decrypt_maxmem_keyword_argument(self): + """Test decrypt function accepts maxmem keyword argument""" + m = scrypt.decrypt(maxmem=self.ten_megabytes, input=self.ciphertext, password=self.password) + self.assertEqual(m, self.input) + + def test_decrypt_maxmemfrac_positional(self): + """Test decrypt function accepts maxmem keyword argument""" + m = scrypt.decrypt(self.ciphertext, self.password, self.five_minutes, self.one_megabyte, 0.0625) + self.assertEqual(m, self.input) + + def test_decrypt_maxmemfrac_keyword_argument(self): + """Test decrypt function accepts maxmem keyword argument""" + m = scrypt.decrypt(maxmemfrac=0.625, input=self.ciphertext, password=self.password) + self.assertEqual(m, self.input) + + def test_decrypt_raises_error_on_too_little_time(self): + """Test decrypt function raises scrypt.error raised if insufficient time allowed for + ciphertext decryption""" + s = scrypt.encrypt(self.input, self.password, 0.1) + self.assertRaises(scrypt.error, + lambda: scrypt.decrypt(s, self.password, .01)) + + +class TestScryptHash(testm.TestCase): + + def setUp(self): + self.input = "message" + self.password = "password" + self.salt = "NaCl" + self.hashes = [] + base_dir = dirname(abspath(__file__)) + sep + hvf = open(base_dir + "hashvectors.csv", "r") + hash_reader = reader(hvf, dialect="excel") + for row in hash_reader: + self.hashes.append(row) + hvf.close() + + def test_hash_vectors_from_csv(self): + """Test hash function with precalculated combinations""" + for row in self.hashes[1:]: + h = scrypt.hash(row[0], row[1], int(row[2]), int(row[3]), int(row[4])) + hhex = b2a_hex(h) + self.assertEqual(hhex, bytes(row[5].encode("utf-8"))) + + def test_hash_buflen_keyword(self): + """Test hash takes keyword valid buflen""" + h64 = scrypt.hash(self.input, self.salt, buflen=64) + h128 = scrypt.hash(self.input, self.salt, buflen=128) + self.assertEqual(len(h64), 64) + self.assertEqual(len(h128), 128) + + def test_hash_n_positional(self): + """Test hash accepts valid N in position 3""" + h = scrypt.hash(self.input, self.salt, 256) + self.assertEqual(len(h), 64) + + def test_hash_n_keyword(self): + """Test hash takes keyword valid N""" + h = scrypt.hash(N=256, password=self.input, salt=self.salt) + self.assertEqual(len(h), 64) + + def test_hash_r_positional(self): + """Test hash accepts valid r in position 4""" + h = scrypt.hash(self.input, self.salt, 256, 16) + self.assertEqual(len(h), 64) + + def test_hash_r_keyword(self): + """Test hash takes keyword valid r""" + h = scrypt.hash(r=16, password=self.input, salt=self.salt) + self.assertEqual(len(h), 64) + + def test_hash_p_positional(self): + """Test hash accepts valid p in position 5""" + h = scrypt.hash(self.input, self.salt, 256, 8, 2) + self.assertEqual(len(h), 64) + + def test_hash_p_keyword(self): + """Test hash takes keyword valid p""" + h = scrypt.hash(p=4, password=self.input, salt=self.salt) + self.assertEqual(len(h), 64) + + def test_hash_raises_error_on_p_equals_zero(self): + """Test hash raises scrypt error on illegal parameter value (p = 0)""" + self.assertRaises(scrypt.error, + lambda: scrypt.hash(self.input, self.salt, p=0)) + + def test_hash_raises_error_on_negative_p(self): + """Test hash raises scrypt error on illegal parameter value (p < 0)""" + self.assertRaises(scrypt.error, + lambda: scrypt.hash(self.input, self.salt, p=-1)) + + def test_hash_raises_error_on_r_equals_zero(self): + """Test hash raises scrypt error on illegal parameter value (r = 0)""" + self.assertRaises(scrypt.error, + lambda: scrypt.hash(self.input, self.salt, r=0)) + + def test_hash_raises_error_on_negative_r(self): + """Test hash raises scrypt error on illegal parameter value (r < 1)""" + self.assertRaises(scrypt.error, + lambda: scrypt.hash(self.input, self.salt, r=-1)) + + def test_hash_raises_error_r_p_over_limit(self): + """Test hash raises scrypt error when parameters r multiplied by p over limit 2**30""" + self.assertRaises(scrypt.error, + lambda: scrypt.hash(self.input, self.salt, r=2, p=2 ** 29)) + + def test_hash_raises_error_n_not_power_of_two(self): + """Test hash raises scrypt error when parameter N is not a power of two {2, 4, 8, 16, etc}""" + self.assertRaises(scrypt.error, + lambda: scrypt.hash(self.input, self.salt, N=3)) + + def test_hash_raises_error_n_under_limit(self): + """Test hash raises scrypt error when parameter N under limit of 1""" + self.assertRaises(scrypt.error, + lambda: scrypt.hash(self.input, self.salt, N=1)) + self.assertRaises(scrypt.error, + lambda: scrypt.hash(self.input, self.salt, N=-1)) + +if __name__ == "__main__": + testm.main() diff --git a/tests/test_scrypt_py2x.py b/tests/test_scrypt_py2x.py new file mode 100644 index 0000000..811cf37 --- /dev/null +++ b/tests/test_scrypt_py2x.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +from sys import version_info + +if ((version_info > (3, 2, 0, 'final', 0)) or + (version_info > (2, 7, 0, 'final', 0) and version_info < (3, 0, 0, 'final', 0))): + import unittest as testm +else: + try: + import unittest2 as testm + except ImportError: + print("Please install unittest2 to run the test suite") + exit(-1) + +import scrypt + + +@testm.skipIf(version_info > (3, 0, 0, 'final', 0), "Tests for Python 2 only") +class TestScryptForPython2(testm.TestCase): + + def setUp(self): + self.input = "message" + self.password = "password" + self.unicode_text = '\xe1\x93\x84\xe1\x93\x87\xe1\x95\x97\xe1\x92\xbb\xe1\x92\xa5\xe1\x90\x85\xe1\x91\xa6'.decode('utf-8') + + def test_py2_encrypt_fails_on_unicode_input(self): + """Test Py2 encrypt raises TypeError when Unicode input passed""" + self.assertRaises(TypeError, lambda: scrypt.encrypt(self.unicode_text, self.password)) + + def test_py2_encrypt_fails_on_unicode_password(self): + """Test Py2 encrypt raises TypeError when Unicode password passed""" + self.assertRaises(TypeError, lambda: scrypt.encrypt(self.input, self.unicode_text)) + + def test_py2_encrypt_returns_string(self): + """Test Py2 encrypt returns str""" + e = scrypt.encrypt(self.input, self.password, 0.1) + self.assertTrue(isinstance(e, str)) + + def test_py2_decrypt_returns_string(self): + """Test Py2 decrypt returns str""" + s = scrypt.encrypt(self.input, self.password, 0.1) + m = scrypt.decrypt(s, self.password) + self.assertTrue(isinstance(m, str)) + + def test_py2_hash_returns_string(self): + """Test Py2 hash return str""" + h = scrypt.hash(self.input, self.password) + self.assertTrue(isinstance(h, str)) + +if __name__ == "__main__": + testm.main() diff --git a/tests/test_scrypt_py3x.py b/tests/test_scrypt_py3x.py new file mode 100644 index 0000000..e03e098 --- /dev/null +++ b/tests/test_scrypt_py3x.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +from sys import version_info + +if ((version_info > (3, 2, 0, 'final', 0)) or + (version_info > (2, 7, 0, 'final', 0) and version_info < (3, 0, 0, 'final', 0))): + import unittest as testm +else: + try: + import unittest2 as testm + except ImportError: + print("Please install unittest2 to run the test suite") + exit(-1) + +import scrypt + + +@testm.skipIf(version_info < (3, 0, 0, 'final', 0), "Tests for Python 3 only") +class TestScryptForPy3(testm.TestCase): + + def setUp(self): + self.input = "message" + self.password = "password" + self.byte_text = b'\xe1\x93\x84\xe1\x93\x87\xe1\x95\x97\xe1\x92\xbb\xe1\x92\xa5\xe1\x90\x85\xe1\x91\xa6' + self.unicode_text = self.byte_text.decode('utf-8', "strict") + + def test_py3_encrypt_allows_bytes_input(self): + """Test Py3 encrypt allows unicode input""" + s = scrypt.encrypt(self.byte_text, self.password, 0.1) + m = scrypt.decrypt(s, self.password) + self.assertEqual(bytes(m.encode("utf-8")), self.byte_text) + + def test_py3_encrypt_allows_bytes_password(self): + """Test Py3 encrypt allows unicode password""" + s = scrypt.encrypt(self.input, self.byte_text, 0.1) + m = scrypt.decrypt(s, self.byte_text) + self.assertEqual(m, self.input) + + def test_py3_encrypt_returns_bytes(self): + """Test Py3 encrypt return bytes""" + s = scrypt.encrypt(self.input, self.password, 0.1) + self.assertTrue(isinstance(s, bytes)) + + def test_py3_decrypt_returns_unicode_string(self): + """Test Py3 decrypt returns Unicode UTF-8 string""" + s = scrypt.encrypt(self.input, self.password, 0.1) + m = scrypt.decrypt(s, self.password) + self.assertTrue(isinstance(m, str)) + + def test_py3_hash_returns_bytes(self): + """Test Py3 hash return bytes""" + h = scrypt.hash(self.input, self.password) + self.assertTrue(isinstance(h, bytes)) + +if __name__ == "__main__": + testm.main() -- cgit v1.2.3