Add two Yubikey to KeepassXC - yubico

I'm testing Yubico Yubikeys 5 NFC, in general, we use KeePassXC to save sensible information. KeePassXC accepts yubikeys but just one... Anyone know if it possible to add more than one to a kdbx file?

After talking to the KeePassXC dev team, it is clear that having two different seeds in two separate Yubikeys is not possible. You need to add the same seed to the other Yubikey to keep a copy of the seed.
In the Docs section, can we read this:
What happens if I break my YubiKey? Can I create backup keys?
You should always make a copy of the HMAC secret that is stored on the YubiKey and keep it in a secure location. This can be an analog paper copy, but since the YubiKey personalization tool allows you to program a custom secret into the key, you may as well program a second key with the same secret
Can I register multiple YubiKeys with my KeePassXC database?
You can only use a single secret for encrypting the database. So you can use multiple YubiKeys, but they all have to be programmed with the same secret (see question above).
and The explanation to how to setup the same id in slot 2 in two yubikeys is here:
https://support.yubico.com/hc/en-us/articles/360013779759-Using-Your-YubiKey-with-KeePass
Just remember in the second key you must copy & paste the same seed
The complete discussion is here: https://github.com/keepassxreboot/keepassxc/discussions/6344

Recommend to use a strong master password on top of the YubiKeys & save the DB regularly to generate new challenge/response pairs. Far from perfect but better than just a password. The following method (Challenge-response with HMAC-SHA1) works on Ubuntu with KeePassXC v2.6.2 and 2x YubiKey 5 NFC with firmware v5.4.3:
Install ykman (part of yubikey-manager)
$ sudo apt-get install yubikey-manager
Check that slot#2 is empty in both key#1 and key#2. You will be overwriting slot#2 on both keys.
$ ykman otp info
Slot 1: programmed
Slot 2: empty
Generate a base32-encoded secret seed (ex: "SECRETSEED") that will be programmed into both keys. RFC2104 recommends that your seed is as long as the underlying hash function (20 bytes for SHA1)
$ base32
SECRETSEED<Enter>
CTRL+D
BASE32SECRETSEED
$
Note that the above method adds a CR to the seed. Store SECRETSEED somewhere safe (ideally not digitally) in case you lose both keys
Program the resulting "BASE32SECRETSEED" to key#1 and key#2
$ ykman otp chalresp -t 2
Enter a secret key: BASE32SECRETSEED
Program a challenge-response credential in slot 2? [y/N]: y
Verify the same challenge gives you the same response using both keys
$ ykman otp calculate 2
Enter a challenge (hex): deadbeef
Touch your YubiKey...
aabbccdd11223344556677889900aabbccdd1122
Add one of your keys to your KeePassXC database
Database > Database Security > Add additional protection > Add YubiKey Challenge-Response
Both keys should now work to unlock/save your DB
Refs:
https://developers.yubico.com/Developer_Program/Guides/Touch_triggered_OTP.html
https://github.com/Yubico/python-yubico/blob/master/examples/rolling_challenge_response
https://wiki.archlinux.org/title/YubiKey
https://www.rfc-editor.org/rfc/rfc2104

Related

Verifyable logfile at customer site

We want to create a logfile at customer site where
the customer is able to read the log (plain text)
we can verify at our site that the log file isn't manipulated
A few hundred bytes of unreadable data is okay. But some customers do not send us files where they can't verify that they do not contain sensible data.
The only reasonable option I see so far is to append a cryptographic checksum (e.g. SHA256(SECRET_VALUE + "logtext")). The SECRET_VALUE would be something hardcoded which is plain "security through obscurity". Is there any better way?
We use the DotNet-library and I do not want to implement any crypto algorithm by hand if that matters.
You can use standard HMAC algorithm with a secret key to perform the checksum.
Using a secret key prevents in a simple way that the checksum can be regenerated directly. A hardcoded key could be extracted from code, but for your use case I think is enough
The result is a binary hash. To insert it into the text file encode the value as hexadecimal or base64, and ensure you are able to revert the process in server side so you can calculate the hash again with the original file.
You could use also a detached hash file to avoid modifying the log file
Target
customer readable logfiles
verifyable by our side
minimum of binary data
must work offline
Options
Public-Private-key-things... (RSA, ...)
would be secure
but only binary data
Add a signature
We are not the first ones with that idea ( https://en.wikipedia.org/wiki/Hash-based_message_authentication_code )
DotNet supports that ( System.Security.Cryptography.HMACSHA256 )
Key must be stored somewhere ... in source
Even with obfuscation: not possible to do so securely
Trusted Timestamping
again: we are not first ( https://en.wikipedia.org/wiki/Trusted_timestamping )
needs connection to "trusted third party" (means: a web service)
Build Hash + TimeStamp -> send to third party -> sign the data (public-private-key stuff) -> send back
Best option so far
Add a signature with HMAC
Store the key in native code (not THAT easy to extract)
Get code obfuscation running and build some extra loops in C#
Every once in a while (5min?) put a signature into log AND into windows application log
application log is at least basically secured against modification (read only)
and it's collected by the our error report
easy to oversee by customer (evil grin)

How should I go about creating safe, encrypted password in Clojure?

I'm building a web application. Among other fields in the table User, there are: enc_passw and salt. What's the idiomatic way to create a hashed/encrypted password in Clojure? What are the most trustworthy and decent libraries?
Also, should I just concatenate the real password and salt to calculate hashed/encrypted password? For example:
(secure_hash (str "my_real_pass" "my_salt"))
Take a look at friend's credential implementation here.
It's using [org.mindrot/jbcrypt "0.3m"].
(defn hash-bcrypt
"Hashes a given plaintext password using bcrypt and an optional
:work-factor (defaults to 10 as of this writing). Should be used to hash
passwords included in stored user credentials that are to be later verified
using `bcrypt-credential-fn`."
[password & {:keys [work-factor]}]
(BCrypt/hashpw password (if work-factor
(BCrypt/gensalt work-factor)
(BCrypt/gensalt))))
If you want an argumentation on bcrypt, read coda's here

How to encrypt the challenge phrase and answer for OpenAM Lost Password Management?

I recently had to convert challenge questions and passwords for an OpenAM implementation.
The plan was to convert these values as part of the user entry in a LDIF file and load it. The attribute to complete is iplanet-am-user-password-reset-question-answer. This is a multi valued attribute to support multiple question/answer pairs.
The challenge question key, answer and question key and question status flag had to be combined in a single line delimited by tabs.
[question-key]\t[answer]\t[1|0]
The value needs to be encrypted. This was the class used to encrypt but it did not work.
AMPasswordUtil().encrypt(question.get(challenge) + "\t" + response + "\t1")
What to do to make this work?
Finally gave up and dropped ForgeRock support a question. They were very helpful and supplied the solution and it worked immediately. Here it is...
It turns out the AMPasswordUtil class should not be used. Instead this should be used
encrypted_str = AccessController.doPrivileged(new EncodeAction( clear_text_str ))
The encryption key needs to be set as a system property
System.setProperty("am.encryption.pwd", key );
The encryption key can be retrieved from OpenAM.

Protect user credentials when connecting R with databases using JDBC/ODBC drivers

Usually I connect to a database with R using JDBC/ODBC driver. A typical code would look like
library(RJDBC)
vDriver = JDBC(driverClass="com.vertica.jdbc.Driver", classPath="/home/Drivers/vertica-jdbc-7.0.1-0.jar")
vertica = dbConnect(vDriver, "jdbc:vertica://servername:5433/db", "username", "password")
I would like others to access the db using my credentials but I want to protect my username and password. So I plan save the above script as a "Connections.r" file and ask users to source this file.
source("/opt/mount1/Connections.r")
If I give execute only permission to Connections.r others cannot source the file
chmod 710 Connections.r
Only if I give read and execute permission R lets users to source it. If I give the read permission my credentials will be exposed. Is there anyways we could solve this by protecting user credentials?
Unless you were to deeply obfuscate your credentials by making an Rcpp function or package that does the initial JDBC connection (which won't be trivial) one of your only lighter obfuscation mechanisms is to store your credentials in a file and have your sourced R script read them from the file, use them in the call and them rm them from the environment right after that call. That will still expose them, but not directly.
One other way, since the users have their own logins to RStudio Server, is to use Hadley's new secure package (a few of us sec folks are running it through it's paces), add the user keys and have your credentials stored encrypted but have your sourced R script auto-decrypt them. You'll still need to do the rm of any variables you use since they'll be part of environment if you don't.
A final way, since you're giving them access to the data anyway, is to use a separate set of credentials (the way you phrased the question it seems you're using your credentials for this) that only work in read-only mode to the databases & tables required for these analyses. That way, it doesn't matter if the creds leak since there's nothing "bad" that can be done with them.
Ultimately, I'm as confused as to why you can't just setup the users with read only permissions on the database side? That's what role-based access controls are for. It's administrative work, but it's absolutely the right thing to do.
Do you want to give someone access, but not have them be able to see your credentials? That's not possible in this case. If my code can read a file, I can see everything in the file.
Make more accounts on the SQL server. Or make one guest account. But you're trying to solve the problem that account management solves.
Have the credentials sent as command arguments? Here's an example of how one would do that:
suppressPackageStartupMessages(library("argparse"))
# create parser object
parser <- ArgumentParser()
# specify our desired options
# by default ArgumentParser will add an help option
parser$add_argument("-v", "--verbose", action="store_true", default=TRUE,
help="Print extra output [default]")
parser$add_argument("-q", "--quietly", action="store_false",
dest="verbose", help="Print little output")
parser$add_argument("-c", "--count", type="integer", default=5,
help="Number of random normals to generate [default %(default)s]",
metavar="number")
parser$add_argument("--generator", default="rnorm",
help = "Function to generate random deviates [default \"%(default)s\"]")
parser$add_argument("--mean", default=0, type="double", help="Mean if generator == \"rnorm\" [default %(default)s]")
parser$add_argument("--sd", default=1, type="double",
metavar="standard deviation",
help="Standard deviation if generator == \"rnorm\" [default %(default)s]")
# get command line options, if help option encountered print help and exit,
# otherwise if options not found on command line then set defaults,
args <- parser$parse_args()
# print some progress messages to stderr if "quietly" wasn't requested
if ( args$verbose ) {
write("writing some verbose output to standard error...\n", stderr())
}
# do some operations based on user input
if( args$generator == "rnorm") {
cat(paste(rnorm(args$count, mean=args$mean, sd=args$sd), collapse="\n"))
} else {
cat(paste(do.call(args$generator, list(args$count)), collapse="\n"))
}
cat("\n")
Sample run (no parameters):
usage: example.R [-h] [-v] [-q] [-c number] [--generator GENERATOR] [--mean MEAN] [--sd standard deviation]
optional arguments:
-h, --help show this help message and exit
-v, --verbose Print extra output [default]
-q, --quietly Print little output
-c number, --count number
Number of random normals to generate [default 5]
--generator GENERATOR
Function to generate random deviates [default "rnorm"]
--mean MEAN Mean if generator == "rnorm" [default 0]
--sd standard deviation
Standard deviation if generator == "rnorm" [default 1]
The package was apparently inspired by the python package of the same name, so looking there may also be useful.
Looking at your code, I'd probably rewrite it as follows:
library(RJDBC)
library(argparse)
args <- ArgumentParser()
args$add_argument('--driver', dest='driver', default="com.vertica.jdbc.Driver")
args$add_argument('--classPath', dest='classPath', default="/home/Drivers/vertica-jdbc-7.0.1-0.jar")
args$add_argument('--url', dest='url', default="jdbc:vertica://servername:5433/db")
args$add_argument('--user', dest='user', default='username')
args$add_argument('--password', dest='password', default='password')
parser <- args$parse_args
vDriver <- JDBC(driverClass=parser$driver, parser$classPath)
vertica <- dbConnect(vDriver, parser$url, parser$user , parser$password)
# continue here
Jana, it seems odd that you are willing to let the users connect via R but not in any other way. How is that obscuring anything from them?
I don't understand why you would not be satisfied with a guest account that has specific SELECT-only access to certain tables (or even views)?

Safely storing encrypted sensitive data 'publicly' online?

How can I safely store sensitive data online?
I want to store some extremely sensitive information online in a public folder, and I'm not sure how to go about it.
Specifically, I want to store bitcoin private keys in a .json file named "walletData.json" in a public folder. The file contains the wallet address and public key in plain text, along with an encrypted version of the private key.
Assuming anyone can access the file and attempt to crack the encryption password with their "super computers", what's the best way to safely encrypt that private key?
I know a longer password would be a good start, but ideally I don't want to need a password longer than 10 characters.
I was thinking of maybe hashing the password 1000 times, then using that hash+password as an AES encryption key. But, as everyone can see the key generation method, i'm not sure that will help? I was also thinking of padding out the encrypted private key with some other random data, but again, I don't know if it'll really help??
Is there a safe way to do this?
EDIT - after Reid's answer:
I'm trying to do this 100% in Javascript/jQuery.
When I export a CoinPrism.com wallet, I get this:
{"keys":[{"addr":"1PNLiLgW2fBokCB2wmfhZTtbmioitkqtMm","priv":"172655af193edeb54467a52fc6eb94c67eeeff8cd03555767e5cf12df694bb88f9c8b25c4019147d9e4993405274c96a","encryptionMode":"PKBDF2-SHA256","iterations":2000}],"salt":"2222b67fc7255aaf0b4027bfcabffb5e62f39e9e0aa13e8ad70f2dc75a484f26"}
The "priv" value is an encrypted private key. I don't know exactly how it's encrypted, but i'm sure that there's a way to decrypt it using just my 10 character password.
Does anyone know how they're doing this?
Is it safe to store this information online?
Well, I will just say outright that you don't need to be the one who writes the code to do this — it is far too easy to mess up, and your post makes suggestions that are concerning. (For instance, you describe something of an ad-hoc key derivation scheme, but one that is insufficient in protection.)
So, you need a library of some kind to handle this business for you.
My suggestion: Use GPG with the ASCII armor option. For example:
gpg --symmetric --armor --cipher-algo AES file.txt
This will symmetrically encrypt (--symmetric) a file (file.txt here) using the AES cipher (--cipher-algo AES) and store the resulting encrypted file in an ASCII armored format (--armor). Note: the resulting encrypted file will be stored in the filename plus the extension .asc; e.g., here, it puts the result in file.txt.asc. You can change this with the --output option.
Now, the above command will prompt you for a passphrase — this passphrase needs to be very strong, far more than 10 characters I'm afraid. This is the burden of passphrase-based encryption: you need passphrases that are strong. Ideally, you want a passphrase that is long and complicated, hard-to-guess and hard-to-bruteforce.
Since we are on StackOverflow, you may be looking to automate the passphrase entry (using scripting). To do that, there are several --passphrase related options for GPG. For example,
gpg --batch --passphrase "test" --symmetric --armor --cipher-algo AES file.txt
will use the passphrase test instead of prompting the user. Command line arguments are not safe, however, on a system, so it would be better to use the --passphrase-from-file option, which takes a single file as an argument. The first line of that file is the passphrase to be used.

Resources