Add the password sub-module

This commit is contained in:
Rodolphe Breard 2017-12-16 19:21:18 +01:00
parent d32160a4c2
commit 26973e7051
12 changed files with 414 additions and 34 deletions

4
MANIFEST.in Normal file
View file

@ -0,0 +1,4 @@
include CHANGELOG.md
include CONTRIBUTING.md
include LICENSE-EN.txt
include LICENSE-FR.txt

15
Pipfile Normal file
View 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
View 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"
}
}
}

View file

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View file

64
tests/test_password.py Normal file
View 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)