Could you help me to point out what is the default RSA padding.
Precisely, if I create cipher instance as below, sure java is using some sort of padding as encrypted text bytes length always shows 256 bytes for 2048 RSA key irrespective of plain text is one characters or 10 characters.
Cipher.getInstance("RSA")
I wanted to know what is default padding java use internally if no padding is specified in Cipher.getInstance("RSA"). is that PKCS#1 v 1.5?
Thanks,
Sam
It's identical to "RSA/ECB/PKCS1Padding" where ECB is a bit of a misnomer, as it does not implement a block cipher mode of operation (it doesn't handle plaintext larger than the "block size"). "RSA/None/PKCS1Padding" would have been a better name or "RSA/None/RSASSA-PKCS1-v1_5" as your guess about the padding mechanism is correct.
This means that it uses a older mode of encryption; OAEP is more resistant against attacks and contains a security proof. Unfortunately OAEP can of course not be made the new default because all existing ciphertext would not decrypt anymore. This is one of the reasons why using defaults is stupid in the first place.
PKCS#1 v1.5 padding also means that the input is restricted to a maximum of the key size minus 11 bytes. Note that the size of the resulting ciphertext is always identical to the key size in PKCS#1; even if the resulting integer is smaller it will be left padded with zero bytes. I'm assuming here that the key size is a multiple of 8.
You should not rely on defaults for the algorithm specification. It makes the code harder to understand and defaults may indeed differ per provider (although most will try to follow Oracle's lead, to avoid incompatibilities). So use this only to understand which algorithm is configured in existing code. The only place where a platform default makes sense is SecureRandom in my opinion.
Related
Im using RSA to encrypt an AES key and some other information. To not be vulnerable to the padding-oracle-attack I instantiate my Cipher the following way:
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
Now in the Oracle documentation (I'm using oracle-java) there are key lengths given: https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
for RSA/ECB/OAEPWithSHA-256AndMGF1Padding it states 1024 and 2048 bits. Does that mean I cannot or should not use this cipher with a key length of 4096? Here's how I generated my key:
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
keygen.initialize(4096, SecureRandom.getInstanceStrong());
KeyPair keyPair = keygen.genKeyPair();
Can I use this key with RSA/ECB/OAEPWithSHA-256AndMGF1Padding?
Yes, you can use it with that key size and most Java providers - including those delivered by default for most runtimes - will be able to handle it.
The two key sizes - of which 1024 should not be used anymore and 2048 is considered rather small - just need to be supported by the default providers delivered by any official Java runtime. However software implementations can generally handle key sizes up to 16Ki bits (that's 16 times 1024 or 16 kibibit, in case you're unfamiliar with the term).
RSA / OAEP has been specified for use with any key size. However, most implementations require that the bit size is a multiple of 8 (to simplify bit / byte conversions), some require 32 bit increments (to simplify implementation using 32 bit integers) and some even require you to use key sizes of the form n = 2^x or n = 2^x + 2^(x-1). Some kind of minimum is obviously required to support the padding scheme as well, so 512 is commonly a lower bound. Some implementations got overly-protective and disallow key sizes smaller than (and sometimes including) 1024 bit.
So as your key is of form 2^x (with x = 12 of course) it is perfectly possible to use it, and the key size is extremely unlikely not to be supported. The unlimited cryptography extensions are not needed for (up to date?) 1.7 versions either, so you don't need to worry about that.
Some hardware modules have severe restrictions on the key size. Smart cards for instance can barely manage 4096 bit keys if they can manage them at all.
For those kind of uses you may want to consider using Elliptic Curve Cryptography instead. In this case you'd require encryption so ECIES which relies on ECDH using Certicom secp256r1 also known as NIST P-256 would be a viable and more secure alternative (until quantum computing becomes of age, in which case you would be screwed faster than with the RSA alternative).
From this on how to achieve password based encryption it is clear that i need to save salt, IV and cipher text in order to decrypt it later.
From this iv and salt can be stored along with cipher text
I am storing the hex value in this format
DatatypeConverter.printHexBinary(salt) + DatatypeConverter.printHexBinary(iv) + DatatypeConverter.printHexBinary(ciphertext);
Do i need to store the values in Binary format ?
DatatypeConverter.printBase64Binary(salt) + DatatypeConverter.printBase64Binary(iv) + DatatypeConverter.printBase64Binary(ciphertext));
output clearly indicates the where the salt , iv is ending which is awful
lIvyAA/PZg4=fE4gTZUCPTrKQpUKo+Z1SA==4/gAdiOqyPOAzXR69i0wlC7YFn9/KOGitZqpOW2y3ms=
Will storing in hex format have any effects of data loss ?
Will the length of IV is constant ? in my case it is always 32 characters (hexadecimal)
Or i need to even store length of IV as well ? as the salt length is fixed initially to 8 bits (16 hexadecimal characters)
(I am using PBKDF2WithHmacSHA1 algorithm for key generation and AES/CBC/PKCS5Padding for cipher)
I think it is worth emphasizing again what the accepted answer above mentioned in passing.
That is, it is unnecessary and unwarranted to make any attempt to hide the salt or the IV. The security of your cryptography is entirely dependent on the secrecy of the secret key, and that of the secret key alone. The IV and the salt can be handed out in clear text along with the ciphertext, and as long as the secret key remains a secret, the ciphertext remains secure.
It's important to understand and accept that, or you will wind yourself about an axle trying to obfuscate things that don't matter. There is no security in obscurity.
It is important to note, however, that the salt should be generated in a cryptographically strong pseudorandom number generator. A new salt should be generated for each new plain text that is being encrypted. Likewise, the IV should be randomly generated for each new ciphertext.
Those parameters need to be independent and unpredictable but need not be secret.
So you can store them in separate fields or delimit them in a single field, or use fixed lengths for the first two of three fields. For maximum flexibility and future proofing, though, I suggest delimited fields, and include all parameters needed to deal with the data. If you are using PBE, I would include the algorithm name and the iteration count, too, rather than rely on default values.
Base64 encodes in chunks of 3 bytes into 4 base64 chars. If the number of bytes that needs to be encoded ain't a multiplum of 3 the last block is padded with one or two =, to indicate that this block ain't full 3 bytes.
As neither the salt nor the IV needs to be kept secret, there really ain't any problem about being able to detect where they start or stop. The base64 padding char = ain't a problem - but you ought to have a way to separate the three encoded strings. You could e.g. simply seperate the parts with a :.
The size of the IV is the same as the block size of your encryption algorithm. In this case you use AES that have a block size of 128 bits, which is 16 bytes. This would give 32 bytes if hex encoded, or 24 bytes if base64 encoded. Salt don't really have a fixed length, and will depend on your implementation.
Can anyone explain the PHP code and give me hints on how to port the code in Java?
Here is the PHP code:
function decode_string($encoded_string, $key) {
$decoded = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encoded_string), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
return $decoded;
}
OK, I'll bite, but I'll let you do the coding:
rtrim(x, "\0"): removes the braindead zero padding (0..15 bytes of zeros) that PHP employs, this to make the plaintext X times the block size, required for CBC. You'll have to program this yourself as it is not present in Bouncy Castle - so don't use any padding mode. Just remove the zero valued bytes at the right of the decrypted plaintext.
mcrypt_decrypt(MCRYPT_RIJNDAEL_256): probably somebody thought that this means AES-256, which it isn't. It is Rijndael with a block size of 256 bits. You need the Bouncy Castle libs in Java to decrypt that non-standardized part of the cipher
MD5($key) somebody needed 256 bits of key material and thought that the hex encoding of the MD5 value over a password was good enough. It isn't, as it only provides half of the entropy (2 hex chars per byte). That and the fact that MD5 is not a password hashing function makes this disingenuous at best
base64_decode($encoded_string): well, expect base 64 encoding, which is alright if the ciphertext needed to be present as ASCII compatible text
MCRYPT_MODE_CBC: that's OK, but as PHP is mainly used as a web language, I expect the message to be vulnerable to padding oracle / plain text oracle attacks, and you should of course expect any alteration of the ciphertext to be undetectable
md5(md5($key)): applying MD5 twice does not make this any more safe than a zero IV and don't forget the hexadecimal conversion performed by each of these functions; fortunately that does mean that the IV is at least 256 bits instead of 128 bits
So you need to use:
new BufferedBlockCipher(new RijndaelEngine(256))
in the lightweight API of Bouncy Castle.
Happy coding, you're good in Java, so this should be a breeze. Upgrade away from this utter crap ASAP.
There were many questions about AES, but I have the following problem.
I'm currently using the following AES implementation to encrypt data
byte [] PRFkey = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
byte [] plaintext = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
SecretKeySpec encryptionKey=new SecretKeySpec(PRFkey, "AES");
Cipher cipher=Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
byte[] encryptedData=cipher.doFinal(plaintext);
And it turned out that result is 32-bytes (256 bits). So I'm using AES-256. This implementation is to slow for me. How can I switch to AES-128? I don't need any padding or mode of operation or key hashing.
Thank you in advance.
You are already using 128-bit AES. This is determined by the length of the key you pass to Cipher.init(), which is sixteen bytes (128 bits) in your example.
The size of your output will depend upon your padding mode (and the size of the input data). Since you neglected to specify an operation mode or padding, your JCE provider has likely defaulted to "AES/ECB/PKCS5Padding". PKCS #5 padding will always add one additional block to the size of your output, hence you received 32 bytes of output and not 16 bytes.
Never allow your provider to select default values for you. Instead, specify the mode and padding explicitly:
Cipher cipher=Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
byte[] encryptedData=cipher.doFinal(plaintext); // will be 16 bytes
Just remember that if you specify no padding, your input data must always be an exact multiple of 16 bytes. Also note that ECB-mode has the property that identical plaintext values will produce identical ciphertext values. This is rarely desirable in a cryptographic system.
A similar question was asked on stack overflow here and will help provide you with the info you are looking for. An important point is that The JCA Reference Guide says that:
(Creating a Cipher Object) If no mode or padding is specified, provider-specific default values for the mode and padding scheme are used. For example, the SunJCE provider uses ECB as the default mode, and PKCS5Padding as the default padding scheme for DES, DES-EDE and Blowfish ciphers. This means that in the case of the SunJCE provider: Cipher.getInstance("DES") and Cipher.getInstance("DES/ECB/PKCS5Padding") are equivalent statements.
Thus since you are only specifying "AES" as the transformation, the default cipher for AES for Oracle JDK 7 is "AES/ECB/PKCS5Padding", link.
Additionally, the Cipher class defines the transformation "AES/ECB/NoPadding" that will get you a non-padded 16 byte value for your encryptedData. ECB is the default mode for AES, you could also choose "AES/CBC/NoPadding".
I'm currently working on a protocol, which uses Diffie-Hellman for an key exchange.
I receive a packet, which consists of an aes-128 encrypted part and a 128 Bit DH Public Key.
In a very last step in the protocol, the aes key is sent to another peer in the network.
This aes-key should be encrypted with a cipher using a 128 bit strong secretkey.
I plan to use Blowfish (can also be another cipher, doesn't really matter for the problem)
Now to encrypt the aes-key, with lets say blowfish, I have to build a secretkey for the encryption with a class called SecretKeySpec (I'm using javax.crypto stuff), which takes an byteArray in the constructor to build the secretKey.
The sharedkey from DH is a 128 Bit BigInteger.
Well, now I can interpret my shared-key as a byteArray (wich gives me still 128 Bit in 16Bytes [where the numbers are interpreted as frames of 8 Bit data])
So my question is, how strong is my key really?
Is there any impact because I only use numbers as input for the byteArray (so does this limit the keyspace in any way?)
I think this is not the case, but I'm not 100% sure.
Maybe someone can do the math and proof me right or wrong.
If I'm wrong what keysize for the shared key give me piece of mind to finally get to the 128Bit SecretKey for the encryption?
The Crypto++ website suggests using a minimum p of 3072 bits (or 256 bits for an ECC implementation) to transport a 128 bit AES key.
You might wish to study the references provided at http://www.keylength.com/en/compare/ for further information about comparing key lengths among different algorithms.
Not an expert in DH here, but to me it seems that DH's keyspace for the shared key represented in n bits is somewhat smaller than 2^n.