What are some of the simplest ways to AES encrypt and decrypt a 16 byte array without the automatic padding? I have found solutions that use external libraries, but I want to avoid that if possible.
My current code is
SecretKeySpec skeySpec = new SecretKeySpec(getCryptoKeyByteArray(length=16)); // 128 bits
Cipher encryptor = Cipher.getInstance("AES");
encryptor.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = encryptor.doFinal(plain);
How can I prevent the padding? The plain data is always fixed length and includes its own padding. How can I allow plain to be 16 bytes without causing encrypted to become 32 bytes?
See my comment. Sorry I probably should have taken a closer look the first time.
Change "AES" to "AES/CBC/NoPadding"
Change decryptor.init(Cipher.DECRYPT_MODE, skeySpec); to decryptor.init(Cipher.DECRYPT_MODE, skeySpec, encryptor.gerParameters());
To encrypt only 16 bytes of data, fixed length, using a method that requires no initialization vector to be saved, Change "AES" to "AES/ECB/NoPadding"
I pick ECB because that is the default.
If you need to encrypt more than 16 bytes, consider using something other than ECB, which suffers a certain repetition detection flaw
In this bitmap example, this image has repeated white blocks, so you can deduce the outline of the image simply by looking for where the blocks become different.
If you are only encrypting one block, it doesn't really matter though, only if you are encrypting multiple blocks that are combined does ECB become revealing.
Related: https://security.stackexchange.com/questions/15740/what-are-the-variables-of-aes
Agree with #rossum, but there's more to it:
CTR mode needs an initialisation vector (IV). This is a "counter" (which is what "CTR" refers to). If you can store the IV separately (it doesn't need to be protected) that would work. You'll need the same IV value when you decrypt the data.
If you don't want to store the IV and you can guarantee that no two values will be encrypted with the same key, it's fine to use a fixed IV (even an array of 0s).
The above is very important because encrypting more than one message with the same key/IV combination destroys security. See the Initialization vector (IV) section in this Wikipedia article:
http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation
An AES CTR implementation of your code might be:
SecretKeySpec skeySpec = new SecretKeySpec(getCryptoKeyByteArray(length=16));
Cipher encryptor = Cipher.getInstance("AES/CTR/NoPadding");
// Initialisation vector:
byte[] iv = new byte[encryptor.getBlockSize()];
SecureRandom.getInstance("SHA1PRNG").nextBytes(iv); // If storing separately
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
encryptor.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
byte[] encrypted = encryptor.doFinal(plain);
CTR mode does not require padding: "AES/CTR/NoPadding".
Related
I need to cipher and decipher text with randomly access. For this I decided to use AES in CTR mode which is a good compromise between CBC and GCM.
But CTR mode is malleable. It is not a big problem because texts that I will cipher have not predefine patterns and I don’t need authentication, I just want to avoid the ability to read the plain text for an attacker.
However, I want to reduce the ability to an attacker to really use the malleability property of CTR.
Here my idea to do it:
public static void main() {
Key key = …;
IVParameterSpec iv = …;
int rSeed = …;
byte[] plainText = …;
byte[] shuffled = shuffle(plainText, rSeed);
byte[] encrypted = encryptAES_CTR(shuffled, key, iv);
…
byte[] decrypted = decryptAES_CTR(encrypted, key, iv);
byte[] unShuffled = unShuffle(decrypted, rSeed);
// Here unShuffled content must be equal to plainText content.
}
Suppose that methods shuffle(…) and unShuffle(…) are complementary and one reverse the other.
The shuffle step is here not to cipher but shuffle the order of bytes of the plain text, in that way it reduces the impact of modifications done on the ciphered text by an attacker because if an attacker changes a part of the ciphered text, the modifications will be spread during the unShuffle phase and will change the content but the chance that the new content can be exploitable is reduced.
However, it is just an idea and I write this post just to know if this idea is really useful or if it is useless and just superficial step which does not reduce the impact of modifications that can be done by an attacker on the ciphered text.
I know that there is the GCM which provides authentication and therefore, is not malleable. But I don’t really need it and GCM cannot be accessed randomly especially if I want modify and re cipher just a part of the plain text.
Hello and sorry in advance for my broken English.
I would like in a project to realize several different encryption from a character string.
So I turned to the counter mode of AES (which I have already used in python without any problem)
But when I use the program below twice on the same string the result is exactly the same.
I probably don't understand how AES works. But I wonder if the counter increments by itself or not.
I tried to use an Iv but must I increment it myself to have a different result?
Here's a sample code:
String key = "thisisa128bitkey";
Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(gu.getGraine().getBytes());
System.out.println("first id : "+Base64.encodeToString(encrypted,Base64.DEFAULT));
byte[] encrypted2 = cipher.doFinal(gu.getGraine().getBytes());
System.out.println("second id: "+Base64.encodeToString(encrypted2,Base64.DEFAULT));
Here gu.getGraine() is a simple string.
For display the two values are identical
Thanks in advance for your time.
The counter is incremented every time a new block (AES is a block cipher) needs to be encrypted. When you feed data into the Cipher object through update or doFinal then it decides internally whether the current block is full and the counter needs to be incremented for further blocks.
I assume that you want different encryptions of the same plaintext to result in different ciphertexts. When you initialize Cipher, you can either pass in your own IV (which defines the initial internal counter) or not specify the IV at all. When omitting the IV, it is internally randomly generated and accessible to you through Cipher#getIV.
Calling Cipher#doFinal resets all internal values to their initial positions after the encryption is finished. When you call it again with the same data on the same Cipher instance the previously generated IV will be used again from the beginning. If you want to have a fresh IV, you need to re-initialze the Cipher instance.
Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec); // generates an IV
byte[] encrypted = cipher.doFinal(gu.getGraine().getBytes());
System.out.println("first id : "+Base64.encodeToString(encrypted,Base64.DEFAULT));
cipher.init(Cipher.ENCRYPT_MODE, skeySpec); // generates a different IV
byte[] encrypted2 = cipher.doFinal(gu.getGraine().getBytes());
System.out.println("second id: "+Base64.encodeToString(encrypted2,Base64.DEFAULT));
Keep in mind that you need the IV later for decryption. The IV is not supposed to be secret and needs only be unique for CTR mode and with the same key. The IV can be set to a static value when it is guaranteed that the key changes for each encryption.
I read some examples about using Java Cipher to encrypt and decrypt data. For example:
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = new SecureRandom();
keyGenerator.init(256, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, secretKey);
I have 2 questions about the decryption process.
Although an IV is required, we can leave it implicit by using Cipher.init(Cipher.ENCRYPT_MODE, Key). A random IV will be automatically applied to it. However, in decryption mode, the same IV must be used. Does it mean only the Cipher.init(int opmode, Key key, AlgorithmParameters params) should be used and the IV should be get from the encryption, stored and passed here?
Beside the '''KeyGenerator''', I also saw the example to generate key with '''SecretKeyFactory''':
String key = ...
SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
SecretKeySpec keySpec = factory.generateSecret(new DESKeySpec(key));
I suppose I can use it for AES if I change last line to
SecretKeySpec keySpec = factory.generateSecret(new SecretKeySpec(key,"AES"));
I am confused about when to use SecretKeyFactory to generate a key and when to use KeyGenerator. It seems the latter is generate a random key, the former is generated from a given key material. So does it mean in decryption mode, only SecretKeyFactory can be used?
Does it mean only the Cipher.init(int opmode, Key key, AlgorithmParameters params) should be used and the IV should be get from the encryption, stored and passed here?
Yes, exactly that, unless you are able to communicate it in other ways. Generally though the IV is randomized during encryption, then prefixed to the ciphertext. For AES-CBC it is always the same size as the block size: 16 bytes.
So does it mean in decryption mode, only SecretKeyFactory can be used?
Yes, although for AES there is a neat little shortcut; you can simply do:
SecretKey aesKey = new SecretKeySpec(keyBytes, "AES");
and be done with it. This is because SecretKeySpec implements SecretKey. For 3DES keys that's not a good idea because it would mean that the parity bits of DES are not set correctly. However, modern keys such as AES keys and HMAC keys solely consist of random data, so for those it is fine. There is one caveat: it will be a problem if you try and generate a key in a hardware device that way: it must be kept in software.
Note that I won't delve too much in key management and how keys need to be created. I've answered that question here, although that answer is certainly far from complete. Heck you could use dice and share the numbers over the phone for all I care :)
I am encrypting in ojb-c with SecKeyEncryptedData and trying to decrypt in Java with javax.Cipher and hitting a problem.
I recently moved to doing long blocks and have needed to use a symmetric encryption with the AES key encrypted with the asymmetric key pair. I am having problems decoding.
I have the iOS key kSecKeyAlgorithmRSAEncryptionPKCS1 working for asymmetric data matched with Cipher.getInstance("RSA/ECB/PKCS1Padding") in Java. This decodes the short blocks.
As I need to send longer blocks, and am trying to switch to kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM on iOS and it encrypts fine, but i cannot find the method to use in Cipher to decrypt it and do not understand if it needs to be done in 2 steps in the cloud in Java.
OBJ-C:
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM;
NSData* cipherText = nil;
cipherText = (NSData*)CFBridgingRelease( // ARC takes ownership
SecKeyCreateEncryptedData(self.pubKey, algorithm,
(__bridge CFDataRef)data, &error));
Java:
try {
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, priv);
byte[] dog = decoder.decode(encString);
dec = cipher.doFinal(dog);
res = new String(dec);
} // handle errors
The decode obviously fails.
So my question is in 2 parts.
is there a Cipher type that will do the decode needed or do i need to break out the encrypted AES key and decrypt it first?
If i need to break it up, how long is that encrypted AES key part of the data block and, if you know the ciphers for that it would be fantastic.
is there a Cipher type that will do the decode needed
You may read the Cipher documentation. I believe you are looking for RSA/ECB/OAEPWithSHA-256AndMGF1Padding
I see the designation doesn't exacly match with the Obj-C name, but this is a common standard so it may worth a try
As I need to send longer blocks, and am trying to switch to kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM
You may try to search for "hybrid encryption". Asymmetric ciphers are VERY slow comparing to symmetric ciphers and intended to encrypt only limited amount of data.
Some implementation may encrypt longer data anyway (for each 256 bit input providing 2048 o 4096 bit output), Java will simply complain and stop
So proper encryption would be
encrypt data with a radom key (DEK - data encryption key) using a symmetric cipher
encrypt the DEK using an asymmetric public key
If the kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM would be not counterpart (compatible) with RSA/ECB/OAEPWithSHA-256AndMGF1Padding, you may still use the PKCS#1 1.5 padding (the old one) with this approach.
Edit: this asnwer may be useful when working with OAEP too RSA/ECB/OAEPWithSHA-256AndMGF1Padding but with MGF1 using SHA-256?
I am trying to do AES encryption in Java. I have the following function:
public static String encrypt(String plainText, String key) throws Exception {
if (plainText == null || plainText.length() == 0) {
return plainText;
}
// get aes key
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
// encrypt
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] bytes = cipher.doFinal(plainText.getBytes("UTF-8"));
//encode
String encoded = Base64.encodeToString(bytes, Base64.NO_PADDING | Base64.NO_WRAP);
return encoded;
}
My aim is to be able to encrypt some text with a given key the same way every time. That is, if I call this function with the same two parameters many times, I want the same string to be returned on every call. I'll say in advance, I know that is not how cryptography is supposed to be done, but I need this functionality for my project.
Unfortunately, that is not the case. The key generated in line 7 seems to encrypt my string differently every time around. I assume there is some kind of extra random automatic salting occurring on the lower levels of this library, preventing me from achieving my goal.
Does anyone know a way in Java how I could go about encrypting a given string with a given key to the same value every time? Thanks.
UPDATE/CLARIFICATION: This is not for security. This is for the encryption of data for it to be obfuscated for certain people that might come in contact with working on the app itself. The information is not highly sensitive, but I do want it encrypted and then decrypted by the same key. I have others working with me on this with libraries in their respective languages, e.g. Ruby, and their libraries allow them to encrypt a value with a given key the same way every time. We all want to use the same parameters of the same encryption algorithm: Key length: 128 bits
Mode of operation: CBC
Initialization Vector: None (all zeros)
Is it perhaps that if one does not set an initialization vector, it is randomly assigned? I've got to check that out.
Yes, Java - or rather the security provider supplying the AES in CBC mode implementation - may default to a random IV (which you then have to retrieve afterwards and include with your ciphertext) if you don't explicitly specify it you get secure, randomized ciphertext.
If you want to use a zero IV you will have to specify it explicitly:
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]);
This is only slightly more secure than ECB mode, as any repetition in different messages in the initial ciphertext blocks will be instantly visible to an attacker.
If you want to have a more secure mode without random IV - which is required for CBC mode to obtain CPA security - then you could check out synthetic IV (SIV) mode or GCM-SIV. For those modes the entire message needs to be identical with a previous one to leak info to an attacker. It's however slowe, not included in the standard VM and the ciphertext could be larger than AES/CBC (inclusion of IV/tag vs padding requirements).