Is there a way to generate a htpasswd entry using R, ie, without using the htpasswd utility itself?
According to the Apache docs,
htpasswd encrypts passwords using either bcrypt, a version of MD5 modified for Apache, SHA1, or the system's crypt() routine. Files managed by htpasswd may contain a mixture of different encoding types of passwords; some user records may have bcrypt or MD5-encrypted passwords while others in the same file may have passwords encrypted with crypt().
I tried using either openssl::md5 or digest::digest, but they don't seem to be producing anything I can recognise.
Here's some sample output using htpasswd on Ubuntu. The result changes each time, presumably because there is a salt being used. The hash doesn't look like it's base64-encoded either.
hongo#hongsdev:~$ echo bar | htpasswd -n -i foo
foo:$apr1$ArTUhiJz$/qjciBNKHEWwpXBof75rb.
hongo#hongsdev:~$ echo bar | htpasswd -n -i foo
foo:$apr1$pZxmtIam$VkfMvV2qR4NBkPm3MKcJ/.
hongo#hongsdev:~$ echo bar | htpasswd -n -i foo
foo:$apr1$IFM43G9p$UkQB9QSONrwD74WpXlP7f/
Some attempts using openssl::md5 and digest::digest:
r$> openssl::md5("bar")
[1] "37b51d194a7513e45b56f6524f2d51f2"
r$> digest::digest("bar", algo="md5")
[1] "cbd2100992f98ebf9169448cf98f63a5"
r$> openssl::base64_encode(openssl::md5("bar"))
[1] "MzdiNTFkMTk0YTc1MTNlNDViNTZmNjUyNGYyZDUxZjI="
Coming back to this....
The bcrypt package provides an R interface to the blowfish password hashing algorithm, and can be used to generate a suitable file. There don't seem to be packages for the other algorithms, but this one works.
library(bcrypt)
user_list <- list(
c("user1", "password1")
)
user_str <- sapply(user_list, function(x) paste(x[1], hashpw(x[2]), sep=":"))
writeLines(user_str, "auth")
Related
I've read on this post that Nginx does not support multiple Authorization headers.
I was wondering if how I would check in the http request if an
authorization header is present.
basically I am adding a basic auth to my webpage since its not ready for production yet. My site is a single page application and I have successfully added authentication in the index page, but my site has also log in feature. When I log in it keeps asking for the authentication again. Im new to nginx and I am not quite sure how to get around with this
location / {
root /path/to/my/app/root/folder;
index index.html index.php;
#I want to only executed these lines only on the index page and login page
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
}
You can use curl to see the headers:
$ curl -v -u your_user_name "http://......."
Look for the > Authorization: Basic ... line which contains a Base64 encoding of user:pass.
You can decode the string using:
printf auth_string | base64 --decode
More details here.
Also, make sure /etc/nginx/.htpasswd has the right permissions for nginx to be able to read it and that it contains your user/pass credentials in a format recognized by nginx (info here):
1. Plain text:
# comment
name1:password1
name2:password2:comment
name3:password3
2. Encrypted/hashed:
encrypted with the crypt() function; can be generated using the “htpasswd” utility from the Apache HTTP Server distribution or the
“openssl passwd” command;
hashed with the Apache variant of the MD5-based password algorithm (apr1); can be generated with the same tools;
specified by the “{scheme}data” syntax (1.0.3+) as described in RFC 2307; currently implemented schemes include PLAIN (an
example one, should not be used), SHA (1.3.13) (plain SHA-1
hashing, should not be used) and SSHA (salted SHA-1 hashing, used
by some software packages, notably OpenLDAP and Dovecot).
$ htpasswd
Usage:
htpasswd [-cimBdpsDv] [-C cost] passwordfile username
htpasswd -b[cmBdpsDv] [-C cost] passwordfile username password
htpasswd -n[imBdps] [-C cost] username
htpasswd -nb[mBdps] [-C cost] username password
-c Create a new file.
-n Don't update file; display results on stdout.
-b Use the password from the command line rather than prompting for it.
-i Read password from stdin without verification (for script usage).
-m Force MD5 encryption of the password (default).
-B Force bcrypt encryption of the password (very secure).
-C Set the computing time used for the bcrypt algorithm
(higher is more secure but slower, default: 5, valid: 4 to 31).
-d Force CRYPT encryption of the password (8 chars max, insecure).
-s Force SHA encryption of the password (insecure).
-p Do not encrypt the password (plaintext, insecure).
-D Delete the specified user.
-v Verify password for the specified user.
On other systems than Windows and NetWare the '-p' flag will probably not work.
The SHA algorithm does not use a salt and is less secure than the MD5 algorithm.
I have a job that runs periodically and signs/encrypts a file like so:
$ gpg --homedir /path/to/.gnupg -r key1#mydomain.com -r key2#mydomain.com --local-user sig1#mydomain.com --batch --passphrase-file /path/to/gpg-password --sign -ea myfile
The command encrypts the file for two recipients: key1#mydomain.com and key2#mydomain.com. It signs the file with sig1#mydomain.com. It runs in batch mode as there is no human interactivity - this is an automated process. It gets the passphrase for the signature from /path/to/gpg-password.
What I would like to do is now sign the file with two signatures at the same time. Like so:
$ gpg --homedir /path/to/.gnupg -r key1#mydomain.com -r key2#mydomain.com --local-user sig1#mydomain.com --local-user sig2#mydomain.com --batch --passphrase-file /path/to/gpg-password --sign -ea myfile
gpg: skipped "sig2#mydomain.com": bad passphrase
It works fine in interactive mode (eg. without --batch), I just have to supply the two passphrases via the command line. However, in batch mode it fails as it tries to get the signatures from the file. The signature is only valid for one of the signing keys.
From the man page:
--passphrase-file file
Read the passphrase from file file. Only the first line will be read from file file. This can only be used if only one passphrase is supplied.
How do I tell it what the password is for each key?
You have different options.
Completely remove the passwords, since they're stored somewhere anyway.
Use the same password (as you already discovered).
Use the gpg-agent and preset the passphrase. I'm unsure whether this is GnuPG 2-only (usually installed as gpg2, maybe to be installed from a gnupg2 package). Presetting the passphrase is as easy as running gpg-preset-passphrase --preset [fingerprint]. You will have to run this command for each of the keys individually, and make sure to cache the passphrase for a given time (at least the processing time of adding all the passphrases, and then signing the file you want to sign).
For the sake of completeness, but impractical: sign the file individually for each key, then take apart the OpenPGP packets and recombine them adding all the signatures one after the other. Signing with multiple keys just creates multiple signature packets.
For anyone else in the same situation as me, I ended up working around this apparent deficiency of gpg by editing one of the signing keys to have the same password as the other (the password stored in the gpg-password file). This doesn't compromise security in this instance since the password is stored in a text file anyway - the real security is the password of the user that this commands runs from and the fact that the secret keys are kept secret). You can change the password on a key by doing gpg --edit-key <key_id>, then passwd. Don't forget to save after.
I've been trying to set up encrypted folder following the instructions in https://wiki.archlinux.org/index.php/ECryptfs#Without_ecryptfs-utils. In that case a mount passphrase is manually created and wrapped using a chosen password ("Arch" in that example). This is working as expected.
There is yet another possibility how to manually set up things. Namely using simple mount e.g.:
mount -t ecryptfs ~/.Private/ ~/Private -o key=passphrase,ecryptfs_cipher=aes,ecryptfs_key_bytes=32,ecryptfs_passthrough=n,ecryptfs_enable_filename_crypto=y
In this case I'm prompted for a [password] and after that folder is mounted.
My question is: where is the mount passphrase hidden in the second example? And how is my entered [password] related to it and to the FEKEK in this case.
Could anybody please explain?
Thank you in advance.
I think the entered passphrase becomes the "file encryption key, encryption key, or FEKEK" itself, and is temporarily stored in the kernel keyring (root's keyring if you need to mount with sudo) while the folder is mounted. You can see the keyring before & after mounting & unmounting with sudo keyctl show.
It does not store the passphrase/FEKEK anywhere on disk, unlike the method "Without ecryptfs-utils" in the ArchWiki you liked to, and the one in the ecryptfs-utils below.
FYI, using the ecryptfs-utils tools it will create a random (16 byte) passphrase to use, if you haven't specified your own passphrase, and it apparently is the file encryption key (FEKEK) / FNEK.
Looking in a couple of the ecryptfs-utils tools, (several are shell scripts) inside ecryptfs-migrate-home it collects some data and calls ecryptfs-setup-private, which has this function to generate a more secure 16 byte random passphrase/FEKEK/FNEK (that then gets "wrapped"/encrypted with your login passphrase and stored on disk):
random_passphrase () {
bytes=$1
# Pull $1 of random data from /dev/urandom,
# and convert to a string of hex digits
od -x -N $bytes --width=$bytes /dev/urandom | head -n 1 | sed "s/^0000000//" | sed "s/\s*//g"
}
I forgot the password to my bitcoin backup and would like to brute-force decrypt it.
I have been given this information;
"The manual backup files are encrypted using your chosen backup password. You can use OpenSSL to decrypt:
openssl enc -d -aes-256-cbc -a -in <filename>"
Unfortunately, I don't have much experience doing this and all I can do it get it in terminal asking for the password. Can anybody give me instructions on how to brute-force decrypt a file using OpenSSL?
n.b. The password was quite simple, using only letters and perhaps one number.
... all I can do it get it in terminal asking for the password.
You need to add -passin pass:XXX options, where XXX is the password you want to try.
There's more options for -passin, see PASS PHRASE ARGUMENTS for openssl(1) command.
You will also need to understand the -k and -K options to openssl enc.
Can anybody give me instructions on how to brute-force decrypt a file using OpenSSL?
Run something like this in a loop:
# Build your list of candidates
PASSWORDS=...
for PASSWORD in $PASSWORDS; do
openssl enc -d -aes-256-cbc -a -in <filename> -passin pass:$PASSWORD
RET=$?
if [ $RET -eq 0 ]; then
echo "Candidate password: $PASSWORD"
fi
done
openssl enc returns 0 on success, non-zero otherwise. Note: you will get false positives because AES/CBC can only determine if "decryption works" based on getting the padding right. If the file decrypts but is not recovered, then remove that candidate password.
Authenticated encryption would fix the ambiguity, but you would have needed to encrypt with AES/CCM, AES/GCM, AES/EAX etc.
If you want to try on your own there is now a bruteforcing tool that will do it very efficiently, called bruteforce-salted-openssl. Note that the digest used back in the days by openssl was md5 (rather than sha256 today), so you would have to specify the digest (-m md5)
Is it possible to add a salt to passwords in .hpasswd files? I assume not since the server would need the salt for each user in order to verify the password and I can't think of how it would get them, but otherwise if the list was to be obtained it would be rather vulnerable. Is there a solution?
Many thanks for your help,
Ben
By default htpasswd uses the standard crypt function and thus passwords are already salted - note in this example that both users have the same password yet the hashes are different:
simon#diablo:~$ htpasswd -b -c htpasswd simon abcd
Adding password for user simon
simon#diablo:~$ htpasswd -b htpasswd simon2 abcd
Adding password for user simon2
simon#diablo:~$ cat htpasswd
simon:NWvm/LCCxQ64E
simon2:2I.LBzsRqULN6
(note: the -b flag is normally discouraged because other users can see your command line arguments and hence the password)
The first two characters of the hash are the salt; passwords are verified by calling crypt() again. Entering the wrong password produces a string that's unequal to the hashed password:
>>> from crypt import crypt
>>> crypt("wrongpass", "NWvm/LCCxQ64E")
'NWbxQgX1unvso'
whereas the correct password produces the expected hash:
>>> crypt("abcd", "NWvm/LCCxQ64E")
'NWvm/LCCxQ64E'
htpasswd -m uses a different algorithm that's MD5-based and uses a longer salt:
simon#diablo:~$ htpasswd -m -b -c htpasswd simon abcd
Adding password for user simon
simon#diablo:~$ cat htpasswd
simon:$apr1$mfvnBVmG$iIHIHOaH9vcImG5G.8eVa/
Here, the salt is the 8 characters between the second and third $.
htpasswd -s stores a SHA-1 digest with no salt; this appears to be for compatibility with Netscape/LDIF:
simon#diablo:~$ htpasswd -s -b -c htpasswd simon abcd
Adding password for user simon
simon#diablo:~$ htpasswd -s -b htpasswd simon2 abcd
Adding password for user simon2
simon#diablo:~$ cat htpasswd
simon:{SHA}gf6L/odXbD7LIkJvjleEc4KRes8=
simon2:{SHA}gf6L/odXbD7LIkJvjleEc4KRes8=
These can easily be reversed - convert into a hex digest:
>>> "".join("%02x" % ord(c)
... for c in "gf6L/odXbD7LIkJvjleEc4KRes8=".decode("base64"))
'81fe8bfe87576c3ecb22426f8e57847382917acf'
then use an online hash database.
The htpasswd utility already does use salts in most cases:
The crypt() and MD5 formats permute the representation by prepending a random salt string, to make dictionary attacks against the passwords more difficult.
And that's (sort of) the purpose of salts in password files. While salts have to be included in the server's .htpasswd file for the server to be able to check passwords, it is the numerous different possibilities of what a salt could be that defends against such attack techniques as rainbow tables.
However, if your users pick weak or common passwords, password cracking is a problem anyways, since the attacker (presumed to have access to the password file) will try those first, very quickly in fact (not limited by the speed of the server and Internet connection), by guessing in the normal way. The best advice I can give is that users should always pick strong passwords.