Rijndael 128/256 decryption - java

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.

Related

How to specify value of AlgorithmParameterSpec in java, for encryption and Decryption puropose, in DES

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.

How are the IV and authentication tag handled for "AES/GCM/NoPadding"?

I'm using AES/GCM/NoPadding encryption in Java 8 and I'm wondering whether my code has a security flaw. My code seems to work, in that it encrypts and decrypts text, but a few details are unclear.
My main question is this:
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????
Does that IV satisfy the requirement of "For a given key, the IV MUST NOT repeat." from RFC 4106?
I'd also appreciate any answers / insight for my related questions (see below), but that first question is bugging me the most. I don't know where to find source code or documentation that answers this.
Here is the full code, roughly. I apologize in case I introduced errors while writing this post:
class Encryptor {
Key key;
Encryptor(byte[] key) {
if (key.length != 32) throw new IllegalArgumentException();
this.key = new SecretKeySpec(key, "AES");
}
// the output is sent to users
byte[] encrypt(byte[] src) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // See question #1
assert iv.length == 12; // See question #2
byte[] cipherText = cipher.doFinal(src);
assert cipherText.length == src.length + 16; // See question #3
byte[] message = new byte[12 + src.length + 16]; // See question #4
System.arraycopy(iv, 0, message, 0, 12);
System.arraycopy(cipherText, 0, message, 12, cipherText.length);
return message;
}
// the input comes from users
byte[] decrypt(byte[] message) throws Exception {
if (message.length < 12 + 16) throw new IllegalArgumentException();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, key, params);
return cipher.doFinal(message, 12, message.length - 12);
}
}
Suppose that users cracking my secret key = game over.
More detailed questions / related questions:
Is the IV returned by cipher.getIV() safe for me to use in this way?
Does it avoid the catastrophe of reusing the IV,key combination in Galois/Counter Mode?
Is it still safe when I have multiple applications running this code at once, all displaying encrypted messages to users from the same src data (possibly in the same millisecond)?
What's the returned IV made of? Is it an atomic counter plus some random noise?
Do I need to avoid cipher.getIV() and construct an IV myself, with my own counter?
Is the source code implementing cipher.getIV() available online somewhere, assuming I'm using Oracle JDK 8 + JCE Unlimited Strength extension?
Is that IV always 12 bytes long?
Is the authentication tag always 16 bytes (128 bits) long?
With #2 and #3, and the lack of padding, does that mean my encrypted messages are always 12 + src.length + 16 bytes long? (And so I can safely squish them into one byte array, for which I know the correct length?)
Is it safe for me to display an unbounded number of src data encryptions to users, given constant src data that the users know?
Is it safe for me to display an unbounded number of src data encryptions to users, if the src data is different every time (e.g. including System.currentTimeMillis() or random numbers)?
Would it help if I padded the src data with random numbers before encryption? Say 8 random bytes in front and back, or only on one end? Or would that not help at all / make my encryption worse?
(Because these questions are all about the same block of my own code, and they are strongly related to each other, and others might/should have the same set of questions when implementing the same functionality, it felt wrong to split the questions into multiple posts. I can re-post them separately if that is more appropriate for StackOverflow's format. Let me know!)
Q1: Is the IV returned by cipher.getIV() safe for me to use in this way?
Yes, it is at least for the Oracle provided implementation. It is generated separately using the default SecureRandom implementation. As it is 12 bytes in size (the default for GCM) then you have 96 bits of randomness. The chance that the counter repeats is abysmally small. You can look up the source in the OpenJDK (GPL'ed) which the Oracle JDK is based on.
I would however still recommend you to generate your own 12 random bytes as other providers may behave differently.
Q2: Is that IV always 12 bytes long?
It's extremely likely as it is the GCM default, but other lengths are valid for GCM. The algorithm will however have to do additional calculations for any other size than 12 bytes. Due to weaknesses it is strongly recommended to keep it at 12 bytes / 96 bits and API's may restrict you to that choice of IV size.
Q3: Is the authentication tag always 16 bytes (128 bits) long?
No, it can have any size in bytes ranging from 64 bits to 128 bits with 8 bit increments. If it is smaller it simply consists of the leftmost bytes of the authentication tag though. You can specify another size of tag using GCMParameterSpec as third parameter for your init call.
Note that the strength of GCM is strongly dependent on the size of the tag. I would recommend keeping it to 128 bits. 96 bits should be the minimum especially if you want to generate a lot of ciphertext.
Q4: With #2 and #3, and the lack of padding, does that mean my encrypted messages are always 12 + src.length + 16 bytes long? (And so I can safely squish them into one byte array, for which I know the correct length?)
See above. For the Oracle provider this is the case. Use GCMParameterSpec to be sure of it.
Q5: Is it safe for me to display an unbounded number of src data encryptions to users, given constant src data that the users know?
Virtually unbound, yes. I would start worrying after about 2^48 encryptions. In general you should however design for key change.
Q6: Is it safe for me to display an unbounded number of src data encryptions to users, if the src data is different every time (e.g. including System.currentTimeMillis() or random numbers)?
See answer to Q5 & Q7
Q7: Would it help if I padded the src data with random numbers before encryption? Say 8 random bytes in front and back, or only on one end? Or would that not help at all / make my encryption worse?
No, it would not help at all. GCM uses CTR mode underneath, so it would just be encrypted with the key stream. It would not act as an IV. Nowadays you could look at AES-GCM-SIV if you have an ever changing message to encrypt, but note that that algorithm is not implemented in any of the JCA providers.
If you need a lot of ciphertexts (higher than 2^48!, or 2^32 - ~4 billion - for the cautious) then I would suggest you use that random number and your key for a key derivation function or KDF. HKDF is currently best of breed, but you may need to use Bouncy Castle or implement it yourself.

Java/Groovy: Randomize Encryption String Better

I use encryption to create query parameters that get emailed to individuals with download links to various files. However, I've noticed that the encrypted strings are fairly similar for similar file names. I'd like to change that.
Here's the code I'm currently using:
Cipher cipher = Cipher.getInstance('AES/CBC/PKCS5Padding')
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec('****************' as byte[], AES'),
new IvParameterSpec('***************' as byte[]))
String fileId = Base64.encodeBase64String(
IOUtils.toByteArray(
new CipherInputStream(
new DeflaterInputStream(
new ByteArrayInputStream(
('File: ' + filename).getBytes('UTF-8')
)
), cipher
)
)
)
For example if I have a file called Something_8.3.0.1471.exe and Something_8.3.0.1471_License.txt I would get the following two strings:
mVjCmP2GCyxMJ1i5GHT1OOZEYXy1%2Buz%2BQ53QMelR4QU%2FTowMdjNcMjojlbjuTJEd
and
mVjCmP2GCyxMJ1i5GHT1OB%2F5S1rolp%2BwK9dATPdPtHn3uQiXnYUhLmym6hMI65TVfjA5IzSYInI9iIjZn9eExg%3D%3D
The first 20 or so characters of the encrypted string are identical, obviously because the beginning of the file names is identical. I was wondering if it's possible to remove this identicallity (if that's a word). Is it possible to have any change in the unencrypted string more prominently impact the whole encrypted string? If so, how would I go about making this change in Java/Groovy in the above code?
The same key and same plain text will always produce the same cipher text when used in deterministic encryption scheme. Probabilistic encryption schemes introduce some randomness factor so that continuous invocations of encryption with the same key and same plain text produce different cipher texts.
Some crypto algorithms (like EC signatures) generate random values internally and do not even expose them to the user as they do not need to store the value of that randomness factor in order to decrypt the cipher text (or validate a signature) but in most ciphers the user is trusted to provide a random factor like initialization vector or nonce.
AES has a block size of 16 bytes, meaning that it splits the input into 16-byte chunks and processes each chunk separately (in ECB mode) or mixing in the previous processing results in some way (in most other cipher modes). For the very first block regardless of the cipher mode used the only inputs are the key, the IV and the first 16 bytes of the input.
In your example the first 16 bytes are the same in both cases, and it seems that you use the same key and same IV (one of the greatest crypto sins, by the way). As expected, the first 16 bytes (or, equivalently, first 20 Base64 characters) are the same.
The next 16 bytes of the input are different, which leads to completely different second block of cipher text.
You must not use the same IV value twice. Use SecureRandom to generate unique IV values for each encryption attempt.
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[16]; // use the proper IV size for selected cipher
random.nextBytes(bytes);
When using a single storage entity (a single file, for example) storing the IV before the cipher text is the de facto standard, but it is not required (you can store the IV and the cipher text in a separate database columns, for example).
You must not use keys created by simply converting a character sequence into a byte sequence. Such keys have predictable properties (for example, for ASCII text your key will never contain bytes in the range of [0..31]). If you need a password-based key then use the proper key derivation function like PBKDF2.

Java encryption ivSpec random or not?

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.

Check encryption key correctness in JAVA

I'm using BouncyCastle to encrypt/decrypt some files using AES and PKCS5 padding in CBC mode :
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
Now two questions:
How can I check that the provided key for decrypting data is correct or not ?
How Can I check encrypted input is untouched (e.g. not changed by user using an HEX editor)?
Thanks
You can use an AEAD mode, like CCM or GCM, in place of CBC. These modes authenticate an encrypted message, so if the wrong key is used, or the cipher text has been altered, you can detect it. You wouldn't be able to distinguish these cases though.
There is support in Java 7's cryptography API for GCM, but the SunJCE provider that ships with Oracle's Java implementation doesn't support it yet. You can get support through third-party providers like BouncyCastle.
You can achieve the same things if you use additional cryptographic services, like a digital signature or message authentication code.
Encryption is not just about the algorithm and the encryption key, it's also a lot about
the system organization.
In general, you can't determine that the key is correct. Any key can be used to decrypt the
data that's supposed to be decrypted, but it's up to some other mechanism to tell you if that
is the "correct" result.
In general, you can't determine if the data to be decrypted is untouched, except through some
external check. It's a property of most encryption systems that changing any of the encrypted
data would change the decrypted output drastically, probably into something you'd interpret
as garbage.
You should add a MAC which first verifies the integrity of the message, and only then you should decrypt it. A common choice of MAC is HMAC with whatever hash function you prefer, such as SHA-2.
Instead of doing this yourself, it's often a good idea to use an authenticated cipher. AES-GCM is a common choice. But you need to be really careful to never reuse an IV in that case.
The JCE ciphers are usually very basic. If you need a full featured protection including integrity and key testing, you need to combine them. And as usual it is better to not device that yourself. So better opt for a more high level format like PKCS7/12 or PGP.
Depending on the Padding used some ciphers will give you a PaddingException when you try to decrypt it with the wrong key. For stronger integrity check I would use a padding consiting of HMAC bytes.
A pretty complete method is included in the JCE, it is the AESWrap algorithm. It requires padded data but will ensure integrity. It is best combined with a length byte as described in RFC 3537. Note, that this is only intended for smaller amounts of secrets (like symmetric keys). The RFC3537 padding is restricted to 255 bytes.
To use this with a password derived key, you can use this:
char[] pass = ... // your password
byte[] codeBytes = ... // up to 255 bytes you want to protect
// generate wrapping key from password
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16]; rand.nextBytes(salt);
SecretKey kek = f.generateSecret(new PBEKeySpec(pass, salt, 1000, 128));
kek = new SecretKeySpec(password.getEncoded(), "AES"); // convert into AES
// RFC3537 padding (lengthbyte)
byte[] wrappedCodeBytes = new byte[codeBytes + 1 % 8];
System.arraycopy(codeBytes,0,wrappedCodeBytes,1,wrappedCodeBytes.length);
paddedCodeBytes[0]=(byte)codeBytes.length;
byte[] pad = new byte[paddedCodeBytes.length - codeBytes.length -1]; rand.nextBytes(pad);
System.arraycopy(pad,0,paddedCodeBytes,codeBytes.length+1,pad.length);
// AESWrap is WRAP_MODE:needs a SecretKey
SecretKey paddedCodeKey = new SecretKeySpec(paddedCodeBytes, "RAW");
// now wrap the password with AESWrap kek is 128 bit
Cipher c = Cipher.getInstance("AESWrap"); // default IV
c.init(Cipher.WRAP_MODE, kek);
byte[] result = c.warp(paddedCodeKey);
The unwrapping is left for the reader as an exercise :) The example code uses 128bit keysize, since more entropy cant be expected from the PBKDF2 anyway.
Note that this will detect wrong passwords with high probability, and some critics will see this as a weakness of AESWrap.
Take a look at this tutorial on BC encryption, specifically the InitCiphers methods, and in detail at the second code block which specifies the actual type of cipher.
How can I check that the provided key for decrypting data is correct or not?
According to JCE Javadocs, specifically the constructor of Class SecretKeySpec:
This constructor does not check if the given bytes indeed specify a secret key of the specified algorithm. For example, if the algorithm is DES, this constructor does not check if key is 8 bytes long, and also does not check for weak or semi-weak keys. In order for those checks to be performed, an algorithm-specific key specification class (in this case: DESKeySpec) should be used.
Note that Interface KeySpec lists all implementing classes, basically a list of validation options.
How Can I check encrypted input is untouched (e.g. not changed by user using an HEX editor)?
Indeed. That's a good one. 'Input' is pretty generic. Do you mean the actual content to decrypt? Well, if it's munged I believe it will not decrypt properly. Does that make sense?
IFF you are talking about the case of a key with parity bits being altered, as described in item (6) at the Bouncy Castle FAQ, you will have to do an actual parity check on the key. Only the first 56 bytes of the key are used for the encryption ops, and the last 8 bytes are reserved for parity checking. So, essentially, the last part of the 'key' can be changed and the first part is still useful. To detect whether either the parity or the key have been altered, you would run a parity check. I found this little ditty on doing a parity check. And, for more info on how parity is set in these keys, see comments in the JDK7 Crypto Provider source for Class DESKeyGenerator by Jan Luehe (near bottom) which discuss parity setting.
I recently had some interaction with BC, and I hope this info helps.

Categories

Resources