Why does this AES implementation unwrap and wrap the key again? - java

I'm trying to understand this comment from AES implementation code:
/**
* This program generates a AES key, retrieves its raw bytes, and
* then reinstantiates a AES key from the key bytes.
* The reinstantiated key is used to initialize a AES cipher for
* encryption and decryption.
*/
I don't understand following points:
What does it mean by raw bytes of AES key?
What does it mean by reinstantiates a AES key from the key bytes?

I think you are reading this web page,
http://java.sun.com/developer/technicalArticles/Security/AES/AES_v1.html
We have code that generates AES keys according to this example also but I think the author is a little bit confused. It generates keys like this,
kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
skey is already an AES key you can use. The second step does nothing. If you look inside skey and skeySpec, they are identical.
So you can ignore the explanation. It doesn't make it any more clear.

Raw bytes probably refers to the storage representation of the key object.
Usually you create a key object and then get a form in which to store it (have a look at java.security.Key#getEncoded(). That storage/exchange representation is a byte array without encoding information - therefore "raw bytes".
These raw bytes then can be used to instantiate the key object again.
Unclear to me is why the program reinstantiates the key object instead of using the one it created earlier.
That probably can only be answered by seeing the code of the program.

AES: Advanced Encyption Standard
The key is a string. So this seems to generate a string.
It likely then converts it to an array of bytes (perhaps for storage).
It then recreates the string from the array of bytes.

Related

AES key size of 512 doesn't work

I am trying to write a native module to generate/store AES keys for realm encryption. For the test application I wrote (when I used 512 key size), I get the following exception:
Exception in thread "main" java.security.InvalidParameterException: Wrong keysize: must be equal to 128, 192 or 256
at com.sun.crypto.provider.AESKeyGenerator.engineInit(AESKeyGenerator.java:93)
at javax.crypto.KeyGenerator.init(KeyGenerator.java:517)
at javax.crypto.KeyGenerator.init(KeyGenerator.java:494)
The code I am using is:
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(512);
SecretKey secretKey = keyGen.generateKey();
final int AES_KEYLENGTH = 512;
byte[] iv = new byte[AES_KEYLENGTH / 8];
SecureRandom prng = new SecureRandom();
prng.nextBytes(iv);
Cipher aesCipherForEncryption = Cipher.getInstance("AES/CBC/PKCS7PADDING");
Can someone please let me know what am I doing wrong here?
Thanks.
If you want to store a 512-bit key "as an AES key", you can just store two 256-bit AES keys, call them LEFT and RIGHT, for example, and concatenate them before passing to Realm.
As others have pointed out in comments, AES does not have 512-bit keys. It may say they are using AES-256 encryption, but I doubt it says anywhere that they are using 512-bit, AES keys.
I suspect, as #Artjom B. mentions in the comment, that it really is a pair of 256-bit keys, one for encryption and one for mac (e.g. HMAC).
If you want to create a 512-bit key, you can just use SecureRandom. There is nothing special about KeyGenerator that SecureRandom cannot provide for AES keys. You just want to be sure that you are using cryptographically strong random data.

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.

Symmetric Key Generation

I have two questions:
When to use SecretKeySpec and when to use KeyGenerator for key generation?
Is it necessary that the Key instance and the Cipher instance has to follow the same Algorithm? What is the concept behind?
Depends on your application
Yes. Different ciphers may use different key lengths. You pass AlgorithmParameterSpec to the key generator.
KeyGenerator creates a new random key each time it is called. The returned key is also guaranteed to have the length compatible with the algorithm specified when obtaining the KeyGenerator instance.
SecretKeySpec wraps an existing byte array. The source of bytes can be a hex or Base64 string or really any other textual or binary representation of the previously generated key. Hence the use case for SecretKeySpec is when you need to reuse the key which was previously stored in some external representation.
Usually an instance of SecretKeySpec can be used directly as a key because SecretKeySpec implements SecretKey and most crypto algorithms that use secret keys support so-called "raw" keys where the "raw" key is basically a random sequence of bytes without specific internal structure.
When an algorithm requires a specific SecretKey representation (usually a subclass of SecretKey internal to algorithm implementation) you will have to use SecretKeyFactory to transform a SecretKeySpec into a proper SecretKey.
If a crypto algorithm supports "raw" keys then the only requirement is that the key length matches the algorithm expectations.
But the implementer of crypto provider can decide that he needs to use a specific key representation which, for example, caches or precalculates some values based on the initial "raw" bytes. In that case the algorithm can require that a SecretKey instance passed into in addition to returning correct identifiers from Key.getAlgorithm() and Key.getFormat() methods is also a specific subclass of SecretKey, so the usage of SecretKeyFactory to convert key spec into a key is mandatory. Such cases are usually documented in the provider documentation.

Android AES problem

I'm tring to encrypt/decrypt my files using AES. I followed this tutorial to encrypt my data, but I modified the code a little bit, so that I could use the same key to encrypt many files.
In addition to encrypting my files, my AES key is also saved using RSA (this page , saveKey() method).
I encrypted files on my PC, and tried to decrypt them on Android. However, I always got BadPaddingException: pad block corrupted. I printed out the AES keys, and found out that with the same private key, the decrypted AES keys were different on PC and Android.
It worked fine if I decrypt the same files on PC.
Why?!
Is there anything wrong with Android's cipher?! Help needed.
your RSA padding cipher could be on the wrong padding scheme
try this?
pkCipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
The code you copied is wrong. It may or may not work depending on Android version. My guess is that it doesn't on newer ones. The part which converts from seed to raw key is flawed (see below): SecureSeed.setSeed() is not guaranteed to set the random generator state, it just adds to it. What this means is that you are not guaranteed to get the same key. To reliably get the same key based on a password, you need to use PBE (Password Based Encryption)
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
// this is wrong!
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
Generally, first make sure you can reliably encrypt/decrypt using AES, then you might move on to using RSA. You might want to tell us what you are trying to achieve, you might be going at it the wrong way. Inventing your own cryptographic protocol is rarely a good idea.

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.

Categories

Resources