all! I am trying to resolve the issue.
I have bat-file with command:
openssl smime -decrypt -binary -inform DER -recip [path to certificate] -inkey [path to private key] <[path to encoded file] >[path to decoded file]
I have implement it on Java.
So I need decode file with RSA private key.
First, I tried this way:
package javatest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.PrivateKey;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
/**
* Test decrypt
*
* @author a.chernyy
*/
public class JavaTest {
/**
* String to hold name of the encryption algorithm.
*/
public static final String ALGORITHM = "RSA";
/**
* String to hold the path to the keys' dir.
*/
public static final String KEYS_DIR = "D:" + File.separator + File.separator + "keystore" + File.separator;
/**
* String to hold the name of the private key file.
*/
public static final String PRIVATE_KEY_FILE = KEYS_DIR + "priv.key";
/**
* String to hold name of the public key file.
*/
public static final String CERT_FILE = KEYS_DIR + "cert.cer";
/**
* String to hold name of the encrypted file.
*/
public static final String ENCRYPTED_FILE = "D:" + File.separator + "Temp" + File.separator + "encrypded.xml";
/**
* String to hold name of the decrypted file.
*/
public static final String DECRYPTED_FILE = "D:" + File.separator + "Temp" + File.separator + "decrypted.xml";
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
try {
//get private key
File keyFl = new File(PRIVATE_KEY_FILE);
Security.addProvider(new BouncyCastleProvider());
PEMParser pemParser = new PEMParser(new InputStreamReader(new FileInputStream(keyFl)));
PEMKeyPair pemKeyPair = (PEMKeyPair) pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
PrivateKey key = converter.getPrivateKey(pemKeyPair.getPrivateKeyInfo());
//decrypt file
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
InputStream is = new FileInputStream(ENCRYPTED_FILE);
OutputStream out = new FileOutputStream(DECRYPTED_FILE);
CipherInputStream cis = new CipherInputStream(is, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = cis.read(buffer)) > 0) {
out.write(buffer, 0, r);
}
cis.close();
is.close();
out.close();
} catch (Exception e) {
System.out.println("It's a pity...");
System.err.println(e.getMessage());
}
System.out.println("THE END");
}
}
But I get error:
javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
Also I tried use this solution. I implemented it that way:
package javatest;
//some imports...
/**
* Test decrypt main class
*
* @author a.chernyy
*/
public class JavaTest {
/**
* String to hold name of the encryption algorithm.
*/
public static final String ALGORITHM = "RSA";
/**
* String to hold the path to the keys' dir.
*/
public static final String KEYS_DIR = "D:" + File.separator + File.separator + "keystore" + File.separator;
/**
* String to hold the name of the private key file.
*/
public static final String PRIVATE_KEY_FILE = KEYS_DIR + "priv.key";
/**
* String to hold name of the public key file.
*/
public static final String CERT_FILE = KEYS_DIR + "cert.cer";
/**
* String to hold name of the encrypted file.
*/
public static final String ENCRYPTED_FILE = "D:" + File.separator + "Temp" + File.separator + "encrypded.xml";
/**
* String to hold name of the decrypted file.
*/
public static final String DECRYPTED_FILE = "D:" + File.separator + "Temp" + File.separator + "decrypted.xml";
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
try {
RSA rsa = RSA.getInstance(PRIVATE_KEY_FILE);
rsa.decrypt(ENCRYPTED_FILE, DECRYPTED_FILE);
} catch (Exception e) {
System.out.println("It's a pity...");
System.err.println(e.getMessage());
}
System.out.println("THE END");
}
}
And:
package javatest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
/**
* Decrypt class
*
* @link http://coding.westreicher.org/?p=23
* @author a.chernyy
*/
public class RSA {
/**
* Singleton class object RSA
*/
private static volatile RSA instance;
/**
* Private key
*/
private final PrivateKey privateKey;
/**
* Cipher
*/
private final Cipher cipher;
/**
* Constructor
*
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
*/
private RSA(String privateKeyPath) throws NoSuchAlgorithmException, NoSuchPaddingException, FileNotFoundException, IOException {
//create cipher
this.cipher = Cipher.getInstance("RSA");
//get private key
File keyFl = new File(privateKeyPath);
Security.addProvider(new BouncyCastleProvider());
PEMParser pemParser = new PEMParser(new InputStreamReader(new FileInputStream(keyFl)));
PEMKeyPair pemKeyPair = (PEMKeyPair) pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
this.privateKey = converter.getPrivateKey(pemKeyPair.getPrivateKeyInfo());
}
//Static methods
/**
* Static method getInstance return single refer on object RSA. If object
* not exists, it will be created
*
* @param privateKeyPath
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws java.io.FileNotFoundException
* @return RSA
*/
public static RSA getInstance(String privateKeyPath) throws NoSuchAlgorithmException, NoSuchPaddingException, FileNotFoundException, IOException {
if (instance == null) {
synchronized (RSA.class) {
if (instance == null) {
instance = new RSA(privateKeyPath);
}
}
}
return instance;
}
/**
* Block chipher
*
* @param bytes
* @param mode
* @return
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
private byte[] blockCipher(byte[] bytes, int mode) throws IllegalBlockSizeException, BadPaddingException {
// string initialize 2 buffers.
// scrambled will hold intermediate results
byte[] scrambled = new byte[0];
// toReturn will hold the total result
byte[] toReturn = new byte[0];
// if we encrypt we use 100 byte long blocks. Decryption requires 128 byte long blocks (because of RSA)
int length = (mode == Cipher.ENCRYPT_MODE) ? 100 : 128;
// another buffer. this one will hold the bytes that have to be modified in this step
byte[] buffer = new byte[length];
for (int i = 0; i < bytes.length; i++) {
// if we filled our buffer array we have our block ready for de- or encryption
if ((i > 0) && (i % length == 0)) {
//execute the operation
scrambled = cipher.doFinal(buffer);
// add the result to our total result.
toReturn = append(toReturn, scrambled);
// here we calculate the length of the next buffer required
int newlength = length;
// if newlength would be longer than remaining bytes in the bytes array we shorten it.
if (i + length > bytes.length) {
newlength = bytes.length - i;
}
// clean the buffer array
buffer = new byte[newlength];
}
// copy byte into our buffer.
buffer[i % length] = bytes[i];
}
// this step is needed if we had a trailing buffer. should only happen when encrypting.
// example: we encrypt 110 bytes. 100 bytes per run means we "forgot" the last 10 bytes. they are in the buffer array
scrambled = cipher.doFinal(buffer);
// final step before we can return the modified data.
toReturn = append(toReturn, scrambled);
return toReturn;
}
/**
* Concatinate bytes
*
* @param prefix
* @param suffix
* @return
*/
private byte[] append(byte[] prefix, byte[] suffix) {
byte[] toReturn = new byte[prefix.length + suffix.length];
for (int i = 0; i < prefix.length; i++) {
toReturn[i] = prefix[i];
}
for (int i = 0; i < suffix.length; i++) {
toReturn[i + prefix.length] = suffix[i];
}
return toReturn;
}
public void decrypt(String filePath, String fileDecryptPath) throws Exception {
//Convert file into bytes
this.cipher.init(Cipher.DECRYPT_MODE, this.privateKey);
File encryptedFile = new File(filePath);
FileInputStream isEncryptedFile = new FileInputStream(encryptedFile);
byte encryptedFileData[] = new byte[(int) encryptedFile.length()];
isEncryptedFile.read(encryptedFileData);
byte[] bts = encryptedFileData;
//decrypt
byte[] decrypted = blockCipher(bts, Cipher.DECRYPT_MODE);
//Push decrypted data into file
//...
}
}
But I got the error:
Decryption error
Can anyone suggest a solution?
S/MIME is based on a standard called PKCS #7, the Cryptographic Message Syntax. An S/MIME–encrypted message is not simply the output of an encryption operation; it's a package of meta-data and (optionally) the encrypted content itself. It has to be parsed to find the cipher text, the encrypted content encryption key(s), the algorithm and parameters applied to the content encryption key, the algorithm and parameters applied to the content itself, etc.
A CMS enveloped-data structure contains information for one or more recipients. Each bundle of recipient information contains an identifier for the recipient and a bit of cipher text encrypted with that recipient's public key. If you have the private key corresponding to one of those recipients, you can decrypt the bit of cipher text, which turns out to be another key for a symmetric cipher. With that, and more meta-data about the symmetric cipher mode and parameters, you can decrypt the actual message itself.
To decrypt it, you'll need an S/MIME or CMS library. (Library recommendations are off-topic, but you can look at BouncyCastle.)
I've found the solution for my question! Thank you all for your advises.
I've found the source. Thank you very much to author of this source.
I implemented it that way:
and
So, it works! :)