how to go about saving passwords

I was hoping you all can help me by sharing some ideas on how to save passwords to the computer. I have a console app that checks emails and I wanted to save the passwords so my app can read them in and check emails. For testing, currently I am writing them to a pref’s file as plain text which is obviously not secure. I am developing for mac and windows.

Might be an overkill, but I store passwords in an encrypted SQLite database.

You might want to take a look at this conversation Joseph…

https://forum.xojo.com/10622-how-to-store-a-hashed-password-in-an-sqlite-db

I doubt that one can ever be too safe when it comes to passwords… if it is hashed as well it is even better.

Thanks guys.

From reviewing Alwyn’s link, it looks like I can use the crypto class to create a key and encrypt the data (email passwords) then save them to a database. Where then would I keep the key stored?

Forgive me if these questions are super basic. I have zero experience with encryption. :slight_smile:

the question is if those are passwords you need in clear text later for login somewhere or if that are passwords for your own app which you store to verify later.
For the second case, please hash them before storing.
An encrypted SQLite database provides some security.

On Mac it should be stored in the OS Keychain. Nowhere else.

Tim great point and reminder for OS X!

Also:
http://documentation.xojo.com/index.php/KeyChain

Is there a feature on windows that is similar to the keychain? Maybe I can do some declares to take advantage of built in features.

If you’re using the passwords internally, you need to store them encrypted. If you’re using passwords that are entered manually (like in a textfield), you only store the hash of the password… then reference the hash of the password entered to the hash stored (if they match, you can assume it is the correct password).

Thank you for the suggestions. So far, here’s my plan:

  1. Have a preferences app with a GUI to enter passwords into edit fields
  2. The app hashes the passwords and enters them into an encrypted sqlite database
  3. My console app (the one that actually checks emails) will open the database to read the passwords

I’m stuck here at this point. Suppose I hash the passwords using the following and save them to a database:

Dim hash As String hash = Crypto.PBKDF2("SaltValue", "YourPasswordSentence", 100, 32, Crypto.Algorithm.SHA512)

How is my console app supposed to read in the passwords and use them to log in to the email servers if they are hashed? I know I’m missing something, the passwords at this point have no way of being “un-hashed”. Is that correct?

Correct. A hash is not encrypted data. You want a password retrieval system, where hashes only work as a method to validate a password. You need to use a cypher/encryption method to store your password with, and a decypher/decryption method to obtain a password with.

Thank you for setting me straight on this!

This is a bit ugly but it roughly how I would store they keys to the credentials database on Windows. In this case I am storing all three pieces of information in the registry but in reality I would put them in three different places.

I would put the saving of the master password in the user’s hand. The database password would be a hash of the user’s password with an appropriate salt.

Create the database:

[code]If txtPW.Text = “” Then
MsgBox(“A password is required to securely store your email account info.”)
Return
End If

’ You will want to warn the user they are about to nuke their existing database. Also a better location would be a sub-folder.
If SpecialFolder.ApplicationData.Child(“cred.db”) <> Nil And SpecialFolder.ApplicationData.Child(“cred.db”).Exists Then
SpecialFolder.ApplicationData.Child(“cred.db”).Delete
End If

’ choose something unique for a salt.
Dim r As New Random
Dim strSalt1 As String = EncodeBase64(Crypto.Hash(System.EnvironmentVariable(“HOME”) + Str(r.InRange(100000, 900000)), Crypto.Algorithm.SHA512))
Dim strSalt2 As String = EncodeBase64(Crypto.Hash(System.EnvironmentVariable(“COMPUTERNAME”) + Str(r.InRange(100000, 900000)), Crypto.Algorithm.SHA512))

Dim reg As New RegistryItem(“HKEY_CURRENT_USER\SOFTWARE\MyCompany\MyApp”, True)
reg.Value(“KeyNameForSalt1”) = strSalt1
reg.Value(“KeyNameForSalt2”) = strSalt2

Dim strPW As String = EncodeBase64(Crypto.Hash(txtPW.Text + strSalt1, Crypto.Algorithm.SHA512))
If chkSave.Value Then
reg.Value(“KeyNameForPWhash”) = strPW
Else
’ You can check this when opening the database to know you need the password.
reg.Value(“KeyNameForPWhash”) = “”
End If

Dim dbKey As String = EncodeBase64(Crypto.Hash(strPW + strSalt2, Crypto.Algorithm.SHA512))

Dim dpCPW As SQLiteDatabase ’ This should really be a property of the application.
dpCPW = New SQLiteDatabase
dpCPW.DatabaseFile = SpecialFolder.ApplicationData.Child(“cred.db”)
dpCPW.EncryptionKey = dbKey
If Not dpCPW.CreateDatabaseFile Then
MsgBox("Unable to create database. " + dpCPW.ErrorMessage)
Else
MsgBox(“Database created.”)
End If[/code]

Use the database:

[code]DIM reg As New RegistryItem(“HKEY_CURRENT_USER\SOFTWARE\MyCompany\MyApp”, False)
Dim strOPW As String = “”
Dim strSalt1 As String = “”
Dim strSalt2 As String = “”

Try
strSalt1 = reg.Value(“KeyNameForSalt1”)
strSalt2 = reg.Value(“KeyNameForSalt2”)
Catch ex As RegistryAccessErrorException
MsgBox(“Unable to load database key.”)
Return
End Try

If txtOPW.Text = “” Then
’ I only use the registry if no password has been entered.
Try
strOPW = reg.Value(“KeyNameForPWhash”)
Catch ex As RegistryAccessErrorException
MsgBox(“You must enter a password.”)
Return
End Try
If strOPW = “” Then
MsgBox(“You must enter a password.”)
Return
End If
Else
strOPW = EncodeBase64(Crypto.Hash(txtOPW.Text + strSalt1, Crypto.Algorithm.SHA512))
End If

Dim dbKey As String = EncodeBase64(Crypto.Hash(strOPW + strSalt2, Crypto.Algorithm.SHA512))

If Not SpecialFolder.ApplicationData.Child(“cred.db”).Exists Then
MsgBox(“file not found.”)
End If

dbOPW = New SQLiteDatabase ’ Should be a property somewhere.
dbOPW.DatabaseFile = SpecialFolder.ApplicationData.Child(“cred.db”)
dbOPW.EncryptionKey = dbKey
If Not dbOPW.Connect Then
MsgBox("Unable to open database. " + dbOPW.ErrorMessage)
Else
MsgBox(“Database opened.”)
End If[/code]