I am trying to RSA encrypt data on Android and send it to server(spring).
getting BadPaddingException :
Approach:
server send public key in a string, which i convert to PublicKey Object and send data from App after encryption as a string.
server has a private key string , which is converted to PublicKey object and then data is decrypted.
Any Help would be much appreciated.
generation of key :
public static KeyPair generateKeyPairRSA() {
try {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024, random);
KeyPair keyPair = keyGen.generateKeyPair();
return keyPair;
} catch (Exception e) {
Log.d(TAG,e.getLocalizedMessage());
}
return null;
}
public byte[] RSAEncrypt(final String plain, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(ALGO_RSA);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(plain.getBytes());
return encryptedBytes;
}
public static PublicKey loadPublicKey1(String stored) throws Exception{
byte[] data = Base64.decode(stored.getBytes());
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance(ALGO_RSA);
return fact.generatePublic(spec);
}
Server Methods :
public byte[] decryptRSA(String inputData) throws Exception {
byte[] inputBytes = Base64.decodeBase64(inputData);
PrivateKey key = loadPrivateKey(getPrivateKey());
Cipher cipher1 = Cipher.getInstance("RSA");
cipher1.init(Cipher.DECRYPT_MODE, key);
return cipher1.doFinal(inputBytes);
}
private PrivateKey loadPrivateKey(String key64) throws Exception {
byte[] pkcs8EncodedBytes = Base64.decodeBase64(key64);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8EncodedBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(keySpec);
}
Got it Working.
So diffrent libs have differenet implementation of Cipher.
so while calling
Cipher.getInstance("RSA/ECB/PKCS1Padding");
Explicitly mention encryption mode and padding.
Hope it helps somebody.
Related
Below I try to send message in multicast socket through group and to provide encryption:
Encrypt the data with the symmetric key
Encrypt the symmetric key with rsa
send the encrypted key and the data
Decrypt the encrypted symmetric key with rsa
decrypt the data with the symmetric key
But I am getting this error
javax.crypto.BadPaddingException: Decryption error at java.base/sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:378) at java.base/sun.security.rsa.RSAPadding.unpad(RSAPadding.java:290) at java.base/com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:366) at java.base/com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:392) at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2208) at Security.RSADecryption(Symmetra.java:63) at ReadThread.run(Symmetra.java:202) at java.base/java.lang.Thread.run(Thread.java:835)
I think I did not understood encryption decryption properly.
See below for the code:
class Security
{
public static SecretKey createAESKey() throws Exception
{
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(128); // The AES key size in number of bits
SecretKey key = generator.generateKey();
return key;
}
public static KeyPair generateRSAkeyPair() throws Exception
{
//SecureRandom secureRandom = new SecureRandom();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
//KeyGenerator keyGenerator = KeyGenerator.getInstance("RSA");
keyPairGenerator.initialize(4096);
KeyPair pair = keyPairGenerator.generateKeyPair();
return pair;
}
public static byte[] AESEncryption(String plaintext, SecretKey secKey) throws Exception
{
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE,secKey);
byte[] cipherText = cipher.doFinal(plaintext.getBytes());
return cipherText;
}
public static byte[] RSAEncryption(PublicKey publicKey, SecretKey key) throws Exception
{
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//cipher.update(plaintext.getBytes());
byte [] encryptedKey = cipher.doFinal(key.getEncoded());
System.out.println(encryptedKey.length);
return encryptedKey;
}
public static byte[] RSADecryption(byte[] encryptedKey, PrivateKey privateKey) throws Exception
{
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte check[] = cipher.doFinal(encryptedKey);
return cipher.doFinal(encryptedKey);
}
public static String AESDecryption(byte[] decryptedKey, byte[] text) throws Exception
{
SecretKey originalKey = new SecretKeySpec(decryptedKey , 0, decryptedKey.length, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, originalKey);
byte[] plaintext = cipher.doFinal(text);
return new String(plaintext);
}
public static KeyPair generate() throws Exception
{
KeyPair keyPair = generateRSAkeyPair();
return keyPair;
}
}
public class TestDemo extends Security
{
public static void main(String args[])
{
KeyPair keyPair = generate();
SecretKey key = createAESKey();
byte[] cipherText = AESEncryption(message,key);
byte[] encryptedKey = RSAEncryption(keyPair.getPublic(), key);
DatagramPacket datagram = new
DatagramPacket(cipherText,cipherText.length,group,port); // It carries encrpyted message
// It carries symmetric key encrypted by RSA
DatagramPacket datagram2 = new
DatagramPacket(encryptedKey,encryptedKey.length,group,port);
socket.send(datagram);
socket.send(datagram2);
}
}
class ReadThread extends Security
{
KeyPair keyPair;
SecretKey key;
try
{
keyPair = generate();
key = createAESKey();
byte[] buffer = new byte[ReadThread.MAX_LEN];
DatagramPacket datagram = new DatagramPacket(buffer,buffer.length,group,port);
byte[] keyBuffer = new byte[512];
DatagramPacket datagram2 = new
DatagramPacket(keyBuffer,keyBuffer.length,group,port);
String message;
try
{
socket.receive(datagram);
socket.receive(datagram2);
byte[] decryptKey = RSADecryption(keyBuffer,keyPair.getPrivate());
String decryptText = AESDecryption(decryptKey, buffer);
message = decryptText;
if(!message.startsWith(Symmetra.name))
System.out.println(message);
}
catch(IOException e)
{
System.out.println("Socket closed!");
}
}
}
Recently I have read an article Seriously, stop using RSA
and I was wondering what is the best way to test my implementation of the RSA keyset generation. I am not a security expert, but I have been working in Java and Software Dev. for quite some time now. However, I am not sure how I would test the strength of a key (flaws in the implementation process).
The Implementation I did for my RSA key gen is the following:
private KeyPairGenerator keyGen;
private PrivateKey privateKey;
private PublicKey publicKey;
private SecureRandom srandom;
public SecreteKeyGenerator() throws NoSuchAlgorithmException {
this.keyGen = KeyPairGenerator.getInstance("RSA");
this.keyGen.initialize(Encryptable.RSA_LENGTH);
this.srandom = new SecureRandom();
}
public void createRSAKeys() {
KeyPair pair = this.keyGen.generateKeyPair();
this.privateKey = pair.getPrivate();
this.publicKey = pair.getPublic();
}
The way I am using this implementation is in combination with AES key. I use AES key to encrypt the data and then I encrypt the key using RSA.
This is a suggested method in Java when dealing with large files.
The variable Encryptable.RSA_LENGTH has a value 2048, which is the length of a key.
After the keys are generated they are written to a files stored on clients machine.
The encryption works properly, as well as the digital signature process. However, I want to be extra sure that I've implemented everything correctly.
This is the code that is handling the encryption process of the file:
public void execute() {
OperationsLogger.getLogger().log(Level.INFO, "Encryption of file started");
AESEncryption aesEncryption = new AESEncryption();
aesEncryption.createAESKey();
aesEncryption.encryptFile(this.targetFilePath, this.publicKeyPath);
OperationsLogger.getLogger().log(Level.INFO, "File encrypted successfully.");
}
//AES Encryption
public void encryptFile(String inputFile, String publicKeyLocation) throws IOException, GeneralSecurityException {
try (FileOutputStream out = new FileOutputStream(inputFile + ".enc")) {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, new RSAEncryption().getPublic(publicKeyLocation));
byte[] b = cipher.doFinal(secretKey.getEncoded());
out.write(b);
out.write(gen.getIv());
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.ENCRYPT_MODE, secretKey, gen.getIvspec());
try (FileInputStream in = new FileInputStream(inputFile)) {
processFile(ci, in, out);
}
}
}
public PublicKey getPublic(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
byte[] keyBytes = Files.readAllBytes(new File(filename).toPath());
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
First of all, I'm a beginner programmer
I created a pair of keys(rsa) on the user's side(android). I intend to send the public key to the server for future operations as a base64 string, and with the public key I will encode the next data and send it to the user.I use the server side of the nodejs. Unfortunately, all the content written in The internet did not mention encrypt with the base64 public key or at least I did not see it. Can someone help me? Thank
this my java code:
public class GenKey {
private String stringPrivateKey;
private String stringPublicKey;
#RequiresApi(api = Build.VERSION_CODES.O)
public GenKey() throws NoSuchAlgorithmException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512,new SecureRandom());//1024 or 2048
KeyPair kp = kpg.generateKeyPair();
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
this.stringPublicKey = Base64.encodeToString(publicKey.getEncoded(), DEFAULT);
this.stringPrivateKey =Base64.encodeToString(privateKey.getEncoded(), DEFAULT);
}
public String getPublicKey(){
return stringPublicKey;
}
public String getPrivateKey(){
return stringPrivateKey;
}
}
and:
public class EncryptDecrypt {
public static String encrypt(String publicKey, String cleartext) throws Exception {
X509EncodedKeySpec ks = new X509EncodedKeySpec(Base64.decode(publicKey,DEFAULT));
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pub = kf.generatePublic(ks);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pub);
byte[] encMsgBinary = cipher.doFinal(cleartext.getBytes());
return Base64.encodeToString(encMsgBinary, DEFAULT);
}
public static String decrypt(String privateKey, String ciphertext) throws Exception {
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(Base64.decode(privateKey,DEFAULT));
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey pvt = kf.generatePrivate(ks);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pvt);
byte [] encrypted = Base64.decode(ciphertext,DEFAULT);
return new String(cipher.doFinal(encrypted));
}
}
solved.use node-rsa;
var NodeRSA = require('node-rsa');
var key = new NodeRSA();
var public="-----BEGIN PUBLIC KEY-----\n"+publicKey+"\n"+"-----END PUBLIC KEY-----";
key.importKey(public,"pkcs8-public-pem");
var encrypted = key.encrypt(text, 'base64');
return encrypted;
and in java EncryptDecrypt class
Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
instead of
Cipher.getInstance("RSA");
see:
enter link description here
I created a KeyStore using KeyStore Explorer with a public/private key pair inside it of type RSA, 4096 bytes, and PKCS#8 formatting.
I get an error when my code runs and hits the cipher.init() method :
"Key for algorithm RSA not suitable for symmetric encryption."
This doesn't really make sense to me because I'm using asymmetric key encryption/decryption. I'm not sure where to go from here or what I'm doing wrong.
Here is what I have:
public TransactionData processData(TransactionData data) throws BTHException {
String keystoreFilePath = manager.getStringValue(KeyStoreFilePath);
String keystorePassword = manager.getStringValue(KeyStoreFilePassword);
String privateKeyPassword = manager.getStringValue(KeyStorePrivateKeyPassword);
String certificateAlias = manager.getStringValue(CertificateAlias);
org.apache.xml.security.Init.init();
try {
InputStream in = data.getDataStream();
byte[] dataBytes = DataUtil.readBytes(in);
String encryptedDataStr = new String(dataBytes);
PrivateKey privateKey = getPrivateKeyFromKeyStore(keystoreFilePath, keystorePassword, certificateAlias, privateKeyPassword);
decrypt(
encryptedDataStr,
privateKey
);
}catch(Exception e){
throw new BTHException(e.getMessage());
}
return data;
}
private PrivateKey getPrivateKeyFromKeyStore(String keyStoreFilePath, String keyStorePassword, String privateKeyCertAlias, String privateKeyPassword) throws BTHException {
PrivateKey privateKey = null;
try {
KeyStore keystore = KeyStore.getInstance("JKS");
BASE64Encoder encoder = new BASE64Encoder();
keystore.load(new FileInputStream(keyStoreFilePath), keyStorePassword.toCharArray());
Key key=keystore.getKey(privateKeyCertAlias,keyStorePassword.toCharArray());
if(key instanceof PrivateKey) {
Certificate cert=keystore.getCertificate(privateKeyCertAlias);
PublicKey publicKey=cert.getPublicKey();
KeyPair keyPair = new KeyPair(publicKey,(PrivateKey)key);
privateKey = keyPair.getPrivate();
}
//privateKeyEncoded = encoder.encode(privateKey.getEncoded());
} catch (Exception e) {
throw new BTHException(e.getMessage());
}
return privateKey;
}
private String decrypt(String cipherText, PrivateKey privateKey) throws IOException, GeneralSecurityException, BTHException {
String decryptedValue = null;
try {
// 1. Get the cipher ready to start doing the AES transformation
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 2. Start the decryption process
// THIS IS WHERE IT FAILS
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 3. Finish the decryption process
decryptedValue = new String(cipher.doFinal(Base64.decodeBase64(cipherText)), "UTF-8");
} catch (Exception e) {
throw new BTHException(e.getMessage());
}
return decryptedValue;
}
Any help would be great. Thanks in advance!
You are trying to initialize your cipher as AES/CBC/PKCS5Padding which is an symmetric encryption and that is where the exception originates.
You should use the Cipher like that:
// 1. Get the cipher ready to start doing the RSA transformation
Cipher cipher = Cipher.getInstance("RSA");
// 2. Start the decryption process
cipher.init(Cipher.DECRYPT_MODE, privateKey);
Here you can find a good example for RSA-Encryption and Decryption.
I have code:
public PublicKey read_public_key(String path)
throws IOException, NoSuchAlgorithmException,
InvalidKeySpecException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
FileInputStream pubKeyStream = new FileInputStream(path);
byte[] pubKeyBytes = new byte[(int)path.length()];
pubKeyStream.read(pubKeyBytes);
pubKeyStream.close();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pubKeyBytes);
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
return pubKey;
}
But I get invalid key format How do I get public key from .pub file? Later I need to:
private static byte[] encrypt(String text, PublicKey key) {
byte[] cipherText = null;
try {
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return cipherText;
}