Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • cebash/sakia
  • santiago/sakia
  • jonas/sakia
3 results
Show changes
Showing
with 0 additions and 3023 deletions
#!/usr/bin/env python
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Modular Crypt Format support for scrypt
Compatible with libscrypt scrypt_mcf_check also supports the $7$ format.
libscrypt format:
$s1$NNrrpp$salt$hash
NN - hex encoded N log2 (two hex digits)
rr - hex encoded r in 1-255
pp - hex encoded p in 1-255
salt - base64 encoded salt 1-16 bytes decoded
hash - base64 encoded 64-byte scrypt hash
$7$ format:
$7$Nrrrrrpppppsalt$hash
N - crypt base64 N log2
rrrrr - crypt base64 r (little-endian 30 bits)
ppppp - crypt base64 p (little-endian 30 bits)
salt - raw salt (0-43 bytes that should be limited to crypt base64)
hash - crypt base64 encoded 32-byte scrypt hash (43 bytes)
(crypt base64 is base64 with the alphabet: ./0-9A-Za-z)
When reading, we are more lax, allowing salts and hashes to be longer and
incorrectly encoded, since the worst that can happen is that the password does
not verify.
"""
import base64, binascii
import os
import struct
from .common import *
def _scrypt_mcf_encode_s1(N, r, p, salt, hash):
h64 = base64.b64encode(hash)
s64 = base64.b64encode(salt)
t = 1
while 2**t < N:
t += 1
params = p + (r << 8) + (t << 16)
return (
b'$s1' +
('$%06x' % params).encode() +
b'$' + s64 +
b'$' + h64
)
def _b64decode(b64):
for b in (b64, b64 + b'=', b64 + b'=='):
try:
return base64.b64decode(b)
except (TypeError, binascii.Error):
pass
raise ValueError('Incorrect base64 in MCF')
def _scrypt_mcf_decode_s1(mcf):
s = mcf.split(b'$')
if not (mcf.startswith(b'$s1$') and len(s) == 5):
return None
params, s64, h64 = s[2:]
params = base64.b16decode(params, True)
salt = _b64decode(s64)
hash = _b64decode(h64)
if len(params) != 3:
raise ValueError('Unrecognized MCF parameters')
t, r, p = struct.unpack('3B', params)
N = 2 ** t
return N, r, p, salt, hash, len(hash)
# Crypt base 64
_cb64 = b'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
_cb64a = bytearray(_cb64)
_icb64 = (
[None] * 46 +
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, None, None, None, None, None,
None, None, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, None, None, None,
None, None, None, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
] +
[None] * 133
)
def _cb64enc(arr):
arr = bytearray(arr)
out = bytearray()
val = bits = pos = 0
for b in arr:
val += b << bits
bits += 8
while bits >= 0:
out.append(_cb64a[val & 0x3f])
bits -= 6
val = val >> 6
return bytes(out)
def _scrypt_mcf_encode_7(N, r, p, salt, hash):
t = 1
while 2**t < N:
t += 1
return (
b'$7$' +
# N
_cb64[t::64] +
# r
_cb64[r & 0x3f::64] + _cb64[(r >> 6) & 0x3f::64] +
_cb64[(r >> 12) & 0x3f::64] + _cb64[(r >> 18) & 0x3f::64] +
_cb64[(r >> 24) & 0x3f::64] +
# p
_cb64[p & 0x3f::64] + _cb64[(p >> 6) & 0x3f::64] +
_cb64[(p >> 12) & 0x3f::64] + _cb64[(p >> 18) & 0x3f::64] +
_cb64[(p >> 24) & 0x3f::64] +
# rest
salt +
b'$' + _cb64enc(hash)
)
def _cb64dec(arr):
out = bytearray()
val = bits = pos = 0
for b in arr:
val += _icb64[b] << bits
bits += 6
if bits >= 8:
out.append(val & 0xff)
bits -= 8
val >>= 8
return out
def _scrypt_mcf_decode_7(mcf):
s = mcf.split(b'$')
if not (mcf.startswith(b'$7$') and len(s) == 4):
return None
s64 = bytearray(s[2])
h64 = bytearray(s[3])
try:
N = 2 ** _icb64[s64[0]]
r = (_icb64[s64[1]] + (_icb64[s64[2]] << 6) + (_icb64[s64[3]] << 12) +
(_icb64[s64[4]] << 18) + (_icb64[s64[5]] << 24))
p = (_icb64[s64[6]] + (_icb64[s64[7]] << 6) + (_icb64[s64[8]] << 12) +
(_icb64[s64[9]] << 18) + (_icb64[s64[10]] << 24))
salt = bytes(s64[11:])
hash = bytes(_cb64dec(h64))
except (IndexError, TypeError):
raise ValueError('Unrecognized MCF format')
return N, r, p, salt, hash, len(hash)
def _scrypt_mcf_7_is_standard(mcf):
params = _scrypt_mcf_decode_7(mcf)
if params is None:
return False
N, r, p, salt, hash, hlen = params
return len(salt) == 43 and hlen == 32
def _scrypt_mcf_decode(mcf):
params = _scrypt_mcf_decode_s1(mcf)
if params is None:
params = _scrypt_mcf_decode_7(mcf)
if params is None:
raise ValueError('Unrecognized MCF hash')
return params
def scrypt_mcf(scrypt, password, salt=None, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p,
prefix=SCRYPT_MCF_PREFIX_DEFAULT):
"""Derives a Modular Crypt Format hash using the scrypt KDF given
Expects the signature:
scrypt(password, salt, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p, olen=64)
If no salt is given, a random salt of 128+ bits is used. (Recommended.)
"""
if salt is not None and not (1 <= len(salt) <= 16):
raise ValueError('salt must be 1-16 bytes')
if r > 255:
raise ValueError('scrypt_mcf r out of range [1,255]')
if p > 255:
raise ValueError('scrypt_mcf p out of range [1,255]')
if N > 2**31:
raise ValueError('scrypt_mcf N out of range [2,2**31]')
if b'\0' in password:
raise ValueError('scrypt_mcf password must not contain zero bytes')
if prefix == SCRYPT_MCF_PREFIX_s1:
if salt is None:
salt = os.urandom(16)
hash = scrypt(password, salt, N, r, p)
return _scrypt_mcf_encode_s1(N, r, p, salt, hash)
elif prefix == SCRYPT_MCF_PREFIX_7 or prefix == SCRYPT_MCF_PREFIX_ANY:
if salt is None:
salt = os.urandom(32)
salt = _cb64enc(salt)
hash = scrypt(password, salt, N, r, p, 32)
return _scrypt_mcf_encode_7(N, r, p, salt, hash)
else:
raise ValueError("Unrecognized MCF format")
def scrypt_mcf_check(scrypt, mcf, password):
"""Returns True if the password matches the given MCF hash
Supports both the libscrypt $s1$ format and the $7$ format.
"""
if not isinstance(mcf, bytes):
raise TypeError
if not isinstance(password, bytes):
raise TypeError
N, r, p, salt, hash, hlen = _scrypt_mcf_decode(mcf)
h = scrypt(password, salt, N=N, r=r, p=p, olen=hlen)
return hash == h
#!/usr/bin/env python
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""PBKDF2 in pure Python, compatible with Python3.4 hashlib.pbkdf2_hmac"""
import hashlib
import hmac
import struct
from .common import *
def pbkdf2_hmac(name, password, salt, rounds, dklen=None):
"""Returns the result of the Password-Based Key Derivation Function 2"""
h = hmac.new(key=password, digestmod=lambda d=b'': hashlib.new(name, d))
hs = h.copy()
hs.update(salt)
blocks = bytearray()
dklen = hs.digest_size if dklen is None else dklen
block_count, last_size = divmod(dklen, hs.digest_size)
block_count += last_size > 0
for block_number in xrange(1, block_count + 1):
hb = hs.copy()
hb.update(struct.pack('>L', block_number))
U = bytearray(hb.digest())
if rounds > 1:
Ui = U
for i in xrange(rounds - 1):
hi = h.copy()
hi.update(Ui)
Ui = bytearray(hi.digest())
for j in xrange(hs.digest_size):
U[j] ^= Ui[j]
blocks.extend(U)
if last_size:
del blocks[dklen:]
return bytes(blocks)
if __name__ == "__main__":
import sys
from . import tests
tests.run_pbkdf2_suite(sys.modules[__name__])
#!/usr/bin/env python
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Scrypt implementation that calls into system libscrypt"""
import base64
import ctypes, ctypes.util
from ctypes import c_char_p, c_size_t, c_uint64, c_uint32
import os
from .common import *
from . import mcf as mcf_mod
_libscrypt_soname = ctypes.util.find_library('scrypt')
if _libscrypt_soname is None:
raise ImportError('Unable to find libscrypt')
try:
_libscrypt = ctypes.CDLL(_libscrypt_soname)
_libscrypt_scrypt = _libscrypt.libscrypt_scrypt
_libscrypt_mcf = _libscrypt.libscrypt_mcf
_libscrypt_check = _libscrypt.libscrypt_check
except OSError:
raise ImportError('Unable to load libscrypt: ' + _libscrypt_soname)
except AttributeError:
raise ImportError('Incompatible libscrypt: ' + _libscrypt_soname)
_libscrypt_scrypt.argtypes = [
c_char_p, # password
c_size_t, # password length
c_char_p, # salt
c_size_t, # salt length
c_uint64, # N
c_uint32, # r
c_uint32, # p
c_char_p, # out
c_size_t, # out length
]
_libscrypt_mcf.argtypes = [
c_uint64, # N
c_uint32, # r
c_uint32, # p
c_char_p, # salt
c_char_p, # hash
c_char_p, # out (125+ bytes)
]
_libscrypt_check.argtypes = [
c_char_p, # mcf (modified)
c_char_p, # hash
]
def scrypt(password, salt, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p, olen=64):
"""Returns a key derived using the scrypt key-derivarion function
N must be a power of two larger than 1 but no larger than 2 ** 63 (insane)
r and p must be positive numbers such that r * p < 2 ** 30
The default values are:
N -- 2**14 (~16k)
r -- 8
p -- 1
Memory usage is proportional to N*r. Defaults require about 16 MiB.
Time taken is proportional to N*p. Defaults take <100ms of a recent x86.
The last one differs from libscrypt defaults, but matches the 'interactive'
work factor from the original paper. For long term storage where runtime of
key derivation is not a problem, you could use 16 as in libscrypt or better
yet increase N if memory is plentiful.
"""
check_args(password, salt, N, r, p, olen)
out = ctypes.create_string_buffer(olen)
ret = _libscrypt_scrypt(password, len(password), salt, len(salt),
N, r, p, out, len(out))
if ret:
raise ValueError
return out.raw
def scrypt_mcf(password, salt=None, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p,
prefix=SCRYPT_MCF_PREFIX_DEFAULT):
"""Derives a Modular Crypt Format hash using the scrypt KDF
Parameter space is smaller than for scrypt():
N must be a power of two larger than 1 but no larger than 2 ** 31
r and p must be positive numbers between 1 and 255
Salt must be a byte string 1-16 bytes long.
If no salt is given, a random salt of 128+ bits is used. (Recommended.)
"""
if (prefix != SCRYPT_MCF_PREFIX_s1 and prefix != SCRYPT_MCF_PREFIX_ANY):
return mcf_mod.scrypt_mcf(scrypt, password, salt, N, r, p, prefix)
if salt is None:
salt = os.urandom(16)
elif not (1 <= len(salt) <= 16):
raise ValueError('salt must be 1-16 bytes')
if N > 2**31:
raise ValueError('N > 2**31 not supported')
if b'\0' in password:
raise ValueError('scrypt_mcf password must not contain zero bytes')
hash = scrypt(password, salt, N, r, p)
h64 = base64.b64encode(hash)
s64 = base64.b64encode(salt)
out = ctypes.create_string_buffer(125)
ret = _libscrypt_mcf(N, r, p, s64, h64, out)
if not ret:
raise ValueError
out = out.raw.strip(b'\0')
# XXX: Hack to support old libscrypt (like in Ubuntu 14.04)
if len(out) == 123:
out = out + b'='
return out
def scrypt_mcf_check(mcf, password):
"""Returns True if the password matches the given MCF hash"""
if not isinstance(mcf, bytes):
raise TypeError
if not isinstance(password, bytes):
raise TypeError
if len(mcf) != 124 or b'\0' in password:
return mcf_mod.scrypt_mcf_check(scrypt, mcf, password)
mcfbuf = ctypes.create_string_buffer(mcf)
ret = _libscrypt_check(mcfbuf, password)
if ret < 0:
return mcf_mod.scrypt_mcf_check(scrypt, mcf, password)
return bool(ret)
if __name__ == "__main__":
import sys
from . import tests
tests.run_scrypt_suite(sys.modules[__name__])
#!/usr/bin/env python
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Scrypt implementation that calls into system libsodium"""
import base64
import ctypes, ctypes.util
from ctypes import c_char_p, c_size_t, c_uint64, c_uint32, c_void_p
import hashlib, hmac
import numbers
import platform
import struct
import sys
from . import mcf as mcf_mod
from .common import *
if platform.python_implementation() == 'PyPy':
from . import pypyscrypt_inline as scr_mod
else:
from . import pylibsodium_salsa as scr_mod
def _get_libsodium():
'''
Locate the nacl c libs to use
'''
__SONAMES = (13, 10, 5, 4)
# Import libsodium from system
sys_sodium = ctypes.util.find_library('sodium')
if sys_sodium is None:
sys_sodium = ctypes.util.find_library('libsodium')
if sys_sodium:
return ctypes.CDLL(sys_sodium)
# Import from local path
if sys.platform.startswith('win'):
try:
return ctypes.cdll.LoadLibrary('libsodium')
except OSError:
pass
for soname_ver in __SONAMES:
try:
return ctypes.cdll.LoadLibrary(
'libsodium-{0}'.format(soname_ver)
)
except OSError:
pass
elif sys.platform.startswith('darwin'):
try:
return ctypes.cdll.LoadLibrary('libsodium.dylib')
except OSError:
pass
else:
try:
return ctypes.cdll.LoadLibrary('libsodium.so')
except OSError:
pass
for soname_ver in __SONAMES:
try:
return ctypes.cdll.LoadLibrary(
'libsodium.so.{0}'.format(soname_ver)
)
except OSError:
pass
_lib = _get_libsodium()
if _lib is None:
raise ImportError('Unable to load libsodium')
try:
_scrypt_ll = _lib.crypto_pwhash_scryptsalsa208sha256_ll
_scrypt_ll.argtypes = [
c_void_p, # passwd
c_size_t, # passwdlen
c_void_p, # salt
c_size_t, # saltlen
c_uint64, # N
c_uint32, # r
c_uint32, # p
c_void_p, # buf
c_size_t, # buflen
]
except AttributeError:
_scrypt_ll = None
try:
_scrypt = _lib.crypto_pwhash_scryptsalsa208sha256
_scrypt_str = _lib.crypto_pwhash_scryptsalsa208sha256_str
_scrypt_str_chk = _lib.crypto_pwhash_scryptsalsa208sha256_str_verify
_scrypt_str_bytes = _lib.crypto_pwhash_scryptsalsa208sha256_strbytes()
_scrypt_salt = _lib.crypto_pwhash_scryptsalsa208sha256_saltbytes()
if _scrypt_str_bytes != 102 and not _scrypt_ll:
raise ImportError('Incompatible libsodium: ' + _lib_soname)
except AttributeError:
try:
_scrypt = _lib.crypto_pwhash_scryptxsalsa208sha256
_scrypt_str = _lib.crypto_pwhash_scryptxsalsa208sha256_str
_scrypt_str_chk = _lib.crypto_pwhash_scryptxsalsa208sha256_str_verify
_scrypt_str_bytes = _lib.crypto_pwhash_scryptxsalsa208sha256_strbytes()
_scrypt_salt = _lib.crypto_pwhash_scryptxsalsa208sha256_saltbytes
_scrypt_salt = _scrypt_salt()
if _scrypt_str_bytes != 102 and not _scrypt_ll:
raise ImportError('Incompatible libsodium: ' + _lib_soname)
except AttributeError:
if not _scrypt_ll:
raise ImportError('Incompatible libsodium: ' + _lib_soname)
_scrypt.argtypes = [
c_void_p, # out
c_uint64, # outlen
c_void_p, # passwd
c_uint64, # passwdlen
c_void_p, # salt
c_uint64, # opslimit
c_size_t, # memlimit
]
_scrypt_str.argtypes = [
c_void_p, # out (102 bytes)
c_void_p, # passwd
c_uint64, # passwdlen
c_uint64, # opslimit
c_size_t, # memlimit
]
_scrypt_str_chk.argtypes = [
c_char_p, # str (102 bytes)
c_void_p, # passwd
c_uint64, # passwdlen
]
def scrypt(password, salt, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p, olen=64):
"""Returns a key derived using the scrypt key-derivarion function
N must be a power of two larger than 1 but no larger than 2 ** 63 (insane)
r and p must be positive numbers such that r * p < 2 ** 30
The default values are:
N -- 2**14 (~16k)
r -- 8
p -- 1
Memory usage is proportional to N*r. Defaults require about 16 MiB.
Time taken is proportional to N*p. Defaults take <100ms of a recent x86.
The last one differs from libscrypt defaults, but matches the 'interactive'
work factor from the original paper. For long term storage where runtime of
key derivation is not a problem, you could use 16 as in libscrypt or better
yet increase N if memory is plentiful.
"""
check_args(password, salt, N, r, p, olen)
if _scrypt_ll:
out = ctypes.create_string_buffer(olen)
if _scrypt_ll(password, len(password), salt, len(salt),
N, r, p, out, olen):
raise ValueError
return out.raw
if len(salt) != _scrypt_salt or r != 8 or (p & (p - 1)) or (N*p <= 512):
return scr_mod.scrypt(password, salt, N, r, p, olen)
s = next(i for i in range(1, 64) if 2**i == N)
t = next(i for i in range(0, 30) if 2**i == p)
m = 2**(10 + s)
o = 2**(5 + t + s)
if s > 53 or t + s > 58:
raise ValueError
out = ctypes.create_string_buffer(olen)
if _scrypt(out, olen, password, len(password), salt, o, m) != 0:
raise ValueError
return out.raw
def scrypt_mcf(password, salt=None, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p,
prefix=SCRYPT_MCF_PREFIX_DEFAULT):
"""Derives a Modular Crypt Format hash using the scrypt KDF
Parameter space is smaller than for scrypt():
N must be a power of two larger than 1 but no larger than 2 ** 31
r and p must be positive numbers between 1 and 255
Salt must be a byte string 1-16 bytes long.
If no salt is given, a random salt of 128+ bits is used. (Recommended.)
"""
if N < 2 or (N & (N - 1)):
raise ValueError('scrypt N must be a power of 2 greater than 1')
if p > 255 or p < 1:
raise ValueError('scrypt_mcf p out of range [1,255]')
if N > 2**31:
raise ValueError('scrypt_mcf N out of range [2,2**31]')
if (salt is not None or r != 8 or (p & (p - 1)) or (N*p <= 512) or
prefix not in (SCRYPT_MCF_PREFIX_7, SCRYPT_MCF_PREFIX_s1,
SCRYPT_MCF_PREFIX_ANY) or
_scrypt_ll):
return mcf_mod.scrypt_mcf(scrypt, password, salt, N, r, p, prefix)
s = next(i for i in range(1, 32) if 2**i == N)
t = next(i for i in range(0, 8) if 2**i == p)
m = 2**(10 + s)
o = 2**(5 + t + s)
mcf = ctypes.create_string_buffer(102)
if _scrypt_str(mcf, password, len(password), o, m) != 0:
return mcf_mod.scrypt_mcf(scrypt, password, salt, N, r, p, prefix)
if prefix in (SCRYPT_MCF_PREFIX_7, SCRYPT_MCF_PREFIX_ANY):
return mcf.raw.strip(b'\0')
_N, _r, _p, salt, hash, olen = mcf_mod._scrypt_mcf_decode_7(mcf.raw[:-1])
assert _N == N and _r == r and _p == p, (_N, _r, _p, N, r, p, o, m)
return mcf_mod._scrypt_mcf_encode_s1(N, r, p, salt, hash)
def scrypt_mcf_check(mcf, password):
"""Returns True if the password matches the given MCF hash"""
if mcf_mod._scrypt_mcf_7_is_standard(mcf) and not _scrypt_ll:
return _scrypt_str_chk(mcf, password, len(password)) == 0
return mcf_mod.scrypt_mcf_check(scrypt, mcf, password)
if __name__ == "__main__":
import sys
from . import tests
try:
from . import pylibscrypt
scr_mod = pylibscrypt
except ImportError:
pass
tests.run_scrypt_suite(sys.modules[__name__])
#!/usr/bin/env python
# Copyright (c) 2014 Richard Moore
# Copyright (c) 2014 Jan Varho
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Scrypt implementation that calls into system libsodium"""
import base64
import ctypes, ctypes.util
from ctypes import c_char_p, c_size_t, c_uint64, c_uint32, c_void_p
import hashlib, hmac
import numbers
import struct
import sys
from . import mcf as mcf_mod
from .common import *
def _get_libsodium():
'''
Locate the nacl c libs to use
'''
__SONAMES = (13, 10, 5, 4)
# Import libsodium from system
sys_sodium = ctypes.util.find_library('sodium')
if sys_sodium is None:
sys_sodium = ctypes.util.find_library('libsodium')
if sys_sodium:
return ctypes.CDLL(sys_sodium)
# Import from local path
if sys.platform.startswith('win'):
try:
return ctypes.cdll.LoadLibrary('libsodium')
except OSError:
pass
for soname_ver in __SONAMES:
try:
return ctypes.cdll.LoadLibrary(
'libsodium-{0}'.format(soname_ver)
)
except OSError:
pass
elif sys.platform.startswith('darwin'):
try:
return ctypes.cdll.LoadLibrary('libsodium.dylib')
except OSError:
pass
else:
try:
return ctypes.cdll.LoadLibrary('libsodium.so')
except OSError:
pass
for soname_ver in __SONAMES:
try:
return ctypes.cdll.LoadLibrary(
'libsodium.so.{0}'.format(soname_ver)
)
except OSError:
pass
_libsodium = _get_libsodium()
if _libsodium is None:
raise ImportError('Unable to load libsodium')
try:
_libsodium_salsa20_8 = _libsodium.crypto_core_salsa208
except AttributeError:
raise ImportError('Incompatible libsodium: ')
_libsodium_salsa20_8.argtypes = [
c_void_p, # out (16*4 bytes)
c_void_p, # in (4*4 bytes)
c_void_p, # k (8*4 bytes)
c_void_p, # c (4*4 bytes)
]
# Python 3.4+ have PBKDF2 in hashlib, so use it...
if 'pbkdf2_hmac' in dir(hashlib):
_pbkdf2 = hashlib.pbkdf2_hmac
else:
# but fall back to Python implementation in < 3.4
from pbkdf2 import pbkdf2_hmac as _pbkdf2
def scrypt(password, salt, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p, olen=64):
"""Returns a key derived using the scrypt key-derivarion function
N must be a power of two larger than 1 but no larger than 2 ** 63 (insane)
r and p must be positive numbers such that r * p < 2 ** 30
The default values are:
N -- 2**14 (~16k)
r -- 8
p -- 1
Memory usage is proportional to N*r. Defaults require about 16 MiB.
Time taken is proportional to N*p. Defaults take <100ms of a recent x86.
The last one differs from libscrypt defaults, but matches the 'interactive'
work factor from the original paper. For long term storage where runtime of
key derivation is not a problem, you could use 16 as in libscrypt or better
yet increase N if memory is plentiful.
"""
def array_overwrite(source, s_start, dest, d_start, length):
dest[d_start:d_start + length] = source[s_start:s_start + length]
def blockxor(source, s_start, dest, d_start, length):
for i in xrange(length):
dest[d_start + i] ^= source[s_start + i]
def integerify(B, r):
"""A bijection from ({0, 1} ** k) to {0, ..., (2 ** k) - 1"""
Bi = (2 * r - 1) * 8
return B[Bi] & 0xffffffff
def salsa20_8(B, x):
"""Salsa 20/8 using libsodium
NaCL/libsodium includes crypto_core_salsa208, but unfortunately it
expects the data in a different order, so we need to mix it up a bit.
"""
hi = 0xffffffff00000000
lo = 0x00000000ffffffff
struct.pack_into('<9Q', x, 0,
(B[0] & lo) + (B[2] & hi), (B[5] & lo) + (B[7] & hi), # c
B[3], B[4], # in
B[0], B[1], (B[2] & lo) + (B[5] & hi), # pad k pad
B[6], B[7],
)
c = ctypes.addressof(x)
i = c + 4*4
k = c + 9*4
_libsodium_salsa20_8(c, i, k, c)
B[:] = struct.unpack('<8Q8x', x)
def blockmix_salsa8(BY, Yi, r):
"""Blockmix; Used by SMix"""
start = (2 * r - 1) * 8
X = BY[start:start+8] # BlockMix - 1
x = ctypes.create_string_buffer(8*9)
for i in xrange(2 * r): # BlockMix - 2
blockxor(BY, i * 8, X, 0, 8) # BlockMix - 3(inner)
salsa20_8(X, x) # BlockMix - 3(outer)
array_overwrite(X, 0, BY, Yi + (i * 8), 8) # BlockMix - 4
for i in xrange(r): # BlockMix - 6
array_overwrite(BY, Yi + (i * 2) * 8, BY, i * 8, 8)
array_overwrite(BY, Yi + (i*2 + 1) * 8, BY, (i + r) * 8, 8)
def smix(B, Bi, r, N, V, X):
"""SMix; a specific case of ROMix based on Salsa20/8"""
array_overwrite(B, Bi, X, 0, 16 * r) # ROMix - 1
for i in xrange(N): # ROMix - 2
array_overwrite(X, 0, V, i * (16 * r), 16 * r) # ROMix - 3
blockmix_salsa8(X, 16 * r, r) # ROMix - 4
for i in xrange(N): # ROMix - 6
j = integerify(X, r) & (N - 1) # ROMix - 7
blockxor(V, j * (16 * r), X, 0, 16 * r) # ROMix - 8(inner)
blockmix_salsa8(X, 16 * r, r) # ROMix - 9(outer)
array_overwrite(X, 0, B, Bi, 16 * r) # ROMix - 10
check_args(password, salt, N, r, p, olen)
# Everything is lists of 64-bit uints for all but pbkdf2
try:
B = _pbkdf2('sha256', password, salt, 1, p * 128 * r)
B = list(struct.unpack('<%dQ' % (len(B) // 8), B))
XY = [0] * (32 * r)
V = [0] * (16 * r * N)
except (MemoryError, OverflowError):
raise ValueError("scrypt parameters don't fit in memory")
for i in xrange(p):
smix(B, i * 16 * r, r, N, V, XY)
B = struct.pack('<%dQ' % len(B), *B)
return _pbkdf2('sha256', password, B, 1, olen)
def scrypt_mcf(password, salt=None, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p,
prefix=b'$s1$'):
"""Derives a Modular Crypt Format hash using the scrypt KDF
Parameter space is smaller than for scrypt():
N must be a power of two larger than 1 but no larger than 2 ** 31
r and p must be positive numbers between 1 and 255
Salt must be a byte string 1-16 bytes long.
If no salt is given, a random salt of 128+ bits is used. (Recommended.)
"""
return mcf_mod.scrypt_mcf(scrypt, password, salt, N, r, p, prefix)
def scrypt_mcf_check(mcf, password):
"""Returns True if the password matches the given MCF hash"""
return mcf_mod.scrypt_mcf_check(scrypt, mcf, password)
if __name__ == "__main__":
import sys
from . import tests
tests.run_scrypt_suite(sys.modules[__name__])
#!/usr/bin/env python
# Copyright (c) 2014 Richard Moore
# Copyright (c) 2014 Jan Varho
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Python implementation of Scrypt password-based key derivation function"""
# Scrypt definition:
# http://www.tarsnap.com/scrypt/scrypt.pdf
# It was originally written for a pure-Python Litecoin CPU miner:
# https://github.com/ricmoo/nightminer
# Imported to this project from:
# https://github.com/ricmoo/pyscrypt
# And owes thanks to:
# https://github.com/wg/scrypt
import hashlib, hmac
import struct
from . import mcf as mcf_mod
from .common import *
# Python 3.4+ have PBKDF2 in hashlib, so use it...
if 'pbkdf2_hmac' in dir(hashlib):
_pbkdf2 = hashlib.pbkdf2_hmac
else:
# but fall back to Python implementation in < 3.4
from pbkdf2 import pbkdf2_hmac as _pbkdf2
def array_overwrite(source, s_start, dest, d_start, length):
dest[d_start:d_start + length] = source[s_start:s_start + length]
def blockxor(source, s_start, dest, d_start, length):
for i in xrange(length):
dest[d_start + i] ^= source[s_start + i]
def integerify(B, r):
"""A bijection from ({0, 1} ** k) to {0, ..., (2 ** k) - 1"""
Bi = (2 * r - 1) * 16
return B[Bi]
def R(X, destination, a1, a2, b):
"""A single Salsa20 row operation"""
a = (X[a1] + X[a2]) & 0xffffffff
X[destination] ^= ((a << b) | (a >> (32 - b)))
def salsa20_8(B, x, src, s_start, dest, d_start):
"""Salsa20/8 http://en.wikipedia.org/wiki/Salsa20"""
# Merged blockxor for speed
for i in xrange(16):
x[i] = B[i] = B[i] ^ src[s_start + i]
# This is the actual Salsa 20/8: four identical double rounds
for i in xrange(4):
R(x, 4, 0,12, 7);R(x, 8, 4, 0, 9);R(x,12, 8, 4,13);R(x, 0,12, 8,18)
R(x, 9, 5, 1, 7);R(x,13, 9, 5, 9);R(x, 1,13, 9,13);R(x, 5, 1,13,18)
R(x,14,10, 6, 7);R(x, 2,14,10, 9);R(x, 6, 2,14,13);R(x,10, 6, 2,18)
R(x, 3,15,11, 7);R(x, 7, 3,15, 9);R(x,11, 7, 3,13);R(x,15,11, 7,18)
R(x, 1, 0, 3, 7);R(x, 2, 1, 0, 9);R(x, 3, 2, 1,13);R(x, 0, 3, 2,18)
R(x, 6, 5, 4, 7);R(x, 7, 6, 5, 9);R(x, 4, 7, 6,13);R(x, 5, 4, 7,18)
R(x,11,10, 9, 7);R(x, 8,11,10, 9);R(x, 9, 8,11,13);R(x,10, 9, 8,18)
R(x,12,15,14, 7);R(x,13,12,15, 9);R(x,14,13,12,13);R(x,15,14,13,18)
# While we are handling the data, write it to the correct dest.
# The latter half is still part of salsa20
for i in xrange(16):
dest[d_start + i] = B[i] = (x[i] + B[i]) & 0xffffffff
def blockmix_salsa8(BY, Yi, r):
"""Blockmix; Used by SMix"""
start = (2 * r - 1) * 16
X = BY[start:start+16] # BlockMix - 1
tmp = [0]*16
for i in xrange(2 * r): # BlockMix - 2
#blockxor(BY, i * 16, X, 0, 16) # BlockMix - 3(inner)
salsa20_8(X, tmp, BY, i * 16, BY, Yi + i*16) # BlockMix - 3(outer)
#array_overwrite(X, 0, BY, Yi + (i * 16), 16) # BlockMix - 4
for i in xrange(r): # BlockMix - 6
array_overwrite(BY, Yi + (i * 2) * 16, BY, i * 16, 16)
array_overwrite(BY, Yi + (i*2 + 1) * 16, BY, (i + r) * 16, 16)
def smix(B, Bi, r, N, V, X):
"""SMix; a specific case of ROMix based on Salsa20/8"""
array_overwrite(B, Bi, X, 0, 32 * r) # ROMix - 1
for i in xrange(N): # ROMix - 2
array_overwrite(X, 0, V, i * (32 * r), 32 * r) # ROMix - 3
blockmix_salsa8(X, 32 * r, r) # ROMix - 4
for i in xrange(N): # ROMix - 6
j = integerify(X, r) & (N - 1) # ROMix - 7
blockxor(V, j * (32 * r), X, 0, 32 * r) # ROMix - 8(inner)
blockmix_salsa8(X, 32 * r, r) # ROMix - 9(outer)
array_overwrite(X, 0, B, Bi, 32 * r) # ROMix - 10
def scrypt(password, salt, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p, olen=64):
"""Returns a key derived using the scrypt key-derivarion function
N must be a power of two larger than 1 but no larger than 2 ** 63 (insane)
r and p must be positive numbers such that r * p < 2 ** 30
The default values are:
N -- 2**14 (~16k)
r -- 8
p -- 1
Memory usage is proportional to N*r. Defaults require about 16 MiB.
Time taken is proportional to N*p. Defaults take <100ms of a recent x86.
The last one differs from libscrypt defaults, but matches the 'interactive'
work factor from the original paper. For long term storage where runtime of
key derivation is not a problem, you could use 16 as in libscrypt or better
yet increase N if memory is plentiful.
"""
check_args(password, salt, N, r, p, olen)
# Everything is lists of 32-bit uints for all but pbkdf2
try:
B = _pbkdf2('sha256', password, salt, 1, p * 128 * r)
B = list(struct.unpack('<%dI' % (len(B) // 4), B))
XY = [0] * (64 * r)
V = [0] * (32 * r * N)
except (MemoryError, OverflowError):
raise ValueError("scrypt parameters don't fit in memory")
for i in xrange(p):
smix(B, i * 32 * r, r, N, V, XY)
B = struct.pack('<%dI' % len(B), *B)
return _pbkdf2('sha256', password, B, 1, olen)
def scrypt_mcf(password, salt=None, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p,
prefix=SCRYPT_MCF_PREFIX_DEFAULT):
"""Derives a Modular Crypt Format hash using the scrypt KDF
Parameter space is smaller than for scrypt():
N must be a power of two larger than 1 but no larger than 2 ** 31
r and p must be positive numbers between 1 and 255
Salt must be a byte string 1-16 bytes long.
If no salt is given, a random salt of 128+ bits is used. (Recommended.)
"""
return mcf_mod.scrypt_mcf(scrypt, password, salt, N, r, p, prefix)
def scrypt_mcf_check(mcf, password):
"""Returns True if the password matches the given MCF hash"""
return mcf_mod.scrypt_mcf_check(scrypt, mcf, password)
__all__ = ['scrypt', 'scrypt_mcf', 'scrypt_mcf_check']
if __name__ == "__main__":
import sys
from . import tests
tests.run_scrypt_suite(sys.modules[__name__])
#!/usr/bin/env python
# Automatically generated file, see inline.py
# Copyright (c) 2014 Richard Moore
# Copyright (c) 2014 Jan Varho
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Python implementation of Scrypt password-based key derivation function"""
# Scrypt definition:
# http://www.tarsnap.com/scrypt/scrypt.pdf
# It was originally written for a pure-Python Litecoin CPU miner:
# https://github.com/ricmoo/nightminer
# Imported to this project from:
# https://github.com/ricmoo/pyscrypt
# And owes thanks to:
# https://github.com/wg/scrypt
import hashlib, hmac
import struct
from . import mcf as mcf_mod
from .common import *
# Python 3.4+ have PBKDF2 in hashlib, so use it...
if 'pbkdf2_hmac' in dir(hashlib):
_pbkdf2 = hashlib.pbkdf2_hmac
else:
# but fall back to Python implementation in < 3.4
from pbkdf2 import pbkdf2_hmac as _pbkdf2
def blockxor(source, s_start, dest, d_start, length):
for i in xrange(length):
dest[d_start + i] ^= source[s_start + i]
def integerify(B, r):
"""A bijection from ({0, 1} ** k) to {0, ..., (2 ** k) - 1"""
Bi = (2 * r - 1) * 16
return B[Bi]
def salsa20_8(B, x, src, s_start, dest, d_start):
"""Salsa20/8 http://en.wikipedia.org/wiki/Salsa20"""
# Merged blockxor for speed
for i in xrange(16):
x[i] = B[i] = B[i] ^ src[s_start + i]
# This is the actual Salsa 20/8: four identical double rounds
for i in xrange(4):
a = (x[0]+x[12]) & 0xffffffff
b = (x[5]+x[1]) & 0xffffffff
x[4] ^= (a << 7) | (a >> 25)
x[9] ^= (b << 7) | (b >> 25)
a = (x[10]+x[6]) & 0xffffffff
b = (x[15]+x[11]) & 0xffffffff
x[14] ^= (a << 7) | (a >> 25)
x[3] ^= (b << 7) | (b >> 25)
a = (x[4]+x[0]) & 0xffffffff
b = (x[9]+x[5]) & 0xffffffff
x[8] ^= (a << 9) | (a >> 23)
x[13] ^= (b << 9) | (b >> 23)
a = (x[14]+x[10]) & 0xffffffff
b = (x[3]+x[15]) & 0xffffffff
x[2] ^= (a << 9) | (a >> 23)
x[7] ^= (b << 9) | (b >> 23)
a = (x[8]+x[4]) & 0xffffffff
b = (x[13]+x[9]) & 0xffffffff
x[12] ^= (a << 13) | (a >> 19)
x[1] ^= (b << 13) | (b >> 19)
a = (x[2]+x[14]) & 0xffffffff
b = (x[7]+x[3]) & 0xffffffff
x[6] ^= (a << 13) | (a >> 19)
x[11] ^= (b << 13) | (b >> 19)
a = (x[12]+x[8]) & 0xffffffff
b = (x[1]+x[13]) & 0xffffffff
x[0] ^= (a << 18) | (a >> 14)
x[5] ^= (b << 18) | (b >> 14)
a = (x[6]+x[2]) & 0xffffffff
b = (x[11]+x[7]) & 0xffffffff
x[10] ^= (a << 18) | (a >> 14)
x[15] ^= (b << 18) | (b >> 14)
a = (x[0]+x[3]) & 0xffffffff
b = (x[5]+x[4]) & 0xffffffff
x[1] ^= (a << 7) | (a >> 25)
x[6] ^= (b << 7) | (b >> 25)
a = (x[10]+x[9]) & 0xffffffff
b = (x[15]+x[14]) & 0xffffffff
x[11] ^= (a << 7) | (a >> 25)
x[12] ^= (b << 7) | (b >> 25)
a = (x[1]+x[0]) & 0xffffffff
b = (x[6]+x[5]) & 0xffffffff
x[2] ^= (a << 9) | (a >> 23)
x[7] ^= (b << 9) | (b >> 23)
a = (x[11]+x[10]) & 0xffffffff
b = (x[12]+x[15]) & 0xffffffff
x[8] ^= (a << 9) | (a >> 23)
x[13] ^= (b << 9) | (b >> 23)
a = (x[2]+x[1]) & 0xffffffff
b = (x[7]+x[6]) & 0xffffffff
x[3] ^= (a << 13) | (a >> 19)
x[4] ^= (b << 13) | (b >> 19)
a = (x[8]+x[11]) & 0xffffffff
b = (x[13]+x[12]) & 0xffffffff
x[9] ^= (a << 13) | (a >> 19)
x[14] ^= (b << 13) | (b >> 19)
a = (x[3]+x[2]) & 0xffffffff
b = (x[4]+x[7]) & 0xffffffff
x[0] ^= (a << 18) | (a >> 14)
x[5] ^= (b << 18) | (b >> 14)
a = (x[9]+x[8]) & 0xffffffff
b = (x[14]+x[13]) & 0xffffffff
x[10] ^= (a << 18) | (a >> 14)
x[15] ^= (b << 18) | (b >> 14)
# While we are handling the data, write it to the correct dest.
# The latter half is still part of salsa20
for i in xrange(16):
dest[d_start + i] = B[i] = (x[i] + B[i]) & 0xffffffff
def blockmix_salsa8(BY, Yi, r):
"""Blockmix; Used by SMix"""
start = (2 * r - 1) * 16
X = BY[start:start+16] # BlockMix - 1
tmp = [0]*16
for i in xrange(2 * r): # BlockMix - 2
#blockxor(BY, i * 16, X, 0, 16) # BlockMix - 3(inner)
salsa20_8(X, tmp, BY, i * 16, BY, Yi + i*16) # BlockMix - 3(outer)
#array_overwrite(X, 0, BY, Yi + (i * 16), 16) # BlockMix - 4
for i in xrange(r): # BlockMix - 6
BY[i * 16:(i * 16)+(16)] = BY[Yi + (i * 2) * 16:(Yi + (i * 2) * 16)+(16)]
BY[(i + r) * 16:((i + r) * 16)+(16)] = BY[Yi + (i*2 + 1) * 16:(Yi + (i*2 + 1) * 16)+(16)]
def smix(B, Bi, r, N, V, X):
"""SMix; a specific case of ROMix based on Salsa20/8"""
X[0:(0)+(32 * r)] = B[Bi:(Bi)+(32 * r)]
for i in xrange(N): # ROMix - 2
V[i * (32 * r):(i * (32 * r))+(32 * r)] = X[0:(0)+(32 * r)]
blockmix_salsa8(X, 32 * r, r) # ROMix - 4
for i in xrange(N): # ROMix - 6
j = integerify(X, r) & (N - 1) # ROMix - 7
blockxor(V, j * (32 * r), X, 0, 32 * r) # ROMix - 8(inner)
blockmix_salsa8(X, 32 * r, r) # ROMix - 9(outer)
B[Bi:(Bi)+(32 * r)] = X[0:(0)+(32 * r)]
def scrypt(password, salt, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p, olen=64):
"""Returns a key derived using the scrypt key-derivarion function
N must be a power of two larger than 1 but no larger than 2 ** 63 (insane)
r and p must be positive numbers such that r * p < 2 ** 30
The default values are:
N -- 2**14 (~16k)
r -- 8
p -- 1
Memory usage is proportional to N*r. Defaults require about 16 MiB.
Time taken is proportional to N*p. Defaults take <100ms of a recent x86.
The last one differs from libscrypt defaults, but matches the 'interactive'
work factor from the original paper. For long term storage where runtime of
key derivation is not a problem, you could use 16 as in libscrypt or better
yet increase N if memory is plentiful.
"""
check_args(password, salt, N, r, p, olen)
# Everything is lists of 32-bit uints for all but pbkdf2
try:
B = _pbkdf2('sha256', password, salt, 1, p * 128 * r)
B = list(struct.unpack('<%dI' % (len(B) // 4), B))
XY = [0] * (64 * r)
V = [0] * (32 * r * N)
except (MemoryError, OverflowError):
raise ValueError("scrypt parameters don't fit in memory")
for i in xrange(p):
smix(B, i * 32 * r, r, N, V, XY)
B = struct.pack('<%dI' % len(B), *B)
return _pbkdf2('sha256', password, B, 1, olen)
def scrypt_mcf(password, salt=None, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p,
prefix=SCRYPT_MCF_PREFIX_DEFAULT):
"""Derives a Modular Crypt Format hash using the scrypt KDF
Parameter space is smaller than for scrypt():
N must be a power of two larger than 1 but no larger than 2 ** 31
r and p must be positive numbers between 1 and 255
Salt must be a byte string 1-16 bytes long.
If no salt is given, a random salt of 128+ bits is used. (Recommended.)
"""
return mcf_mod.scrypt_mcf(scrypt, password, salt, N, r, p, prefix)
def scrypt_mcf_check(mcf, password):
"""Returns True if the password matches the given MCF hash"""
return mcf_mod.scrypt_mcf_check(scrypt, mcf, password)
__all__ = ['scrypt', 'scrypt_mcf', 'scrypt_mcf_check']
if __name__ == "__main__":
import sys
from . import tests
tests.run_scrypt_suite(sys.modules[__name__])
#!/usr/bin/env python
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Scrypt implementation that calls into the 'scrypt' python module"""
import numbers
from scrypt import hash as _scrypt
from . import mcf as mcf_mod
from .common import *
# scrypt < 0.6 doesn't support hash length
try:
_scrypt(b'password', b'NaCl', N=2, r=1, p=1, buflen=42)
except TypeError:
raise ImportError('scrypt module version unsupported, 0.6+ required')
def scrypt(password, salt, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p, olen=64):
"""Returns a key derived using the scrypt key-derivarion function
N must be a power of two larger than 1 but no larger than 2 ** 63 (insane)
r and p must be positive numbers such that r * p < 2 ** 30
The default values are:
N -- 2**14 (~16k)
r -- 8
p -- 1
Memory usage is proportional to N*r. Defaults require about 16 MiB.
Time taken is proportional to N*p. Defaults take <100ms of a recent x86.
The last one differs from libscrypt defaults, but matches the 'interactive'
work factor from the original paper. For long term storage where runtime of
key derivation is not a problem, you could use 16 as in libscrypt or better
yet increase N if memory is plentiful.
"""
check_args(password, salt, N, r, p, olen)
try:
return _scrypt(password=password, salt=salt, N=N, r=r, p=p, buflen=olen)
except:
raise ValueError
def scrypt_mcf(password, salt=None, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p,
prefix=SCRYPT_MCF_PREFIX_DEFAULT):
"""Derives a Modular Crypt Format hash using the scrypt KDF
Parameter space is smaller than for scrypt():
N must be a power of two larger than 1 but no larger than 2 ** 31
r and p must be positive numbers between 1 and 255
Salt must be a byte string 1-16 bytes long.
If no salt is given, a random salt of 128+ bits is used. (Recommended.)
"""
return mcf_mod.scrypt_mcf(scrypt, password, salt, N, r, p, prefix)
def scrypt_mcf_check(mcf, password):
"""Returns True if the password matches the given MCF hash"""
return mcf_mod.scrypt_mcf_check(scrypt, mcf, password)
if __name__ == "__main__":
import sys
from . import tests
tests.run_scrypt_suite(sys.modules[__name__])
This diff is collapsed.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Authors:
# Caner Candan <caner@candan.fr>, http://caner.candan.fr
#
PROTOCOL_VERSION="1"
MANAGED_API=["BASIC_MERKLED_API"]
This diff is collapsed.
This diff is collapsed.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Authors:
# Caner Candan <caner@candan.fr>, http://caner.candan.fr
#
from .. import API, logging
logger = logging.getLogger("ucoin/network")
class Network(API):
def __init__(self, connection_handler, module='network'):
super(Network, self).__init__(connection_handler, module)
class Peering(Network):
"""GET peering information about a peer."""
def __get__(self, **kwargs):
return self.requests_get('/peering', **kwargs).json()
from . import peering
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.