Java simple helloworld AES encryption decryption [duplicate] - java

This question already has answers here:
UTF-8 byte[] to String
(11 answers)
Closed 8 years ago.
I got a code snippet from another SO question and modified it a bit but I can't seem to get it to work. Can anyone figure out why? it's currently printing [B#405e70bc or similar values. All I'm trying to do is store a password in an encrypted form just for the sole purpose of keeping it away from curious eyes, is there a better way to do that?
String secret = "1234567812345678";
Key key = new SecretKeySpec(secret.getBytes(), "AES");
// Encrypt
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedData = cipher.doFinal("helloworld".getBytes());
// Decrypt
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedData = cipher.doFinal(encryptedData);
System.out.println(decryptedData.toString());

There is nothing wrong with your encryption / decryption logic. The problem is with you calling .toString() on a byte [].
Use this output statement instead:
System.out.println(new String(decryptedData));

Thanks Alexander.
This worked
String secret = "1234567812345678";
Key key = new SecretKeySpec(secret.getBytes(), "AES");
// Encrypt
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedData = cipher.doFinal("helloworld".getBytes());
// Decrypt
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedData = cipher.doFinal(encryptedData);
System.out.println(new String(decryptedData, "UTF-8"));

Please don't use this for anything critical. The standard Java AES code makes use of a fixed-length block cipher which can result in identical encrypted byte data. The upshot is a gradual leakage of plaintext information.
You should look into Cipher Block Chaining and Initialisation Vectors if you want your code to be more robust. http://www.javamex.com/tutorials/cryptography/block_modes.shtml
It may be overkill for your needs, but just thought i'd mention it.

Related

Java AES encryption issue

Every time the encryption values changed by using AES, let anyone investigate the below code and let me know the issue
code:
private static final String secretKeys = "58BA833E57A51CBF9BF8BAB696BF9"
public static String encrypt() throws Exception {
byte[] salt = new byte[16];
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
PBEKeySpec pbeKeySpec = new PBEKeySpec(secretKeys.getChars(),salt,1000, 256);
Key secretKey = factory.generateSecret(pbeKeySpec);
byte[] key = new byte[32];
byte[] iv = new byte[16];
SecretKeySpec secret = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] result = cipher.doFinal("welcome".getBytes("UTF-8"));
String s = Base64.getEncoder().encodeToString(result);
return s
}
Output
first time I got the below-encrypted string
CZRIP35M4CnJtuDQ6YpmaQ==
The second time I got the below-encrypted string
/fylTjohAZDsnCaHhiZo3A==
I have three questions:
why the encrypted string not a constant?
how can I set the Blocksize? ( AES.BlockSize = 128;)
How can I set the padding mode? (AES.Padding = PaddingMode.PKCS7;)
For the first question, #Freiheit already answered this.
Long story short, based on the iv (initilization vector) which acts as a salt and will be different for each encryption.
Having that said, encrypting the same plain text will result in different encrypted text, but the decryption (if necessary) will result back into the same plain text.
IV is helpful to make the encryption predictable.
Having stored the same password for 2 different users in a database will have different values, but will be the same password.
With the current cipher configured, you already have 128 block size. You can read more about the different cypher transformation here. You can also find more information of the block sizes for different algorithms here
You just need to change the Cipher.getInstance() to AES/CBC/PKCS7Padding
1) the encrypted text is always different because the Cipher initialization is providing it's own IV since you are not providing one. You need to provide the IV you've "computed" in order to have a consistent output. Remember you never want to use an IV more than once for whatever this code is ultimately intended to do.
2) The keysize can be 128, 192 or 256 but the blocksize is always 128.
3) Java only provides PKCS5, but there is no difference in the implementation for AES. see what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding
As was already pointed out there are several problems with the code provided such as the first lines not actually doing anything and the key and iv both being uninitialized. I would additionally suggest you use SecureRandom to initialize your key and iv. If you plan on using only a single AES key, this can be computed once and placed in the code or configuration file instead of running PBKDF2 every time.
Only adding to the answer provided by #micker, you need to invoke another version of Cipher.init(); one that takes the IV into account:
...
byte[] iv = new byte[16];
IvParameterSpec ivSpec = new IvParameterSpec(iv); // <= Wrap your IV bytes here.
SecretKeySpec secret = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret, ivSpec); // <= Add IV here.
...
That being said, the implementation suffers from a slew of other issues (key being all zeroes, IV being all zeroes, first 4 line don't do anything for you (as #JBNizet pointed out)). I hope you are only using it to study how Java's encryption mechanics works.

How can i encrypt and decrypt images in java android [duplicate]

I want to encrypt file and store it in SD card. I want to decrypt that encrypted file and store it in SD card again. I have tried to encrypt file by opening it as file stream and encrypt it but it is not working. I want some idea on how to do this.
Use a CipherOutputStream or CipherInputStream with a Cipher and your FileInputStream / FileOutputStream.
I would suggest something like Cipher.getInstance("AES/CBC/PKCS5Padding") for creating the Cipher class. CBC mode is secure and does not have the vulnerabilities of ECB mode for non-random plaintexts. It should be present in any generic cryptographic library, ensuring high compatibility.
Don't forget to use a Initialization Vector (IV) generated by a secure random generator if you want to encrypt multiple files with the same key. You can prefix the plain IV at the start of the ciphertext. It is always exactly one block (16 bytes) in size.
If you want to use a password, please make sure you do use a good key derivation mechanism (look up password based encryption or password based key derivation). PBKDF2 is the most commonly used Password Based Key Derivation scheme and it is present in most Java runtimes, including Android. Note that SHA-1 is a bit outdated hash function, but it should be fine in PBKDF2, and does currently present the most compatible option.
Always specify the character encoding when encoding/decoding strings, or you'll be in trouble when the platform encoding differs from the previous one. In other words, don't use String.getBytes() but use String.getBytes(StandardCharsets.UTF_8).
To make it more secure, please add cryptographic integrity and authenticity by adding a secure checksum (MAC or HMAC) over the ciphertext and IV, preferably using a different key. Without an authentication tag the ciphertext may be changed in such a way that the change cannot be detected.
Be warned that CipherInputStream may not report BadPaddingException, this includes BadPaddingException generated for authenticated ciphers such as GCM. This would make the streams incompatible and insecure for these kind of authenticated ciphers.
I had a similar problem and for encrypt/decrypt i came up with this solution:
public static byte[] generateKey(String password) throws Exception
{
byte[] keyStart = password.getBytes("UTF-8");
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
sr.setSeed(keyStart);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
return skey.getEncoded();
}
public static byte[] encodeFile(byte[] key, byte[] fileData) throws Exception
{
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(fileData);
return encrypted;
}
public static byte[] decodeFile(byte[] key, byte[] fileData) throws Exception
{
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(fileData);
return decrypted;
}
To save a encrypted file to sd do:
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "your_folder_on_sd", "file_name");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
byte[] yourKey = generateKey("password");
byte[] filesBytes = encodeFile(yourKey, yourByteArrayContainigDataToEncrypt);
bos.write(fileBytes);
bos.flush();
bos.close();
To decode a file use:
byte[] yourKey = generateKey("password");
byte[] decodedData = decodeFile(yourKey, bytesOfYourFile);
For reading in a file to a byte Array there a different way out there. A Example: http://examples.javacodegeeks.com/core-java/io/fileinputstream/read-file-in-byte-array-with-fileinputstream/
You could use java-aes-crypto or Facebook's Conceal
java-aes-crypto
Quoting from the repo
A simple Android class for encrypting & decrypting strings, aiming to
avoid the classic mistakes that most such classes suffer from.
Facebook's conceal
Quoting from the repo
Conceal provides easy Android APIs for performing fast encryption and
authentication of data

Android use CFB

I'm trying to encode my String with AES and CFB. If im doing this
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
, it works fine. But if i'm using "AES/CFB/NoPadding" instead of "AES", then the same String with the same password is different. Here is my Code:
SecretKeySpec key = new SecretKeySpec(cryptPassword.getBytes(), "AES");
byte[] cryptByte = cryptString.getBytes("UTF8");
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] hans = cipher.doFinal(cryptByte);
cryptString = Base64.encodeToString(hans,Base64.DEFAULT);
Can someone help me?
Thanks a lot!!!
Assuming that the question is about the difference of Cipher.getInstance("AES") and Cipher.getInstance("AES/CFB/NoPadding"):
For Oracle JDK the default mode/padding when you do not specify them in the transformation string is "ECB/PKCS5Padding", meaning that Cipher.getInstance("AES") is the same as Cipher.getInstance("AES/ECB/PKCS5Padding").
The result of encoding some data with AES/ECB/PKCS5Padding is predictably different from encoding the same data with AES/CFB/NoPadding.
To minimize the confusion you should always specify the full transformation with explicit mode and padding values.

Decryption bug using des ede, javax.crypto.badpaddingexception

I've been stuck on a bug in my code, it will not let me decrypt properly!
I am only passing eight bytes of data to dataBytes and I am passing
a 24 byte key to keyBytes.
I am trying to return the decrypted data as an array of bytes.
I keep getting the bad padding exception.
Thanks!
Here is the code snippet:
private static byte[] DESEdeDecrypt(byte[] keyBytes, byte[] dataBytes){
byte[] decryptedData = null;
try{
DESedeKeySpec keySpec = new DESedeKeySpec(keyBytes, 0);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey key = keyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedData = cipher.doFinal(dataBytes);
}
catch(Exception e){System.out.println(e);}
return decryptedData;
You must use the same padding to decrypt as you did to encrypt. It is better to set it explicitly rather than to rely on defaults. Best also to specify the mode at both ends as well:
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
DESede is slow and obsolescent. You shouldn't use it except for compatibility with old code. For new work it is better to use AES.

what is wrong in java AES decrypt function?

i modified the code available on
http://java.sun.com/developer/technicalArticles/Security/AES/AES_v1.html
and made encrypt and decrypt methods in program. but i am getting BadpaddingException..
also the function is returning null..
why it is happing?? whats going wrong? please help me..
these are variables i am using:
kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
raw = new byte[]{(byte)0x00,(byte)0x11,(byte)0x22,(byte)0x33,(byte)0x44,(byte)0x55,(byte)0x66,(byte)0x77,(byte)0x88,(byte)0x99,(byte)0xaa,(byte)0xbb,(byte)0xcc,(byte)0xdd,(byte)0xee,(byte)0xff};
skeySpec = new SecretKeySpec(raw, "AES");
cipher = Cipher.getInstance("AES");
plainText=null;
cipherText=null;
following is decrypt function..
public String decrypt(String cipherText)
{
try
{
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(cipherText.getBytes());
plainText = new String(original);
}
catch(BadPaddingException e)
{
}
return plainText;
}
From the Java-Security archives
One common mistakes that people made is to put the encrypted bytes inside a
string and upon decryption they use String.getBytes() to retrieve it.
Since String does its own character encoding, the byte[] that you used to
construct the String object and the byte[] that you get from its getBytes()
are not necessarily equal.
Where is cipherText actually coming from? It needs to be a "raw" byte array (not a string), and needs to have been encrypted in a way that the Cipher can understand.
AES (and block ciphers in general) can be run in different "block modes" and with different "padding", and when you instantiate a Cipher, you should indicate which block mode you're using (or which was used to originally encrypt the data). If you get a BadPaddingException when passing in raw bytes, then it generally means the data has been encrypted using a different mode or padding. (In this case, it could just be an artefact of converting the data to a String, as I think another poster has mentioned.)
Some information I've written that might be helpful:
AES and block ciphers in Java
block modes
Since you've shown very little code it's hard to help predict what might be causing the exception.
plainText is null because it is initialized to null and the decrypt function is throwing an exception before assigning a value to plainText.
What do you do with kgen? In the example you linked to it is used to generate the raw byte array for the secret key spec. In your variable instantiation list you manually define the raw byte array.
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

Categories