2

I have been reading some codes regarding encrypting a password in Java. Which seems a bit more computing intensive.

Is there a quick way to encrypt a string similar to C or Ruby?

For example, in Ruby:

'hello'.crypt('$6$salt') # => "$6$salt$ghQ6Rhatj/sug12c6v8Ao/bXUoyJ1O1SqdumufgGEO3b3NYPvm/dSWDKWfNm1VxFoFiy/cw9eRaY0xu4GDQSU/"

The method String#crypt() is from C, which is used in Linux to store hashed password in /etc/shadow:

$ sudo cat /etc/shadow | grep $USER
sourav:$6$Vx0wkV1M2PM43WOE$b2pYu.funKjk/snGSqiMTgh1e9dGQYDEKrjfuc2T/tP5qs7lXU56MjFvWd35rgzmYBXK33DrjQqnxTcPtcMXi/:18013:0:99999:7:::

Here's a small program...

Knowing that my system password is 55, in Ruby:

pass = IO.readlines('/etc/shadow').find { |x| x.start_with?(ENV['USER']) }
=> "sourav:$6$Vx0wkV1M2PM43WOE$b2pYu.funKjk/snGSqiMTgh1e9dGQYDEKrjfuc2T/tP5qs7lXU56MjFvWd35rgzmYBXK33DrjQqnxTcPtcMXi/:18013:0:99999:7:::\n"

h = ?$ + pass.split(?$)[1..2].join(?$)
=> "$6$Vx0wkV1M2PM43WOE"

s = pass.split(?$)[-1].split(?:)[0]
=> "b2pYu.funKjk/snGSqiMTgh1e9dGQYDEKrjfuc2T/tP5qs7lXU56MjFvWd35rgzmYBXK33DrjQqnxTcPtcMXi/"

hs = h + ?$ + s
=> "$6$Vx0wkV1M2PM43WOE$b2pYu.funKjk/snGSqiMTgh1e9dGQYDEKrjfuc2T/tP5qs7lXU56MjFvWd35rgzmYBXK33DrjQqnxTcPtcMXi/"

'55'.crypt(h) == hs
=> true

So the system can confirm my password is 55 and let me log in.

Is there a similar method in Java that can encrypt a string? Can I similarly run 'string.crypt("$6$salt")' and decrypt /etc/shadow's account password if the account password is given?

15 Volts
  • 1,946
  • 15
  • 37
  • 2
    https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/Crypt.html – Joop Eggen Nov 21 '19 at 13:35
  • 1
    Note: `byte[] b = s.getBytes("UTF-8"); s = new String(b, "UTF-8");` or `StandardCharsets.UTF_8` i.o.` "UTF-8"`. – Joop Eggen Nov 21 '19 at 13:37
  • IDK why, but it says `error: cannot find symbol` I can't import `org.apache.commons.codec.digest.Crypt` as well, which doesn't exist :( – 15 Volts Nov 21 '19 at 13:52
  • @S.Goswami did you include the commons-codec jar in your buildpath? – Federico klez Culloca Nov 21 '19 at 13:53
  • Ok, so I have included that, and importing `import org.apache.commons.codec.digest.Crypt`, which seems to work fine. But there's the error of cannot find symbol while using the `crypt()` from example in the given link... – 15 Volts Nov 21 '19 at 13:57
  • The compile option was `javac -cp sqlite-jdbc-3.27.2.1.jar:. -cp commons-codec-1.13/commons-codec-1.13.jar:. Register.java && java Register `, the app is called Register – 15 Volts Nov 21 '19 at 13:59
  • `javac -cp sqlite-jdbc-3.27.2.1.jar:commons-codec-1.13/commons-codec-1.13.jar:. ...` – Joop Eggen Nov 21 '19 at 14:02
  • Thanks a lot. The compilation was successful. But `System.out.println(Crypt.crypt("secret", "$1$xxxx")) ;` crashes for some reason :( – 15 Volts Nov 21 '19 at 14:13
  • @S.Goswami ´ crashes for some reason´ that's not something we could help with – gusto2 Nov 21 '19 at 14:24
  • Oh got it, I was running `javac -cp sqlite-jdbc-3.27.2.1.jar:commons-codec-1.13/commons-codec-1.13.jar:. Register.java && java Register`. But it firxes the problem if I do: `javac -cp sqlite-jdbc-3.27.2.1.jar:commons-codec-1.13/commons-codec-1.13.jar:. Register.java && java -cp commons-codec-1.13/commons-codec-1.13.jar:. Register` – 15 Volts Nov 21 '19 at 14:28

3 Answers3

2

Java includes since 1.4 a package named javax.crypto, which allows you to encrypt and decrypt data using a Cipher.

TutorialsPoint has a tutorial for this package. Here is a little Java snippet which first encrypts data, then decrypts it:

public class CipherSample {
 public static void main(String args[]) throws Exception{
  //Creating a Signature object
  Signature sign = Signature.getInstance("SHA256withRSA");

  //Creating KeyPair generator object
  KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");

  //Initializing the key pair generator
  keyPairGen.initialize(2048);

  //Generating the pair of keys
  KeyPair pair = keyPairGen.generateKeyPair();      

  //Creating a Cipher object
  Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

  //Initializing a Cipher object
  cipher.init(Cipher.ENCRYPT_MODE, pair.getPublic());

  //Adding data to the cipher
  byte[] input = "Welcome to Tutorialspoint".getBytes();      
  cipher.update(input);

  //encrypting the data
  byte[] cipherText = cipher.doFinal();  
  System.out.println(new String(cipherText, "UTF8"));

  //Initializing the same cipher for decryption
  cipher.init(Cipher.DECRYPT_MODE, pair.getPrivate());

  //Decrypting the text
  byte[] decipheredText = cipher.doFinal(cipherText);
  System.out.println(new String(decipheredText));
  }
}

Not as straightforward, but still simple.

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
Yassine Badache
  • 1,810
  • 1
  • 19
  • 38
  • I'm not so sure this does the same thing the [`crypt`](http://man7.org/linux/man-pages/man3/crypt.3.html) function does – Federico klez Culloca Nov 21 '19 at 13:55
  • 1
    Even the asking person mixes hash and ciphertext, this answer is wrong an doesn't solve the question (it is even misleading) – gusto2 Nov 21 '19 at 14:16
  • 1
    I don't think this is Crypt(). Before asking the question, I read this on tutorialspoint, and there's a question on stackoverflow regarding cryptography in Java, but they are other algorithms... – 15 Volts Nov 21 '19 at 14:18
2

and decrypt /etc/shadow's account password if the account password is given

The crypt() function is not encryption, the function creates a salted password hash.

Hash is a one-way function and one of its primary features is that nobody should be able to recover password based from the (cryptographic) hash value.

So the system can confirm my password is 55 and let me log in.

This is possible. Effectively you compute a new salted hash (using the same salt) and compare with the stored value.

Is there a similar method in Java that can encrypt a string?

import org.apache.commons.codec.digest.Crypt;

...

String hash = Crypt.crypt("password".getBytes());
System.out.println("salted hash: "+hash);
// salt is $X$some_bytes
String salt = hash.substring(0, hash.indexOf("$", 3));
System.out.println("salt: "+salt);
// validation:
String testString = Crypt.crypt("password", salt);
if(testString.equals(hash)) {
  System.out.println("Password match");
} else {
  System.out.println("Invalid password");
}
gusto2
  • 11,210
  • 2
  • 17
  • 36
-2

The crypt C library function uses DES as its encryption. You have to use the same algorithm if you want exactly the same result in Java.

In a nutshell:

    KeyGenerator keygenerator = KeyGenerator.getInstance("DES");
    SecretKey desKey = keygenerator.generateKey();

    Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");

    cipher.init(Cipher.ENCRYPT_MODE, desKey);

    byte[] encrypted = desCipher.doFinal(clearText.getBytes());

You can find a tutorial here: https://www.mkyong.com/java/jce-encryption-data-encryption-standard-des-tutorial/

jbx
  • 21,365
  • 18
  • 90
  • 144