I have a method in a class which decrypts a variable, and returns it. I remove the returned variable with "del" after use.
What is the danger of these garbage values being accessed...and how can I best protect myself from them?
Here is the code:
import decrypter
import gc
# mangled variable names used
def decrypt(__var):
__cleartext = decrypter.removeencryption(__var)
return __cleartext
__p_var = "<512 encrypted password text>"
__p_cleartext = decrypt(__p_var)
<....do login with __p_cleartext...>
del __p_var, __p_cleartext
gc.collect()
Could any of the variables, including __var and __cleartext be exploited at this point?
Thanks!
I've done a little more googling. Before I spend a few hours going down the wrong path...what I'm hearing is:
- Store the password as a salted hash on the system (which it is doing now).
- The salt for the hash should be entered in by the user at suite start (being done now)
- However, the salt should be held in C process and not python.
- The python script should pass the hash to to the C process for decryption.
The python script is handling the login for a mysql database, and the password is needed to open the DB connection.
If the code were along the lines of...
# MySQLdb.connect(host, user, password, database)
mysql_host = 'localhost'
mysql_db = 'myFunDatabase'
hashed_user = '\xghjd\xhjiw\xhjiw\x783\xjkgd6\xcdw8'
hashed_password = 'ghjkde\xhu78\x8y9tyk\x89g\x5de56x\xhyu8'
db = MySQLdb.connect(mysql_host, <call_c(hashed_user)>, <call_c(hashed_password)>, mysql_db])
Would this resolve (at least) the issue of python leaving garbage all over?
P.s. I also found the post about memset (Mark data as sensitive in python) but I'm assuming if I use C to decrypt the hash, this is not helpful.
P.P.S. The dycrypter is currentlt a python script. If I were to add memset to the script and then "compile" it using py2exe or pyinstaller....would this actually do anything to help protect the password? My instincts say no, since all pyinstaller does is package up the normal interpreter and the same bytecode the local interpreter creates...but I don;t know enough about it...?
So...following Aya's suggestion of making the encryption module in C, how much of a discernible memory footprint would the following setup leave. Part of the big issue is; the ability to decrypt the password must remain available throughout the run of the program as it will be called repeatedly...it's not a one-time thing.
Make a C object which is started when the user logins in. It contains the decryption routine and the holds a copy of the salt entered by the user at login. The stored salt is obscured in the running object (in memory) by having been hashed by it's own encryption routine using a randomly generated salt.
The randomly generated salt would still have to be held in a variable in the object too. This is not really to secure the salt, but just to try and obfuscate the memory footprint if someone should take a peek at it (making the salt hard to identify). I.e. c-obj
mlock() /*to keep the code memory resident (no swap)*/
char encrypt(data, salt){
(...)
return encrypted_data
}
char decrypt(data, salt){
(...)
return decrypted_data
}
stream_callback(stream_data){
return decrypt(stream_data, decrypt(s-gdhen, jhgtdyuwj))
}
void main{
char jhgtdyuwj=rand();
s-gdhen = encrypt(<raw_user_input>, jhgtdyuwj);
}
Then, the python script calls the C object directly, which passes the unencrypted result right into the MySQLdb call without storing any returns in any variable. I.e.
#!/usr/bin/python
encrypted_username = 'feh9876\xhu378\x&457(oy\x'
encrypted_password = 'dee\x\xhuie\xhjfirihy\x^\xhjfkekl'
# MySQLdb.connect(host, username, password, database)
db = MySQLdb.connect(self.mysql_host,
c-obj.stream_callabck(encrypted_username),
c-obj.stream_callback(encrypted_password),
self.mysql_database)
What kind of memory footprint might this leave which could be snooped?