Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
Smash_pass
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Smashpass
Smash_pass
Commits
6d7da466
Commit
6d7da466
authored
Dec 23, 2024
by
Benjamin REED
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cleanup and doc comments
parent
ad9e425c
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
66 additions
and
18 deletions
+66
-18
main.py
main.py
+66
-18
No files found.
main.py
View file @
6d7da466
...
...
@@ -49,6 +49,9 @@ CHARSET_MAP = {
SAFEST
=
50
"""
Simple function that prints a prompt message to get a confirmation message.
"""
def
confirm
(
msg
,
yes
,
no
):
i
=
input
(
msg
+
f
" ({yes}/{no})"
)
i
.
strip
()
...
...
@@ -90,6 +93,16 @@ def encrypt(message: bytes, key: bytes) -> bytes:
def
decrypt
(
token
:
bytes
,
key
:
bytes
)
->
bytes
:
return
Fernet
(
key
)
.
decrypt
(
token
)
"""
Password class contains:
- key => The key used to encrypt and decrypt the password, 'int' for caesar, 'Tuple(bigint, bigint)' for RSA
- mode => 'rsa' or 'csr', the encryption method used for the password
- password => the unencrypted password
Note: it is probably a bad idea to have the program open on a multi-user device, as the passwords
are stored in Python interpreter memory unobfuscated, and as such can be found using simple C function calls.
Memory obfuscation is possibly a feature to add in the future or to use as the consumer of this program.
"""
class
Password
:
def
__init__
(
self
,
password
,
key
,
mode
):
self
.
password
=
password
...
...
@@ -102,6 +115,12 @@ class Password:
def
__repr__
(
self
):
return
self
.
__str__
()
"""
Accept a key and an encrypted password and return the decrypted password.
NOTE: this uses an unbeleivably dangerous loophole with 'eval' that should
not be allowed to release into the final version
"""
def
decrypt
(
password
,
key
,
mode
):
if
mode
==
"csr"
:
s
=
[]
...
...
@@ -116,6 +135,9 @@ class Password:
password
=
eval
(
password
)
return
rsa
.
decrypt_data
(
key
.
q
,
password
)
"""
Returns the encrypted bytes of the password depending on password type.
"""
def
encrypt
(
self
):
match
self
.
mode
:
case
"rsa"
:
...
...
@@ -125,18 +147,31 @@ class Password:
case
_
:
raise
Exception
"""Returns serialized string representing this password for saving.
"""
def
serialize
(
self
):
return
f
"{self.key},{self.encrypt()}"
"""
Encrypt a password with helper functions from the rsa.py module.
"""
def
rsa_encrypt
(
self
):
return
rsa
.
encrypt_data
(
self
.
key
.
p
,
self
.
password
)
"""
Increment the index of each character by one.
"""
def
csr_encrypt
(
self
):
s
=
[]
for
l
in
str
(
self
.
password
):
s
.
append
(
chr
(
ord
(
l
)
+
int
(
self
.
key
)))
return
""
.
join
(
s
)
"""
State of password manager, passwords, keys, and path of database file.
NOTE: the class's constructor is also its load function.
"""
class
State
:
def
__init__
(
self
,
filepath
,
password
):
if
not
os
.
path
.
isfile
(
filepath
):
...
...
@@ -218,6 +253,11 @@ class State:
file
.
close
()
"""
Add a password to the state depending on what type of password it is.
NOTE: an empty string as a label will cause the label to be the number of passwords + 1
"""
def
add_password
(
self
,
label
,
password_in
,
mode
,
key
=
None
):
if
label
is
None
:
label
=
str
(
len
(
self
.
passwords
)
+
1
)
...
...
@@ -233,8 +273,10 @@ class State:
p
=
Password
(
password_in
,
key
,
mode
)
self
.
passwords
[
label
]
=
p
#self.passwords[label] = encrypt(password.encode, self.key)
"""
Returns password as bytes.
"""
def
get_password
(
self
,
label
):
if
label
in
self
.
passwords
:
p
=
self
.
passwords
[
label
]
...
...
@@ -245,16 +287,25 @@ class State:
else
:
return
b
"[ERROR: no such label found]"
def
serialize_password
(
self
,
label
,
password
):
if
label
in
self
.
to_remove
:
return
f
"rm({label}),{password.encrypt()}"
# elif key in self.overwritten:
# del self.overwritten[self.overwritten.index(key)]
# return f"old({key}),{value.decode('utf-8')}"
else
:
return
f
"{label},{password.encrypt()}"
"""
Saves the State to State.filepath.
NOTE: the database file currently contains no version data, making incompatibility un unnoticed error.
FORMAT:
<head> <-- verification that inputted password is correct using Fernet encryption
<rsa key> <-- RSA key corresponding to this state
<foreach p in passwords>
if p is caesar:
'mode:csr:<p.key>' <-- each caesar password has its own key
'<p.label>,<p.encrypted_password>' <-- comma separated
<end>
'mode:rsa:_' <-- _ means the key is defined at the top of the file
<foreach p in passwords>
if p is rsa:
'<p.label>,<p.encrypted_password>' <-- same format as caesar, just in a different section
<end>
"""
def
save
(
self
):
content
=
self
.
head
+
"
\n
"
content
+=
f
"{self.rsa_key}"
+
"
\n
"
...
...
@@ -277,16 +328,15 @@ class State:
file
.
write
(
content
)
file
.
close
()
"""
Generate a password given a 'set' object of characters to choose from.
"""
def
generate_password
(
length
,
charset
):
s
=
[]
for
i
in
range
(
0
,
length
):
s
.
append
(
random
.
choice
(
list
(
charset
)))
return
''
.
join
(
s
)
def
aes_256
(
inp
):
pass
def
handle_args
(
db
:
str
,
password
:
str
):
state
=
State
(
db
,
password
)
return
state
...
...
@@ -352,7 +402,6 @@ def main():
print
(
f
"Error parsing database {filepath}: {e}"
)
return
# TODO: make this serialized (somehow... :[)
cfg
=
{
"hints"
:
True
}
...
...
@@ -470,7 +519,7 @@ def main():
print
(
"You will have to rename this password to restore it."
)
label_in
=
input
(
"New label (If left empty, a number will be used): "
)
if
label_in
==
""
:
label
=
str
(
len
(
state
.
passwords
)
+
1
)
# oh so hacky, i hate python and i want my damn state to be operated on by its own damn functions. I hate this.
label
=
str
(
len
(
state
.
passwords
)
+
1
)
else
:
label_in
.
strip
()
label
=
label_in
.
lower
()
...
...
@@ -589,7 +638,6 @@ def main():
state
.
add_password
(
label
,
password
.
encode
(),
mode
,
key
)
elif
command
==
"list"
or
command
==
"ls"
:
if
len
(
args
)
==
1
:
# if state.passwords.len() >= 10:
# TODO: make it possible to scroll thru a list of passwords
for
l
in
state
.
passwords
:
if
l
not
in
state
.
to_remove
and
"old"
not
in
l
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment