cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
JMP is taking Discovery online, April 16 and 18. Register today and join us for interactive sessions featuring popular presentation topics, networking, and discussions with the experts.
Choose Language Hide Translation Bar
vince_faller
Super User (Alumni)

save passwords securely

Does anyone have a secure way to store passwords so users don't have to enter their password every time?  

I don't want to just store the password as plain text in a preferences file or anything like that.  

 

Names default to here(1);
nw = new window("Login", 
	lineupbox(ncol(2), 
		textbox("Username"), teb_uid = texteditbox("Vincent", <<Set Width(200)), 
		textbox("Password"), teb_pwd = texteditbox("thisisapassword", <<Width(200), <<Password Style(1))
	), 
	cb_save = checkbox({"Remember Me"}), 
	buttonbox("OK", 
		uid = teb_uid << Get Text();
		pwd = teb_pwd << Get Text();
		nw << close window();
	)
);

Vince Faller - Predictum
1 ACCEPTED SOLUTION

Accepted Solutions

Re: save passwords securely

You can look at doing encryption using a JMP add-in. Understand that shipping an encryption library has legal and export ramifications. Your best bet would be to write an add-in that calls into the native encryption libraries already on the host OS, and then still run it past your legal team.

View solution in original post

12 REPLIES 12
txnelson
Super User

Re: save passwords securely

Create a script that contains the passwords........in Associative Arrays, or in lists, etc.  Then save that script as an encrypted script.

Jim
vince_faller
Super User (Alumni)

Re: save passwords securely

That would involve me having access to all users passwords.  Definitely not doable.  And telling a user to save their password as an encrypted script also isn't a viable option.  I truly want a "remember me" option where I can store whatever username/password  they type programmatically, but that storage is secure.  

Vince Faller - Predictum
vince_faller
Super User (Alumni)

Re: save passwords securely

Figured I'd try to bump this to see if anyone has any ideas.  

Because now I'm having issues with other types of secrets as well.  User Access Codes and what not.  

Vince Faller - Predictum

Re: save passwords securely

Secure storage of credentials is a difficult issue.  It's really difficult to do right.  At very least you likely still need the user to enter some form of credentials once per session, to prevent unauthorized use of the secrets you are trying to protect.  So for each 'user' you will likely need to store a password for their credential store.  Then you need the credential store itself.  How secure is enough?  Do you just need obfuscation, such as a simple substitution cipher like rot13 ( shift the letters of the alphabet by 13 so m => z, a =>n or do you need something stronger like AES encryption, or Public Key encryption?  You could create your data store using a JMP table, a text file or a database table, JMP has ODBC support for database connectivity.  Better checksums and encryption support, either written in JSL, or loaded from shared libraries via JMP's add-in capability or through the Python bridge.

 

Securing passwords,

A traditional way to keep passwords files secure it to use a hash function.  One way has functions such as MD5, the SHA family, SHA1, SHA256, ... all take data and create a hash that cannot be reversed to reveal the original data.  The idea is you take the data you want to secure and create a hash from the data.  Usually such hashes are stirred with a SALT value, a random value that is stored with the password data.  The salt make it far more costly to keep lookup tables of known data to hash values. Then when the user type in the password, you hash the entered value and compare the hash against the stored value. If they match == success and password is validated.  JMP exposes the MD5 checksum to JSL.  From the scripting index, see Blob MD5(). Please note that MD5's use for cryptographic purposes is not secure against modern cryptographic techniques, but for low level security is still should be fine.

 

Then, you can use the hash or even combine the hash with additional data create a derived hash or HMAC https://en.wikipedia.org/wiki/HMAC to act as the password key to your protected data store.  Some databases have encrypt functionality for data fields, or you may have to encrypt the data yourself and store in the table.

 

Lastly if you need greater security, look at JMP's add-in functionality that can call into shared libraries, there you could implement as complex a data management scheme as you desire.  Or look to JMP's Python interface, calling out to Python packages can give you access to sqlite, and better checksums and encryption methods. 

 

How I would go about building such a data store?  I would lean heavily on JMP's Python interface.  The sqlite database support is built into Python, and would use that or JMP tables for my data store.  Further Python is generally built with crypt support, checksums and encryption algorithms.  I would first start by creating a password table table which has a hash of the passwords.  Then build a data store as another table which have encrypted fields.  Just how secure, how complicated, a matter of how much code and how much testing...

Re: save passwords securely

Sample python script to create a sqlite data store, 

#! /usr/bin/env/python3
#
# Author: Paul Nelson - JMP Statistical Discovery, From SAS
# Date: 9 Mar 2020
#
# Description: This sample shows the python code using sqlite to create a data data store
# for saving passwords, credentails...  While Python has hash functions, the standard library
# does not include ciphers.  For purposes of this sample I used lzma compression to 'encode' and
# decompression to 'decrypt'  For use from JSL, I would turn this into a python module and then
# import 'my_dataStore_api' to cut down code in the JSL string.
#
# sample python program using sqlite to create a secure store for passwords and
# key, value data storage.
#
# While Python contains hash functions, does not include encryption primitives in the standard library.
# an example using PyCrypto can be found
# https://stackoverflow.com/questions/12524994/encrypt-decrypt-using-pycrypto-aes-265
# however pycrypto has no been updated since 2014... https://github.com/dlitz/pycrypto
#
# pyca/cryptography - https://cryptography.io/    https://github.com/pyca/cryptography
# seems to be currently maintained.
#
# Don't create your own encryption! The above packages or, openssl, or many other providers are
# better than writing your own.
#
# It is an exercise left to the reader to replace the code using lzma compression with real encrypt
# and decrypt code.  :)
# 
# 
import sqlite3
import hashlib
import os
from pathlib import Path
import lzma

# Salt should be random quantity, get from OS entropy source
salt = os.urandom(16);
mypasswd = b'JMP in a dried up lake'
dk = hashlib.pbkdf2_hmac('sha256', mypasswd, salt, 1000)
# dk.hex()  will be the actual hashed password saved to db
# but the binary dk, will be what we use as the encryption key
# dkhex = dk.hex()
# binDk = bytes.fromhex(dkhex)
# 

# Path to my credential store , my home directory + AppData
data_path = str(Path.home()) + '/AppData/'
filename = 'dataStore'

# Create directory if it doesn't exist
os.makedirs(data_path, exist_ok=True)

# will create database if it doesn't exist
db = sqlite3.connect(data_path + filename + '.db')

# my username
me = 'jmpuser'

# create our password table storing hashed passwords
db.execute('CREATE TABLE IF NOT EXISTS passwd (uid INTEGER PRIMARY KEY, name TEXT, salt TEXT, key TEXT)')

# should check to see if user is in database and only insert if not found
# exercise left to the reader
db.execute("INSERT INTO passwd (name, salt, key) VALUES( ?,?,? ) ", (me, salt.hex(), dk.hex()) )
db.commit()
print('******* passwd database *******')
for row in db.execute('SELECT * from passwd'):
    print(row)
print('*******************************')    

# create our credentials table which will store the name of the credential, and its value
db.execute('CREATE TABLE IF NOT EXISTS credentials (id INTEGER PRIMARY KEY, uid INTEGER, key TEXT, value TEXT)')

# first we need to have validated that user gave propper password, and we authenticated against passwd
# table assuming user is authenticated

# should check to see if user is in database and only insert if not found, potentially update if found
# exercise left to the reader.

# my user id in this scheme 
id = 0

#The value data I'm going to store into the database
myson1 = """
{
   user: paul
   magic_key: JMP Rocks!
}"""

myson2 = """
{
   user: paul
   magic_key: supercalifragilisticexpialidocious
}"""

# 'encrypt' my data
lvalue = lzma.compress( myson2.encode() )
lvalue2 = lzma.compress( myson1.encode() )

# you could encrypt the 'key' as well as the value if you really want security
db.execute("INSERT INTO credentials (uid, key, value) VALUES( ?,?,? ) ", (id, 'JMPCommunity', lvalue.hex()) )
db.execute("INSERT INTO credentials (uid, key, value) VALUES( ?,?,? ) ", (id, 'WDW', lvalue2.hex()) )
db.commit()
print('******* credentials database *******')
for row in db.execute('SELECT * from credentials WHERE uid=?', (id,) ):
    print(row)
    value = bytes.fromhex(row[3])
    print(lzma.decompress(value).decode())
print('************************************')
db.close()
ih
Super User (Alumni) ih
Super User (Alumni)

Re: save passwords securely

Found this while looking for a better solution for myself.  For scripts on my own machine, I call R and use the keyring function.  It uses Keychain on mac, Credential Store on Windows, and the Secret Service API on Linux.  Obviously this comes with overhead, it would be nice to do this without R.  If interested, I put a JMP Wish List item to create these functions in JMP.

 

https://github.com/r-lib/keyring

 

R Init();
R Submit(
	"library(keyring)
	pw <- keyring::key_get(\!"DomainAccount\!", \!"username\!")"
);
pw = R Get("pw");
R Term();
vince_faller
Super User (Alumni)

Re: save passwords securely

I like this.  I unfortunately can't force customers to install python (some have explicitly forbidden their users to install it).  But I have convinced most to install the sqlite odbc driver so maybe I can use that with MD5.  

I'd still have to find some way to do encryption. 

Thanks for the help, I've definitely got some research to do.  

Vince Faller - Predictum

Re: save passwords securely

You can look at doing encryption using a JMP add-in. Understand that shipping an encryption library has legal and export ramifications. Your best bet would be to write an add-in that calls into the native encryption libraries already on the host OS, and then still run it past your legal team.
vince_faller
Super User (Alumni)

Re: save passwords securely

You've been more than helpful.  Thank you.  

Vince Faller - Predictum