71

The previous SF questions I've seen have lead to answers that produce MD5 hashed password.

Does anyone have a suggestion on to produce an SHA-512 hashed password? I'd prefer a one liner instead of a script but, if a script is the only solution, that's fine as well.

Update

Replacing previous py2 versions with this one:

python3 -c "import crypt;print(crypt.crypt(input('clear-text pw: '), crypt.mksalt(crypt.METHOD_SHA512)))"
Belmin Fernandez
  • 10,629
  • 26
  • 84
  • 145
  • 5
    SHA and MD5 are *not* encryption. They're hashing algorithms. The crucial difference being that the hashed data is not recoverable. What do you need to do? – SmallClanger Nov 11 '11 at 11:28
  • Thank you. Modified the question. `man 5 shadow` refers to it as "encrypted password" so I went along with that term. – Belmin Fernandez Nov 11 '11 at 12:22
  • 3
    Apologies if that was a bit snarky. Are you trying to manually generate shadow-compatible password hashes? If so, take a look at your `/etc/shadow` contents. You'll see `$x$salt$hash`. `x` denotes the algorithm used by `crypt`, with `6` being typical on modern linuxes, which is sha512 (see `man 3 crypt`). Either of the below answers will produce the same hash, so long as you give it the same salt. – SmallClanger Nov 11 '11 at 13:20
  • 2
    Oh no, not snarky at all. You clarified something I was confused about so I am very thankful sir! – Belmin Fernandez Nov 11 '11 at 15:26
  • 2
    Thank you! The passlib-based one is the only one I've been able to make work on OS X. – Stig Brautaset Sep 01 '15 at 15:49
  • I'm being picky here, but I'm not 100% sure random.choice is using a cryptographically secure random number generator, is it? – Ztyx Sep 22 '15 at 12:30
  • Feel free to suggest a better choice for the salt. – Belmin Fernandez Sep 22 '15 at 13:13

20 Answers20

75

Edit: Please note this answer is 10+ years old.

Here's a one liner:

python -c 'import crypt; print crypt.crypt("test", "$6$random_salt")'

Python 3.3+ includes mksalt in crypt, which makes it much easier (and more secure) to use:

python3 -c 'import crypt; print(crypt.crypt("test", crypt.mksalt(crypt.METHOD_SHA512)))'

If you don't provide an argument to crypt.mksalt (it could accept crypt.METHOD_CRYPT, ...MD5, SHA256, and SHA512), it will use the strongest available.

The ID of the hash (number after the first $) is related to the method used:

  • 1 -> MD5
  • 2a -> Blowfish (not in mainline glibc; added in some Linux distributions)
  • 5 -> SHA-256 (since glibc 2.7)
  • 6 -> SHA-512 (since glibc 2.7)

I'd recommend you look up what salts are and such and as per smallclamgers comment the difference between encryption and hashing.

Update 1: The string produced is suitable for shadow and kickstart scripts.
Update 2: Warning. If you are using a Mac, see the comment about using this in python on a mac where it doesn't seem to work as expected.

On macOS you should not use the versions above, because Python uses the system's version of crypt() which does not behave the same and uses insecure DES encryption. You can use this platform independent one liner (requires passlib – install with pip3 install passlib):

python3 -c 'import passlib.hash; print(passlib.hash.sha512_crypt.hash("test"))'
gm3dmo
  • 9,632
  • 1
  • 40
  • 35
  • 1
    Importing the `getpass` and `pwd` modules is not necessary. – akaihola Feb 16 '12 at 13:17
  • Why does it need the `random_salt` (or `SALTsalt`) bits? – Wilf Jun 06 '14 at 15:58
  • 6
    Replace `random_salt` with an actual random salt. – Belmin Fernandez Jul 31 '14 at 13:44
  • 6
    I can't get this to work in Yosemite. This is what it spits out: `$6asQOJRqB1i2` - that doesn't seem nearly long enough to be correct! – Stig Brautaset Jul 12 '15 at 11:12
  • You might want to try the passlib library. See this answer: http://serverfault.com/questions/330069/how-to-create-an-sha-512-hashed-password-for-shadow – gm3dmo Jul 13 '15 at 13:40
  • Shouldn't that be `"$6$random_salt$"` (with a dollar sign at end) ? – Pithikos Aug 28 '15 at 11:33
  • 5
    Let the crypt module make the salt for you: `python -c 'import crypt; print crypt.crypt("test", crypt.mksalt(crypt.METHOD_SHA512))'` – rrauenza Sep 14 '15 at 17:32
  • @rrauenza Is that supposed to be version 2 or version 3? On all distributions I have tested `python` invokes version 2, and you are using version 2 syntax for `print`. But I only see `crypt.mksalt` and `crypt.METHOD_SHA512` in version 3. This variant works for me: `python3 -c 'from crypt import *; print(crypt("test", METHOD_SHA512))'` – kasperd Oct 20 '15 at 20:24
  • Including the actual salt in the command line is risky because it will be visible to other processes for the duration of the command. And it may end up in your `.bash_history`. It would be better to let the user type the password through the tty. – kasperd Oct 20 '15 at 20:29
  • 1
    @kasperd I should have looked at the [docs; it's in 3.3+](https://docs.python.org/3/library/crypt.html#module-crypt) – Nick T Oct 20 '15 at 20:48
  • @kasperd I was using Python 2.7.5 on CentOS7. Hadn't tried 3.x. – rrauenza Oct 20 '15 at 22:27
  • 3
    glibc by default only uses [5000 rounds](https://github.com/lattera/glibc/blob/master/crypt/sha512-crypt.c#L86) which is fairly weak these days. You can specify the number of rounds by adding "$rounds=###", for instance: `crypt.crypt("test", "$6$rounds=200000$random_salt")`. 200000 takes around 100ms on my current laptop. – srparish Sep 14 '16 at 00:20
  • Why is the second one liner returning the same exact hash every time? Seems like this is the worst misdocumentation in the history of stack overflow, thousands of systems are probably using the hash "$6". – Ron Reiter Apr 03 '18 at 08:03
  • Actually, it seems that the bug is in Python and not in this post. – Ron Reiter Apr 03 '18 at 08:24
  • 3
    This should not be used, at least on a Mac. On a Mac (10.13.5) this returns the same incorrect result each time. – oskarpearson Aug 01 '18 at 12:56
  • I fail to understand why this answer has so many upvotes. As already mentioned by @StigBrautaset, this is far from enough for /etc/shadow. It generates a string of 11 characters. You need a far longer hash than that. – Lethargos Aug 03 '19 at 13:59
  • On macOS you can use this (requires passlib: `pip3 install passlib`): `python3 -c 'import getpass,passlib.hash;print(passlib.hash.sha512_crypt.hash(getpass.getpass("Input password:")))'` – Martin M. Dec 21 '20 at 17:54
  • The thing is, as mentioned by @srparish in the comment section, `crypt.mksalt()` already prefixes with `$6$...`, so how would you specify custom `rounds`? Parse the output (i.e. `crypt.mksalt(crypt.METHOD_SHA512)[3:]`)? I mean... why would a developer make the prefix hardcoded in the first place... – Faither Dec 23 '21 at 23:04
40

On Debian you can use mkpasswd to create passwords with different hashing algorithms suitable for /etc/shadow. It is included in the package whois (according to apt-file)

mkpasswd -m sha-512
mkpasswd -m md5

to get a list of available hashing algoritms type:

mkpasswd -m help 

HTH

mrossi
  • 538
  • 4
  • 8
  • 3
    What package provides it? There's a `mkpasswd` program (part of expect) under Fedora too, but it's useless for this purpose. – Cristian Ciupitu Mar 02 '13 at 02:31
  • As he said, the version of `mkpasswd` he's talking about is for Debian/Ubuntu. The `mkpasswd` on Fedora (at least up to 14) is missing the `-m` switch. – slm May 19 '13 at 03:47
  • 4
    Curiously, it's the whois package, legacy from Debian. See `dpkg -S /usr/bin/mkpasswd` I couldn't believe it myself :D – Robert Cutajar Jun 18 '14 at 21:23
  • 1
    To check a password, if the first digit is 6, use the part between the second and third dollar as salt. For example for `root:$6$AbCdE$xyz:...` you should use: `mkpasswd -m sha-512 -S AbCdE`. With the correct password, you should get the same hash. – Luc Dec 09 '16 at 13:18
25

Using grub-crypt

Usage: grub-crypt [OPTION]...
Encrypt a password.

-h, --helpPrint this message and exit
-v, --version           Print the version information and exit
--md5                   Use MD5 to encrypt the password
--sha-256               Use SHA-256 to encrypt the password
**--sha-512             Use SHA-512 to encrypt the password (default)**
noraj
  • 241
  • 2
  • 8
Wayne
  • 251
  • 3
  • 2
  • 1
    Simple solution..worked for me on CentOS 6. – Banjer May 01 '13 at 12:15
  • 5
    On systems that have the `grub-crypt` command, this really is the most foolproof & convenient way to do it. No sense playing around with salts manually when you could screw it up. The problem is that more and more modern systems have GRUB2 and will thus not include this command. – rsaw Jul 03 '15 at 18:22
14

Here's a short C code to generate the SHA-512 password on various Unix type OSes.

File: passwd-sha512.c

#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  if ( argc < 3 || (int) strlen(argv[2]) > 16 ) {
    printf("usage: %s password salt\n", argv[0]);
    printf("--salt must not larger than 16 characters\n");
    return;
  }

  char salt[21];
  sprintf(salt, "$6$%s$", argv[2]);

  printf("%s\n", crypt((char*) argv[1], (char*) salt));
  return;
}

to compile:

/usr/bin/gcc -lcrypt -o passwd-sha512 passwd-sha512.c

usage:

passwd-sha512 <password> <salt (16 chars max)>
Craig McQueen
  • 720
  • 6
  • 18
BoogieBug
  • 241
  • 2
  • 2
7

Surprising that no answer suggests the simple openssl passwd command with the -6 option. Maybe it wasn't available yet in 2011?

If you don't care providing the password on the command-line (risking it staying in the command history), then you can do:

openssl passwd -6 YourPassword

It will generate the salt, and output a line like this:

$6$/57kpVAA/kuPUtzV$Ugxo0RTL2uXCvU7WH43c1qn0quMy2ve.qiBYJPG75tFgTN8gI5Jp/FYPXFOzIsASqVTqM42kjN2805VYLHKzm1

With the stdin option, it can also read the password from STDIN (or a file), so you don't leave it behind in the history:

openssl passwd -6 -stdin
mivk
  • 3,457
  • 1
  • 34
  • 29
4

Perl one-liner solution to generate SHA-512 hashed password:

perl -le 'print crypt "desiredPassword", "\$6\$customSalt\$"'

Worked on RHEL 6

sigjuice
  • 197
  • 1
  • 5
Ivan Chau
  • 231
  • 1
  • 12
2

Why not perform the following check and modification to Centos/RHEL machines to ensure that all password hashing for /etc/shadow is done with sha512. Then you can just set your passworkd normally with the passwd command

#Set stronger password hasing
/usr/sbin/authconfig --test | grep sha512 > /dev/null
if [ $? -ne 0 ]; then
echo "Configuring sha512 password hashing"
sudo /usr/sbin/authconfig --enableshadow --passalgo=sha512 --updateall
fi
ckliborn
  • 2,750
  • 4
  • 24
  • 36
2

Here is a one-liner that uses shell commands to create a SHA-512 hashed password with a random salt:

[root@host] mkpasswd -m sha-512 MyPAsSwOrD $(openssl rand -base64 16 | tr -d '+=' | head -c 16)

Notes

  1. You may need to install the "whois" package (Debian, SuSE, etc.), which provides "mkpasswd".
  2. See crypt(3) for details on the format of lines in "/etc/shadow".
ajchace
  • 67
  • 3
  • Unfortunately the `whois` package from Fedora 18 doesn't provide any `mkpasswd`. – Cristian Ciupitu Mar 02 '13 at 02:38
  • 1
    In Arch Linux: /usr/bin/mkpasswd is owned by expect 5.45-3 – Nowaker Nov 09 '13 at 21:18
  • Same on Fedora 20 and it does something else. – Cristian Ciupitu Apr 17 '14 at 19:23
  • 2
    Unfortunately the suggested command has two problems: 1) The supplied password is now stored in your shell's history, and is visible to anyone with the 'history' command or similar. 2) You don't need to supply the random salt on the command line - and I think you should let mkpasswd do it for you instead of using funky openssl tricks. (Note that this is true at least on Ubuntu Quantal. You can test it by running 'mkpasswd -m sha-512 foo' multiple times. You will see the salt changes. The salt is the value between the 2nd and 3rd $ characters.) – oskarpearson Jun 03 '14 at 08:40
2

Read the comment below to learn about security implications of this answer

For those of the Ruby mindset here is a one-liner:

'password'.crypt('$6$' + rand(36 ** 8).to_s(36))
Sven
  • 97,248
  • 13
  • 177
  • 225
TrueDuality
  • 1,844
  • 5
  • 27
  • 37
  • 1
    This is incorrect: Ruby's rand function is not secure - it uses a PRNG, so this will generate results that can be reverse-engineered based on a guess of the time/state of the moment you ran this. – oskarpearson Aug 01 '18 at 12:53
  • @oskarpearson We don't it's a PRNG since it's only used to generate the salt and not the password. – noraj Apr 23 '22 at 18:48
1

All examples will be using SHA-512, <password> as password placeholder and <salt> as salt placeholder.

mkpasswd

Note: mkpasswd binary is installed via the package whois on Debian / Ubuntu only. On other Linux distribution such as ArchLinux, Fedora, CentOS, openSUSE, etc. mkpasswd is provided by the expect package but is an totally different utility which is available as expect_mkpasswd on Debian / Ubuntu. whois of all other Linux distro doesn't include mkpasswd but the source (C lang) can be found on the original repository https://github.com/rfc1036/whois.

# With a random password and random salt
mkpasswd -m sha-512
# With a random random salt
mkpasswd -m sha-512 '<password>'
# Choosing both password and salt
mkpasswd -m sha-512 '<password>' '<salt>'
# Read password from stdin to avoid leaking it in shell command history
mkpasswd -m sha-512 --stdin

OpenSSL

# With a random random salt
openssl passwd -6 '<password>'
# Choosing both password and salt
openssl passwd -6 --salt '<salt>' '<password>'
# Read password from stdin to avoid leaking it in shell command history
openssl passwd -6 -stdin
openssl passwd -6

Ruby

# With a random password and random salt
ruby -e 'require "securerandom"; puts SecureRandom.alphanumeric(20).crypt("$6$" + rand(36 ** 8).to_s(36))'
# With a random random salt
ruby -e 'puts "<password>".crypt("$6$" + rand(36 ** 8).to_s(36))'
# Choosing both password and salt
ruby -e 'puts "<password>".crypt("$6$<salt>")'
# Read password from stdin to avoid leaking it in shell command history
ruby -e 'require "io/console"; puts IO::console.getpass.crypt("$6$" + rand(36 ** 8).to_s(36))'

Note: for those who complains that Random#rand is a PRNG, you can use the secure SecureRandom#rand but it's not very important is rand is used only to generate the salt which is publicly available in the hash at the end.

ruby -e 'require "securerandom"; puts "<password>".crypt("$6$" + SecureRandom.rand(36 ** 8).to_s(36))'

Perl

# Choosing both password and salt
perl -le 'print crypt "<password>", "\$6\$<salt>\$"'

Python

Requires Python >= 3.3

# With a random random salt
python -c 'import crypt; print(crypt.crypt("<password>", crypt.mksalt(crypt.METHOD_SHA512)))'
# Choosing both password and salt
python -c 'import crypt; print(crypt.crypt("<password>", "$6$<salt>"))'
# Read password from stdin to avoid leaking it in shell command history
python -c 'import crypt,getpass; print(crypt.crypt(getpass.getpass(), crypt.mksalt(crypt.METHOD_SHA512)))

grub-crypt

Note: The grub package doesn't include grub-crypt in many distros.

# With a random random salt
# Read password from stdin to avoid leaking it in shell command history
grub-crypt --sha-512
noraj
  • 241
  • 2
  • 8
1

This script worked for me on Ubuntu 12.04 LTS: https://gist.github.com/JensRantil/ac691a4854a4f6cb4bd9

#!/bin/bash
read -p "Enter username: " username
read -s -p "Enter password: " mypassword
echo
echo -n $username:$mypassword | chpasswd -S -c SHA512

It has the following features which some of the other alternatives lack:

  • It generates its salt securely. Nobody should rely on doing this manually. Ever.
  • it doesn't store anything in shell history.
  • for clarity, it prints which user's password it generated which can be nice when generating many users' passwords.
slm
  • 7,355
  • 16
  • 54
  • 72
Ztyx
  • 1,365
  • 3
  • 13
  • 27
0

After the Customer changes the password, you can copy the encrypted password from /etc/shadow to the kickstart file. How to do it:

export CRYPTED_PASSWORD=$(grep root /etc/shadow | cut –d ”:” –f 2)
echo "s;rootpw -–iscrypted .*;rootpw –-iscrypted $CRYPTED_PASSWORD;" > sed_script
sed –i –f sed_script template.ks
Andrew Schulman
  • 8,561
  • 21
  • 31
  • 47
0

I saw the note from @chris about crypt not being ideal for this, and that it doesn't support PBKDF2. Well since Python 3.4 hashlib does contain a PBKDF2 HMAC function:

import os
import hashlib
import base64

salt = base64.b64encode(os.urandom(12))
password = base64.b64encode(hashlib.pbkdf2_hmac('sha512', bytes(passin, 'UTF-8'), salt, 200000, 64))

print(f"$6${salt.decode('UTF-8')}${password.decode('UTF-8')})"

I'm by far no cryptographical expert so I don't know the validity of crypt not being appropriate for this. And this method comes with a warning from the manpages:

Deprecated since version 3.10: Slow Python implementation of pbkdf2_hmac is deprecated. In the future the function will only be available when Python is compiled with OpenSSL.

As stated by the hashlib man page tho, I tried to set an appropriate iteration count of 200'000: NIST-SP-800-132 and stackexchange pbkdf2 iterations question.

Torxed
  • 215
  • 1
  • 5
  • 17
0

HASH algos are for producing MESSAGE digests, they are never suitable for passwords, which should use some kind of HKDF ( http://tools.ietf.org/rfc/rfc5869.txt ) - see PBKDF2 or BCrypt

chris
  • 9
  • 1
0
#!/usr/bin/env python

import getpass

from passlib.hash import sha512_crypt

if __name__ == "__main__":
    passwd = getpass.getpass('Password to hash: ')
    hash = sha512_crypt.encrypt(passwd)

    print hash

You can clone it from my github repo if you want: https://github.com/antoncohen/mksha

Anton Cohen
  • 1,112
  • 6
  • 7
0

Its not a one liner, but it might help someone:

import crypt, getpass, pwd, string, sys, random
randomsalt = ""
password = getpass.getpass()
choices = string.ascii_uppercase + string.digits + string.ascii_lowercase
for _ in range(0,8):
    randomsalt += random.choice(choices)
print crypt.crypt(password, '$6$%s$' % randomsalt)
jordixou
  • 9
  • 3
  • `random` is not cryptographically secure, `os.urandom` should be used. 8 characters from 56 character long dictionary is way too little too. Concatentating a sting over and over in python is bad form too (it has O(n^2) complexity) – Hubert Kario Nov 27 '17 at 16:14
0
$ htpasswd -c /tmp/my_hash user1
New password: 
Re-type new password: 
Adding password for user user1
$ cat /tmp/my_hash
user1:$apr1$oj1ypcQz$4.6lFVtKz2nr8acsQ8hD30

Obviously, you just grab the 2nd field, and can delete the file once you're added it to shadow or for use with sudo (still most likely shadow).

Felix Frank
  • 3,063
  • 1
  • 15
  • 22
0

Take a look at the man page for crypt (3) and I think that you will find that the crypt tool has been updated to use glibc and sha256 ($5) and sha512 ($6) , multiple rounds, much larger salt, and so on.

Clearly SHA512 is relevant to how /etc/shadow works.

That said, this web page was very helpful - in particular the MKPASSWD , as this solved MY problem.

Given a potentially "lost" password, I can use MKPASSWD and the salt, to generate the SHA512 hash, and confirm/deny a list of candidate passwords.

I would use John the ripper - but at least on my hardware (Raspberry Pi) and my budget (nothing) - John can't do it (it does not seem to support the advanced crypt/glibc stuff in the raspbian free version.

Mind you, since I have enough permission to read/write /etc/shadow, I COULD just overwrite the hash, and get on with life... this is an academic exercise.


NOTES Glibc notes The glibc2 version of this function supports additional encryp‐ tion algorithms.

   If salt is a  character  string  starting  with  the  characters
   "$id$" followed by a string terminated by "$":

          $id$salt$encrypted

   then instead of using the DES machine, id identifies the encryp‐
   tion method used and this then determines how the  rest  of  the
   password  string is interpreted.  The following values of id are
   supported:

          ID  | Method
          ─────────────────────────────────────────────────────────
          1   | MD5
          2a  | Blowfish (not in mainline glibc; added in some
              | Linux distributions)
          5   | SHA-256 (since glibc 2.7)
          6   | SHA-512 (since glibc 2.7)

   So  $5$salt$encrypted  is  an  SHA-256  encoded   password   and
   $6$salt$encrypted is an SHA-512 encoded one.
Michael Hampton
  • 237,123
  • 42
  • 477
  • 940
0

If you need an alternative to one-liners written in perl/python, mkpasswd is a good match. While it is included in the Debian whois package, it is missing on CentOS/RHEL systems. I've modified the Debian version of mkpasswd and included a stronger salt generation mechanism based on OpenSSL. The resulting binary fully preserves all Debian's version command line parameters. The code is avaiable on github and should compile on any Linux flavor: mkpasswd

Liviu
  • 1
-4

I'm not sure how SHA-512 is related to /etc/shadow. These passwords are crypted.

But if you want a password hashed with SHA-512 you can do this by echo -n the_password | sha512sum. You can't use the output for /etc/shadow.

mailq
  • 16,882
  • 2
  • 36
  • 66
  • 2
    `echo -n the_password` so you're not hashing the newline. – SmallClanger Nov 11 '11 at 13:14
  • Passwords in `shadow` aren't crypt()ed any more since years. Modern systems use at least md5. – Alexander Janssen Oct 03 '12 at 20:40
  • 6
    Actually passwords in `shadow` are still `crypt()`ed but the function has been updated to support several different algorithms. Regardless, the method described in this answer does not produce suitable hash for `/etc/shadow`. The algorithm is more complex than a single SHA-512 hash round. – snap Jan 05 '13 at 00:12