I am trying to send an encrypted text with each HttpResponse and when I get the next HttpRequest with the encrypted text, I decrypt it and do some stuff :) with it.
I am curious about the best practices surrounding the storage/retrievel of the keys and ivSpec's (or nonce's) in general, but specifically looking at the code posted by #sherif based on #VoidPointer 's suggestions in How to encrypt String in Java,
a) Do we have to initialize ivSpec with random bytes for each string that I want to encrypt?
b) If so, do we store the generated ivSpec in some db and look it up when I need to decrypt using that?
c) If so, how do we look it up? When an encrypted string needs to be decrypted how do we pick the correct ivSpec from db?
d) One suggestion is to send ivParameter along with the encrypted string! itself (which is probably what is happening with #sherif 's implementation!). If we chose to do so, how can I modify the class provided by #sherif to decrypt and separate the iv parameter and encrypted string instead of providing the iv parameter while initializing decrypt cipher?
A. If you do not change the vector, each time you encrypt the same string, you get the same encrypted result.
By changing the IV each time, you make it so that every single encrypted output looks different (even if it's the same input).
Think of it as a the "salt" you use when you are hashing a password.
so under normal circumstances it would be desirable to use a random iv.
B&C. You need to look the IV up, yes. But storing it into a DB isn't very useful. You already have a piece of information that you keep stored secretly: that's the password. IV is just here to increase randomness, no need to keep it, push it out with the output.
D. Sending it is the usual way to go.
One way is to concatenate it at the beginning of the ouput. (output = IV + encrypted data). Then before decrypting first split the input (IV = 32 first bytes of input) and decrypt the rest (crypt_data_to_decrpt = input after byte number 32)
Another way is to have a constant IV and a random part at the beginning:
you simply use a string of NUL byte as an IV.
Then you encrypt 32 bytes of pure random garbage
Then you encrypt your input. (When using a good encryption method, this should always produce a different encrypted output because the beginning was different).
For decryption, you use the same empty IV, then you decrypt everything. You ignore the 32bytes at the beginning. You split and only take the bytes after the 32nd. That's your decrypted output.
Related
My qustion is about how should I specify the custom value of AlgorithmParameterSpec in the below program? So that I could use the exact same output value for two different programs, one of which is Server and other is Client. Like I have used the fixed value for Key Generation, I want the same for this AlgorithmParameterSpec.
Client Code Snippet
....
String desKey = "0123456789abcdef"; // value from user
byte[] keyBytes = DatatypeConverter.parseHexBinary(desKey);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
SecretKey key = factory.generateSecret(new DESKeySpec(keyBytes));
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
....
Both client and server are on different pcs and are connected on same LAN. However I dont want to send any file from one to another, and neither do I want to write the value of that parameter from client into any file and use it in server. That has already caused too much problems. Is there a way to do this? Or I have to send this generated value from client to server using readUTF and writeUTF?
Original DES aka single-DES has been broken since last century, and should not be used.
In Java, instantiating plain DES like that defaults to DES/ECB/PKCS5Padding (in general Java treats PKCS5 padding as including PKCS7). ECB does not use an IV, and DES has no other parameters, so a java Cipher object for DES/ECB does not need or use any type of parameters object. However, in most applications, ECB mode even with a good cipher (not DES) is insecure and should not be used.
If you change to a more secure mode that does use an IV, like CTR CBC OFB CFB, or better in most applications but only supported in j8+ GCM, then IvParameterSpec is indeed the correct type to use.
However, with modes that use an IV, using a fixed or otherwise duplicated IV is almost always insecure, so you must have a process that provides a unique IV for each encryption and the corresponding decryption(s).
This is often done by choosing a random IV when encrypting and transmitting and/or storing it along with the ciphertext (sometimes simply as the first part of the ciphertext) to be used when decrypting, but other designs that accomplish the same thing are possible. For CTR-based modes including GCM, especially when applied to a stream of traffic between the same parties, using a (scaled) counter provides uniqueness. For CBC the IVs must not only be unique but unpredictable; random is usually easiest for this but it is possible to use an encrypted counter.
Both key and IV (when used) should actually be bits not characters. However it is often convenient to represent them in characters using hex (as you did) or base64. Such character representations can be transmitted and received by a huge variety of methods, of which DataInput/OutputStream or ObjectInput/OutputStream is one among many. There are also many ways to transmit bits (binary) on all networks used in this century (although back in the 1970s and 1980s this was often problematical). Choosing among these may depend on what else your programs are doing and in particular whether they already use things like HTTP, XML, JSON, etc.
I'm using the jpbc java library to achieve the HIBE encryption in order to encrypt and decrypt a String data.
In this case, i found a function that's allowed me to get an Element from a String as it shown below and it make me able to encrypt & decrypt this Element :
private static void elementFromString(Element h, String s) throws NoSuchAlgorithmException
{
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(s.getBytes());
h.setFromHash(digest, 0, digest.length);
}
But now, i need a solution to get the string data from the Element after decryption or any other idea can help me.
Thank you
Hashing is not encrypting. SHA-1 is a one-way function, i.e. you can possibly guess the input given the output, but you cannot retrieve the input by any calculation.
To encrypt and decrypt you need a cipher. A cipher often consists of a block cipher and a mode of operation such as "AES/GCM/NoPadding". Kind of surprising, it is represented by the Java Cipher class.
You may need to generate a key or key pair and store it somewhere, such as a KeyStore.
Trying to perform crypto without understanding what you are doing may result in code that runs - eventually. However, the chances that it will be secure is minimal. First try and learn about the subject.
Note that calling getBytes on a String results in platform specific encoding. This can be fun if you switch platforms in the future. Explicitly specifying UTF-8 is a good idea.
I'm using this code for DES-encryption: How do I use 3des encryption/decryption in Java?
Now, I want to encrypt a byte array with this. How can I do that?
I have changed the name of algo from DESede to DES and am obviously using an 8-byte key (not 24).
Cipher#doFinal takes and returns byte[]. The only thing that you need to do is removing the additional encoding steps like
message.getBytes("utf-8") // before encryption
and
new String(plainText, "UTF-8") // after decryption
Obviously, you need to change the method signature from String to byte[] for both encryption and decryption.
I tried many answers from SO and all over the web but still without success.
I use following tool to encrypt.
text to encrypt: tom
key: exo123exo1exo123
input (textfield or selected file above) is: text/binary
Convert output to: [i leave this unselected]
Mode: CTR
Ciphers: Rijndael-128 and Rijndael-256
After getting result I move here:
and encode it with base64.
Then I copy string and send it as a parameter to my function:
public String authenticate(String base64EncodedData){
byte[] input = Base64.decodeBase64(base64EncodedData);
byte[] ivBytes = "1234567812345678".getBytes();
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(
Cipher.DECRYPT_MODE,
new SecretKeySpec("exo123exo1exo123".getBytes(), "AES"),
new IvParameterSpec(ivBytes)
);
byte[] plainText = new byte[cipher.getOutputSize(input.length)];
int plainTextLength = cipher.update(input, 0, input.length, plainText, 0);
plainTextLength += cipher.doFinal(plainText, plainTextLength);
return new String(plainText);
}
Result I got is always something similar to this (no matter if I use Rijndael-128 or 256 encrypted string):
.�v�Y�
When I try to return input value - I get the encrypted string. So base64 works just fine.
What I do wrong?
Am slowly getting mad here.
Thank you.
There are some problem with your assumptions and your code:
The output of the first tool is already Base 64 encoded. RIJNDAEL-128: r0GR and RIJNDAEL-256: yAVy. It doesn't need to be encoded a second time. It automatically selects this option, because binary data cannot be printed.
There is no native Rijndael-256 in Java, you will have to use BouncyCastle for this. Rijndael-128 is supposed to be AES which means that both have a block size of 128-bit.
The IV almost certainly needs to consist of zero bytes. For example:
byte[] ivBytes = new byte[16];
Arrays.fill(ivBytes, (byte)0); // might not be necessary
Note that CTR mode doesn't use an IV, but rather a nonce.
Always specify an encoding when retrieving bytes: "exo123exo1exo123".getBytes("UTF-8"). It is probably best to use UTF-8 everywhere. If you send data across systems that use different system encodings, it will lead to hard to find problems.
On second look at the online tool is not usable for anything, because it is unclear how it works. What I found:
Any key produces a ciphertext regardless of size, which suggests that the "key" that you enter is actually hashed and there exist a million ways that could be done. I could decrypt it with the above method, so the key is actually uses as-is without hashing. This suggests that the key is filled up with 0x00 bytes until a valid key size. When the key size is too big, it is probably truncated.
Plaintext of 16 characters encrypts to a ciphertext of 16 bytes (encoded 24) and a plaintext of 17 characters encrypts to a ciphertext of 32 bytes (encoded 44). This means that no discernible padding is used which might actually be zero padding.
And here is the deal breaker:
Every time you encrypt something, you get a different ciphertext. In CBC mode it means a random IV is generated before encrypting. The problem is that this IV is not shown. So there is no way to decrypt this fully. So if you encrypt more than 16 characters you can recover all but the first 16 characters when you decrypt it in the way I describe it in the first part of this answer.
You shouldn't make your system dependent on closed source online tools. Write your own encryption tool. Some general advice:
IV should be generated randomly every time you encrypt something. It is not secrect, but should be unique. Simply prepend it to the ciphertext after encryption and slice it off before decryption.
Use an authenticated mode like CCM or GCM where possible. It is harder to do authenticated encryption yourself, but the other way to go would be to use encrypt-then-mac paradigm.
How can I do an AES encryption using a password and a salt in such a way that I can decrypt using only that same password and salt in Java. I need this because I want to encrypt my data before putting them in the database and I do not want to store any IV byte array in the database for decryption. I just want to encrypt the data using a password and a salt store the encrypted data in the database so that when I need the data, I get it from the database and decrypt it using the same password and salt, nothing more.
AES is a block cipher that encrypts in blocks of 16 bytes. If you encrypt the same 16 bytes of data with the same key (or password + salt), you will end up with the same encrypted data. This have some undesirable (insecure) properties that the initialization vector is used to solves.
If you don't want to keep track of an initialization vector, you can instead make the first 16 bytes of your data be random, and then use an initialization vector set to 16 zero's. This will give the same effect.
I can think of two possibilities:
Use AES-CTR. Counter mode does not require an IV.
Derive both your key and IV from your password and salt. Something like:
key <- hash(password + salt + "KEY")
IV <- hash(password + salt + "IV")
Obviously in real life you would use a standard key derivation function, depending on how much security you need.
You might also wish to think about authentication to check that what comes back from the database is the same as what you put there. For built-in authentication use AES-GCM instead of AES-CTR or else add an HMAC if you are using the second option.