With symmetric ciphers, encryption and decryption speed can be several gigabytes per seconds on a common PC core, with RSA encryption, on comparable hardware, we are talking tens of thousands encryptions per second, and only few hundreds of decryption per seconds, for common key sizes, and small messages (like 1 bit to 250 bytes, way enough for a session keys and authenticators).
The distinguishing technique used in public key cryptography is the use of asymmetric key algorithms, where the key used to encrypt a message is not the same as the key used to decrypt it. Each user has a pair of cryptographic keys—a public encryption key and a private decryption key. The publicly available encrypting-key is widely distributed, while the private decrypting-key is known only to the recipient. Messages are encrypted with the recipient's public key and can only be decrypted with the corresponding private key. The keys are related mathematically, but the private key cannot feasibly (ie. in actual or projected practice) be derived from the public key. The discovery of algorithms that could produce public/private key pairs revolutionized the practice of cryptography beginning in the middle 1970s.
RSA has some operational constraints. With the most used variant (the one known as PKCS#1 v1.5), if the size of the RSA key is "1024 bits" (meaning that the central mathematical component of the key pair is a 1024-bit integer), then RSA can encrypt a message up to 117 bytes in length, and yields an encrypted message of length 128 bytes. That limited size, and the size increase when encrypting, are unavoidable consequences of the mathematical structure of the RSA encryption process. Due to these constraints, we do not usually encrypt data directly with RSA; instead, we select a small sequence of random bytes, which we call session key. We encrypt the session key with RSA; and then we use the session key with a symmetric encryption algorithm to process the whole message. This is called hybrid encryption.
The distinguishing technique used in public key cryptography is the use of asymmetric key algorithms, where the key used to encrypt a message is not the same as the key used to decrypt it. Each user has a pair of cryptographic keys—a public encryption key and a private decryption key. The publicly available encrypting-key is widely distributed, while the private decrypting-key is known only to the recipient. Messages are encrypted with the recipient's public key and can only be decrypted with the corresponding private key. The keys are related mathematically, but the private key cannot feasibly (ie. in actual or projected practice) be derived from the public key. The discovery of algorithms that could produce public/private key pairs revolutionized the practice of cryptography beginning in the middle 1970s.
RSA has some operational constraints. With the most used variant (the one known as PKCS#1 v1.5), if the size of the RSA key is "1024 bits" (meaning that the central mathematical component of the key pair is a 1024-bit integer), then RSA can encrypt a message up to 117 bytes in length, and yields an encrypted message of length 128 bytes. That limited size, and the size increase when encrypting, are unavoidable consequences of the mathematical structure of the RSA encryption process. Due to these constraints, we do not usually encrypt data directly with RSA; instead, we select a small sequence of random bytes, which we call session key. We encrypt the session key with RSA; and then we use the session key with a symmetric encryption algorithm to process the whole message. This is called hybrid encryption.
- Provides authenticity of the source Allows message authentication) - As public key encryption allows using digital signatures, message recipients will be able to verify messages to be truly coming from a particular sender.
- It is convenient (Private keys are never exposed) - Asymmetric encryption solves the problem of distributing keys for encryption, with everyone publishing their public keys, while private keys being kept secret.
- It allows for non-repudiation - Digitally signed messages are like physically signed documents. Basically, it is like acknowledging a message, and therefore, the sender will not be able to deny it.
- It detects tampering - With digital signatures in public key encryption, message recipients can detect if a message was altered in transit.
Disadvantages of Asymmetric
Cryptography
- It is a slow process - Very slow compared to symmetric cryptography (100 to 1000 times slower)Public key encryption in this method is slow compared with symmetric encryption, which means that it is not suitable for decrypting bulk messages.
- Size of encrypted data limited by performance considerations - Not suitable for encrypting large amounts of data
- Public key management (public keys are not authenticated) - Basically, no one absolutely knows that a public key belongs to the individual it specifies, which means that users will have to verify that their public keys truly belong to them.
- It risks loss of private key, which may be irreparable - When you lose your private key, your received messages will not be decrypted.
- It risks widespread security compromise - If your private key is identified by an attacker, all of your messages can be read by him/her.
Diffie-Hellman : Actually it mathematically helps two parties which involves in the communication to generate a Secret Key(symmetric key) at each side which are identical and same. this key is used for encrypt and decrypt at both sides. Diffe-Hellman is used for key exchange using the concept of primitive root and then both parties use that common key for subsequent data exchange using symmetric key encryption.
RSA : Actually it mathematically helps two parties which involves in the communication to generate a pair of keys (public and private) at each side, where public key is used for encrypt and private key is used for decrypt. RSA algorithm is used for actual asymmetric key encryption . It generates public-private key pair and then use them for exchanging data.RSA isn't really built to encrypt large pieces of plaintext
RSA isn't well suited for encrypting large data sizes. The usual approach would be to use a symmetric cipher like AES or Triple-DES, and then to use RSA just to encrypt the AES/Triple-DES key (like PGP a Hybrid Crypto System (Symmetric & Asymmetric) ). RSA can only be used to encrypt data that is no longer than the RSA key size. With a key size of 2048 bits that would be somewhat less than 256 bytes. We could use an even larger key size, but that would make the process rather slow.
Each RSA "round" can encrypt 117 bytes of data, and to encrypt more, you'd have to use some chaining mode. Currently, this means extra overhead, slowness (remember, RSA is pretty slow), and security uncertainty (RSA-chaningMode hasn't been scrutinized as other types of encryption schemes).
Hybrid approach of using RSA
- Not only is RSA too slow to use on bulk data, but it even has certain weaknesses that can be exploited in some special cases of particular kinds of messages that are fed to the RSA cipher, even for large keys.
- These special cases can be avoided by using the hybrid approach of using RSA to encrypt random session keys for a conventional cipher, like PGP does. So the bottom line is this: Using pure RSA on bulk data is the wrong approach, period. It's too slow, it's not stronger, and may even be weaker.
- The additional mechanisms performed by PGP (compression and random key generation) rather than any difference in the performance of the encryption algorithms themselves.
- We also note that Diffie-Hellman marginly outperforms RSA, which is directly in contradiction with earlier findings where RSA was significantly faster. This second point might be the result of the initialisation phase of RSA being more costly and so on a very small amount of data (the randomly generated key), it becomes less efficient than Diffie-Hellman.
- Size of cryptogram: symmetric encryption does not increase the size of the cryptogram (asymptotically), but asymmetric encryption does. If we take the example of RSAES-OAEP in PKCS#1v2 with a 1024-bit key and 160-bit SHA-1 hash, a 1024-bit cryptogram can convey a maximum of 688 bit of useful information. Thus data enciphered in this way would cost 49% more space to store, or more time to move over a given link.
- Performance: on a modern CPU with hardware AES support, encryption or decryption speed is over 2000 megabyte/second (per core); while decryption of a 1024-bit cryptogram in the above scheme can perhaps run at 4000 per second (per thread of a comparable CPU), thus a throughput of 0.4 megabyte/second, 5000 times slower; that's also moreless the ratio of power usage. That ratio tends to get even worse as security increases. While there are more efficient schemes, it is safe to say that a symmetric scheme is orders of magnitude faster and less power hungry than an asymmetric one, at least for decryption (some asymmetric schemes, including RSA with low public exponent, are considerably faster on the encryption side than they are on the decryption side, and can approach the throughput of some symmetric cryptography).
RSA encryption (publickey/privatekey) is powerful encryption but its really only meant to encrypt small things like other encryption keys. The maximum size of the amount of data an rsa public key can encrypt is: (key_size/8).floor - 11 i,e It can only encrypt data that has a maximum byte length of the RSA key length in bits divided with eight minus eleven padding bytes, i.e. number of maximum bytes = key length in bits / 8 - 11. RSA encryption usually is only used for messages that fit into one block.
- 1024-bit RSA key invocation can encrypt a message up to 117 bytes, and results in a 128-byte value
- 2048-bit RSA key invocation can encrypt a message up to 245 bytes
No.
|
RSA Key Size
|
Max Bytes =
[Key length / 8) - 11 |
Data Size
|
Key Initialize Time
|
Encrytpion Time
|
Decryption Time
|
1
|
1024 bits
|
(1024/8) - 11 = 117
|
117 bytes
|
0.359 Secs
|
0.234 Secs
|
0.007 Secs
|
2
|
2048 bits
|
(2048/8) - 11 = 245
|
245 bytes
|
0.734 Secs
|
0.249 Secs
|
0.016 Secs
|
3
|
3072 bits
|
(3072/8) - 11 = 373
|
373 bytes
|
3.262 Secs
|
0.254 Secs
|
0.016 Secs
|
4
|
4096 bits
|
(4096/8) - 11 = 501
|
501 bytes
|
3.984 Secs
|
0.250 Secs
|
0.052 Secs
|
5
|
5120 bits
|
(5120/8) - 11 = 629
|
629 bytes
|
5.584 Secs
|
0.315 Secs
|
0.172 Secs
|
6
|
6144 bits
|
(6144/8) - 11 = 757
|
757 bytes
|
11.265 Secs
|
0.280 Secs
|
0.203 Secs
|
7
|
7168 bits
|
(7168/8) - 11 = 885
|
885 bytes
|
40.832 Secs
|
0.282 Secs
|
0.282 Secs
|
8
|
8192 bits
|
(8192/8) - 11 = 1013
|
1013 bytes
|
42.861 Secs
|
0.249 Secs
|
0.384 Secs
|
9
|
9216 bits
|
(9216/8) - 11 = 1141
|
1141 bytes
|
66.939 Secs
|
0.243 Secs
|
0.549 Secs
|
10
|
10240 bits
|
(10240/8)-11 = 1269
|
1269 bytes
|
93.505 Secs
|
0.115 Secs
|
0.688 Secs
|
11
|
11264 bits
|
(11264/8)-11 = 1397
|
1397 bytes
|
45.006 Secs
|
0.195 Secs
|
0.921 Secs
|
12
|
12288 bits
|
(12288/8)-11 = 1525
|
1525 bytes
|
403.526 Secs
|
0.250 Secs
|
1.155 Secs
|
13
|
13312 bits
|
(13312/8)-11 = 1653
|
1653 bytes
|
216.144 Secs
|
0.305 Secs
|
1.476 Secs
|
14
|
14336 bits
|
(14336/8)-11 = 1781
|
1781 bytes
|
123.481 Secs
|
0.325 Secs
|
1.827 Secs
|
15
|
15360 bits
|
(15360/8)-11 = 1909
|
1909 bytes
|
1601.172 Secs
|
0.315 Secs
|
2.232 Secs
|
RSA Decryption Benchmark in Java
import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.Calendar; import javax.crypto.Cipher; public class RSAUtil { private static PrivateKey privateKey; private static PublicKey publicKey; public static PublicKey getPublicKey(String base64PublicKey){ PublicKey publicKey = null; try{ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(base64PublicKey.getBytes())); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); publicKey = keyFactory.generatePublic(keySpec); return publicKey; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeySpecException e) { e.printStackTrace(); } return publicKey; } public static PrivateKey getPrivateKey(String base64PrivateKey){ PrivateKey privateKey = null; PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64PrivateKey.getBytes())); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } try { privateKey = keyFactory.generatePrivate(keySpec); } catch (InvalidKeySpecException e) { e.printStackTrace(); } return privateKey; } public static byte[] encrypt(String data) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data.getBytes()); } public static String decrypt(byte[] data) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return new String(cipher.doFinal(data)); } public static String decrypt(String data) throws Exception { return decrypt(Base64.getDecoder().decode(data.getBytes())); } public static void main(String[] args) { generateKeyAndRandomData(1024*1, 117); generateKeyAndRandomData(1024*2, 245); generateKeyAndRandomData(1024*3, 373); generateKeyAndRandomData(1024*4, 501); generateKeyAndRandomData(1024*5, 629); generateKeyAndRandomData(1024*6, 757); generateKeyAndRandomData(1024*7, 885); generateKeyAndRandomData(1024*8, 1013); generateKeyAndRandomData(1024*9, 1141); generateKeyAndRandomData(1024*10, 1269); generateKeyAndRandomData(1024*11, 1397); generateKeyAndRandomData(1024*12, 1525); generateKeyAndRandomData(1024*13, 1653); generateKeyAndRandomData(1024*14, 1781); generateKeyAndRandomData(1024*15, 1909); } private static void generateKeyAndRandomData(int keyInBits, int randomDataSize) { try { System.out.println("###################################"); String data = getAlphaNumericString(randomDataSize); long start = Calendar.getInstance().getTimeInMillis(); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); System.out.println("Key Length : "+keyInBits + " bits/" + (keyInBits / 8) + " bytes, Plain Data Length :"+randomDataSize); keyGen.initialize(keyInBits); KeyPair pair = keyGen.generateKeyPair(); privateKey = pair.getPrivate(); publicKey = pair.getPublic(); long end = Calendar.getInstance().getTimeInMillis(); System.out.println("Key Generation Time Taken in MilliSec: " + (end - start)); start = Calendar.getInstance().getTimeInMillis(); String encryptedString = Base64.getEncoder().encodeToString(encrypt(data)); //System.out.println(encryptedString); end = Calendar.getInstance().getTimeInMillis(); System.out.println("Encryption Time Taken in MilliSec: " + (end - start)); start = Calendar.getInstance().getTimeInMillis(); String decryptedString = decrypt(encryptedString); //System.out.println(decryptedString); end = Calendar.getInstance().getTimeInMillis(); System.out.println("Decryption Time Taken in MilliSec: " + (end - start)); } catch (Exception e) { System.err.println(e.getMessage()); } } // function to generate a random string of length n static String getAlphaNumericString(int n) { // chose a Character random from this String String AlphaNumericString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "abcdefghijklmnopqrstuvxyz"; // create StringBuffer size of AlphaNumericString StringBuilder sb = new StringBuilder(n); for (int i = 0; i < n; i++) { // generate a random number between 0 to AlphaNumericString variable length int index = (int) (AlphaNumericString.length() * Math.random()); // add Character one by one in end of sb sb.append(AlphaNumericString.charAt(index)); } return sb.toString(); } }Output :
################################### Key Length : 1024 bits/128 bytes, Plain Data Length :117 Key Generation Time Taken in MilliSec: 443 Encryption Time Taken in MilliSec: 343 Decryption Time Taken in MilliSec: 3 ################################### Key Length : 2048 bits/256 bytes, Plain Data Length :245 Key Generation Time Taken in MilliSec: 494 Encryption Time Taken in MilliSec: 1 Decryption Time Taken in MilliSec: 16 ################################### Key Length : 3072 bits/384 bytes, Plain Data Length :373 Key Generation Time Taken in MilliSec: 486 Encryption Time Taken in MilliSec: 1 Decryption Time Taken in MilliSec: 27 ################################### Key Length : 4096 bits/512 bytes, Plain Data Length :501 Key Generation Time Taken in MilliSec: 2074 Encryption Time Taken in MilliSec: 1 Decryption Time Taken in MilliSec: 52 ################################### Key Length : 5120 bits/640 bytes, Plain Data Length :629 Key Generation Time Taken in MilliSec: 19014 Encryption Time Taken in MilliSec: 2 Decryption Time Taken in MilliSec: 109 ################################### Key Length : 6144 bits/768 bytes, Plain Data Length :757 Key Generation Time Taken in MilliSec: 15109 Encryption Time Taken in MilliSec: 2 Decryption Time Taken in MilliSec: 165 ################################### Key Length : 7168 bits/896 bytes, Plain Data Length :885 Key Generation Time Taken in MilliSec: 108552 Encryption Time Taken in MilliSec: 2 Decryption Time Taken in MilliSec: 256 ################################### Key Length : 8192 bits/1024 bytes, Plain Data Length :1013 Key Generation Time Taken in MilliSec: 71350 Encryption Time Taken in MilliSec: 3 Decryption Time Taken in MilliSec: 372 ################################### Key Length : 9216 bits/1152 bytes, Plain Data Length :1141 Key Generation Time Taken in MilliSec: 34918 Encryption Time Taken in MilliSec: 4 Decryption Time Taken in MilliSec: 527 ################################### Key Length : 10240 bits/1280 bytes, Plain Data Length :1269 Key Generation Time Taken in MilliSec: 65355 Encryption Time Taken in MilliSec: 5 Decryption Time Taken in MilliSec: 704 ################################### Key Length : 11264 bits/1408 bytes, Plain Data Length :1397 Key Generation Time Taken in MilliSec: 522685 Encryption Time Taken in MilliSec: 5 Decryption Time Taken in MilliSec: 930 ################################### Key Length : 12288 bits/1536 bytes, Plain Data Length :1525 Key Generation Time Taken in MilliSec: 30906 Encryption Time Taken in MilliSec: 7 Decryption Time Taken in MilliSec: 1239 ################################### Key Length : 13312 bits/1664 bytes, Plain Data Length :1653 Key Generation Time Taken in MilliSec: 26756 Encryption Time Taken in MilliSec: 7 Decryption Time Taken in MilliSec: 1512 ################################### Key Length : 14336 bits/1792 bytes, Plain Data Length :1781 Key Generation Time Taken in MilliSec: 1839642 Encryption Time Taken in MilliSec: 8 Decryption Time Taken in MilliSec: 1867 ################################### Key Length : 15360 bits/1920 bytes, Plain Data Length :1909 Key Generation Time Taken in MilliSec: 577723 Encryption Time Taken in MilliSec: 10 Decryption Time Taken in MilliSec: 2517
What is the maximum length of private and public RSA keys?
- In theory, there is no limit. In practice, there is a limit. Also, limits are usually imposed on the modulus size (n = p*q), and not the public or private key per se.
- For OpenSSL and RSA, your RSA keys are limited to 16K at generation. There's also a limit imposed by OpenSSL's s_client utility used during key exchange. The limit during key exchange is 2K, and it seems artificially low to me. You can side-step the s_client limit by avoiding key transport schemes used during key agreement (i.e., use DH or EDH instead of RSA).
- If you start hitting the limits, then it usually indicates its time to switch to elliptic curves. 16K RSA and 521-bit EC provides about 512-bits of security.
Note : The NIST recommends 2048-bit keys for RSA. An RSA key length of 3072 bits should be used if security is required beyond 2030. NIST key management guidelines further suggest that 15360-bit RSA keys are equivalent in strength to 256-bit symmetric keys.
A larger key increases the maximum number of bytes that we can encrypt at once, and also the security of the encryption. But it has a serious problem in practice:
- With every doubling of the RSA key length, decryption is 6-7 times times slower.
- The key length also affects the speed of encryption, but it's usually the speed of decryption that we're more concerned about because (a) that's the part that takes place on the server, and (b) decryption is much much slower than encryption, because the decryption exponent is huge whereas the encryption exponent is typically small.
- If we use a 4096-bit modulus, it takes around a second of CPU time to decrypt a block of data. Even if you were able to sacrifice this amount of CPU to every log on, it leaves us with the problem that an attacker can effectively burn a second of CPU time on our server by firing some random data at it. With a 1024-bit key length, decryption takes just 25 milliseconds; with suitable restrictions on the rate of login attemps (and thus decryptions) we allow per remote client, protecting against a "CPU burn" attack is more feasible.
Maximum Key Length Allowed by JCE
Implicit include bunch of random bytes using SecureRandom:
Plain Text : Give me the same result
Cipher Text 1 : ZjDokVp31oFX+cjaVA2IP0ljtWlNZmzolPn96Q9osbxBJ2P/qCPologKfHHT8lf............................
Cipher Text 2 : ZjDokVp31oFX+cjaVA2IP0ljtWlNZmzolPn96Q9osbxBJ2P/qCPologKfHHT8lf............................
Where RSA Algorithim would be Use :
If we will check the set of algorithms that cipher suites usually contain include: a key exchange algorithm, a bulk encryption algorithm, and a message authentication code (MAC) algorithm.
Structure of Cipher Suite : Protocol_keyexchange_keyauthentication_WITH_bulkencryption_effectivebits_ciphermode_messageauth, where RSA will always be found for Key Authentication but not for bulk encryption.
Hybrid approach of using RSA (Encrypt the data with a symmetric key like AES, and encrypt that symmetric AES key with Asymmetric key like RSA)
Step 1 : Generate a symmetric key(AES with 128 bits)
Step 5 : Decrypt the encrypted symmetric key with RSA private key
import java.security.Security; import java.util.Set; import javax.crypto.Cipher; public class CheckKeySize { public static void main(String[] args) { try { SetOutput :algorithms = Security.getAlgorithms("Cipher"); for(String algorithm: algorithms) { System.out.printf("%-30s: %dbit%n", algorithm, Cipher.getMaxAllowedKeyLength(algorithm)); } } catch (Exception e) { e.printStackTrace(); } } }
PBEWITHHMACSHA384ANDAES_128 : 2147483647bit AES_256/GCM/NOPADDING : 2147483647bit AES_192/GCM/NOPADDING : 2147483647bit PBEWITHHMACSHA512ANDAES_128 : 2147483647bit AES_256/CBC/NOPADDING : 2147483647bit AES_256/ECB/NOPADDING : 2147483647bit PBEWITHHMACSHA224ANDAES_256 : 2147483647bit AES_128/CBC/NOPADDING : 2147483647bit AESWRAP_192 : 2147483647bit AESWRAP : 2147483647bit PBEWITHMD5ANDDES : 2147483647bit AES_192/CBC/NOPADDING : 2147483647bit PBEWITHHMACSHA256ANDAES_256 : 2147483647bit PBEWITHHMACSHA1ANDAES_128 : 2147483647bit PBEWITHSHA1ANDRC4_128 : 2147483647bit AES_192/OFB/NOPADDING : 2147483647bit AES_128/ECB/NOPADDING : 2147483647bit DESEDEWRAP : 2147483647bit AESWRAP_256 : 2147483647bit RC2 : 2147483647bit PBEWITHSHA1ANDRC4_40 : 2147483647bit RSA : 2147483647bit AESWRAP_128 : 2147483647bit PBEWITHHMACSHA512ANDAES_256 : 2147483647bit AES_192/CFB/NOPADDING : 2147483647bit DESEDE : 2147483647bit AES_128/CFB/NOPADDING : 2147483647bit AES_192/ECB/NOPADDING : 2147483647bit BLOWFISH : 2147483647bit ARCFOUR : 2147483647bit AES_256/CFB/NOPADDING : 2147483647bit AES : 2147483647bit RSA/ECB/PKCS1PADDING : 2147483647bit AES_128/OFB/NOPADDING : 2147483647bit AES_128/GCM/NOPADDING : 2147483647bit DES : 2147483647bit PBEWITHHMACSHA256ANDAES_128 : 2147483647bit PBEWITHSHA1ANDDESEDE : 2147483647bit PBEWITHSHA1ANDRC2_40 : 2147483647bit PBEWITHHMACSHA384ANDAES_256 : 2147483647bit AES_256/OFB/NOPADDING : 2147483647bit PBEWITHSHA1ANDRC2_128 : 2147483647bit PBEWITHMD5ANDTRIPLEDES : 2147483647bit PBEWITHHMACSHA1ANDAES_256 : 2147483647bit PBEWITHHMACSHA224ANDAES_128 : 2147483647bit
RSA by itself is deterministic ,
this is why you are getting different result for the same text message.
Why would not use private key for
encryption and public key for decryption ?
- Mathematically it will work just fine. "Encrypt" with the private key, "decrypt" with the public key.
- Typically a hash function and padding is involved for signing a message.
- We would completely defeat the purpose of public key cryptography i,e reason why we sign with a private key and not the public key.
- Using the private key for encrypting and the public for decrypting , that’s the process of signing a message/verifying that a message is coming from a particular source.
- Using the public key for encrypting and the private for decrypting , that’s secure communication.
- A secure RSA encryption is implemented with an appropriate padding scheme, which includes some randomness ( PKCS#1 or OAEP or PSS).
- The RSA encryption encrypts message padded with '0's and and a string of random bit. In the process,the random string is "hidden" in the ciphertext by cryptographic hashing and XORing. On decryption, the RSA decryption recovers the random string from the ciphertext and use it to recover message.
- PKCS#1 also describes a newer padding scheme, called PSS, which is more complex but with a stronger security proof.PSS includes a bunch of random bytes, so you will get a distinct signature every time.
Implicit include bunch of random bytes using SecureRandom:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));Explicit include bunch of random bytes using SecureRandom :
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey),new SecureRandom());The above code will produce distinct cipher text every time , as SecureRandom will add random bytes with plain text and that bytes will be distinct.
Plain Text : Give me the same result
Cipher Text 1 : JBYqC3FugRnpIsLQydDlCKwPuMrdcNRItqCJjCkfOb7zOS91x2isErk2A7HrPrUKl0rDoHHFZ0IK8PbWW................
Cipher Text 2 : Ff02kTTbsM2KHAb6z8re7s49D2zGw6+aAkuJFGQ87cefsTuVc+6ypFRbfDu1PBx853zl54oDf+/MYB6.................
Cipher Text 1 : JBYqC3FugRnpIsLQydDlCKwPuMrdcNRItqCJjCkfOb7zOS91x2isErk2A7HrPrUKl0rDoHHFZ0IK8PbWW................
Cipher Text 2 : Ff02kTTbsM2KHAb6z8re7s49D2zGw6+aAkuJFGQ87cefsTuVc+6ypFRbfDu1PBx853zl54oDf+/MYB6.................
How RSA encrypted text(cipher
text) will give same result for the same text ?
- As PKCS#1 / PSS includes a bunch of random bytes with the plain text before encryption , which will get a distinct cipher text every time for same input.
- So instead of including a bunch of random bytes , we can include explicitly a fixed bytes of salt to get the same cipher text every time for same input.
Example: (Get a unique cipher text every time - Static bunch of random bytes using SecureRandom)
Provided explicit fixed bytes into SecureRandom:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey),new SecureRandom("MY-OWN-FIXED-SECURE-SALT".getBytes()));The above code will produce same cipher text every time , as SecureRandom won't add random bytes with plain text and it will be add fixed bytes("MY-OWN-FIXED-SECURE-SALT") every time.
Plain Text : Give me the same result
Cipher Text 1 : ZjDokVp31oFX+cjaVA2IP0ljtWlNZmzolPn96Q9osbxBJ2P/qCPologKfHHT8lf............................
Cipher Text 2 : ZjDokVp31oFX+cjaVA2IP0ljtWlNZmzolPn96Q9osbxBJ2P/qCPologKfHHT8lf............................
Where RSA Algorithim would be Use :
If we will check the set of algorithms that cipher suites usually contain include: a key exchange algorithm, a bulk encryption algorithm, and a message authentication code (MAC) algorithm.
Structure of Cipher Suite : Protocol_keyexchange_keyauthentication_WITH_bulkencryption_effectivebits_ciphermode_messageauth, where RSA will always be found for Key Authentication but not for bulk encryption.
Hybrid approach of using RSA (Encrypt the data with a symmetric key like AES, and encrypt that symmetric AES key with Asymmetric key like RSA)
Step 1 : Generate a symmetric key(AES with 128 bits)
KeyGenerator generator = KeyGenerator.getInstance("AES"); generator.init(128); SecretKey secKey = generator.generateKey(); symmetricSecretKey = Base64.encodeBase64String(secKey.getEncoded()); System.out.println("Generated Symmetric Secret Key :" + symmetricSecretKey);Step 2 : Encrypt the data with above symmetric key
String plainText = "JAVA2DEPTH Hybrid Encryption demo..."; Cipher aesEncryptionCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); aesEncryptionCipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(Base64.decodeBase64(symmetricSecretKey), "AES")); byte[] byteCipherText = aesEncryptionCipher.doFinal(plainText.getBytes()); String encryptedData = Base64.encodeBase64String(byteCipherText); System.out.println("Encrypted Cipher Text using Symmetric Secret Key: " + encryptedData);Step 3 : Encrypt the symmetric key with RSA 2048 bits
KeyFactory fact = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec spec = fact.getKeySpec(keyPair.getPrivate(), PKCS8EncodedKeySpec.class); byte[] packed = spec.getEncoded(); assymetricPrivateKey = Base64.encodeBase64String(packed); Arrays.fill(packed, (byte) 0); System.out.println("Generated ASymmetric RSA Private Key : " + assymetricPrivateKey); String encryptedSymmetricKey = rsaEncryptData(assymetricPublicKey, symmetricSecretKey); System.out.println("Encrypted Symmetric Secret Key using RSA Private Key :" + encryptedSymmetricKey);Step 4 : Send encrypted data (byteCipherText) + encrypted AES Key (encryptedKey)
Step 5 : Decrypt the encrypted symmetric key with RSA private key
String decryptedSymmetricKey = rsaDecryptData(encryptedSymmetricKey, assymetricPrivateKey); System.out.println("Decrypted Symmetric Secret Key using RSA Public Key :" + encryptedSymmetricKey);Step 6 : Decrypt the data with the symmetric key
Cipher aesDecryptionCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); aesDecryptionCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(decryptedSymmetricKey), "AES")); byte[] bytePlainText = aesDecryptionCipher.doFinal(Base64.decodeBase64(encryptedData)); String message = new String(bytePlainText); System.out.println("Decrypted Plain Text using Symmetric Secret Key : " + message);Full Example :
import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; public class HybridEncryption { private static String assymetricPublicKey = ""; private static String assymetricPrivateKey = ""; private static String symmetricSecretKey = ""; public static void main(String[] args) throws Exception { // Sender Side KeyGenerator generator = KeyGenerator.getInstance("AES"); generator.init(128); SecretKey secKey = generator.generateKey(); symmetricSecretKey = Base64.encodeBase64String(secKey.getEncoded()); System.out.println("Generated Symmetric Secret Key :" + symmetricSecretKey); String plainText = "JAVA2DEPTH Hybrid Encryption demo..."; Cipher aesEncryptionCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); aesEncryptionCipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(Base64.decodeBase64(symmetricSecretKey), "AES")); byte[] byteCipherText = aesEncryptionCipher.doFinal(plainText.getBytes()); String encryptedData = Base64.encodeBase64String(byteCipherText); System.out.println("Encrypted Cipher Text using Symmetric Secret Key: " + encryptedData); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); KeyPair keyPair = keyPairGenerator.generateKeyPair(); byte[] keyBytes = keyPair.getPublic().getEncoded(); assymetricPublicKey = Base64.encodeBase64String(keyBytes); assymetricPublicKey = assymetricPublicKey.replaceAll("\n", "\\\\n"); System.out.println("Generated ASymmetric RSA Public Key :" + assymetricPublicKey); KeyFactory fact = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec spec = fact.getKeySpec(keyPair.getPrivate(), PKCS8EncodedKeySpec.class); byte[] packed = spec.getEncoded(); assymetricPrivateKey = Base64.encodeBase64String(packed); Arrays.fill(packed, (byte) 0); System.out.println("Generated ASymmetric RSA Private Key : " + assymetricPrivateKey); String encryptedSymmetricKey = rsaEncryptData(assymetricPublicKey, symmetricSecretKey); System.out.println("Encrypted Symmetric Secret Key using RSA Private Key :" + encryptedSymmetricKey); // Reciever Side String decryptedSymmetricKey = rsaDecryptData(encryptedSymmetricKey, assymetricPrivateKey); System.out.println("Decrypted Symmetric Secret Key using RSA Public Key :" + encryptedSymmetricKey); Cipher aesDecryptionCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); aesDecryptionCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(decryptedSymmetricKey), "AES")); byte[] bytePlainText = aesDecryptionCipher.doFinal(Base64.decodeBase64(encryptedData)); String message = new String(bytePlainText); System.out.println("Decrypted Plain Text using Symmetric Secret Key : " + message); } private static String rsaEncryptData(String publicKey, String message) { byte[] cipherBytes = null; String encryptData64Encoded = ""; try { Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding"); cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey)); byte[] eMessageBytes = message.getBytes(); cipherBytes = cipher.doFinal(eMessageBytes); encryptData64Encoded = new String(Base64.encodeBase64(cipherBytes)); } catch (Exception e) { e.printStackTrace(); } return encryptData64Encoded; } private static String rsaDecryptData(String encryptData, String privatekey) { String dectyptedText = ""; try { byte[] dataEncoded = Base64.decodeBase64(encryptData); Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding"); cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privatekey)); dectyptedText = new String(cipher.doFinal(dataEncoded)); } catch (Exception e) { e.printStackTrace(); } return dectyptedText; } private static PrivateKey getPrivateKey(String privatekey) { PrivateKey privateKeyObj = null; try { byte[] clear = Base64.decodeBase64(privatekey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear); KeyFactory fact = KeyFactory.getInstance("RSA"); privateKeyObj = fact.generatePrivate(keySpec); Arrays.fill(clear, (byte) 0); } catch (Exception e) { e.printStackTrace(); } return privateKeyObj; } private static PublicKey getPublicKey(String stored) { PublicKey publicObj = null; try { byte[] data = Base64.decodeBase64(stored); X509EncodedKeySpec spec = new X509EncodedKeySpec(data); KeyFactory fact = KeyFactory.getInstance("RSA"); publicObj = fact.generatePublic(spec); } catch (Exception e) { e.printStackTrace(); } return publicObj; } }Output :
Generated Symmetric Secret Key :yDv3bqfbzS1hiuCE9it/nA== Encrypted Cipher Text using Symmetric Secret Key: w149Rjf6b7WzVoYzvqCJFP19vy6gqenZtY2YwnO0qgrs4Z61BWEzHyhHE3Sei+UI Generated ASymmetric RSA Public Key :MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgP+CGTQW01AmDSi+kcPX/9A/i7+opvjgyvcI47HbUd80622+umVWJIVrksmAuc+i2d8kG/rbVlBep90LPXpttef6gI+Ubqr/6AzfWEFdKdXFC3ELff2rR2zmJD3e0zzuwHoUvHL/lFFAyDLyonj0fDlQ/0jJaHJd6gpb0KOCCedewhBNamOzFusbp8TpgwV60tECykItp5YCnC7xw01hcni9dc4dzTb4IQ7NSa/ZNzoSnZStXo6X7qpqQ3FNUF09HPn4gh0c8XNyA4uyC28qDyVki51VUSiXeZ1oXOJ5YTMbQaIYAFcfY1ZKyb3irDx7gdA8n2LdpuMAuD3YAjlQ4QIDAQAB Generated ASymmetric RSA Private Key : MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCA/4IZNBbTUCYNKL6Rw9f/0D+Lv6im+ODK9wjjsdtR3zTrbb66ZVYkhWuSyYC5z6LZ3yQb+ttWUF6n3Qs9em215/qAj5Ruqv/oDN9YQV0p1cULcQt9/atHbOYkPd7TPO7AehS8cv+UUUDIMvKiePR8OVD/SMlocl3qClvQo4IJ517CEE1qY7MW6xunxOmDBXrS0QLKQi2nlgKcLvHDTWFyeL11zh3NNvghDs1Jr9k3OhKdlK1ejpfuqmpDcU1QXT0c+fiCHRzxc3IDi7ILbyoPJWSLnVVRKJd5nWhc4nlhMxtBohgAVx9jVkrJveKsPHuB0DyfYt2m4wC4PdgCOVDhAgMBAAECggEAMNYKf9YrigZ+0V6Kfw7AuHUziYmepM/18oEBmYoc+Ori0vpySYjRyvPD3QdyN2Y3RfpnZjxbS1sT6sMRXU37OPHA8WjqDdepGEW/TF86kPsAJSu/6QvfCyRcIH5X3GrmDHJrZUi4H4N/XguDtiTKkjj0xCDfNy6NBWy0g9FTCsJFhfW9UErE7VccMcq0Rh9715m4DTVh2zUap2F1Q2JPU69RO86rWFao9Q7PHQu4RAnDMmLtX6mnhU3ZsVx0LJANkq/09Gul/EpyG0b2h7CB7o+yfqWrbs25sltDMo54RQ/nJESzDHuR7R4I7WOfGzJG+lwSq31OrQIiGMagAyEsrQKBgQDNkBOhpaYiqh/SnrT6ELH9KZczfsLF49aNmdkROUalCl+UPX3nyoDUHjdpeVbmeR5TD3Z8iEQvsf06qzem8mXYmIRffq80VBv37NH8R23erkmr+PDes8mTNrAhz+cBMHj5f2hjYH6J1gpuRE8uan5nxrDOEEaLfrBuKfNclwfoVwKBgQCgpjTO89ypDYxXBxJpNg0E7eBDbL+FTy+QSPC+Y2ElMkM6dcdXUSjCpJwEsZS09f2Lh7145vl90p0pfpgAo5xNzMMxWtZVPkHA34X85CfTZl82irok6XG1LE9qK5q6zEJGnOLdsCxM3WU4/J7P1rW6XtaI7RENTT28SGOrqG2thwKBgQDCBSgSXYg2lb5djICiullU6wmUiCOMpmSe2ERCdn4QTn8yKuwIeGEqVK7Wdbmo5U7S9PhPyEobfnLWCj8H6yhnzGS8wZTa3jxbwIHeDQlNsdFFaTzn5mfu9CJAd7vAqqC0VSYRDkXBEW5c70qRM+DFUIsWo9QB2/zord3OWZsUFwKBgC8IWf+Y76piuAqmnGJHG8qspfK3fN7XjxJL+IeU6tUMARi1cLYEoc1SigbpwqK0PhXCmNszrCmFJtQGJxRQ0isI3sCtWoC8aF3CUyT12x8OIqQCO3shCVREc7+eon872892kQjcUivyyXbEpu4sayn0KBUQauSdD4z3GI8iEXIzAoGBAMHXkraNV1p7s105Oc8VmsErFzlr9uSdrl5pT2vaNkEayVgVXiGXtfA+IvBweOOTOz4V9U8NbAdFxdW8kNwhU/G6gBA8V+S+49IWNCqtWKlnSfT5paSCsHgjNSOUX7FstZhzOUKin1qQWTAQpzZc3/o3gz6QI3Bu6zoaWVxSN7em Encrypted Symmetric Secret Key using RSA Private Key :GEcbSDzCyp+J6bAj1PcORkFJBiapSC0NzxOTbwigDA1xMKn+C16s325BcleFqfMYfCJX4Wk5/x41jeTf1CNJQFGQNrRI4HJXNzfy0DGNjqEMgFBOev6X9cnpMG6qgX+ByU9IoeCOKwgPSMmYMAvpNPLubSzbLtcRdVwjawL3jpm4L1ZyRpzH3l2pVgukkjZxVGWD+CJTJZfow8oY/1xLpgeIfpbxLkoebMJRiCJ2Q5RCP8lqogfEV1tk+4+n0Kuk4TYsB8AnUVONjHBCoArHMsNXqKYEsvfDndKfEnQNnW9KZ5S00+vD9WF1m0iwT9y0WKKDqTbq0XcD9VIfHD1zqQ== Decrypted Symmetric Secret Key using RSA Public Key :GEcbSDzCyp+J6bAj1PcORkFJBiapSC0NzxOTbwigDA1xMKn+C16s325BcleFqfMYfCJX4Wk5/x41jeTf1CNJQFGQNrRI4HJXNzfy0DGNjqEMgFBOev6X9cnpMG6qgX+ByU9IoeCOKwgPSMmYMAvpNPLubSzbLtcRdVwjawL3jpm4L1ZyRpzH3l2pVgukkjZxVGWD+CJTJZfow8oY/1xLpgeIfpbxLkoebMJRiCJ2Q5RCP8lqogfEV1tk+4+n0Kuk4TYsB8AnUVONjHBCoArHMsNXqKYEsvfDndKfEnQNnW9KZ5S00+vD9WF1m0iwT9y0WKKDqTbq0XcD9VIfHD1zqQ== Decrypted Plain Text using Symmetric Secret Key : JAVA2DEPTH Hybrid Encryption demo...