utilosafe 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- utilosafe-1.0.0/PKG-INFO +21 -0
- utilosafe-1.0.0/README +1 -0
- utilosafe-1.0.0/pyproject.toml +67 -0
- utilosafe-1.0.0/setup.cfg +4 -0
- utilosafe-1.0.0/tests/test_cli.py +46 -0
- utilosafe-1.0.0/tests/test_rsa.py +66 -0
- utilosafe-1.0.0/utilosafe/__init__.py +29 -0
- utilosafe-1.0.0/utilosafe/cli.py +43 -0
- utilosafe-1.0.0/utilosafe/password.py +64 -0
- utilosafe-1.0.0/utilosafe/public.py +40 -0
- utilosafe-1.0.0/utilosafe/rsa.py +115 -0
- utilosafe-1.0.0/utilosafe/utils.py +56 -0
- utilosafe-1.0.0/utilosafe.egg-info/PKG-INFO +21 -0
- utilosafe-1.0.0/utilosafe.egg-info/SOURCES.txt +16 -0
- utilosafe-1.0.0/utilosafe.egg-info/dependency_links.txt +1 -0
- utilosafe-1.0.0/utilosafe.egg-info/entry_points.txt +2 -0
- utilosafe-1.0.0/utilosafe.egg-info/requires.txt +8 -0
- utilosafe-1.0.0/utilosafe.egg-info/top_level.txt +1 -0
utilosafe-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: utilosafe
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Author-email: Helmut Konrad Schewe <helmutus@outlook.com>
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/anaticulae/utilosafe
|
|
7
|
+
Project-URL: Repository, https://github.com/anaticulae/utilosafe
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: utilo<3.0.0,>=2.107.3
|
|
14
|
+
Requires-Dist: configos<3.0.0,>=1.0.4
|
|
15
|
+
Requires-Dist: cryptography<39.0.0,>=38.0.3
|
|
16
|
+
Requires-Dist: bcrypt<5.0.0,>=4.0.1
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: utilotest<1.0.0,>=0.26.0; extra == "dev"
|
|
19
|
+
Requires-Dist: power<3.0.0,==2.20.1; extra == "dev"
|
|
20
|
+
|
|
21
|
+
# utilosafe
|
utilosafe-1.0.0/README
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# utilosafe
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "utilosafe"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = ""
|
|
5
|
+
readme = {file = "README", content-type = "text/markdown"}
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
authors = [
|
|
8
|
+
{name = "Helmut Konrad Schewe", email = "helmutus@outlook.com"}
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
"utilo>=2.107.3,<3.0.0",
|
|
13
|
+
"configos>=1.0.4,<3.0.0",
|
|
14
|
+
|
|
15
|
+
"cryptography>=38.0.3,<39.0.0",
|
|
16
|
+
"bcrypt>=4.0.1,<5.0.0",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
# Optional but recommended metadata
|
|
20
|
+
keywords = []
|
|
21
|
+
classifiers = [
|
|
22
|
+
'Programming Language :: Python :: 3.12',
|
|
23
|
+
'Programming Language :: Python :: 3.13',
|
|
24
|
+
'Programming Language :: Python :: 3.14',
|
|
25
|
+
]
|
|
26
|
+
license = "MIT"
|
|
27
|
+
license-files = ["LICENSE"]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
safeme_create = "utilosafe.cli:main"
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = [
|
|
34
|
+
"utilotest>=0.26.0,<1.0.0",
|
|
35
|
+
"power==2.20.1,<3.0.0",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/anaticulae/utilosafe"
|
|
40
|
+
Repository = "https://github.com/anaticulae/utilosafe"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = [
|
|
44
|
+
"setuptools>=82.0.1",
|
|
45
|
+
"wheel>=0.46.3"
|
|
46
|
+
]
|
|
47
|
+
build-backend = "setuptools.build_meta"
|
|
48
|
+
|
|
49
|
+
[tool.semantic_release]
|
|
50
|
+
version_toml = ["pyproject.toml:project.version"]
|
|
51
|
+
[tool.semantic_release.changelog.default_templates]
|
|
52
|
+
changelog_file = "CHANGELOG"
|
|
53
|
+
[tool.semantic_release.changelog]
|
|
54
|
+
mode = "init"
|
|
55
|
+
output_format = "md"
|
|
56
|
+
[tool.semantic_release.commit_parser_options]
|
|
57
|
+
# allways generate a new version
|
|
58
|
+
patch_tags = ["fix", "perf", "build", "chore", "ci", "docs", "style", "refactor", "test", "deps"]
|
|
59
|
+
|
|
60
|
+
[tool.setuptools.packages.find]
|
|
61
|
+
where = ["."]
|
|
62
|
+
include = [
|
|
63
|
+
"utilosafe",
|
|
64
|
+
]
|
|
65
|
+
exclude = [
|
|
66
|
+
"tests*",
|
|
67
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import functools
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
import utilo
|
|
14
|
+
import utilotest
|
|
15
|
+
|
|
16
|
+
import utilosafe
|
|
17
|
+
import utilosafe.cli
|
|
18
|
+
|
|
19
|
+
run = functools.partial(
|
|
20
|
+
utilotest.run_cov,
|
|
21
|
+
process='safeme_create',
|
|
22
|
+
main=utilosafe.cli.main,
|
|
23
|
+
expect=True,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@utilotest.longrun
|
|
28
|
+
def test_generate_cli(testdir, monkeypatch):
|
|
29
|
+
password = b'helm'
|
|
30
|
+
utilo.file_create_binary('password', password)
|
|
31
|
+
with monkeypatch.context() as context:
|
|
32
|
+
context.setattr(
|
|
33
|
+
utilosafe.cli,
|
|
34
|
+
'insert_password',
|
|
35
|
+
lambda: password,
|
|
36
|
+
)
|
|
37
|
+
# safeme_create < password
|
|
38
|
+
run('', mp=monkeypatch)
|
|
39
|
+
private = str(testdir.tmpdir.join('private.pem'))
|
|
40
|
+
loaded = utilosafe.load_rsa_private( # nosec
|
|
41
|
+
private,
|
|
42
|
+
passphrase=b'helm',
|
|
43
|
+
)
|
|
44
|
+
assert loaded
|
|
45
|
+
assert os.path.exists('private.pem')
|
|
46
|
+
assert os.path.exists('public.pem')
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
# import power
|
|
11
|
+
import utilotest
|
|
12
|
+
|
|
13
|
+
import utilosafe
|
|
14
|
+
import utilosafe.rsa
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@utilotest.longrun
|
|
18
|
+
def test_generate_write_load_rsa(testdir):
|
|
19
|
+
outfile = testdir.tmpdir.join('rsa')
|
|
20
|
+
private = utilosafe.create_private_key()
|
|
21
|
+
expected = utilosafe.create_public_key(private)
|
|
22
|
+
# write file
|
|
23
|
+
utilosafe.write_rsa(outfile, expected)
|
|
24
|
+
# create RSA object
|
|
25
|
+
loaded = utilosafe.rsa.dump_public_key(utilosafe.load_rsa_public(outfile))
|
|
26
|
+
assert loaded == expected
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# @pytest.mark.xfail(reason='rework large encryption')
|
|
30
|
+
# @utilotest.nightly
|
|
31
|
+
# def test_write_large_file(testdir):
|
|
32
|
+
# loaded = utilo.file_read_binary(power.BACHELOR128_PDF)
|
|
33
|
+
# private = utilosafe.create_private_key()
|
|
34
|
+
# public = utilosafe.create_public_key(private)
|
|
35
|
+
# # write file
|
|
36
|
+
# encrypted = utilosafe.encrypt(loaded, public)
|
|
37
|
+
# utilo.file_create('blabla', encrypted)
|
|
38
|
+
# decrypted = utilosafe.decrypt(encrypted, private)
|
|
39
|
+
# assert len(decrypted) == len(loaded)
|
|
40
|
+
# assert decrypted == loaded
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_public_special_bytes():
|
|
44
|
+
"""Do not remove starting \x00-zero bits when using rsa decryption."""
|
|
45
|
+
data = (b'\x00\x00\x00\x00\xf4\x0b;\xc77\xdd\xe5\x97\x08'
|
|
46
|
+
b'\xdd2\x12\x9f#\xe0\x98\xd0I\xedv\xd3-\xa6\xa6')
|
|
47
|
+
private = utilosafe.create_private_key()
|
|
48
|
+
public = utilosafe.create_public_key(private)
|
|
49
|
+
encrypted = utilosafe.encrypt(data, public)
|
|
50
|
+
decrypted = utilosafe.decrypt(encrypted, private)
|
|
51
|
+
assert decrypted == data
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_public_password(testdir, monkeypatch):
|
|
55
|
+
data = b'Helm is Hier'
|
|
56
|
+
private = utilosafe.create_private_key()
|
|
57
|
+
public = utilosafe.create_public_key(private)
|
|
58
|
+
utilosafe.write_rsa('public.pem', public)
|
|
59
|
+
path = str(testdir.tmpdir.join('public.pem'))
|
|
60
|
+
with monkeypatch.context() as context:
|
|
61
|
+
utilosafe.public_password.cache_clear()
|
|
62
|
+
context.setenv(utilosafe.UTILOSAFE_PUBLIC_KEY, path)
|
|
63
|
+
encrypted = utilosafe.encrypt(data)
|
|
64
|
+
assert encrypted != data
|
|
65
|
+
decrypted = utilosafe.decrypt(encrypted, key=private)
|
|
66
|
+
assert decrypted == data
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#==============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
#------------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
#==============================================================================
|
|
9
|
+
|
|
10
|
+
import importlib.metadata
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
__version__ = importlib.metadata.version('utilosafe')
|
|
14
|
+
|
|
15
|
+
from utilosafe.password import decrypt as decrypt_password
|
|
16
|
+
from utilosafe.password import encrypt as encrypt_password
|
|
17
|
+
from utilosafe.public import decrypt
|
|
18
|
+
from utilosafe.public import encrypt
|
|
19
|
+
from utilosafe.rsa import create_private_key
|
|
20
|
+
from utilosafe.rsa import create_public_key
|
|
21
|
+
from utilosafe.rsa import load_rsa_private
|
|
22
|
+
from utilosafe.rsa import load_rsa_public
|
|
23
|
+
from utilosafe.rsa import write_rsa
|
|
24
|
+
from utilosafe.utils import UTILOSAFE_PUBLIC_KEY
|
|
25
|
+
from utilosafe.utils import UTILOSAFE_USER_PASSWORD
|
|
26
|
+
from utilosafe.utils import public_password
|
|
27
|
+
from utilosafe.utils import user_password
|
|
28
|
+
|
|
29
|
+
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
import utilo
|
|
14
|
+
|
|
15
|
+
import utilosafe
|
|
16
|
+
import utilosafe.rsa
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main():
|
|
20
|
+
cwd = os.getcwd()
|
|
21
|
+
password = insert_password()
|
|
22
|
+
|
|
23
|
+
path_private = os.path.join(cwd, 'private.pem')
|
|
24
|
+
private = utilosafe.rsa.create_private_key(passphrase=password)
|
|
25
|
+
utilo.log(f'write private: {path_private}')
|
|
26
|
+
utilosafe.write_rsa(path_private, private)
|
|
27
|
+
|
|
28
|
+
path_public = os.path.join(cwd, 'public.pem')
|
|
29
|
+
public = utilosafe.rsa.create_public_key(private, passphrase=password)
|
|
30
|
+
utilo.log(f'write public: {path_public}')
|
|
31
|
+
utilosafe.write_rsa(path_public, public)
|
|
32
|
+
|
|
33
|
+
sys.exit(utilo.SUCCESS)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def insert_password():
|
|
37
|
+
password = input('password\n')
|
|
38
|
+
if password:
|
|
39
|
+
password = password.strip()
|
|
40
|
+
password = password.encode('utf8')
|
|
41
|
+
else:
|
|
42
|
+
password = None
|
|
43
|
+
return password
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import utilo
|
|
11
|
+
|
|
12
|
+
import utilosafe
|
|
13
|
+
import utilosafe.utils
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def encrypt(plaintext: bytes) -> bytes:
|
|
17
|
+
r"""Convert plain text to cipher text.
|
|
18
|
+
|
|
19
|
+
>>> len(encrypt(b'hello')) > 25
|
|
20
|
+
True
|
|
21
|
+
>>> decrypt(encrypt(b'hello'))
|
|
22
|
+
b'hello'
|
|
23
|
+
"""
|
|
24
|
+
if isinstance(plaintext, str):
|
|
25
|
+
plaintext = plaintext.encode(
|
|
26
|
+
encoding='utf8',
|
|
27
|
+
errors='xmlcharrefreplace',
|
|
28
|
+
)
|
|
29
|
+
plaintext = utilosafe.utils.create_block(plaintext)
|
|
30
|
+
ciphertext = aes().encrypt(plaintext)
|
|
31
|
+
return ciphertext
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def decrypt(ciphertext: bytes, string: bool = False) -> bytes:
|
|
35
|
+
"""Convert cipher text to plain text."""
|
|
36
|
+
plaintext = aes().decrypt(ciphertext)
|
|
37
|
+
plaintext = utilosafe.utils.remove_block(plaintext)
|
|
38
|
+
if string:
|
|
39
|
+
plaintext: str = plaintext.decode(encoding='utf8')
|
|
40
|
+
return plaintext
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def aes():
|
|
44
|
+
pwd = utilosafe.user_password()
|
|
45
|
+
# normalize password
|
|
46
|
+
pwd = utilo.secure_hash(pwd, digits=32)
|
|
47
|
+
pwd: bytes = pwd.encode('utf8')
|
|
48
|
+
# TODO: VERIFY PROS AND CONS OF MODE
|
|
49
|
+
try:
|
|
50
|
+
from Crypto.Cipher import AES # nosec # TODO: VERIFY THIS
|
|
51
|
+
except ImportError:
|
|
52
|
+
utilo.error('could not import Crypto.Cipher')
|
|
53
|
+
return NoPassword()
|
|
54
|
+
result = AES.new(pwd, AES.MODE_ECB)
|
|
55
|
+
return result
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class NoPassword:
|
|
59
|
+
|
|
60
|
+
def decrypt(self, ciphertext): # pylint:disable=R0201
|
|
61
|
+
return ciphertext
|
|
62
|
+
|
|
63
|
+
def encrypt(self, plaintext): # pylint:disable=R0201
|
|
64
|
+
return plaintext
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
"""\
|
|
10
|
+
>>> import utilosafe.rsa
|
|
11
|
+
|
|
12
|
+
>>> PRIVATE = utilosafe.rsa.create_private_key()
|
|
13
|
+
>>> PUBLIC = utilosafe.rsa.create_public_key(PRIVATE)
|
|
14
|
+
|
|
15
|
+
>>> encrypted = encrypt(b'Hello', public=PUBLIC)
|
|
16
|
+
>>> decrypt(encrypted, PRIVATE)
|
|
17
|
+
b'Hello'
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import utilosafe.rsa
|
|
21
|
+
import utilosafe.utils
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def encrypt(plaintext: bytes, public: bytes = None) -> int:
|
|
25
|
+
if public is None:
|
|
26
|
+
public = utilosafe.utils.public_password()
|
|
27
|
+
result = utilosafe.rsa.encrypt(
|
|
28
|
+
plaintext,
|
|
29
|
+
public,
|
|
30
|
+
)
|
|
31
|
+
return result
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def decrypt(ciphertext: bytes, key: str, passphrase: bytes = None) -> bytes:
|
|
35
|
+
result = utilosafe.rsa.decrypt(
|
|
36
|
+
ciphertext,
|
|
37
|
+
key,
|
|
38
|
+
passphrase=passphrase,
|
|
39
|
+
)
|
|
40
|
+
return result
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
"""\
|
|
10
|
+
>>> import utilosafe.rsa
|
|
11
|
+
|
|
12
|
+
>>> PRIVATE = utilosafe.rsa.create_private_key()
|
|
13
|
+
>>> PUBLIC = utilosafe.rsa.create_public_key(PRIVATE)
|
|
14
|
+
|
|
15
|
+
>>> encrypted = encrypt(b'Hello', public=PUBLIC)
|
|
16
|
+
>>> decrypt(encrypted, PRIVATE)
|
|
17
|
+
b'Hello'
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import utilo
|
|
21
|
+
from cryptography.hazmat.primitives import serialization
|
|
22
|
+
from cryptography.hazmat.primitives.asymmetric import padding
|
|
23
|
+
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
24
|
+
|
|
25
|
+
PUBLIC_EXPONENT = 65537
|
|
26
|
+
|
|
27
|
+
PADDING = padding.PKCS1v15()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def encrypt(plaintext: bytes, public: bytes) -> int:
|
|
31
|
+
if isinstance(public, bytes):
|
|
32
|
+
public = serialization.load_ssh_public_key(public)
|
|
33
|
+
result = public.encrypt(
|
|
34
|
+
plaintext=plaintext,
|
|
35
|
+
padding=PADDING,
|
|
36
|
+
)
|
|
37
|
+
return result
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def decrypt(ciphertext: bytes, path: str, passphrase: bytes = None) -> bytes:
|
|
41
|
+
loaded = load_rsa_private(path, passphrase=passphrase)
|
|
42
|
+
result = loaded.decrypt(
|
|
43
|
+
ciphertext=ciphertext,
|
|
44
|
+
padding=PADDING,
|
|
45
|
+
)
|
|
46
|
+
return result
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def create_private_key(passphrase: bytes = None, bits: int = 1024) -> bytes:
|
|
50
|
+
r"""\
|
|
51
|
+
>>> create_private_key(b'HelmIsSafe')
|
|
52
|
+
b'-----BEGIN OPENSSH PRIVATE KEY-----...---END OPENSSH PRIVATE KEY-----\n'
|
|
53
|
+
"""
|
|
54
|
+
private = rsa.generate_private_key(
|
|
55
|
+
public_exponent=PUBLIC_EXPONENT,
|
|
56
|
+
key_size=bits,
|
|
57
|
+
)
|
|
58
|
+
algo = serialization.NoEncryption()
|
|
59
|
+
if passphrase:
|
|
60
|
+
algo = serialization.BestAvailableEncryption(password=passphrase) # pylint:disable=R0204
|
|
61
|
+
result = private.private_bytes(
|
|
62
|
+
encoding=serialization.Encoding.PEM,
|
|
63
|
+
format=serialization.PrivateFormat.OpenSSH,
|
|
64
|
+
encryption_algorithm=algo,
|
|
65
|
+
)
|
|
66
|
+
return result
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def create_public_key(private: bytes, passphrase=None) -> bytes:
|
|
70
|
+
"""\
|
|
71
|
+
>>> create_public_key(create_private_key())
|
|
72
|
+
b'ssh-rsa ...=='
|
|
73
|
+
>>> create_public_key(create_private_key(passphrase=b'helm'), b'helm')
|
|
74
|
+
b'ssh-rsa ...=='
|
|
75
|
+
"""
|
|
76
|
+
result = serialization.load_ssh_private_key(
|
|
77
|
+
data=private,
|
|
78
|
+
password=passphrase,
|
|
79
|
+
)
|
|
80
|
+
public = result.public_key()
|
|
81
|
+
result = dump_public_key(public)
|
|
82
|
+
return result
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def dump_public_key(public) -> bytes:
|
|
86
|
+
result = public.public_bytes(
|
|
87
|
+
encoding=serialization.Encoding.OpenSSH,
|
|
88
|
+
format=serialization.PublicFormat.OpenSSH,
|
|
89
|
+
)
|
|
90
|
+
return result
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def write_rsa(path, key: bytes):
|
|
94
|
+
utilo.file_replace_binary(path, key)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def load_rsa_private(
|
|
98
|
+
path,
|
|
99
|
+
passphrase: bytes = None,
|
|
100
|
+
) -> '_SSH_PRIVATE_KEY_TYPES':
|
|
101
|
+
if isinstance(path, str):
|
|
102
|
+
loaded = utilo.file_read_binary(path)
|
|
103
|
+
else:
|
|
104
|
+
loaded = path
|
|
105
|
+
result = serialization.load_ssh_private_key(
|
|
106
|
+
data=loaded,
|
|
107
|
+
password=passphrase,
|
|
108
|
+
)
|
|
109
|
+
return result
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def load_rsa_public(path) -> '_SSH_PUBLIC_KEY_TYPES':
|
|
113
|
+
data = utilo.file_read_binary(path)
|
|
114
|
+
result = serialization.load_ssh_public_key(data=data)
|
|
115
|
+
return result
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import math
|
|
11
|
+
|
|
12
|
+
import configos
|
|
13
|
+
import utilo
|
|
14
|
+
|
|
15
|
+
import utilosafe
|
|
16
|
+
|
|
17
|
+
BLOCKSIZE = 32
|
|
18
|
+
|
|
19
|
+
UTILOSAFE_PUBLIC_KEY = 'UTILOSAFE_PUBLIC_KEY' # nosec
|
|
20
|
+
UTILOSAFE_USER_PASSWORD = 'UTILOSAFE_USER_PASSWORD' # nosec
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def create_block(content: bytes, blocksize: int = BLOCKSIZE) -> bytes:
|
|
24
|
+
"""\
|
|
25
|
+
>>> create_block(b'abc' * 15)
|
|
26
|
+
b'abcabcabcabcabcabcabcabcabcabcabcabcabcabcabc '
|
|
27
|
+
"""
|
|
28
|
+
if not len(content) % blocksize:
|
|
29
|
+
return content
|
|
30
|
+
missing = math.ceil(len(content) / blocksize) * blocksize - len(content)
|
|
31
|
+
content = content + b' ' * missing
|
|
32
|
+
return content
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def remove_block(content: bytes) -> bytes:
|
|
36
|
+
stripped = content.rstrip()
|
|
37
|
+
if content[len(stripped):len(stripped) + 1] == b'\n':
|
|
38
|
+
# valid file ends with newline
|
|
39
|
+
stripped = content[0:len(stripped) + 1]
|
|
40
|
+
return stripped
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@utilo.cacheme
|
|
44
|
+
def user_password() -> str:
|
|
45
|
+
result = configos.env(UTILOSAFE_USER_PASSWORD, 'NOPASSWORD')
|
|
46
|
+
return result
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@utilo.cacheme
|
|
50
|
+
def public_password() -> 'RSA':
|
|
51
|
+
path = configos.env(UTILOSAFE_PUBLIC_KEY, None)
|
|
52
|
+
if not path:
|
|
53
|
+
utilo.error(f'missing env {UTILOSAFE_PUBLIC_KEY}')
|
|
54
|
+
return None
|
|
55
|
+
result = utilosafe.load_rsa_public(path)
|
|
56
|
+
return result
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: utilosafe
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Author-email: Helmut Konrad Schewe <helmutus@outlook.com>
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/anaticulae/utilosafe
|
|
7
|
+
Project-URL: Repository, https://github.com/anaticulae/utilosafe
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: utilo<3.0.0,>=2.107.3
|
|
14
|
+
Requires-Dist: configos<3.0.0,>=1.0.4
|
|
15
|
+
Requires-Dist: cryptography<39.0.0,>=38.0.3
|
|
16
|
+
Requires-Dist: bcrypt<5.0.0,>=4.0.1
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: utilotest<1.0.0,>=0.26.0; extra == "dev"
|
|
19
|
+
Requires-Dist: power<3.0.0,==2.20.1; extra == "dev"
|
|
20
|
+
|
|
21
|
+
# utilosafe
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
README
|
|
2
|
+
pyproject.toml
|
|
3
|
+
tests/test_cli.py
|
|
4
|
+
tests/test_rsa.py
|
|
5
|
+
utilosafe/__init__.py
|
|
6
|
+
utilosafe/cli.py
|
|
7
|
+
utilosafe/password.py
|
|
8
|
+
utilosafe/public.py
|
|
9
|
+
utilosafe/rsa.py
|
|
10
|
+
utilosafe/utils.py
|
|
11
|
+
utilosafe.egg-info/PKG-INFO
|
|
12
|
+
utilosafe.egg-info/SOURCES.txt
|
|
13
|
+
utilosafe.egg-info/dependency_links.txt
|
|
14
|
+
utilosafe.egg-info/entry_points.txt
|
|
15
|
+
utilosafe.egg-info/requires.txt
|
|
16
|
+
utilosafe.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
utilosafe
|