21

I would like to store an encrypted password in a Java file. I saw at a solution using javax.crypto, but the problem with that was that the key was being generated on the fly and it was random.

This password will be then taken and decrypted in the Java program in runtime. Given that I am going to store an already encrypted password in a file - I want to get the right text when decrypting it.

Is there a way to tell the javax.crypto method:

key = KeyGenerator.getInstance(algorithm).generateKey()

Can this be replaced with my own key generated once based on some private key?

Can anyone point me to some resources on how to do this?

oneiros
  • 3,527
  • 12
  • 44
  • 71

8 Answers8

32

Symmetric Key Cryptography : Symmetric key uses the same key for encryption and decryption. The main challenge with this type of cryptography is the exchange of the secret key between the two parties sender and receiver.

Example : The following example uses symmetric key for encryption and decryption algorithm available as part of the Sun's JCE(Java Cryptography Extension). Sun JCE is has two layers, the crypto API layer and the provider layer.

DES (Data Encryption Standard) was a popular symmetric key algorithm. Presently DES is outdated and considered insecure. Triple DES and a stronger variant of DES. It is a symmetric-key block cipher. There are other algorithms like Blowfish, Twofish and AES(Advanced Encryption Standard). AES is the latest encryption standard over the DES.

Steps :

  1. Add the Security Provider : We are using the SunJCE Provider that is available with the JDK.
  2. Generate Secret Key : Use KeyGenerator and an algorithm to generate a secret key. We are using DESede (DESede is descriptive name for 3DES implementation: DESede = DES-Encrypt-Decrypt-Encrypt = Triple DES).
  3. Encode Text : For consistency across platform encode the plain text as byte using UTF-8 encoding.
  4. Encrypt Text : Instantiate Cipher with ENCRYPT_MODE, use the secret key and encrypt the bytes.
  5. Decrypt Text : Instantiate Cipher with DECRYPT_MODE, use the same secret key and decrypt the bytes.

All the above given steps and concept are same, we just replace algorithms.

import java.util.Base64;    
import javax.crypto.Cipher;  
import javax.crypto.KeyGenerator;   
import javax.crypto.SecretKey;  
public class EncryptionDecryptionAES {  
    static Cipher cipher;  

    public static void main(String[] args) throws Exception {
        /* 
         create key 
         If we need to generate a new key use a KeyGenerator
         If we have existing plaintext key use a SecretKeyFactory
        */ 
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128); // block size is 128bits
        SecretKey secretKey = keyGenerator.generateKey();
        
        /*
          Cipher Info
          Algorithm : for the encryption of electronic data
          mode of operation : to avoid repeated blocks encrypt to the same values.
          padding: ensuring messages are the proper length necessary for certain ciphers 
          mode/padding are not used with stream cyphers.  
         */
        cipher = Cipher.getInstance("AES"); //SunJCE provider AES algorithm, mode(optional) and padding schema(optional)  

        String plainText = "AES Symmetric Encryption Decryption";
        System.out.println("Plain Text Before Encryption: " + plainText);

        String encryptedText = encrypt(plainText, secretKey);
        System.out.println("Encrypted Text After Encryption: " + encryptedText);

        String decryptedText = decrypt(encryptedText, secretKey);
        System.out.println("Decrypted Text After Decryption: " + decryptedText);
    }

    public static String encrypt(String plainText, SecretKey secretKey)
            throws Exception {
        byte[] plainTextByte = plainText.getBytes();
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedByte = cipher.doFinal(plainTextByte);
        Base64.Encoder encoder = Base64.getEncoder();
        String encryptedText = encoder.encodeToString(encryptedByte);
        return encryptedText;
    }

    public static String decrypt(String encryptedText, SecretKey secretKey)
            throws Exception {
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] encryptedTextByte = decoder.decode(encryptedText);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decryptedByte = cipher.doFinal(encryptedTextByte);
        String decryptedText = new String(decryptedByte);
        return decryptedText;
    }
}

Output:

Plain Text Before Encryption: AES Symmetric Encryption Decryption
Encrypted Text After Encryption: sY6vkQrWRg0fvRzbqSAYxepeBIXg4AySj7Xh3x4vDv8TBTkNiTfca7wW/dxiMMJl
Decrypted Text After Decryption: AES Symmetric Encryption Decryption

Source

Example: Cipher with two modes, they are encrypt and decrypt. we have to start every time after setting mode to encrypt or decrypt a text. enter image description here

Premraj
  • 72,055
  • 26
  • 237
  • 180
30

Here is a solution using the javax.crypto library and the apache commons codec library for encoding and decoding in Base64 that I was looking for:

import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import org.apache.commons.codec.binary.Base64;

public class TrippleDes {

    private static final String UNICODE_FORMAT = "UTF8";
    public static final String DESEDE_ENCRYPTION_SCHEME = "DESede";
    private KeySpec ks;
    private SecretKeyFactory skf;
    private Cipher cipher;
    byte[] arrayBytes;
    private String myEncryptionKey;
    private String myEncryptionScheme;
    SecretKey key;

    public TrippleDes() throws Exception {
        myEncryptionKey = "ThisIsSpartaThisIsSparta";
        myEncryptionScheme = DESEDE_ENCRYPTION_SCHEME;
        arrayBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
        ks = new DESedeKeySpec(arrayBytes);
        skf = SecretKeyFactory.getInstance(myEncryptionScheme);
        cipher = Cipher.getInstance(myEncryptionScheme);
        key = skf.generateSecret(ks);
    }


    public String encrypt(String unencryptedString) {
        String encryptedString = null;
        try {
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] plainText = unencryptedString.getBytes(UNICODE_FORMAT);
            byte[] encryptedText = cipher.doFinal(plainText);
            encryptedString = new String(Base64.encodeBase64(encryptedText));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encryptedString;
    }


    public String decrypt(String encryptedString) {
        String decryptedText=null;
        try {
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] encryptedText = Base64.decodeBase64(encryptedString);
            byte[] plainText = cipher.doFinal(encryptedText);
            decryptedText= new String(plainText);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decryptedText;
    }


    public static void main(String args []) throws Exception
    {
        TrippleDes td= new TrippleDes();

        String target="imparator";
        String encrypted=td.encrypt(target);
        String decrypted=td.decrypt(encrypted);

        System.out.println("String To Encrypt: "+ target);
        System.out.println("Encrypted String:" + encrypted);
        System.out.println("Decrypted String:" + decrypted);

    }

}

Running the above program results with the following output:

String To Encrypt: imparator
Encrypted String:FdBNaYWfjpWN9eYghMpbRA==
Decrypted String:imparator
oneiros
  • 3,527
  • 12
  • 44
  • 71
  • 5
    This example goes a long way regarding some cryptographic functions, but it fouls up on too many others. The example is using a `String` as a key. Furthermore, it silently uses the insecure ECB mode encryption. There is no authenticity or integrity control either. The (character) encoding / decoding is OK, and so is the default padding mode. *But in general this code is **not secure***. – Maarten Bodewes Jun 12 '13 at 20:21
  • oneiros also have a look at my question. .http://stackoverflow.com/questions/38007478/encrypt-and-decrypt-string-using-chacha20 – Zar E Ahmer Jun 24 '16 at 09:19
  • 1
    byte[] encryptedText = Base64.decodeBase64((encryptedString); error in this line. String can not be converted into byte. – Adnan Ali May 13 '18 at 11:02
  • In late but why use apache commons for Base64. Java has base64 built in. – Mr00Anderson Jul 02 '18 at 19:30
  • Anyway, keeping the key in the code is not so a full safety measure – Ashok kumar Ganesan Jul 13 '22 at 17:55
5

KeyGenerator is used to generate keys

You may want to check KeySpec, SecretKey and SecretKeyFactory classes

http://docs.oracle.com/javase/1.5.0/docs/api/javax/crypto/spec/package-summary.html

jambriz
  • 1,273
  • 1
  • 10
  • 25
2

You may want to use the jasypt library (Java Simplified Encryption), which is quite easy to use. ( Also, it's recommended to check against the encrypted password rather than decrypting the encrypted password )

To use jasypt, if you're using maven, you can include jasypt into your pom.xml file as follows:

<dependency>
    <groupId>org.jasypt</groupId>
    <artifactId>jasypt</artifactId>
    <version>1.9.3</version>
    <scope>compile</scope>
</dependency>

And then to encrypt the password, you can use StrongPasswordEncryptor

public static String encryptPassword(String inputPassword) {
    StrongPasswordEncryptor encryptor = new StrongPasswordEncryptor();
    return encryptor.encryptPassword(inputPassword);
}

Note: the encrypted password is different every time you call encryptPassword but the checkPassword method can still check that the unencrypted password still matches each of the encrypted passwords.

And to check the unencrypted password against the encrypted password, you can use the checkPassword method:

public static boolean checkPassword(String inputPassword, String encryptedStoredPassword) {
    StrongPasswordEncryptor encryptor = new StrongPasswordEncryptor();
    return encryptor.checkPassword(inputPassword, encryptedStoredPassword);
}

The page below provides detailed information on the complexities involved in creating safe encrypted passwords.

http://www.jasypt.org/howtoencryptuserpasswords.html

shunkana
  • 334
  • 2
  • 4
2

Simple and easy solution :- jasypt library. To use this library in your maven project include below dependency

<dependency>
    <groupId>org.jasypt</groupId>
    <artifactId>jasypt</artifactId>
    <version>1.9.3</version>
    <scope>compile</scope>
</dependency>

There is one security advantage of using this library is it does not provide any direct method to decrypt the password.

User can not pick any ecrypted password and pass it to library to get original password. To validate any user jasypt library provide a method which accept 2 parameters i.e. input password and encrypted password, the method will return true if the password is correct and false if password is wrong.

Just create a Utility Class like this.

public class EncryptDecryptPassword {
public static String encryptPassword(String inputPassword) {
    StrongPasswordEncryptor encryptor = new StrongPasswordEncryptor();
    return encryptor.encryptPassword(inputPassword);
}

public static boolean checkPassword(String inputPassword, String encryptedStoredPassword) {
    StrongPasswordEncryptor encryptor = new StrongPasswordEncryptor();
    return encryptor.checkPassword(inputPassword, encryptedStoredPassword);
}

}

Use these static methods from anywhere from your project to perform encryption.

  • 2
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 23 '22 at 12:17
1

Here is a sample I made a couple of months ago The class encrypt and decrypt data

import java.security.*;
import java.security.spec.*;

import java.io.*;
import javax.crypto.*;
import javax.crypto.spec.*;

public class TestEncryptDecrypt {

private final String ALGO = "DES";
private final String MODE = "ECB";
private final String PADDING = "PKCS5Padding";
private static int mode = 0;

public static void main(String args[]) {
    TestEncryptDecrypt me = new TestEncryptDecrypt();
    if(args.length == 0) mode = 2;
    else mode = Integer.parseInt(args[0]);
    switch (mode) {
    case 0:
        me.encrypt();
        break;
    case 1:
        me.decrypt();
        break;
    default:
        me.encrypt();
        me.decrypt();
    }
}

public void encrypt() {
try {
    System.out.println("Start encryption ...");

    /* Get Input Data */
    String input = getInputData();
    System.out.println("Input data : "+input);

    /* Create Secret Key */
    KeyGenerator keyGen = KeyGenerator.getInstance(ALGO);
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
    keyGen.init(56,random);
      Key sharedKey = keyGen.generateKey();

    /* Create the Cipher and init it with the secret key */
    Cipher c = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING);
    //System.out.println("\n" + c.getProvider().getInfo());
    c.init(Cipher.ENCRYPT_MODE,sharedKey);
    byte[] ciphertext = c.doFinal(input.getBytes());
    System.out.println("Input Encrypted : "+new String(ciphertext,"UTF8"));

    /* Save key to a file */
    save(sharedKey.getEncoded(),"shared.key");

    /* Save encrypted data to a file */
    save(ciphertext,"encrypted.txt");
} catch (Exception e) {
    e.printStackTrace();
}   
}

public void decrypt() {
try {
    System.out.println("Start decryption ...");

    /* Get encoded shared key from file*/
    byte[] encoded = load("shared.key");
      SecretKeyFactory kf = SecretKeyFactory.getInstance(ALGO);
    KeySpec ks = new DESKeySpec(encoded);
    SecretKey ky = kf.generateSecret(ks);

    /* Get encoded data */
    byte[] ciphertext = load("encrypted.txt");
    System.out.println("Encoded data = " + new String(ciphertext,"UTF8"));

    /* Create a Cipher object and initialize it with the secret key */
    Cipher c = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING);
    c.init(Cipher.DECRYPT_MODE,ky);

    /* Update and decrypt */
    byte[] plainText = c.doFinal(ciphertext);
    System.out.println("Plain Text : "+new String(plainText,"UTF8"));
} catch (Exception e) {
    e.printStackTrace();
}   
}

private String getInputData() {
    String id = "owner.id=...";
    String name = "owner.name=...";
    String contact = "owner.contact=...";
    String tel = "owner.tel=...";
    final String rc = System.getProperty("line.separator");
    StringBuffer buf = new StringBuffer();
    buf.append(id);
    buf.append(rc);
    buf.append(name);
    buf.append(rc);
    buf.append(contact);
    buf.append(rc);
    buf.append(tel);
    return buf.toString();
}


private void save(byte[] buf, String file) throws IOException {
      FileOutputStream fos = new FileOutputStream(file);
      fos.write(buf);
      fos.close();
}

private byte[] load(String file) throws FileNotFoundException, IOException {
    FileInputStream fis = new FileInputStream(file);
    byte[] buf = new byte[fis.available()];
    fis.read(buf);
    fis.close();
    return buf;
}
}
Hugues
  • 375
  • 1
  • 3
  • 10
  • 1
    -1 you cannot save encrypted text as string, as it may contain any byte value, which may not encode and more importantly, they may not decode to a `String`. So the above code will fail *now and then*. – Maarten Bodewes Jun 12 '13 at 20:25
0
public class GenerateEncryptedPassword {

    public static void main(String[] args){

        Scanner sc= new Scanner(System.in);    
        System.out.println("Please enter the password that needs to be encrypted :");
        String input = sc.next();

        try {
            String encryptedPassword= AESencrp.encrypt(input);
            System.out.println("Encrypted password generated is :"+encryptedPassword);
        } catch (Exception ex) {
            Logger.getLogger(GenerateEncryptedPassword.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
Pankaj Lilan
  • 4,245
  • 1
  • 29
  • 48
0

If you use a static key, encrypt and decrypt always give the same result;

public static final String CRYPTOR_KEY = "your static key here";
byte[] keyByte = Base64.getDecoder().decode(CRYPTOR_KEY);
key = new SecretKeySpec(keyByte, "AES");
Yunus ER
  • 1,999
  • 2
  • 9
  • 14