Add the password sub-module
This commit is contained in:
parent
d32160a4c2
commit
26973e7051
12 changed files with 414 additions and 34 deletions
4
MANIFEST.in
Normal file
4
MANIFEST.in
Normal file
|
@ -0,0 +1,4 @@
|
|||
include CHANGELOG.md
|
||||
include CONTRIBUTING.md
|
||||
include LICENSE-EN.txt
|
||||
include LICENSE-FR.txt
|
15
Pipfile
Normal file
15
Pipfile
Normal file
|
@ -0,0 +1,15 @@
|
|||
[[source]]
|
||||
|
||||
url = "https://pypi.python.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
|
||||
[packages]
|
||||
|
||||
|
||||
|
||||
[dev-packages]
|
||||
|
||||
twine = "*"
|
||||
wheel = "*"
|
102
Pipfile.lock
generated
Normal file
102
Pipfile.lock
generated
Normal file
|
@ -0,0 +1,102 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "bc2f3999187c6f5eee3a8a8f26c22b796b5034c7a412de94fd6f95c37c020cc4"
|
||||
},
|
||||
"host-environment-markers": {
|
||||
"implementation_name": "cpython",
|
||||
"implementation_version": "3.6.3",
|
||||
"os_name": "posix",
|
||||
"platform_machine": "x86_64",
|
||||
"platform_python_implementation": "CPython",
|
||||
"platform_release": "4.13.12-1-ARCH",
|
||||
"platform_system": "Linux",
|
||||
"platform_version": "#1 SMP PREEMPT Wed Nov 8 11:54:06 CET 2017",
|
||||
"python_full_version": "3.6.3",
|
||||
"python_version": "3.6",
|
||||
"sys_platform": "linux"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.python.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {},
|
||||
"develop": {
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:244be0d93b71e93fc0a0a479862051414d0e00e16435707e5bf5000f92e04694",
|
||||
"sha256:5ec74291ca1136b40f0379e1128ff80e866597e4e2c1e755739a913bbc3613c0"
|
||||
],
|
||||
"version": "==2017.11.5"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
|
||||
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f"
|
||||
],
|
||||
"version": "==2.6"
|
||||
},
|
||||
"pkginfo": {
|
||||
"hashes": [
|
||||
"sha256:31a49103180ae1518b65d3f4ce09c784e2bc54e338197668b4fb7dc539521024",
|
||||
"sha256:bb1a6aeabfc898f5df124e7e00303a5b3ec9a489535f346bfbddb081af93f89e"
|
||||
],
|
||||
"version": "==1.4.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
|
||||
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
|
||||
],
|
||||
"version": "==2.18.4"
|
||||
},
|
||||
"requests-toolbelt": {
|
||||
"hashes": [
|
||||
"sha256:42c9c170abc2cacb78b8ab23ac957945c7716249206f90874651971a4acff237",
|
||||
"sha256:f6a531936c6fa4c6cfce1b9c10d5c4f498d16528d2a54a22ca00011205a187b5"
|
||||
],
|
||||
"version": "==0.8.0"
|
||||
},
|
||||
"tqdm": {
|
||||
"hashes": [
|
||||
"sha256:733ce813ab83e17a03da34043c6265e29f6731e3cbbbe305b12694ced0af6770",
|
||||
"sha256:7ca803c2ea268c6bdb541e2dac74a3af23cf4bf7b4132a6a78926d255f8c8df1"
|
||||
],
|
||||
"version": "==4.19.4"
|
||||
},
|
||||
"twine": {
|
||||
"hashes": [
|
||||
"sha256:d3ce5c480c22ccfb761cd358526e862b32546d2fe4bc93d46b5cf04ea3cc46ca",
|
||||
"sha256:caa45b7987fc96321258cd7668e3be2ff34064f5c66d2d975b641adca659c1ab"
|
||||
],
|
||||
"version": "==1.9.1"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
|
||||
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
|
||||
],
|
||||
"version": "==1.22"
|
||||
},
|
||||
"wheel": {
|
||||
"hashes": [
|
||||
"sha256:e721e53864f084f956f40f96124a74da0631ac13fbbd1ba99e8e2b5e9cafdf64",
|
||||
"sha256:9515fe0a94e823fd90b08d22de45d7bde57c90edce705b22f5e1ecf7e1b653c8"
|
||||
],
|
||||
"version": "==0.30.0"
|
||||
}
|
||||
}
|
||||
}
|
34
README.md
34
README.md
|
@ -1,34 +0,0 @@
|
|||
# Python LibreAuth
|
||||
|
||||
Python bindings to the LibreAuth library.
|
||||
LibreAuth is a collection of tools for user authentication written in Rust.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
:warning: This is a work in progress. Some features may not be available.
|
||||
|
||||
- Password / passphrase authentication
|
||||
- [ ] no character-set limitation
|
||||
- [ ] reasonable lenth limit ([security vs. DOS](http://arstechnica.com/security/2013/09/long-passwords-are-good-but-too-much-length-can-be-bad-for-security/))
|
||||
- [ ] strong, evolutive and retro-compatible password hashing functions
|
||||
- [ ] optional NIST Special Publication 800-63B compatibility
|
||||
- HOTP - HMAC-based One-time Password Algorithm ([OATH](http://www.openauthentication.org/) - [RFC 4226](https://tools.ietf.org/html/rfc4226))
|
||||
- [ ] the key can be passed as bytes, an ASCII string, an hexadicimal string or a base32 string
|
||||
- [ ] customizable counter
|
||||
- [ ] customizable hash function (sha1, sha256, sha512)
|
||||
- [ ] customizable output length
|
||||
- [ ] customizable output alphabet
|
||||
- TOTP - Time-based One-time Password Algorithm ([OATH](http://www.openauthentication.org/) - [RFC 6238](https://tools.ietf.org/html/rfc6238))
|
||||
- [ ] the key can be passed as bytes, an ASCII string, an hexadicimal string or a base32 string
|
||||
- [ ] customizable timestamp
|
||||
- [ ] customizable period
|
||||
- [ ] customizable initial time (T0)
|
||||
- [ ] customizable hash function (sha1, sha256, sha512)
|
||||
- [ ] customizable output length
|
||||
- [ ] customizable output alphabet
|
||||
- [ ] customizable positive and negative period tolerance
|
||||
- ~~U2F - Universal 2nd Factor~~ ([FIDO Alliance](https://fidoalliance.org/specifications/download/)) :warning: Not started
|
||||
- [ ] virtual device API
|
||||
- [ ] client API
|
||||
- [ ] server API
|
38
README.rst
Normal file
38
README.rst
Normal file
|
@ -0,0 +1,38 @@
|
|||
Python LibreAuth
|
||||
================
|
||||
|
||||
Python bindings to the LibreAuth library.
|
||||
LibreAuth is a collection of tools for user authentication written in Rust.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
This is a work in progress. Some features may not be available.
|
||||
|
||||
* Password / passphrase authentication
|
||||
- ✓ no character-set limitation
|
||||
- ✓ reasonable lenth limit ([security vs. DOS](http://arstechnica.com/security/2013/09/long-passwords-are-good-but-too-much-length-can-be-bad-for-security/))
|
||||
- ✓ strong, evolutive and retro-compatible password hashing functions
|
||||
- ✓ optional NIST Special Publication 800-63B compatibility
|
||||
* HOTP - HMAC-based One-time Password Algorithm ([OATH](http://www.openauthentication.org/) - [RFC 4226](https://tools.ietf.org/html/rfc4226))
|
||||
- ✗ the key can be passed as bytes, an ASCII string, an hexadicimal string or a base32 string
|
||||
- ✗ customizable counter
|
||||
- ✗ customizable hash function (sha1, sha256, sha512)
|
||||
- ✗ customizable output length
|
||||
- ✗ customizable output alphabet
|
||||
* TOTP - Time-based One-time Password Algorithm ([OATH](http://www.openauthentication.org/) - [RFC 6238](https://tools.ietf.org/html/rfc6238))
|
||||
- ✗ the key can be passed as bytes, an ASCII string, an hexadicimal string or a base32 string
|
||||
- ✗ customizable timestamp
|
||||
- ✗ customizable period
|
||||
- ✗ customizable initial time (T0)
|
||||
- ✗ customizable hash function (sha1, sha256, sha512)
|
||||
- ✗ customizable output length
|
||||
- ✗ customizable output alphabet
|
||||
- ✗ customizable positive and negative period tolerance
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
LibreAuth 0.6 or higher.
|
38
libreauth/__init__.py
Normal file
38
libreauth/__init__.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Copyright Rodolphe Breard (2017)
|
||||
# Author: Rodolphe Breard (2017)
|
||||
#
|
||||
# This software is a computer library whose purpose is to offer a
|
||||
# collection of tools for user authentication.
|
||||
#
|
||||
# This software is governed by the CeCILL license under French law and
|
||||
# abiding by the rules of distribution of free software. You can use,
|
||||
# modify and/ or redistribute the software under the terms of the CeCILL
|
||||
# license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
# "http://www.cecill.info".
|
||||
#
|
||||
# As a counterpart to the access to the source code and rights to copy,
|
||||
# modify and redistribute granted by the license, users are provided only
|
||||
# with a limited warranty and the software's author, the holder of the
|
||||
# economic rights, and the successive licensors have only limited
|
||||
# liability.
|
||||
#
|
||||
# In this respect, the user's attention is drawn to the risks associated
|
||||
# with loading, using, modifying and/or developing or reproducing the
|
||||
# software by the user in light of its specific status of free software,
|
||||
# that may mean that it is complicated to manipulate, and that also
|
||||
# therefore means that it is reserved for developers and experienced
|
||||
# professionals having in-depth computer knowledge. Users are therefore
|
||||
# encouraged to load and test the software's suitability as regards their
|
||||
# requirements in conditions enabling the security of their systems and/or
|
||||
# data to be ensured and, more generally, to use and operate it in the
|
||||
# same conditions as regards security.
|
||||
#
|
||||
# The fact that you are presently reading this means that you have had
|
||||
# knowledge of the CeCILL license and that you accept its terms.
|
||||
|
||||
from ctypes.util import find_library
|
||||
from ctypes import cdll
|
||||
from os import getenv
|
||||
|
||||
lib_path = getenv('LIBREAUTH_LIB_PATH') or find_library('libreauth')
|
||||
lib = cdll.LoadLibrary(lib_path)
|
33
libreauth/oath.py
Normal file
33
libreauth/oath.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Copyright Rodolphe Breard (2017)
|
||||
# Author: Rodolphe Breard (2017)
|
||||
#
|
||||
# This software is a computer library whose purpose is to offer a
|
||||
# collection of tools for user authentication.
|
||||
#
|
||||
# This software is governed by the CeCILL license under French law and
|
||||
# abiding by the rules of distribution of free software. You can use,
|
||||
# modify and/ or redistribute the software under the terms of the CeCILL
|
||||
# license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
# "http://www.cecill.info".
|
||||
#
|
||||
# As a counterpart to the access to the source code and rights to copy,
|
||||
# modify and redistribute granted by the license, users are provided only
|
||||
# with a limited warranty and the software's author, the holder of the
|
||||
# economic rights, and the successive licensors have only limited
|
||||
# liability.
|
||||
#
|
||||
# In this respect, the user's attention is drawn to the risks associated
|
||||
# with loading, using, modifying and/or developing or reproducing the
|
||||
# software by the user in light of its specific status of free software,
|
||||
# that may mean that it is complicated to manipulate, and that also
|
||||
# therefore means that it is reserved for developers and experienced
|
||||
# professionals having in-depth computer knowledge. Users are therefore
|
||||
# encouraged to load and test the software's suitability as regards their
|
||||
# requirements in conditions enabling the security of their systems and/or
|
||||
# data to be ensured and, more generally, to use and operate it in the
|
||||
# same conditions as regards security.
|
||||
#
|
||||
# The fact that you are presently reading this means that you have had
|
||||
# knowledge of the CeCILL license and that you accept its terms.
|
||||
|
||||
|
85
libreauth/password.py
Normal file
85
libreauth/password.py
Normal file
|
@ -0,0 +1,85 @@
|
|||
# Copyright Rodolphe Breard (2017)
|
||||
# Author: Rodolphe Breard (2017)
|
||||
#
|
||||
# This software is a computer library whose purpose is to offer a
|
||||
# collection of tools for user authentication.
|
||||
#
|
||||
# This software is governed by the CeCILL license under French law and
|
||||
# abiding by the rules of distribution of free software. You can use,
|
||||
# modify and/ or redistribute the software under the terms of the CeCILL
|
||||
# license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
# "http://www.cecill.info".
|
||||
#
|
||||
# As a counterpart to the access to the source code and rights to copy,
|
||||
# modify and redistribute granted by the license, users are provided only
|
||||
# with a limited warranty and the software's author, the holder of the
|
||||
# economic rights, and the successive licensors have only limited
|
||||
# liability.
|
||||
#
|
||||
# In this respect, the user's attention is drawn to the risks associated
|
||||
# with loading, using, modifying and/or developing or reproducing the
|
||||
# software by the user in light of its specific status of free software,
|
||||
# that may mean that it is complicated to manipulate, and that also
|
||||
# therefore means that it is reserved for developers and experienced
|
||||
# professionals having in-depth computer knowledge. Users are therefore
|
||||
# encouraged to load and test the software's suitability as regards their
|
||||
# requirements in conditions enabling the security of their systems and/or
|
||||
# data to be ensured and, more generally, to use and operate it in the
|
||||
# same conditions as regards security.
|
||||
#
|
||||
# The fact that you are presently reading this means that you have had
|
||||
# knowledge of the CeCILL license and that you accept its terms.
|
||||
|
||||
from ctypes import *
|
||||
from . import lib
|
||||
|
||||
PASSWORD_MIN_LEN = 8
|
||||
PASSWORD_MAX_LEN = 128
|
||||
PASSWORD_STORAGE_LEN = 1024
|
||||
|
||||
NOSTANDARD = 0
|
||||
NIST80063B = 1
|
||||
|
||||
|
||||
class LibreAuthPassError(Exception):
|
||||
"""Exception raised for errors in the password authentication module.
|
||||
|
||||
Attributes:
|
||||
code -- error code
|
||||
message -- explanation of the error
|
||||
"""
|
||||
|
||||
def __init__(self, code):
|
||||
valid_codes = {
|
||||
0: 'success',
|
||||
1: 'password is too short',
|
||||
2: 'password is too long',
|
||||
10: 'invalid password format',
|
||||
20: 'not enough space',
|
||||
}
|
||||
self.code = code
|
||||
if code in valid_codes:
|
||||
self.message = valid_codes[code]
|
||||
else:
|
||||
self.message = 'unknown error'
|
||||
|
||||
def password_hash(password):
|
||||
return password_hash_standard(password, NOSTANDARD)
|
||||
|
||||
def password_hash_standard(password, standard):
|
||||
pass_len = len(password)
|
||||
if pass_len < PASSWORD_MIN_LEN:
|
||||
raise LibreAuthPassError(1)
|
||||
if pass_len > PASSWORD_MAX_LEN:
|
||||
raise LibreAuthPassError(2)
|
||||
buff = create_string_buffer(b'\000' * PASSWORD_STORAGE_LEN)
|
||||
c_pass = create_string_buffer(password)
|
||||
err = lib.libreauth_password_hash(c_pass, buff, PASSWORD_STORAGE_LEN, standard)
|
||||
if err != 0:
|
||||
raise LibreAuthPassError(err)
|
||||
return str(buff.value, encoding="utf-8")
|
||||
|
||||
def is_valid(password, reference):
|
||||
c_pass = create_string_buffer(password)
|
||||
c_ref = create_string_buffer(bytes(reference, encoding='utf-8'))
|
||||
return bool(lib.libreauth_password_is_valid(c_pass, c_ref))
|
4
setup.cfg
Normal file
4
setup.cfg
Normal file
|
@ -0,0 +1,4 @@
|
|||
[bdist_wheel]
|
||||
# See PEP 425
|
||||
# https://www.python.org/dev/peps/pep-0425/
|
||||
python-tag = py3
|
31
setup.py
Normal file
31
setup.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
from setuptools import setup, find_packages
|
||||
from codecs import open
|
||||
from os import path
|
||||
|
||||
here = path.abspath(path.dirname(__file__))
|
||||
|
||||
# Get the long description from the README file
|
||||
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
|
||||
long_description = f.read()
|
||||
|
||||
setup(
|
||||
name='libreauth',
|
||||
version='0.1.0.dev2',
|
||||
description='Python bindings to the LibreAuth library.',
|
||||
long_description=long_description,
|
||||
url='https://github.com/breard-r/py-libreauth',
|
||||
author='Rodolphe Bréard',
|
||||
author_email='rodolphe@breard.tf',
|
||||
license='CeCILL',
|
||||
classifiers=[
|
||||
'Development Status :: 1 - Planning',
|
||||
'License :: OSI Approved :: CEA CNRS Inria Logiciel Libre License, version 2.1 (CeCILL-2.1)',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Topic :: Security',
|
||||
],
|
||||
keywords='authentication password oath hotp totp',
|
||||
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
|
||||
data_files=[
|
||||
('license', ['LICENSE-EN.txt', 'LICENSE-FR.txt']),
|
||||
],
|
||||
)
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
64
tests/test_password.py
Normal file
64
tests/test_password.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
# Copyright Rodolphe Breard (2017)
|
||||
# Author: Rodolphe Breard (2017)
|
||||
#
|
||||
# This software is a computer library whose purpose is to offer a
|
||||
# collection of tools for user authentication.
|
||||
#
|
||||
# This software is governed by the CeCILL license under French law and
|
||||
# abiding by the rules of distribution of free software. You can use,
|
||||
# modify and/ or redistribute the software under the terms of the CeCILL
|
||||
# license as circulated by CEA, CNRS and INRIA at the following URL
|
||||
# "http://www.cecill.info".
|
||||
#
|
||||
# As a counterpart to the access to the source code and rights to copy,
|
||||
# modify and redistribute granted by the license, users are provided only
|
||||
# with a limited warranty and the software's author, the holder of the
|
||||
# economic rights, and the successive licensors have only limited
|
||||
# liability.
|
||||
#
|
||||
# In this respect, the user's attention is drawn to the risks associated
|
||||
# with loading, using, modifying and/or developing or reproducing the
|
||||
# software by the user in light of its specific status of free software,
|
||||
# that may mean that it is complicated to manipulate, and that also
|
||||
# therefore means that it is reserved for developers and experienced
|
||||
# professionals having in-depth computer knowledge. Users are therefore
|
||||
# encouraged to load and test the software's suitability as regards their
|
||||
# requirements in conditions enabling the security of their systems and/or
|
||||
# data to be ensured and, more generally, to use and operate it in the
|
||||
# same conditions as regards security.
|
||||
#
|
||||
# The fact that you are presently reading this means that you have had
|
||||
# knowledge of the CeCILL license and that you accept its terms.
|
||||
|
||||
from libreauth.password import *
|
||||
import unittest
|
||||
|
||||
class PasswordTestCase(unittest.TestCase):
|
||||
def test_default(self):
|
||||
p = b'my super password'
|
||||
h = password_hash(p)
|
||||
self.assertTrue(h.startswith('$'))
|
||||
self.assertEqual(len(h.split('$')), 5)
|
||||
self.assertTrue(is_valid(p, h))
|
||||
self.assertFalse(is_valid(b'bad password', h))
|
||||
|
||||
def test_std(self):
|
||||
p = b'my super password'
|
||||
for std in (NOSTANDARD, NIST80063B, ):
|
||||
h = password_hash_standard(p, NIST80063B)
|
||||
self.assertTrue(h.startswith('$'))
|
||||
self.assertEqual(len(h.split('$')), 5)
|
||||
self.assertTrue(is_valid(p, h))
|
||||
self.assertFalse(is_valid(b'bad password', h))
|
||||
|
||||
def test_invalid_pass_len(self):
|
||||
for p in (b'', b'a', b'1234567'):
|
||||
with self.assertRaises(LibreAuthPassError) as cm:
|
||||
password_hash(p)
|
||||
e = cm.exception
|
||||
self.assertEqual(e.code, 1)
|
||||
for p in (b'a' * 129, b'1' * 256):
|
||||
with self.assertRaises(LibreAuthPassError) as cm:
|
||||
password_hash(p)
|
||||
e = cm.exception
|
||||
self.assertEqual(e.code, 2)
|
Reference in a new issue