utilosafe 1.0.0__py3-none-any.whl

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/__init__.py ADDED
@@ -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__), '..'))
utilosafe/cli.py ADDED
@@ -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
utilosafe/password.py ADDED
@@ -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
utilosafe/public.py ADDED
@@ -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
utilosafe/rsa.py ADDED
@@ -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
utilosafe/utils.py ADDED
@@ -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,11 @@
1
+ utilosafe/__init__.py,sha256=DyAELVSdsjxgMumSOzR_wWHw82Uu61a9XWzC5Ktt5NY,1305
2
+ utilosafe/cli.py,sha256=OF7uQUcjaSkKfGZiNa2vzCdglptnopIzamvrDzwhbeM,1368
3
+ utilosafe/password.py,sha256=PxhTFgma3FAfqUtA5T5ayDAvd0t5ysiFmKGkwoqfuFQ,1994
4
+ utilosafe/public.py,sha256=DEjNm0g_5tNVKnD-T3PG7LFggCyTVyxXmRSqg_eSvck,1260
5
+ utilosafe/rsa.py,sha256=QoB3m-RXOgerrpx4AdS0O0Jt152ZzHC1fQNnLCCBezY,3422
6
+ utilosafe/utils.py,sha256=MUQZbO60SlwOgKGNOBKch-O7jxQjT1mhqtzg-ZneLdE,1767
7
+ utilosafe-1.0.0.dist-info/METADATA,sha256=6229QXyfZIs_2qnsuP53eh_vSv9oBhkZxweMOij_CWo,776
8
+ utilosafe-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
9
+ utilosafe-1.0.0.dist-info/entry_points.txt,sha256=Ka6oJiAW5CxtTCqs6O6Ra-7-J5iMEll-qY73Zul-_jQ,53
10
+ utilosafe-1.0.0.dist-info/top_level.txt,sha256=OesrUiuVJzJPD9KT94h0OnYcZwQ7-uJOfIMQVYrgMmU,10
11
+ utilosafe-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ safeme_create = utilosafe.cli:main
@@ -0,0 +1 @@
1
+ utilosafe