[java] How to encrypt String in Java

What I need is to encrypt string which will show up in 2D barcode(PDF-417) so when someone get an idea to scan it will get nothing readable.

Other requirements:

  • should not be complicated
  • it should not consist of RSA, PKI infrastructure, key pairs, etc.

It must be simple enough to get rid of the people snooping around, and easy to decrypt for other companies interested in getting that data. They call us, we tell them the standard or give them some simple key which can then be used for decryption.

Probably those companies could use different technologies so it would be good to stick to some standard which is not tied to some special platform or technology.

What do you suggest? Is there some Java class doing encrypt() & decrypt() without much complication in achieving high security standards?

This question is related to java encryption

The answer is


Here's my implementation from meta64.com as a Spring Singleton. If you want to create a ciper instance for each call that would work also, and then you could remove the 'synchronized' calls, but beware 'cipher' is not thread-safe.

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("singleton")
public class Encryptor {

    @Value("${aeskey}")
    private String keyStr;

    private Key aesKey = null;
    private Cipher cipher = null;

    synchronized private void init() throws Exception {
        if (keyStr == null || keyStr.length() != 16) {
            throw new Exception("bad aes key configured");
        }
        if (aesKey == null) {
            aesKey = new SecretKeySpec(keyStr.getBytes(), "AES");
            cipher = Cipher.getInstance("AES");
        }
    }

    synchronized public String encrypt(String text) throws Exception {
        init();
        cipher.init(Cipher.ENCRYPT_MODE, aesKey);
        return toHexString(cipher.doFinal(text.getBytes()));
    }

    synchronized public String decrypt(String text) throws Exception {
        init();
        cipher.init(Cipher.DECRYPT_MODE, aesKey);
        return new String(cipher.doFinal(toByteArray(text)));
    }

    public static String toHexString(byte[] array) {
        return DatatypeConverter.printHexBinary(array);
    }

    public static byte[] toByteArray(String s) {
        return DatatypeConverter.parseHexBinary(s);
    }

    /*
     * DO NOT DELETE
     * 
     * Use this commented code if you don't like using DatatypeConverter dependency
     */
    // public static String toHexStringOld(byte[] bytes) {
    // StringBuilder sb = new StringBuilder();
    // for (byte b : bytes) {
    // sb.append(String.format("%02X", b));
    // }
    // return sb.toString();
    // }
    //
    // public static byte[] toByteArrayOld(String s) {
    // int len = s.length();
    // byte[] data = new byte[len / 2];
    // for (int i = 0; i < len; i += 2) {
    // data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i +
    // 1), 16));
    // }
    // return data;
    // }
}

This is the first page that shows up via Google and the security vulnerabilities in all the implementations make me cringe so I'm posting this to add information regarding encryption for others as it has been 7 Years from the original post. I hold a Masters Degree in Computer Engineering and spent a lot of time studying and learning Cryptography so I'm throwing my two cents to make the internet a safer place.

Also, do note that a lot of implementation might be secure for a given situation, but why use those and potentially accidentally make a mistake? Use the strongest tools you have available unless you have a specific reason not to. Overall I highly advise using a library and staying away from the nitty gritty details if you can.

UPDATE 4/5/18: I rewrote some parts to make them simpler to understand and changed the recommended library from Jasypt to Google's new library Tink, I would recommend completely removing Jasypt from an existing setup.

Foreword

I will outline the basics of secure symmetric cryptography below and point out common mistakes I see online when people implement crypto on their own with the standard Java library. If you want to just skip all the details run over to Google's new library Tink import that into your project and use AES-GCM mode for all your encryptions and you shall be secure.

Now if you want to learn the nitty gritty details on how to encrypt in java read on :)

Block Ciphers

First thing first you need to pick a symmetric key Block Cipher. A Block Cipher is a computer function/program used to create Pseudo-Randomness. Pseudo-Randomness is fake randomness that no computer other than a Quantum Computer would be able to tell the difference between it and real randomness. The Block Cipher is like the building block to cryptography, and when used with different modes or schemes we can create encryptions.

Now regarding Block Cipher Algorithms available today, Make sure to NEVER, I repeat NEVER use DES, I would even say NEVER use 3DES. The only Block Cipher that even Snowden's NSA release was able to verify being truly as close to Pseudo-Random as possible is AES 256. There also exists AES 128; the difference is AES 256 works in 256-bit blocks, while AES 128 works in 128 blocks. All in all, AES 128 is considered secure although some weaknesses have been discovered, but 256 is as solid as it gets.

Fun fact DES was broken by the NSA back when it was initially founded and actually kept a secret for a few years. Although some people still claim 3DES is secure, there are quite a few research papers that have found and analyzed weaknesses in 3DES.

Encryption Modes

Encryption is created when you take a block cipher and use a specific scheme so that the randomness is combined with a key to creating something that is reversible as long as you know the key. This is referred to as an Encryption Mode.

Here is an example of an encryption mode and the simplest mode known as ECB just so you can visually understand what is happening:

ECB Mode

The encryption modes you will see most commonly online are the following:

ECB CTR, CBC, GCM

There exist other modes outside of the ones listed and researchers are always working toward new modes to improve existing problems.

Now let's move on to implementations and what is secure. NEVER use ECB this is bad at hiding repeating data as shown by the famous Linux penguin.Linux Penguin Example

When implementing in Java, note that if you use the following code, ECB mode is set by default:

Cipher cipher = Cipher.getInstance("AES");

... DANGER THIS IS A VULNERABILITY! and unfortunately, this is seen all over StackOverflow and online in tutorials and examples.

Nonces and IVs

In response to the issue found with ECB mode nounces also known as IVs were created. The idea is that we generate a new random variable and attach it to every encryption so that when you encrypt two messages that are the same they come out different. The beauty behind this is that an IV or nonce is public knowledge. That means an attacker can have access to this but as long as they don't have your key, they cant do anything with that knowledge.

Common issues I will see is that people will set the IV as a static value as in the same fixed value in their code. and here is the pitfall to IVs the moment you repeat one you actually compromise the entire security of your encryption.

Generating A Random IV

SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);

Note: SHA1 is broken but I couldn't find how to implement SHA256 into this use case properly, so if anyone wants to take a crack at this and update it would be awesome! Also SHA1 attacks still are unconventional as it can take a few years on a huge cluster to crack. Check out details here.

CTR Implementation

No padding is required for CTR mode.

 Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

CBC Implementation

If you choose to implement CBC Mode do so with PKCS7Padding as follows:

 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

CBC and CTR Vulnerability and Why You Should Use GCM

Although some other modes such as CBC and CTR are secure they run into the issue where an attacker can flip the encrypted data, changing its value when decrypted. So let's say you encrypt an imaginary bank message "Sell 100", your encrypted message looks like this "eu23ng" the attacker changes one bit to "eu53ng" and all of a sudden when decrypted your message, it reads as "Sell 900".

To avoid this the majority of the internet uses GCM, and every time you see HTTPS they are probably using GCM. GCM signs the encrypted message with a hash and checks to verify that the message has not been changed using this signature.

I would avoid implementing GCM because of its complexity. You are better off using Googles new library Tink because here again if you accidentally repeat an IV you are compromising the key in the case with GCM, which is the ultimate security flaw. New researchers are working towards IV repeat resistant encryption modes where even if you repeat the IV the key is not in danger but this has yet to come mainstream.

Now if you do want to implement GCM, here is a link to a nice GCM implementation. However, I can not ensure the security or if its properly implemented but it gets the basis down. Also note with GCM there is no padding.

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

Keys vs Passwords

Another very important note, is that when it comes to cryptography a Key and a Password are not the same things. A Key in cryptography needs to have a certain amount of entropy and randomness to be considered secure. This is why you need to make sure to use the proper cryptographic libraries to generate the key for you.

So you really have two implementations you can do here, the first is to use the code found on this StackOverflow thread for Random Key Generation. This solution uses a secure random number generator to create a key from scratch that you can the use.

The other less secure option is to use, user input such as a password. The issue as we discussed is that the password doesn't have enough entropy, so we would have to use PBKDF2, an algorithm that takes the password and strengthens it. Here is a StackOverflow implementation I liked. However Google Tink library has all this built in and you should take advantage of it.

Android Developers

One important point to point out here is know that your android code is reverse engineerable and most cases most java code is too. That means if you store the password in plain text in your code. A hacker can easily retrieve it. Usually, for these type of encryption, you want to use Asymmetric Cryptography and so on. This is outside the scope of this post so I will avoid diving into it.

An interesting reading from 2013: Points out that 88% of Crypto implementations in Android were done improperly.

Final Thoughts

Once again I would suggest avoid implementing the java library for crypto directly and use Google Tink, it will save you the headache as they have really done a good job of implementing all the algorithms properly. And even then make sure you check up on issues brought up on the Tink github, vulnerabilities popup here and there.

If you have any questions or feedback feel free to comment! Security is always changing and you need to do your best to keep up with it :)


You might want to consider some automated tool to do the encryption / decryption code generation eg. https://www.stringencrypt.com/java-encryption/

It can generate different encryption and decryption code each time for the string or file encryption.

It's pretty handy when it comes to fast string encryption without using RSA, AES etc.

Sample results:

// encrypted with https://www.stringencrypt.com (v1.1.0) [Java]
// szTest = "Encryption in Java!"
String szTest = "\u9E3F\uA60F\uAE07\uB61B\uBE1F\uC62B\uCE2D\uD611" +
                "\uDE03\uE5FF\uEEED\uF699\uFE3D\u071C\u0ED2\u1692" +
                "\u1E06\u26AE\u2EDC";

for (int iatwS = 0, qUJQG = 0; iatwS < 19; iatwS++)
{
        qUJQG = szTest.charAt(iatwS);
        qUJQG ++;
        qUJQG = ((qUJQG << 5) | ( (qUJQG & 0xFFFF) >> 11)) & 0xFFFF;
        qUJQG -= iatwS;
        qUJQG = (((qUJQG & 0xFFFF) >> 6) | (qUJQG << 10)) & 0xFFFF;
        qUJQG ^= iatwS;
        qUJQG -= iatwS;
        qUJQG = (((qUJQG & 0xFFFF) >> 3) | (qUJQG << 13)) & 0xFFFF;
        qUJQG ^= 0xFFFF;
        qUJQG ^= 0xB6EC;
        qUJQG = ((qUJQG << 8) | ( (qUJQG & 0xFFFF) >> 8)) & 0xFFFF;
        qUJQG --;
        qUJQG = (((qUJQG & 0xFFFF) >> 5) | (qUJQG << 11)) & 0xFFFF;
        qUJQG ++;
        qUJQG ^= 0xFFFF;
        qUJQG += iatwS;
        szTest = szTest.substring(0, iatwS) + (char)(qUJQG & 0xFFFF) + szTest.substring(iatwS + 1);
}

System.out.println(szTest);

We use it all the time in our company.


Here is a copy/paste solution. I also recommend reading and voting for @Konstantino's answer even though it doesn't provider any code. The initialization vector (IV) is like a salt - it doesn't have to be kept secret. I am new to GCM and apparently AAD is optional and only used in certain circumstances. Set the key in the environment variable SECRET_KEY_BASE. Use something like KeePass to generate a 32 character password. This solution is modeled after my Ruby solution.

    public static String encrypt(String s) {
        try {
            byte[] input = s.getBytes("UTF-8");
            String keyString = System.getProperty("SECRET_KEY_BASE", System.getenv("SECRET_KEY_BASE"));
            if (keyString == null || keyString.length() == 0) {
                Logger.error(Utils.class, "encrypt()", "$SECRET_KEY_BASE is not set.");
                return null;
            }
            byte[] keyBytes = keyString.getBytes("UTF-8");
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
            // generate IV
            SecureRandom secureRandom = SecureRandom.getInstanceStrong();
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            byte[] ivBytes = new byte[cipher.getBlockSize()];
            secureRandom.nextBytes(ivBytes);
            GCMParameterSpec gcmSpec = new GCMParameterSpec(96, ivBytes); // 96 bit tag length
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec);
            // generate AAD
//          byte[] aadBytes = new byte[cipher.getBlockSize()];
//          secureRandom.nextBytes(aadBytes);
//          cipher.updateAAD(aadBytes);
            // encrypt
            byte[] encrypted = cipher.doFinal(input);
            byte[] returnBytes = new byte[ivBytes.length + encrypted.length];
//          byte[] returnBytes = new byte[ivBytes.length + aadBytes.length + encrypted.length];
            System.arraycopy(ivBytes, 0, returnBytes, 0, ivBytes.length);
//          System.arraycopy(aadBytes, 0, returnBytes, ivBytes.length, aadBytes.length);
            System.arraycopy(encrypted, 0, returnBytes, ivBytes.length, encrypted.length);
//          System.arraycopy(encrypted, 0, returnBytes, ivBytes.length+aadBytes.length, encrypted.length);
            String encryptedString = Base64.getEncoder().encodeToString(returnBytes);
            return encryptedString;
        } catch (UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | 
                InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            Logger.error(Utils.class, "encrypt()", "Could not encrypt string: " + e.getMessage());
            return null;
        }
    }

    public static String decrypt(String s) {
        if (s == null || s.length() == 0) return "";
        try {
            byte[] encrypted = Base64.getDecoder().decode(s);
            String keyString = System.getProperty("SECRET_KEY_BASE", System.getenv("SECRET_KEY_BASE"));
            if (keyString == null || keyString.length() == 0) {
                Logger.error(Utils.class, "encrypt()", "$SECRET_KEY_BASE is not set.");
                return null;
            }
            byte[] keyBytes = keyString.getBytes("UTF-8");
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            byte[] ivBytes = new byte[cipher.getBlockSize()];
            System.arraycopy(encrypted, 0, ivBytes, 0, ivBytes.length);
            GCMParameterSpec gcmSpec = new GCMParameterSpec(96, ivBytes);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec);
//          cipher.updateAAD(encrypted, ivBytes.length, cipher.getBlockSize());
            byte[] decrypted = cipher.doFinal(encrypted, cipher.getBlockSize(), encrypted.length - cipher.getBlockSize());
//          byte[] decrypted = cipher.doFinal(encrypted, cipher.getBlockSize()*2, encrypted.length - cipher.getBlockSize()*2);
            String decryptedString = new String(decrypted, "UTF-8");
            return decryptedString;
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedEncodingException | InvalidKeyException | 
                InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            Logger.error(Utils.class, "decrypt()", "Could not decrypt string: " + e.getMessage());
            return null;
        }
    }

Here is an example:

    String s = "This is a test.";
    String enc = Utils.encrypt(s);
    System.out.println(enc);
    // fQHfYjbD+xAuN5XzH2ojk/EWNeKXUrKRSfx8LU+5dpuKkM/pueCMBjKCZw==
    String dec = Utils.decrypt(enc);
    System.out.println(dec);
    // This is a test.

Here are some links you can read what Java supports

Encrypting/decrypting a data stream.

This example demonstrates how to encrypt (using a symmetric encryption algorithm such as AES, Blowfish, RC2, 3DES, etc) a large amount of data. The data is passed in chunks to one of the encrypt methods: EncryptBytes, EncryptString, EncryptBytesENC, or EncryptStringENC. (The method name indicates the type of input (string or byte array) and the return type (encoded string or byte array). The FirstChunk and LastChunk properties are used to indicate whether a chunk is the first, middle, or last in a stream to be encrypted. By default, both FirstChunk and LastChunk equal true -- meaning that the data passed is the entire amount.

JCERefGuide

Java Encryption Examples


thanks ive made this class using your code maybe someone finds it userfull

object crypter

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


public class ObjectCrypter {

private Cipher deCipher;
private Cipher enCipher;
private SecretKeySpec key;
private IvParameterSpec ivSpec;


public ObjectCrypter(byte[] keyBytes,   byte[] ivBytes) {
    // wrap key data in Key/IV specs to pass to cipher


     ivSpec = new IvParameterSpec(ivBytes);
    // create the cipher with the algorithm you choose
    // see javadoc for Cipher class for more info, e.g.
    try {
         DESKeySpec dkey = new  DESKeySpec(keyBytes);
          key = new SecretKeySpec(dkey.getKey(), "DES");
         deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
         enCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
public byte[] encrypt(Object obj) throws InvalidKeyException, InvalidAlgorithmParameterException, IOException, IllegalBlockSizeException, ShortBufferException, BadPaddingException {
    byte[] input = convertToByteArray(obj);
    enCipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

    return enCipher.doFinal(input);




//  cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
//  byte[] encypted = new byte[cipher.getOutputSize(input.length)];
//  int enc_len = cipher.update(input, 0, input.length, encypted, 0);
//  enc_len += cipher.doFinal(encypted, enc_len);
//  return encypted;


}
public Object decrypt( byte[]  encrypted) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException, ClassNotFoundException {
    deCipher.init(Cipher.DECRYPT_MODE, key, ivSpec);

    return convertFromByteArray(deCipher.doFinal(encrypted));

}



private Object convertFromByteArray(byte[] byteObject) throws IOException,
        ClassNotFoundException {
    ByteArrayInputStream bais;

    ObjectInputStream in;
    bais = new ByteArrayInputStream(byteObject);
    in = new ObjectInputStream(bais);
    Object o = in.readObject();
    in.close();
    return o;

}



private byte[] convertToByteArray(Object complexObject) throws IOException {
    ByteArrayOutputStream baos;

    ObjectOutputStream out;

    baos = new ByteArrayOutputStream();

    out = new ObjectOutputStream(baos);

    out.writeObject(complexObject);

    out.close();

    return baos.toByteArray();

}


}

Like many of the guys have already told, you should use a standard cypher that is overly used like DES or AES.

A simple example of how you can encrypt and decrypt a string in java using AES.

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class EncryptorDemo {

    public static String encrypt(String key, String randomVector, String value) {
        try {
            IvParameterSpec iv = new IvParameterSpec(randomVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(value.getBytes());
            System.out.println("encrypted text: "  + Base64.encodeBase64String(encrypted));
            return Base64.encodeBase64String(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String key, String randomVector, String encrypted) {
        try {
            IvParameterSpec iv = new IvParameterSpec(randomVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] originalText = cipher.doFinal(Base64.decodeBase64(encrypted));
            System.out.println("decrypted text: "  + new String(originalText));
            return new String(originalText);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        String key = "JavasEncryptDemo"; // 128 bit key
        String randomVector = "RandomJavaVector"; // 16 bytes IV
        decrypt(key, randomVector, encrypt(key, randomVector, "Anything you want to encrypt!"));

    }
}

How about this:

private static byte[] xor(final byte[] input, final byte[] secret) {
    final byte[] output = new byte[input.length];
    if (secret.length == 0) {
        throw new IllegalArgumentException("empty security key");
    }
    int spos = 0;
    for (int pos = 0; pos < input.length; ++pos) {
        output[pos] = (byte) (input[pos] ^ secret[spos]);
        ++spos;
        if (spos >= secret.length) {
            spos = 0;
        }
    }
    return output;
}

Works fine for me and is rather compact.


Update on 12-DEC-2019

Unlike some other modes like CBC, GCM mode does not require the IV to be unpredictable. The only requirement is that the IV has to be unique for each invocation with a given key. If it repeats once for a given key, security can be compromised. An easy way to achieve this is to use a random IV from a strong pseudo random number generator as shown below.

Using a sequence or timestamp as IV is also possible, but it may not be as trivial as it may sound. For example, if the system does not correctly keep track of the sequences already used as IV in a persistent store, an invocation may repeat an IV after a system reboot. Likewise, there is no perfect clock. Computer clock readjusts etc.

Also, the key should be rotated after every 2^32 invocations. For further details on the IV requirement, refer to this answer and the NIST recommendations.


This is the encryption & decryption code I just wrote in Java 8 considering the following points. Hope someone would find this useful:

  1. Encryption Algorithm: Block cipher AES with 256 bits key is considered secure enough. To encrypt a complete message, a mode needs to be selected. Authenticated encryption (which provides both confidentiality and integrity) is recommended. GCM, CCM and EAX are most commonly used authenticated encryption modes. GCM is usually preferred and it performs well in Intel architectures which provide dedicated instructions for GCM. All these three modes are CTR-based (counter-based) modes and therefore they do not need padding. As a result they are not vulnerable to padding related attacks

  2. An initialization Vector (IV) is required for GCM. The IV is not a secret. The only requirement being it has to be random or unpredictable. In Java, the SecuredRandom class is meant to produce cryptographically strong pseudo random numbers. The pseudo-random number generation algorithm can be specified in the getInstance() method. However, since Java 8, the recommended way is to use getInstanceStrong() method which will use the strongest algorithm configured and provided by the Provider

  3. NIST recommends 96 bit IV for GCM to promote interoperability, efficiency, and simplicity of design

  4. To ensure additional security, in the following implementation SecureRandom is re-seeded after producing every 2^16 bytes of pseudo random byte generation

  5. The recipient needs to know the IV to be able to decrypt the cipher text. Therefore the IV needs to be transferred along with the cipher text. Some implementations send the IV as AD (Associated Data) which means that the authentication tag will be calculated on both the cipher text and the IV. However, that is not required. The IV can be simply pre-pended with the cipher text because if the IV is changed during transmission due to a deliberate attack or network/file system error, the authentication tag validation will fail anyway

  6. Strings should not be used to hold the clear text message or the key as Strings are immutable and thus we cannot clear them after use. These uncleared Strings then linger in the memory and may show up in a heap dump. For the same reason, the client calling these encryption or decryption methods should clear all the variables or arrays holding the message or the key after they are no longer needed.

  7. No provider is hard coded in the code following the general recommendations

  8. Finally for transmission over network or storage, the key or the cipher text should be encoded using Base64 encoding. The details of Base64 can be found here. The Java 8 approach should be followed

Byte arrays can be cleared using:

Arrays.fill(clearTextMessageByteArray, Byte.MIN_VALUE);

However, as of Java 8, there is no easy way to clear SecretKeyspec and SecretKey as the implementations of these two interfaces do not seem to have implemented the method destroy() of the interface Destroyable. In the following code, a separate method is written to clear the SecretKeySpec and SecretKey using reflection.

Key should be generated using one of the two approaches mentioned below.

Note that keys are secrets like passwords, but unlike passwords which are meant for human use, keys are meant to be used by cryptographic algorithms and hence should be generated using the above way only.

package com.sapbasu.javastudy;

import java.lang.reflect.Field;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Crypto {

  private static final int AUTH_TAG_SIZE = 128; // bits

  // NIST recommendation: "For IVs, it is recommended that implementations
  // restrict support to the length of 96 bits, to
  // promote interoperability, efficiency, and simplicity of design."
  private static final int IV_LEN = 12; // bytes

  // number of random number bytes generated before re-seeding
  private static final double PRNG_RESEED_INTERVAL = Math.pow(2, 16);

  private static final String ENCRYPT_ALGO = "AES/GCM/NoPadding";

  private static final List<Integer> ALLOWED_KEY_SIZES = Arrays
      .asList(new Integer[] {128, 192, 256}); // bits

  private static SecureRandom prng;

  // Used to keep track of random number bytes generated by PRNG
  // (for the purpose of re-seeding)
  private static int bytesGenerated = 0;

  public byte[] encrypt(byte[] input, SecretKeySpec key) throws Exception {

    Objects.requireNonNull(input, "Input message cannot be null");
    Objects.requireNonNull(key, "key cannot be null");

    if (input.length == 0) {
      throw new IllegalArgumentException("Length of message cannot be 0");
    }

    if (!ALLOWED_KEY_SIZES.contains(key.getEncoded().length * 8)) {
      throw new IllegalArgumentException("Size of key must be 128, 192 or 256");
    }

    Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);

    byte[] iv = getIV(IV_LEN);

    GCMParameterSpec gcmParamSpec = new GCMParameterSpec(AUTH_TAG_SIZE, iv);

    cipher.init(Cipher.ENCRYPT_MODE, key, gcmParamSpec);
    byte[] messageCipher = cipher.doFinal(input);

    // Prepend the IV with the message cipher
    byte[] cipherText = new byte[messageCipher.length + IV_LEN];
    System.arraycopy(iv, 0, cipherText, 0, IV_LEN);
    System.arraycopy(messageCipher, 0, cipherText, IV_LEN,
        messageCipher.length);
    return cipherText;
  }

  public byte[] decrypt(byte[] input, SecretKeySpec key) throws Exception {
    Objects.requireNonNull(input, "Input message cannot be null");
    Objects.requireNonNull(key, "key cannot be null");

    if (input.length == 0) {
      throw new IllegalArgumentException("Input array cannot be empty");
    }

    byte[] iv = new byte[IV_LEN];
    System.arraycopy(input, 0, iv, 0, IV_LEN);

    byte[] messageCipher = new byte[input.length - IV_LEN];
    System.arraycopy(input, IV_LEN, messageCipher, 0, input.length - IV_LEN);

    GCMParameterSpec gcmParamSpec = new GCMParameterSpec(AUTH_TAG_SIZE, iv);

    Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
    cipher.init(Cipher.DECRYPT_MODE, key, gcmParamSpec);

    return cipher.doFinal(messageCipher);
  }

  public byte[] getIV(int bytesNum) {

    if (bytesNum < 1) throw new IllegalArgumentException(
        "Number of bytes must be greater than 0");

    byte[] iv = new byte[bytesNum];

    prng = Optional.ofNullable(prng).orElseGet(() -> {
      try {
        prng = SecureRandom.getInstanceStrong();
      } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("Wrong algorithm name", e);
      }
      return prng;
    });

    if (bytesGenerated > PRNG_RESEED_INTERVAL || bytesGenerated == 0) {
      prng.setSeed(prng.generateSeed(bytesNum));
      bytesGenerated = 0;
    }

    prng.nextBytes(iv);
    bytesGenerated = bytesGenerated + bytesNum;

    return iv;
  }

  private static void clearSecret(Destroyable key)
      throws IllegalArgumentException, IllegalAccessException,
      NoSuchFieldException, SecurityException {
    Field keyField = key.getClass().getDeclaredField("key");
    keyField.setAccessible(true);
    byte[] encodedKey = (byte[]) keyField.get(key);
    Arrays.fill(encodedKey, Byte.MIN_VALUE);
  }
}

The encryption key can be generated primarily in two ways:

  • Without any password

    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(KEY_LEN, SecureRandom.getInstanceStrong());
    SecretKey secretKey = keyGen.generateKey();
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(),
        "AES");
    Crypto.clearSecret(secretKey);
    // After encryption or decryption with key
    Crypto.clearSecret(secretKeySpec);
    
  • With password

    SecureRandom random = SecureRandom.getInstanceStrong();
    byte[] salt = new byte[32];
    random.nextBytes(salt);
    PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterations, 
       keyLength);
    SecretKeyFactory keyFactory = 
        SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    SecretKey secretKey = keyFactory.generateSecret(keySpec);
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(),
        "AES");
    Crypto.clearSecret(secretKey);
    // After encryption or decryption with key
    Crypto.clearSecret(secretKeySpec);
    

Update Based on Comments

As pointed out by @MaartenBodewes, my answer did not handle any String as is required by the question. Therefore, I'll make an attempt to fill that gap just in case someone stumbles upon this answer and leaves wondering about handling String.

As indicated earlier in the answer, handling sensitive information in a String is, in general, not a good idea because String is immutable and thus we cannot clear it off after use. And as we know, even when a String doesn't have a strong reference, the garbage collector does not immediately rush to remove it off heap. Thus, the String continues to be around in the memory for an unknown window of time even though it is not accessible to the program. The issue with that is, a heap dump during that time frame would reveal the sensitive information. Therefore, it is always better to handle all sensitive information in a byte array or char array and then fill the array with 0s once their purpose is served.

However, with all that knowledge, if we still end up in a situation where the sensitive information to be encrypted is in a String, we first need to convert it into a byte array and invoke the encrypt and decrypt functions introduced above. (The other input key can be generated using the code snippet provided above).

A String can be converted into bytes in the following way:

byte[] inputBytes = inputString.getBytes(StandardCharsets.UTF_8);

As of Java 8, String is internally stored in heap with UTF-16 encoding. However, we have used UTF-8 here as it usually takes less space than UTF-16, especially for ASCII characters.

Likewise, the encrypted byte array can also be converted into a String as below:

String encryptedString = new String(encryptedBytes, StandardCharsets.UTF_8);

Here a simple solution with only java.* and javax.crypto.* dependencies for encryption of bytes providing confidentiality and integrity. It shall be indistinguishable under a choosen plaintext attack for short messages in the order of kilobytes.

It uses AES in the GCM mode with no padding, a 128bit key is derived by PBKDF2 with lots of iterations and a static salt from the provided password. This makes sure brute forcing passwords is hard and distributes the entropy over the entire key.

A random initialisation vector (IV) is generated and will be prepended to the ciphertext. Furthermore, the static byte 0x01 is prepended as the first byte as a 'version'.

The entire message goes into the message authentication code (MAC) generated by AES/GCM.

Here it goes, zero external dependencies encryption class providing confidentiality and integrity:

package ch.n1b.tcrypt.utils;

import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * This class implements AES-GCM symmetric key encryption with a PBKDF2 derived password.
 * It provides confidentiality and integrity of the plaintext.
 *
 * @author Thomas Richner
 * @created 2018-12-07
 */
public class AesGcmCryptor {

    // https://crypto.stackexchange.com/questions/26783/ciphertext-and-tag-size-and-iv-transmission-with-aes-in-gcm-mode
    private static final byte VERSION_BYTE = 0x01;
    private static final int VERSION_BYTE_LENGTH = 1;
    private static final int AES_KEY_BITS_LENGTH = 128;


    // fixed AES-GCM constants
    private static final String GCM_CRYPTO_NAME = "AES/GCM/NoPadding";
    private static final int GCM_IV_BYTES_LENGTH = 12;
    private static final int GCM_TAG_BYTES_LENGTH = 16;

    // can be tweaked, more iterations = more compute intensive to brute-force password
    private static final int PBKDF2_ITERATIONS = 1024;

    // protects against rainbow tables
    private static final byte[] PBKDF2_SALT = hexStringToByteArray("4d3fe0d71d2abd2828e7a3196ea450d4");

    public String encryptString(char[] password, String plaintext) throws CryptoException {

        byte[] encrypted = null;
        try {
            encrypted = encrypt(password, plaintext.getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException //
                | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException //
                | InvalidKeySpecException e) {
            throw new CryptoException(e);
        }
        return byteArrayToHexString(encrypted);
    }

    public String decryptString(char[] password, String ciphertext)
            throws CryptoException {

        byte[] ct = hexStringToByteArray(ciphertext);
        byte[] plaintext = null;
        try {
            plaintext = decrypt(password, ct);
        } catch (AEADBadTagException e) {
            throw new CryptoException(e);
        } catch ( //
                NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeySpecException //
                        | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException //
                        | BadPaddingException e) {
            throw new CryptoException(e);
        }
        return new String(plaintext, StandardCharsets.UTF_8);
    }

    /**
     * Decrypts an AES-GCM encrypted ciphertext and is
     * the reverse operation of {@link AesGcmCryptor#encrypt(char[], byte[])}
     *
     * @param password   passphrase for decryption
     * @param ciphertext encrypted bytes
     * @return plaintext bytes
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws InvalidKeySpecException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws IllegalArgumentException           if the length or format of the ciphertext is bad
     * @throws CryptoException
     */
    public byte[] decrypt(char[] password, byte[] ciphertext)
            throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException,
            InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {

        // input validation
        if (ciphertext == null) {
            throw new IllegalArgumentException("ciphertext cannot be null");
        }

        if (ciphertext.length <= VERSION_BYTE_LENGTH + GCM_IV_BYTES_LENGTH + GCM_TAG_BYTES_LENGTH) {
            throw new IllegalArgumentException("ciphertext too short");
        }

        // the version must match, we don't decrypt other versions
        if (ciphertext[0] != VERSION_BYTE) {
            throw new IllegalArgumentException("wrong version: " + ciphertext[0]);
        }

        // input seems legit, lets decrypt and check integrity

        // derive key from password
        SecretKey key = deriveAesKey(password, PBKDF2_SALT, AES_KEY_BITS_LENGTH);

        // init cipher
        Cipher cipher = Cipher.getInstance(GCM_CRYPTO_NAME);
        GCMParameterSpec params = new GCMParameterSpec(GCM_TAG_BYTES_LENGTH * 8,
                ciphertext,
                VERSION_BYTE_LENGTH,
                GCM_IV_BYTES_LENGTH
        );
        cipher.init(Cipher.DECRYPT_MODE, key, params);

        final int ciphertextOffset = VERSION_BYTE_LENGTH + GCM_IV_BYTES_LENGTH;

        // add version and IV to MAC
        cipher.updateAAD(ciphertext, 0, ciphertextOffset);

        // decipher and check MAC
        return cipher.doFinal(ciphertext, ciphertextOffset, ciphertext.length - ciphertextOffset);
    }

    /**
     * Encrypts a plaintext with a password.
     * <p>
     * The encryption provides the following security properties:
     * Confidentiality + Integrity
     * <p>
     * This is achieved my using the AES-GCM AEAD blockmode with a randomized IV.
     * <p>
     * The tag is calculated over the version byte, the IV as well as the ciphertext.
     * <p>
     * Finally the encrypted bytes have the following structure:
     * <pre>
     *          +-------------------------------------------------------------------+
     *          |         |               |                             |           |
     *          | version | IV bytes      | ciphertext bytes            |    tag    |
     *          |         |               |                             |           |
     *          +-------------------------------------------------------------------+
     * Length:     1B        12B            len(plaintext) bytes            16B
     * </pre>
     * Note: There is no padding required for AES-GCM, but this also implies that
     * the exact plaintext length is revealed.
     *
     * @param password  password to use for encryption
     * @param plaintext plaintext to encrypt
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws NoSuchPaddingException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws InvalidKeySpecException
     */
    public byte[] encrypt(char[] password, byte[] plaintext)
            throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException,
            InvalidKeySpecException {

        // initialise random and generate IV (initialisation vector)
        SecretKey key = deriveAesKey(password, PBKDF2_SALT, AES_KEY_BITS_LENGTH);
        final byte[] iv = new byte[GCM_IV_BYTES_LENGTH];
        SecureRandom random = SecureRandom.getInstanceStrong();
        random.nextBytes(iv);

        // encrypt
        Cipher cipher = Cipher.getInstance(GCM_CRYPTO_NAME);
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_BYTES_LENGTH * 8, iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);

        // add IV to MAC
        final byte[] versionBytes = new byte[]{VERSION_BYTE};
        cipher.updateAAD(versionBytes);
        cipher.updateAAD(iv);

        // encrypt and MAC plaintext
        byte[] ciphertext = cipher.doFinal(plaintext);

        // prepend VERSION and IV to ciphertext
        byte[] encrypted = new byte[1 + GCM_IV_BYTES_LENGTH + ciphertext.length];
        int pos = 0;
        System.arraycopy(versionBytes, 0, encrypted, 0, VERSION_BYTE_LENGTH);
        pos += VERSION_BYTE_LENGTH;
        System.arraycopy(iv, 0, encrypted, pos, iv.length);
        pos += iv.length;
        System.arraycopy(ciphertext, 0, encrypted, pos, ciphertext.length);

        return encrypted;
    }

    /**
     * We derive a fixed length AES key with uniform entropy from a provided
     * passphrase. This is done with PBKDF2/HMAC256 with a fixed count
     * of iterations and a provided salt.
     *
     * @param password passphrase to derive key from
     * @param salt     salt for PBKDF2 if possible use a per-key salt, alternatively
     *                 a random constant salt is better than no salt.
     * @param keyLen   number of key bits to output
     * @return a SecretKey for AES derived from a passphrase
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    private SecretKey deriveAesKey(char[] password, byte[] salt, int keyLen)
            throws NoSuchAlgorithmException, InvalidKeySpecException {

        if (password == null || salt == null || keyLen <= 0) {
            throw new IllegalArgumentException();
        }
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(password, salt, PBKDF2_ITERATIONS, keyLen);
        SecretKey pbeKey = factory.generateSecret(spec);

        return new SecretKeySpec(pbeKey.getEncoded(), "AES");
    }

    /**
     * Helper to convert hex strings to bytes.
     * <p>
     * May be used to read bytes from constants.
     */
    private static byte[] hexStringToByteArray(String s) {

        if (s == null) {
            throw new IllegalArgumentException("Provided `null` string.");
        }

        int len = s.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("Invalid length: " + len);
        }

        byte[] data = new byte[len / 2];
        for (int i = 0; i < len - 1; i += 2) {
            byte b = (byte) toHexDigit(s, i);
            b <<= 4;
            b |= toHexDigit(s, i + 1);
            data[i / 2] = b;
        }
        return data;
    }

    private static int toHexDigit(String s, int pos) {
        int d = Character.digit(s.charAt(pos), 16);
        if (d < 0) {
            throw new IllegalArgumentException("Cannot parse hex digit: " + s + " at " + pos);
        }
        return d;
    }

    private static String byteArrayToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }

    public class CryptoException extends Exception {

        public CryptoException(Throwable cause) {
            super(cause);
        }
    }
}

Here the entire project with a nice CLI: https://github.com/trichner/tcrypt

Edit: now with appropriate encryptString and decryptString


String s1="arshad"; 
char[] s2=s1.toCharArray(); 
int s3= s2.length; 

  System.out.println(s3);
 int i=0; 

// for(int j=0;j<s3;j++) 
// System.out.println(s2[j]); 

for(i=0;i<((s3)/2);i++) { 

char z,f=10; 
z=(char) (s2[i] * f); 
s2[i]=s2[(s3-1)-i]; 
s2[(s3-1)-i]=z; 

String b=new String(s2);

 print(b);  }

I'd recommend to use some standard symmetric cypher that is widely available like DES, 3DES or AES. While that is not the most secure algorithm, there are loads of implementations and you'd just need to give the key to anyone that is supposed to decrypt the information in the barcode. javax.crypto.Cipher is what you want to work with here.

Let's assume the bytes to encrypt are in

byte[] input;

Next, you'll need the key and initialization vector bytes

byte[] keyBytes;
byte[] ivBytes;

Now you can initialize the Cipher for the algorithm that you select:

// wrap key data in Key/IV specs to pass to cipher
SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
// create the cipher with the algorithm you choose
// see javadoc for Cipher class for more info, e.g.
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

Encryption would go like this:

cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encrypted= new byte[cipher.getOutputSize(input.length)];
int enc_len = cipher.update(input, 0, input.length, encrypted, 0);
enc_len += cipher.doFinal(encrypted, enc_len);

And decryption like this:

cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = new byte[cipher.getOutputSize(enc_len)];
int dec_len = cipher.update(encrypted, 0, enc_len, decrypted, 0);
dec_len += cipher.doFinal(decrypted, dec_len);

You can use Jasypt

With Jasypt, encrypting and checking a password can be as simple as...

StrongTextEncryptor textEncryptor = new StrongTextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);

Encryption:

String myEncryptedText = textEncryptor.encrypt(myText);

Decryption:

String plainText = textEncryptor.decrypt(myEncryptedText);

Gradle:

compile group: 'org.jasypt', name: 'jasypt', version: '1.9.2'

Features:

Jasypt provides you with easy unidirectional (digest) and bidirectional encryption techniques.

Open API for use with any JCE provider, and not only the default Java VM one. Jasypt can be easily used with well-known providers like Bouncy Castle. Learn more.

Higher security for your users' passwords. Learn more.

Binary encryption support. Jasypt allows the digest and encryption of binaries (byte arrays). Encrypt your objects or files when needed (for being sent over the net, for example).

Number encryption support. Besides texts and binaries, it allows the digest and encryption of numeric values (BigInteger and BigDecimal, other numeric types are supported when encrypting for Hibernate persistence). Learn more.

Completely thread-safe.

Support for encryptor/digester pooling, in order to achieve high performance in multi-processor/multi-core systems.

Includes a lightweight ("lite") version of the library for better manageability in size-restrictive environments like mobile platforms.

Provides both easy, no-configuration encryption tools for users new to encryption, and also highly configurable standard encryption tools, for power-users.

Hibernate 3 and 4 optional integration for persisting fields of your mapped entities in an encrypted manner. Encryption of fields is defined in the Hibernate mapping files, and it remains transparent for the rest of the application (useful for sensitive personal data, databases with many read-enabled users...). Encrypt texts, binaries, numbers, booleans, dates... Learn more.

Seamlessly integrable into a Spring application, with specific integration features for Spring 2, Spring 3.0 and Spring 3.1. All the digesters and encryptors in jasypt are designed to be easily used (instantiated, dependency-injected...) from Spring. And, because of their being thread-safe, they can be used without synchronization worries in a singleton-oriented environment like Spring. Learn more: Spring 2, Spring 3.0, Spring 3.1.

Spring Security (formerly Acegi Security) optional integration for performing password encryption and matching tasks for the security framework, improving the security of your users' passwords by using safer password encryption mechanisms and providing you with a higher degree of configuration and control. Learn more.

Provides advanced functionality for encrypting all or part of an application's configuration files, including sensitive information like database passwords. Seamlessly integrate encrypted configuration into plain, Spring-based and/or Hibernate-enabled applications. Learn more.

Provides easy to use CLI (Command Line Interface) tools to allow developers initialise their encrypted data and include encryption/decryption/digest operations in maintenance tasks or scripts. Learn more.

Integrates into Apache Wicket, for more robust encryption of URLs in your secure applications.

Comprehensive guides and javadoc documentation, to allow developers to better understand what they are really doing to their data.

Robust charset support, designed to adequately encrypt and digest texts whichever the original charset is. Complete support for languages like Japanese, Korean, Arabic... with no encoding or platform issues.

Very high level of configuration capabilities: The developer can implement tricks like instructing an "encryptor" to ask a, for example, remote HTTPS server for the password to be used for encryption. It lets you meet your security needs.


I would consider using something like https://www.bouncycastle.org/ It is a prebuilt library that allows you to encrypt whatever you like with a number of different Ciphers I understand that you only want to protect from snooping, but if you really want to protect the information, using Base64 won't actually protect you.


public static String encryptParams(String myTextInput) {

        String myKey = "40674244454045cb9a70040a30e1c007";
        String myVector = "@1B2c3D4e5F6g7H8";

        String encData = "";

        try{
            JavaEncryprtionUtil encUtil = new JavaEncryprtionUtil();
            encData = Base64.encodeToString(encUtil.encrypt(myTextInput.getBytes("UTF-8"), myKey.getBytes("UTF-8"), myVector.getBytes("UTF-8")),Base64.DEFAULT);
            System.out.println(encData);
        }catch(NoSuchAlgorithmException ex){
            ex.printStackTrace();
        }catch(NoSuchPaddingException ex){
            ex.printStackTrace();
        }catch(InvalidKeyException ex){
            ex.printStackTrace();
        }catch(InvalidAlgorithmParameterException ex){
            ex.printStackTrace();
        }catch(IllegalBlockSizeException ex){
            ex.printStackTrace();
        }catch(BadPaddingException ex){
            ex.printStackTrace();
        }catch(UnsupportedEncodingException ex){
            ex.printStackTrace();
        }

        return encData;
    }