Getting a RSA Cipher's block size - java

I have created a Cipher using the RSA algorithm and I have a problem when I want to get the block size used. The Cipher is declared with the following snippet :
encrypt=Cipher.getInstance("RSA");
encrypt.init(Cipher.ENCRYPT_MODE,myPublicKey);
When I try to get the block size with encrypt.getBlockSize(), I get "0" which, according to the Javadoc, is the answer when the algorithm used isn't a block cipher, which is not the case of the RSA algorithm.
In debug mode, if I dig into the Cipher, I can see in the 'spi' member that a buffer exists, and it's size seems to correspond to the actual block size.
Does anybody know why getBlockSize() returns "0" instead of the spi's buffer size?

RSA is not considered a block cipher. Block ciphers are symmetric, using the same key to encrypt and decrypt. Unlike AES, where the block size is fixed regardless of the key size, the output of an RSA encryption or signature operation will vary depending on the key size.
If you want to know the size of an RSA cipher text, examine the modulus of the key to be used.

The interface of the Cipher class does not reveal the allowed input data size and it depends in a non-trivial way from the modulus bit length and applied padding algorithm.
There are the options:
[Sun Java] encrypting a block with more than modulus length will raise a IllegalBlockSizeException with a message "Data must not be longer than [n] bytes", may be parsed.
[Sun Java] Use reflection to access the length of member buffer of Cipher implementation class RSACipher
[Common] Use a search algorithm to evaluate the maximum allowed input data size, not raising an IllegalBlockSizeException.

Related

How to store iv, salt and cipher text?

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.

What size of initialization vector needed for AES-256 encryption in java?

I am using AES-256 encryption with CFB mode. I have to use 32 byte key.
But I am little bit confused about the initialization vector.
How many bytes of initialization vector should be used with AES-256 ?
Is it 16 bytes or 32 bytes ?
Any code example will be appreciated.
TL;DR: AES in CFB mode requires a unique (but not necessarily randomized) IV of 16 bytes.
The size of the IV depends on the mode, but typically it is the same size as the block size, which for AES is always 16 bytes. There are modes that differ from this, notably GCM mode which has a default size of 12 bytes but can take any sized IV - although keeping to the default is highly recommended.
The old school modes such as CBC and CFB however simply require an IV of the same size as the block size. Even CTR commonly requires 16 bytes, although in principle the IV can be any size less than 16, in which case it is (again, commonly) right padded with zero valued bytes. Note that CTR is often initialized with an initial counter value which means you must make sure that the counter is not repeated yourself.
The block size of AES is 16 bytes, whatever the key size. Saying that you have AES-256 and a key of 32 bytes is superfluous information. For AES-256 the key size must be 256 bits or 32 bytes.
The IV for CFB mode - as stated earlier - must always be 16 bytes as AES is a 128 bit block cipher. AES is restricted with regards to the block size compared with the Rijndael cipher. Rijndael may be configured with different block sizes.

Default RSA padding in SUN JCE/Oracle JCE

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.

How to switch from AES-256 to AES-128?

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".

Encrypted data length is very large with RSA

I want that encrypted data have the same length as my original text, because I must respect the constraint of length. I am using BouncyCastle.
Here's my code to generate the keys pair:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(512);
KeyPair keypair = keyGen.genKeyPair();
PublicKey pub = keypair.getPublic();
byte[] pubs = pub.getEncoded();
And here's my code to encrypt:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
PublicKey pk = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pubs));
cipher.init(Cipher.ENCRYPT_MODE, pk);
byte[] cipherBytes = cipher.doFinal(plainArray);
The encoded data is very large, what can I do to make as small as original data ?
Nothing, at least not regarding the RSA. RSA requires a certain amount of padding to be secure, and as the data will be seen as random data by any compression method, you cannot compress it either.
Of course, you should not directly encrypt data directly using RSA, you should encrypt a random session/data key instead. But even then, you will have the encrypted session key as overhead.
You can remove some bits for the asymmetric encrypted data/key by using Elliptic Curve Cryptography (the output of which is double the key size minimum, but key sizes are much smaller to achieve the same level of security). EC cryptography is not for the meek though, it has lots of complexity.
512 bit RSA is considered insecure by the way. Use 1024 as minimum or keep to the ECRYPT II or NIST recommendations listed at http://www.keylength.com/ .
If you can keep the key secret, you can use a symmetric cryptosystem like AES. If used in CFB mode, it can be adapted to any bit length. I.e. #bits input & output is identical.
RSA and ElGamal -- the main public-key cryptosystems-- can be broken in a matter of hours even at 512 bits as you are selecting. 1024 - 4096 bits is normal. Less than 512 bits is worthless unless your opponent is limited to using 1990s hardware. :-)
The nature of RSA is such that you use exponentiation in encryption and decryption.
Basically, for public key e and private key d, you take a message m and then you get a compressed message equal to c=m^e and mod it by n. Then you decrypt with m=c^d and again mod it by n (mod means take the remainder).
If you think about it, a message to the power of something results in a larger number. Because you do a mod n, you end up with a number that is at most n-1. n is the key length.
So basically, whatever message you take, you encrypt to something as large as n. The message has to be less than n.
But the message has to be turned into an integer using a padding scheme (so you can do the exponentiation). This padding scheme may require less than n bits. And so, you end up with larger files than the size of the data being encrypted. Also, the last chunk may be less than n bits, but will encrypt into size n.

Categories

Resources