Week 143 — How can one encrypt a message using RSA?

Question of the Week #143
How can one encrypt a message using RSA?
4 Replies
Eric McIntyre
Eric McIntyre4w ago
RSA is an algorithm for asymmetric encryption. It allows encrypting message with a public key that can then be decrypted with a private key. Similarly, if a message is signed with the private key, it can be verified using the public key. The private and public keys are generated together and form a key pair. The public key is intended to be shared with anyone while the private key should be kept secret. To generate a key pair consisting of a private and corresponding public key, one can obtain a KeyPairGenerator for RSA keys, specify the key size and then generate a KeyPair:
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(4096);//set key size
KeyPair rsaKeyPair = generator.generateKeyPair();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(4096);//set key size
KeyPair rsaKeyPair = generator.generateKeyPair();
The private key can be obtained using the getPrivate() method on KeyPair and should be kept secret. The public key can be obtained using the getPublic() method and can be shared with anyone who should be able to encrypt or verify messages. To actually work with messages, one can obtain a Cypher object. That objects needs to be initialized for encryption or decryption:
PublicKey publicKey = rsaKeyPair.getPublic();


byte[] secretData = new byte[]{ 13, 37, 12, 34, 56 };//some example data
Cipher rsaEncryptionCipher = Cipher.getInstance("RSA");
rsaEncryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey);//configure the cipher for encryption with the public key
byte[] encryptedData = rsaEncryptionCipher.doFinal(secretData);//perform the encryption
PublicKey publicKey = rsaKeyPair.getPublic();


byte[] secretData = new byte[]{ 13, 37, 12, 34, 56 };//some example data
Cipher rsaEncryptionCipher = Cipher.getInstance("RSA");
rsaEncryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey);//configure the cipher for encryption with the public key
byte[] encryptedData = rsaEncryptionCipher.doFinal(secretData);//perform the encryption
After the data is encrypted with the public key as done above, it can be decrypted only using the private key. This can be done similar to decryption except that the arguments to the init method need to be different:
Cipher rsaDecryptionCipher = Cipher.getInstance("RSA");
rsaDecryptionCipher.init(Cipher.DECRYPT_MODE, rsaKeyPair.getPrivate());//configure the cipher for decryption with the private key
byte[] reconstructedData = rsaDecryptionCipher.doFinal(encryptedData);//perform the decryption

System.out.println(Arrays.toString(reconstructedData));//[13, 37, 12, 34, 56]
Cipher rsaDecryptionCipher = Cipher.getInstance("RSA");
rsaDecryptionCipher.init(Cipher.DECRYPT_MODE, rsaKeyPair.getPrivate());//configure the cipher for decryption with the private key
byte[] reconstructedData = rsaDecryptionCipher.doFinal(encryptedData);//perform the decryption

System.out.println(Arrays.toString(reconstructedData));//[13, 37, 12, 34, 56]
Signing is the process of ensuring the integrity of a message. It is used to prove that a message has been created by some entity and has not been modified. Signing works just like encryption but using the private key. Only the entity who possesses the private key is able to encrypt message in a way such that decrypting these messages with the public key leads to the original message.
byte[] bytesToSign = "If you can read this, you can read.".getBytes(StandardCharsets.UTF_8);

Cipher rsaSigningCipher = Cipher.getInstance("RSA");
rsaSigningCipher.init(Cipher.ENCRYPT_MODE, rsaKeyPair.getPrivate());//configure the cipher for encryption with the public key
byte[] unfakableData = rsaSigningCipher.doFinal(bytesToSign);//encrypt the data such it can be decrypted by anyone with the public key
byte[] bytesToSign = "If you can read this, you can read.".getBytes(StandardCharsets.UTF_8);

Cipher rsaSigningCipher = Cipher.getInstance("RSA");
rsaSigningCipher.init(Cipher.ENCRYPT_MODE, rsaKeyPair.getPrivate());//configure the cipher for encryption with the public key
byte[] unfakableData = rsaSigningCipher.doFinal(bytesToSign);//encrypt the data such it can be decrypted by anyone with the public key
To verify the message, one can just decrypt the message using the public key.
Cipher rsaDecryptionCipher = Cipher.getInstance("RSA");
rsaDecryptionCipher.init(Cipher.DECRYPT_MODE, publicKey);//configure the cipher for decryption with the public key
byte[] reconstructedSignedData = rsaDecryptionCipher.doFinal(unfakableData);//perform the decryption resulting in the original bytes

System.out.println(new String(reconstructedSignedData, StandardCharsets.UTF_8));
Cipher rsaDecryptionCipher = Cipher.getInstance("RSA");
rsaDecryptionCipher.init(Cipher.DECRYPT_MODE, publicKey);//configure the cipher for decryption with the public key
byte[] reconstructedSignedData = rsaDecryptionCipher.doFinal(unfakableData);//perform the decryption resulting in the original bytes

System.out.println(new String(reconstructedSignedData, StandardCharsets.UTF_8));
Eric McIntyre
Eric McIntyre4w ago
Encrypting and decrypting large messages with RSA is slow. In practice, RSA is typically used for key exchange where the asymmetric nature of the algorithm (and its ability to be used to sign messages) is used to exchange a key for symmetric encryption (e.g. an AES key). Once both parties have exchanged the same key, they can securely communicate with each other. On the other hand, signing large messages is typically not done by encrypting the full message with the private key. Instead, the entity signing the message computes a hash of the message, signs that with RSA (or another algorithm) and transmits both the message and the hash. The entity verifying the message decrypts the encrypted hash received from the other party. They can then computes the hash from the message as well and compare it to the decrypted hash. If they match, they can be sure that the message came from someone in posession of the private key and that the message has not been modified by someone else.
📖 Sample answer from dan1st
Eric McIntyre
Eric McIntyre4w ago
this will encrypt the message "very secret message" using a randomly generated RSA keypair.
import java.security.*;
import javax.crypto.Cipher;
import java.util.Base64;

public class QOTWAnswer {
public static String encrypt(String message, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(message.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes); // convert to base64 for readability
}

public static void main(String[] args) throws Exception {
String message = "very secret message";
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048); // 2048 bits again
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
String encryptedMessage = encrypt(message, publicKey);
System.out.println("encrypted msg: " + encryptedMessage);
}
}
import java.security.*;
import javax.crypto.Cipher;
import java.util.Base64;

public class QOTWAnswer {
public static String encrypt(String message, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(message.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes); // convert to base64 for readability
}

public static void main(String[] args) throws Exception {
String message = "very secret message";
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048); // 2048 bits again
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
String encryptedMessage = encrypt(message, publicKey);
System.out.println("encrypted msg: " + encryptedMessage);
}
}
output: encrypted msg: s8Gq848C8BIpmm4dLwN8OJ/IuYq69hOV76o8D6mJdOAUK74Ms32Hlj+UQoJFJRpLnOyAkOWJkVNSBWwHRsSHqAuKmGpTJTd92uZUEq5yF0niynuTMLBtq3TiB1dECEC2iGW8NyZNkZ6gJNvVllpAnY2V3oBnrWQuhsnRAe44EQCwRG2MT5KULO9MDfNpOlQQdArtb4cjECS+UjGQRYcME1J/R5CoHKRxvEl4rMmV/FrwCEIj9l7K2il6crq5NFeie0iXodp0R48/78M3V+dPFSRUfD5K0i0UwUlfItf9my2HJYAc/95BqRDK1IivanODSw4ZSscY/Pan/37q2QGk8g==
Submission from zeeplockd
Eric McIntyre
Eric McIntyre4w ago
RSA is an asymmetric encryption algorithm using a pair of keys: a public key for encryption and a private key for decryption. To encrypt a message in Java, you typically use the java.security and javax.crypto libraries. Here’s an 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.RSAPublicKeySpec; import javax.crypto.Cipher; import java.math.BigInteger; public class RSAEncryptionExample { public static void main(String[] args) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(2048); // key size KeyPair keyPair = keyGen.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate();
String message = "Hello RSA!"; byte[] messageBytes = message.getBytes();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encryptedBytes = cipher.doFinal(messageBytes); System.out.println("Encrypted (hex): " + bytesToHex(encryptedBytes)); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedBytes = cipher.doFinal(encryptedBytes); String decryptedMessage = new String(decryptedBytes); System.out.println("Decrypted: " + decryptedMessage); } private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X", b)); } return sb.toString(); } }
Submission from lilit0611

Did you find this page helpful?