To generate AES key in java i had used as fallow
public byte[] GenerateAESKey() {
// Generate a new AES key
SecretKey key = null;
try {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128);
key = keygen.generateKey();
return key.getEncoded();
} catch (NoSuchAlgorithmException e) {
return null;
}
}
In iOS I tried it in this way using iOS-Crypto-API.
id<SecretKey> key=[[[AESKeyGenerator alloc] init] generate:128 onError:&error];
NSLog(#"Key: %# ",key.key);
When I print both keys looks different, Is that above generated iOS Key is correct or not? Help me to solve this out.
AES keys are essentially bit strings. So when you generate a new AES key, it will be created using some randomness of the system or the library. Even if you generate two keys in the same library, they will be different as collisions for 128-bit keys are really unlikely to happen.
For encryption and decryption you need the same key at both ends, so you need to transport it in some way. Depending on your system, you could do this at system setup (key embedded in the source code or in some way static) or using asymmetric encryption to send the key from one machine to the next (possibly secured with Diffie-Hellman Key Exchange).
You will have to encode the key in some way that is acceptable by the library. Popular encodings are Base 64 and Hex. You may need to convert between encodings.
Symmetric keys are, basically, byte arrays which are obtained from random source. The length of the keys depends on the cipher algorithm that is going to use such keys.
When you generate a secret key (i.e., a symmetric key) you get a random byte array. If you generate it again, you will get a different one.
Therefore, it is totally normal to get two different keys from two different key generations.
Related
so I'm creating a game for my A level project and I'm now at the stage where I need to be able to encrypt and decrypt text files.
I have figured out encryption using AES-256 in GCM mode however I am using a randomly generated key and IV in order to encrypt the data in the first place. So I was wondering, is there any way in which I can decrypt the text file without knowing the key and iv.
Alternatively, from the encryption method shown below, is there anything I could change so that I will know the key and iv when decrypting the text later on.
NOTE: I'm using the libGDX library to create the game which is why I'm not using the standard method to write to the text file.
Encryption method:
public void encrypt ()
{
byte[] input = w.getSprites().toString().getBytes(); // Data to be encrypted
byte[] encrypted = null; // Encrypted output
Cipher cipher; // Cipher algorithm to be used
try {
// Setup the cipher algorithm to use and select the wanted mode
// AES is the cipher algorithm GCM is the mode
cipher = Cipher.getInstance("AES/GCM/NoPadding");
// Generate a random key for the encryption
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
SecretKey key = keyGenerator.generateKey();
// Generate a random iv for the encryption
SecureRandom randomSecureRandom = new SecureRandom();
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
// Encrypt the data
cipher.init(Cipher.ENCRYPT_MODE, key, randomSecureRandom);
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);
}
catch (NoSuchAlgorithmException |
NoSuchPaddingException |
InvalidKeyException |
ShortBufferException |
IllegalBlockSizeException |
BadPaddingException e) { e.printStackTrace(); }
FileHandle f = Gdx.files.local("bin/default/saves/default/test.txt");
f.writeString(encrypted.toString(), false);
}
Thank you in advance for any answers, they are very much appreciated.
No, you cannot decrypt without knowing the key. What would the point of encryption be if anyone could decrypt the message without even having the key?
If this is intended to hide data from a local user, then pretty much the best you can is obfuscate the data. The machine needs to know the key in order to encrypt and decrypt it and anyone with access to that machine can eventually find that key and use it to decrypt the data for themselves. Even if you don't write anything to disk, local users could look at memory and find the key. Also remember that code can be decompiled.
Basically just keep in mind that anyone with physical access is king and you can't really stop them, just slow them down.
So the best you can do is make it as painful as possible to get the key. String literals in classfiles or property files are easy to read and not at all painful so avoid using those.
See this question for related ways to handle local security.
Also consider using a tool like Proguard to obfuscate (and optimize) your code in general as well.
You could try a brute force attack.
Breaking a symmetric 256-bit key by brute force requires 2128 times more computational power than a 128-bit key. Fifty supercomputers that could check a billion billion (1018) AES keys per second (if such a device could ever be made) would, in theory, require about 3×1051 years to exhaust the 256-bit key space.
Per wikipedia
In reality the 256-bit AES is considered computationally infeasible. The only 'feasible' way to decrypt would be using the same key used to encrypt. Some background on AES.
There is a faster method (still computationally infeasible for 256 bit) called Biclique attack. but I think this is a bit outside the scope of what your asking.
If you decide you need to pass your AES key from the encryption person to the decrytion person you can use RSA encryption which uses asymetric keys. Take a look at my github for a basic RSA implementation.
i've got the following problem. My application is divided in two different parts: 1) the first part encrypts some data using AES/CBC (Java), 2) the second part must retrieve the data and decrypt (Android).
To generate the secret key i use the following code
SecureRandom saltRand = new SecureRandom(new byte[] { 1, 2, 3, 4 });
byte[] salt = new byte[16];
saltRand.nextBytes(salt);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 1024, 128);
SecretKey key = factory.generateSecret(spec);
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(key.getEncoded());
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128, sr);
sksCrypt = new SecretKeySpec((kg.generateKey()).getEncoded(), "AES");
My program doesn't need differents "source key" (the string password), however it needs to compute the same secret key as long as source key is the same. unfortunately, the key generated by the two parts of the program are different and the decryption phase fails.
Any suggestion on how to solve this issue?
You are using a random key generator to generate a secret key from given input key material. Key derivation functions are functions that derive keys from secrets. There are password based key derivation functions such as PBKDF2 which use a password (plus a salt and a specific iteration count) as secret input. And there are key based key derivation functions such as HKDF that use a key and possibly a label or other output key specific information as input material.
Java does provide you with a set of PBKDF's, PBKDF1 and PBKDF2 where PBKDF2 is the newer one that you are currently using. Unfortunately it doesn't provide a KBKDF out of the box. You would need to use the (lightweight) Bouncy Castle API to do provide this kind of functionality. I know because I provided the initial implementation of the various KBKDF's for Bouncy.
Unfortunately using SecureRandom as replacement KBKDF doesn't work, as you've found out. The SHA1PRNG algorithm is not specified well; it is a function that depends on the SHA-1 secure hash function, but that's all. So implementations can and do differ, for instance between Android (which was loosely based on GNU classpath) and Oracle's Java. SHA1PRNG may or may not rely entirely on the seed. And in newer Android versions it may even be replaced by something entirely different.
As you only derive a single key from your input key material, you might as well wrap key.getEncoded() with SecretKeySpec directly and use that as a key. There is no need to perform an additional key generation at all; you already derived a key using PBKDF2. The additional wrapping doesn't do anything with the keying material. It may just be required to set the algorithm to, e.g., "AES".
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.
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.
when you want to encrypt something dont you want the key to decrypt to be decided by you and not generator by some random number generator ?
i see this code in stackoverflow post. but i dont want the key to be generated randomly i want to the user to be asked to enter the key and on that bases the encryption should happen..
any suggestions how should i modify the code ?
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
The whole idea of encryption is that noone except the needed parties can ever deduce the key since the key is the only secret.
If you choose keys yourself you're likely to follow some habitual pattern, so if you compomise one key you expose that pattern and the attacker can use that information to simplify finding other keys you use. Using a good random number generator eliminates this possibility and makes the encryption much more efficient.
The code you show doesn't generate a random key. The generated key is a function of the password, and will be exactly the same every time a given password is used.
In this case, the user should be asked to enter the password. That password is used as the seed for an algorithm that deterministically produces a string of bytes which can be used as a cryptographic key.
There is something that should be chosen randomly for each operation: the initialization vector used for ciphers in CBC mode. This produces different ciphertexts even when the same key is used to encrypt the same plaintext.