Java AES security implementation - java

I want to encrypt a String to interger with fix lenght, How can I do that in Java.
tring to implement AES Algorithm but the out is a special Character and not a number.
String text = "Test TEST";
String key = "deadbeefbeefdead"; // 128 bit key
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher..doFinal(text.getBytes());
System.err.println(new String(encrypted));
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted = new String(cipher.doFinal(encrypted));
System.err.println(decrypted
);

The question is not clear but here is some information:
Encryption generates a sequence of 8-bit bytes, not characters, not all 8-bit bytes are printable characters or even characters in most encodings. Generally if you require a printable string the encrypted data is Base64 or hex encoded. Each encrypted byte can be considered a uint8_t "integer".
AES is a block cipher, it takes 16-byte chunks and outputs 16-byte chunks. If the input is not a multiple of the block size padding (extra bytes) must be added to the input prior to encryption. "Bhaumik Patel" is 13 bytes so 3 bytes must be added prior to encryption and removed after decryption. Most block encryption libraries include a padding option, generally PKCS#7 (PKCS#5) but occasionally null padding.
There is also a mode,most commonally ECB (not secure) and CBC. In the case of CBC there is also a block-sized iv (initialization vector), generally a random sequence of bytes.
Unfortunately, encryption alone is generally only part of a secure solution.
Edit: The question text input was changed from "Bhaumik Patel" to ""Test TEST"".

Related

Accessing random lsb bit in steganography

I'm trying to do audio steganography. Before hiding data inside audio I encrypt the data with aes and then I embed bits at lsb in sequential bytes. The recovery and aes decryption works fine.
But if I try random bits for lsb it gives me the following error:
-->Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
the error points to
public byte[] decr**strong text**yptText(byte[] byteCipherText,Key secKey) throws Exception {
// AES defaults to AES/ECB/PKCS5Padding in Java 7
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.DECRYPT_MODE, secKey);
byte[] bytePlainText = aesCipher.doFinal(byteCipherText);
See PKCS padding, note that PKCS#5 is a misnomer for PKCS#7 WRT AES because the AES implementation developers were to lazy to include the correct option name.
Because PKCS#7 padding has format requirements and there few byte sequences (~ 1^16 + 2^16 + ... + 15^16) that form correct padding out of 256^16 possible byte sequences the chance that random bytes would form valid PKCS#7 padding is very small.
You might be better off using CTR mode which does not require padding, just a unique key/counter pair for each encryption.

Wrong cipher text length when using 3DESede with PKS5 padding of javax.crypto

I am using the following code in my android application to encrypt a string in Triple DES using the Encrypted Code Book (ECB) mode with three independent keys (aka 3DESede), which are provided as a 24 byte sized key array. Therefore I use the Java Crypto API. This works pretty well, but if I encrypt an eight character string I get a 16 byte cipher text, which should not happen as 3DES operates on chunks of 64 bit (resp. 8 byte). Same holds for the PKCS5 padding as this also operates on chunks of 64 bit. So my question is what causes this problem?
private static byte[] encryptText(String plaintext, byte[] keyBytes) throws Exception {
// Get plaintext as ASCII byte array
final byte[] plainBytes;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
plainBytes = plaintext.getBytes(StandardCharsets.US_ASCII);
} else {
plainBytes = plaintext.getBytes("US-ASCII");
}
// Generate triple DES key from byte array
final DESedeKeySpec keySpec = new DESedeKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey key = keyFactory.generateSecret(keySpec);
// Setup the cipher
final Cipher c3des = Cipher.getInstance("DESede/ECB/PKCS5Padding");
c3des.init(Cipher.ENCRYPT_MODE, key);
// Return ciphertext
return c3des.doFinal(plainBytes);
}
PKCS5Padding adds 1-8 bytes of padding when used with DES. If you encrypt 8 bytes you will get 8 additional bytes of padding to get to an even number of blocks.
If you used Cipher.getInstance("DES/ECB/NoPadding") and encrypted 8 bytes, you will get 8 bytes of cipher text.
When PKCS#5 padding is used it must always add padding otherwise on decryption there would be no way to determine if padding was added. So, even if the input data is an exact multiple of the block size padding must be added and that will be 8 bytes.
See PKCS padding:
If the original data is an integer multiple of N bytes, then an extra block of bytes with value N is added. This is necessary so the deciphering algorithm can determine with certainty whether the last byte of the last block is a pad byte indicating the number of padding bytes added or part of the plaintext message. Consider a plaintext message that is an integer multiple of N bytes with the last byte of plaintext being 01. With no additional information, the deciphering algorithm will not be able to determine whether the last byte is a plaintext byte or a pad byte. However, by adding N bytes each of value N after the 01 plaintext byte, the deciphering algorithm can always treat the last byte as a pad byte and strip the appropriate number of pad bytes off the end of the ciphertext; said number of bytes to be stripped based on the value of the last byte.
PKCS#5 padding is identical to PKCS#7 padding, except that it has only been defined for block ciphers that use a 64-bit (8 byte) block size. In practice the two can be used interchangeably.

Android cryptography API not generating safe IV for AES

I'm using javax.crypto to do some cryptographic operations in my application. I use AES for encryption/decryption like this:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] cipherText = cipher.doFinal(plaintext);
byte[] iv = cipher.getIV(); //The problematic IV
The generated IV is prepended to the ciphertext after the enncryption.
The Java specification clearly says that the IV must be generated automatically if its is not provided to cipher.init():
If this cipher requires any algorithm parameters that cannot be derived from the given key, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values)
But sometimes I end up with ciphertexts that don't seem very random, such as this one (in base64):
AAAAAAAAAAAAAAAAAAAAAOmI9Qh1fMiG6HV3tKZK3q5sCruaPdYqYnoUOM00rs6YZY3EvecYfR6vTHzZqk7ugknR9ZMipedYWJB1YOLmSYg=
The bunch of A characters at the front is the IV. The IV is actually 16 zero-bytes.
Most of the time, the library generates proper, random IVs, but sometimes, it just pops out zeros. Why is this happening?
Some (most?) providers simply use a zero-byte filled IV as their default. My emphasis of your quote:
If this cipher requires any algorithm parameters that cannot be derived from the given key, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values)
When you look to the front of your ciphertext, you see that it starts with a bunch of "A" characters. It's Base 64 for 0x00 bytes.
If you want to make sure that you have a random IV, you have to generate it yourself:
SecureRandom r = new SecureRandom();
byte[] ivBytes = new byte[16];
r.nextBytes(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(ivBytes));
The IV is not secure. It is prepended to the cyphertext, so any attacker only has to read the cyphertext and look at the first 16 bytes to see what it is.
It is not a good idea to always use the same IV -- it effectively turns the first block of your actual cyphertext into ECB mode, which is insecure.
I recommend generating your own random IV. You do not need to use a cryptographically secure RNG, since an attacker can see it anyway. You just need to avoid using the same IV for different messages. Even something simple like 8 bytes of random with an 8 byte (64 bit) counter will be enough to avoid the ECB effect. Change the key before the counter rolls over, and reset the counter to 0 when you change the key.

One block cipher decryption with an AES and long key

I was given this key in hex String: "140b41b22a29beb4061bda66b6747e14" and requested to decrypt an one block cipher with an AES implementing a ECB.
As we know, the key must be 16 bytes long. But the given key contains elements which correspond to characters larger than one byte (e.g. 0xb2 whose char value is ² corresponding to 2 bytes).
In fact, if I convert the hex String key into a key String I obtain " A²*)¾´Úf¶t~ ", then if I apply the method key.getBytes().length what I get is that the key is 21 bytes long.
My question is: is there any way to encrypt a 16 bytes long ciphertext with an AES given this key in Java?
Your key looks correctly sized - just don't think of it as a string with meaningful characters. Instead, use a hex conversion method to convert it into a 16 byte array and use that as the key.
E.g.
String keyString = "140b41b22a29beb4061bda66b6747e14";
byte[] keyBytes = DatatypeConverter.parseHexBinary(keyString);
SecretKey key = new SecretKeySpec(keyBytes, "AES");

I encrypt data with 32 byte length using AES algorithm the result(cipher text) is 64 byte length,Is this valid?

I implement this via java , BouncyCastle Provider
use Block mode = ECB and Padding mode = PKCS7Padding
I noticte that if i encrypt data that has 32 byte length(such as 61626162616261626162616261626162 which is hex value of abababababababab) i get 64 bytes length cipher text(f21ee0564ebd5274e10bf4590594b1e16a19592b917b19ee106f71d41d165289) is this cipher text valid? from what i read it look like if you encrypt less than 32 byte length data the algorithm will padding it to 32 byte length and produce a 32 byte length cipher text but if you put in exactly 32 byte length data shouldn't you receive the 32 byte length cipher text ,also if i put in data with more length than 32 byte it will padded to 64 byte cipher text correctly
this is what my code look like :
public static byte[] encrypt(byte[] plainText, byte[] keyBytes)
throws GeneralSecurityException {
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = cipher.doFinal(plainText);
return cipherText;
}
thx for your reply
You are confusing hexadecimal characters and bytes. Two hexadecimal characters can be used to represent a single byte. So your input is likely 16 bytes and your output then becomes 32 bytes. AES is a 128 bits = 16-byte block cipher.
PKCS#7 padding is defined to pad 16 byte block ciphers. To make sure that the last byte of the plain text is not mistaken for padding, PKCS#7 padding always pads. This means that in the unfortunate circumstance that the plain text is dividable by 16, it will add an entire block of padding. The padding consists of a string of bytes indicating the length of the string in each byte, so for your case the padding consists of the following bytes, represented by hexadecimals: 10101010101010101010101010101010.
Note that the default provider of Java uses "PKCS5Padding" instead of "PKCS7Padding". Both are identical, although PKCS#5 padding officially is only for 64 bit = 8 byte block ciphers. Bouncy Castle will accept that string as well, so it is better to specify "PKCS5Padding" for the sake of compatibility.
There is no padding specified for AES that would use 32 bytes as it is only a 16 byte block cipher. It would make sense for Rijndael-256 which is a 32 byte block cipher, but that algorithm hasn't been standardized by NIST and should therefore be avoided.
The PKCS7 padding is explained here:
http://en.wikipedia.org/wiki/Padding_(cryptography)#Byte_padding
It adds between 1 and blockLength bytes, all of which are equal to the size of the padding. This means your message will be padded by 16 16's, creating a 32-byte message that gets subsequently encoded with AES.
Note that your message is 16 bytes, not 32.
In general, a padding of zero length is never used, because it cannot be distinguished from non-zero padding (and the padding must be done in a reversible fashion).

Categories

Resources