Java AES En/decryption for a String - java

I have found an useful AES256 implementation to en/decrypt strings, all work fine except the fact i have to store the initialization vector (IV) for the decoding.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
All there any (secure) alternative methods maybe without CBC, because with CBC i have to store an IV (and in my case i have to share the IV which is really not secure).
I have read an article on this platform concerning it´s possible to encode without CBC but that´s not a good idea because of dictionary attacks.
so, are there any alternatives to encode a string with aes256 (without storing additional data like IV, or salt arrays)?

The idea behind an IV is to use a distinct new random one for every encryption (with the same key).
This is very important to ensure the the security of cipher-modes such as CTR or CBC which would not be secure at all without an IV. Also when using the same key to encrypt the same message twice it will result in two distinct ciphertexts (since the two IVs were distinct).
In short, you should always use an IV.
Usually you just prepend them to the ciphertexts and then extract them before encryption, so you don't have to store them individually.

Related

Cipher.getInstance() and Cipher.getInit() for each message in case of random IV for AES encryption

In a multi threaded Java application, we are using AES-256 for encryption and decryption of files to the disk. Please note that multiple threads can make concurrent calls to the encryption and decryption methods for different files.
Encryption:
Cipher encrypter = Cipher.getInstance(algorithm, new BouncyCastleProvider());
IvParameterSpec ivSpec = getIvParamSpec(encrypter.getBlockSize());
encrypter.init(Cipher.ENCRYPT_MODE, key, ivSpec);
//..encrypt the data
Decryption:
Cipher decrypter = Cipher.getInstance(algorithm, new BouncyCastleProvider());
IvParameterSpec ivSpec = readIvParamSpec(decrypter.getBlockSize(), is);
decrypter.init(Cipher.DECRYPT_MODE, key, ivSpec);
//.. decrypt the data
In our understanding, it is better to use random IV for encryption instead of static/fixed IV. For this purpose, we are using SecureRandom API to generate the IV. The random IV is persisted in the encrypted file at the start.
SecureRandom random = new SecureRandom();
byte[] iv = new byte[ivSizeBytes];
random.nextBytes(iv);
new IvParameterSpec(iv);
My question is, since I am using random IV for each encryption, do I need to call Cipher.getInstance() and Cipher.Init() for all the calls? For performance improvement, can these be called only once during the class initialization and then reuse the individual cipher instances to encrypt and decrypt the data?
Thanks in advance!
My question is, since I am using random IV for each encryption, do I need to call Cipher.getInstance() and Cipher.Init() for all the calls?
You can reuse Cipher instances as long as you don't share them among threads. As Artjom mentioned, Cipher instances are stateful. They store both the IV but also the last ciphertext (used as next vector for CBC mode encryption) and possibly some buffered plaintext. Mixing that state with the input from different threads will result in chaos.
As you need a new random for each file encryption you do need to call init again after calling a doFinal method. Init is not that heavyweight; the one thing that can take a bit of performance is the subkey derivation for AES, but generally that's not a big issue.
Note that, although performing the encryption and decryption can be relatively heavy weight operations, the instances themselves contain very little state and getInstance() and init are relatively lightweight operations. So creating a few more Cipher instances - possibly with the same key - is fine for multiple threads.
Recreating the BouncyCastleProvider multiple times is a very bad idea, even though it probably uses some kind of singleton underneath. But basically you don't need the Java only Bouncy Castle implementation. The Oracle one may use AES-NI intrinsics that will directly use the AES-NI instruction set on compatible processors. That will run circles around Bouncy Castle - expect a speedup of around 7 to 13 times (!).
Yes, you need to use a different Cipher instance for each thread, because they are stateful. If you don't, then threads can break the ciphertext of other threads.
Let's assume we have two threads t1 and t2 which want to encrypt two plaintexts p1_1 | p1_2 and p2_1 | p2_1 (split on block boundary). Let's take CBC as an example:
time........................................................................
root 1. init with IV
t1 2. E(p1_1 XOR IV) = c1_1 4. E(p1_2 XOR c2_1) = c1_2
t2 3. E(p2_1 XOR c1_1) = c2_1 5. E(p2_2 XOR c1_2) = c2_2
c1_1 is ok, but c2_1 is not ok, because the state from t1 was used for start the encryption. It is as though the encryption was initialized with c1_1 as the IV.
This example works only for CBC mode, but other modes of operation are similar. If we assume that encryption happens only block-wise, then you could just use ECB mode in a thread-safe fashion, but this is only an illusion, because you cannot be sure that the implementation only handles the internal state block-wise and not byte-wise.

Is this the best/secure method for encryption in Java?

I am new in security and I'm wondering if I can make my program better, like changing or adding something to make it better ( more secure )
(I have doubt from the program output)
Here is the output:
Encrypted Message: +g#þóv«5Ùû`ž
keybyte: [B#71e7a66b
Original string: Message
Original string (Hex): [B#2ac1fdc4
Here is the code:
public class AES {
public static void main(String ... args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
final String Algo="AES";
String key = "aaaaaaaaaaaaaaaa";
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
MessageDigest sha= MessageDigest.getInstance("SHA-1");
keyBytes=sha.digest(keyBytes);
keyBytes=Arrays.copyOf(keyBytes, 16);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, Algo);
Cipher cipher = Cipher.getInstance(Algo);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] ciphertext = cipher.doFinal("Message".getBytes());
System.out.println("Encrypted Message: " +new String(ciphertext));
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] original = cipher.doFinal(ciphertext);
String originalString = new String(original);
System.out.println("keybyte: "+keyBytes);
System.out.println("Original string: " + originalString + "\nOriginal string (Hex): " +original);
}
}
No, this code is pretty terrible:
Your key is fixed and a string that is then hashed. This looks to me like your key is actually supposed to be a password. A single hash is not enough to derive a key from a password. You need to use a strong hashing scheme like PBKDF2, bcrypt, scrypt and Argon2. Be sure to use a high cost factor/iteration count. It is common to choose the cost so that a single iteration takes at least 100ms. See more: How to securely hash passwords?
Always use a fully qualified Cipher string. Cipher.getInstance("AES"); may result in different ciphers depending on the default security provider. It most likely results in "AES/ECB/PKCS5Padding", but it doesn't have to be. If it changes, you'll lose compatibility between different JVMs. For reference: Java default Crypto/AES behavior
ECB mode is pretty bad. It's deterministic and therefore not semantically secure. You should at the very least use a randomized mode like CBC or CTR.
Without authentication you have the threat of not detecting (malicious) modifications of your ciphertexts. It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme through HMAC with a strong hash function such as SHA-256.
Because of these issues you should use a library instead. Try JNCryptor or this library.
There are at least two problems with your implementation:
Unless you specify otherwise, you are using AES in ECB mode. ECB mode is not secure regardless of what cipher is under the hood. There are a number of secure modes, but usually people implement CBC mode, which is accomplished by changing your Algo to "AES/CBC/PKCS5Padding" (which really is PKCS7 padding, Java just does not know better). Then, you need to choose an IV via SecureRandom() to encrypt this way. This OWASP example seems to do it right (FYI -- 99% of the implementations you will find on the web have security problems somewhere).
Your key is not a key, instead it is a password that is being turned into a key. You shouldn't be hardcoding this, but I assume you are doing that for proof of concept only. In any case, the problem is using a hash function such as SHA-1 to turn a password into a key is not a good decision because passwords tend to have low entropy and can be brute forced. For this reason, you should be using a function that is dedicated to resisting brute force when turning a password into a key. Such functions include pbkdf2, bcrypt, scrypt, and argon2. For more information, Troy Hunt (a .Net guy) gives a good overview on the problems with using something like SHA-1 (or anything from the SHA2 family for that matter) in this context.
The other thing to keep in mind is that encryption does not generally provide message integrity. What this means is that just because you have encrypted the data does not mean somebody cannot modify it, and your software will still decrypt the modified data without being aware that it is modified. If you need to know that your data was not modified, then you will need to add on something like HMAC, or else you will need to switch to a mode of operation such as GCM.
Finally, AES is an excellent choice for security. But you need to use it in the right mode, you need to implement it right, and you need to understand whether you need more than just encryption.

AES-256 encryption: Generate 256bits(32bytes) key from my fixed string

I would like to use AES256 to encrypt a text, I'd like to use my email test#gmail.com as the key to encrypt it.
This is what I tried:
String key = "test#gmail.com";
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
byte iv[] = SOME_RANDOM_32_BYTES;
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] encryptedResult = cipher.doFinal(text.getBytes("UTF-8"));
When I run above code, I got InvalidKeyException:
java.security.InvalidKeyException: Key length not 128/192/256 bits.
I checked on internet, the reason is my key is not 128/192/256 bits. My question is, how can I generate a 256bits(32bytes) key from my email string test#gmail.com ?
You can hash your key string (test#gmail.com) to a 256bit value using SHA256.
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(yourEmail.getBytes());
byte[] encryptionKey = md.digest();
There can be multiple reasons for this. One of them is below.
Usually this error comes when you don't have the update policy in your JRE.
Java by default provide AES with 128, for 256 we have to put new policies provided by Java.
You should not bake your own crypto! (Unless you are very knowledgeable on the matter, that is.)
You should use an existing (and audited) encryption library.
Also, you should not use a guessable string such as your e-mail address as a password. Please, look for advice on how to choose a good password.
Now that I have said this, here are more details.
The proper way to implement password based encryption is to use a KDF (Key Derivation Function) to generate an encryption key from your password. Here are a few KDFs that you can use for this task: Argon2, Scrypt, Bcrypt and PBKDF2.
Key derivation functions include mechanisms to defend against know attacks such as rainbow tables and dictionary attacks, notably a "salt" and a work factor. Modern KDFs such as Argon2 also attempt to prevent attackers from gaining an advantage by using hardware more suitable to the task.
Generally speaking, here how this is used:
Select a work factor (the largest you can afford)
Generate the salt using a CSPRNG
Generate the encryption key and a MAC secret using your chosen KDF with the password, salt and work factor.
Generate an IV (initialization vector) using a CSPRNG
Encrypt the data to be protected using the generated encryption key.
Compute the MAC of the encrypted message using the generated secret.
Serialize the salt, the work factor, the computed MAC and the encrypted data. (Optionally, identifiers indicating what are the chosen KDF, encryption scheme and MAC should also be included if these are not fixed.)
Your encrypted message is the serialized data produced in step 7. Get any of the steps wrong (and that is easy) and your encryption code will probably break in horrible ways.
Perhaps now you get a sense of why you should use an existing library?
Note: the current best practice is to use AEAD (Authenticated Encryption with Associated Data) instead of encrypt-then-MAC as described above. Look this up if you are interested: I am not going to discuss this here.

decipher encfs volume key in java

I'm trying to decipher the encfs volume key in Java. I ran encfs with the standard settings (ie, 192 bit aes encryption). Is there any way to do this?
This is not really a Java question, more an issue of cryptography. A brief investigation into EncFS suggests that the volume key is encrypted by a key derived from a user password. It's probable that this represents the best attack vector: a brute force attack on what is hopefully a weak password. I wouldn't hold out too much hope, however.
For what it's worth, the Java JCE classes in javax.crypto would be your route towards performing symmetric cryptography in Java. The following code snippet shows how you might perform some AES decryption with a plaintext key:
byte[] keyBytes = ...
byte[] volumeKeyFileContents = ...
SecretKeyFactory factory = SecretKeyFactory.getInstance("AES");
SecretKey aesKey = factory.generateSecret(new SecretKeySpec(keyBytes, "AES"));
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // for example
cipher.init(Cipher.DECRYPT_MODE, aesKey);
byte[] plaintext = cipher.doFinal(volumeKeyFileContents);
// (written from memory so may not compile without tweaks)
You would then need to use the plaintext value as a potential candidate for the volume key. Clearly this is a simplified solution and makes many assumptions; you will need to research in more depth the format of these volume key files and the algorithms, modes and padding used during the construction of the encrypted copy.
Good luck.
There is a Java library at https://github.com/mrpdaemon/encfs-java that provides read & experimental write access to the encfs file systems.

Encryption code segment which I do not understand

I am reading about encryption and having a lot of difficulty understanding these 3 Java statements of an encryption program.
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
encrypted = cipher.doFinal(str.getBytes())
Can somebody help?
In simpler terms,
create a new Encrypting Device using the AES algorithm;
make it ready
get the bytes of the string str and encrypt them; return the result into the encrypted object, whatever that is.
what exactly did you not understand?
cipher = Cipher.getInstance("AES");
Get a Cipher object that can encrypt/decrypt using the AES algorithm. Java's cryptography code is a bit weird - instead of directly creating objects, you generally use a getInstance call with a String argument. (Note that "cipher" means "way of encrypting something".)
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
Tell the cipher that you would like to encrypt something (Cipher.ENCRYPT_MODE), and give it the encryption key skeyspec.
encrypted = cipher.doFinal(str.getBytes())
The way ciphers work is that you feed them chunks of byte data using the update method, which causes the cipher to accumulate the encrypted data within itself. For the final block of data, doFinal is used, which tells the cipher that the encryption process is done. A different method is needed because the cipher often has to pad out the data returned to a particular length. doFinal then returns the final bit of encrypted information.
However, if there is a single readily available chunk of data, you can just call doFinal and it will give you all the encrypted bytes at once. But this explains why the method is called doFinal, not say, "process".
So in summary, the code above creates an AES encryption engine, gives it an encryption key, then uses it to encrypt the String str into the byte array encrypted.
Note that cryptography is very tricky business and very easy to get wrong. There's all kinds of things you need warning about that I haven't touched on because my wrists hurt now. So I would heavily recommend you get a copy of Beginning Cryptography with Java - it's where I learned to understand this stuff.

Categories

Resources