Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1PADDING","BC");
I will make a guess here that the jar you got from BouncyCastle was
digitally signed using Jarsigner. Have a peak inside the jar at the
manifests to see. BouncyCastle's certificate may have been backed by
a CA not in your .cacerts. What you would then need to do is import
the root cert of that CA as a certificate authority.
Perhaps some file YOU created has the same problem, possibly a
self-signed certificate.
You can use keytool.exe. see
http://mindprod.com/jgloss/keytoolexe.html#UPDATINGROOTS
or keyman. See
http://mindprod.com/jgloss/keyman.html
Also see
http://mindprod.com/jgloss/certificate.html#UPDATING
see also
http://www.jensign.com/JavaScience/dotnet/RSAEncrypt/index.html
for an example of RSA ciphers.
I wrote the following SSCCE to see if I could help you out.
Unfortunately, my code does not work and I can't figure out why.
It just gets -1 when I try to read back the encrypted length I put on
the front of the stream.
JCE code rarely works first time. However, I am having a different
problem from you, so perhaps this code might give you a clue.
package com.mindprod.example;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
* Demonstrate use of CipherOutputStream and CipherInputStream to
encipher and decipher a message.
* This particular version uses RSA/ECB/PKCS1Padding
* but it fairly easy to convert it to use other algorithms.
* RSA requires a digital certificate in your .keystore.
* <p/>
* composed with IntelliJ IDEA
*
* @author Roedy Green, Canadian Mind Products
* @version 1.0 2008-07-07
*/
public class TestCipherRSA
{
// ------------------------------ FIELDS
------------------------------
/**
* configure with encryption algorithm to use. Changes to
algorithm may require additional ivParms.
*/
private static final String ALGORITHM = "RSA";
/**
* configure with block mode to use. We have to use insecure ECB
since Sun support nothing else.
*/
private static final String BLOCK_MODE = "ECB";
/**
* where to find .keystore
*/
private static final String KEYSTORE_FILENAME =
"C:/users/roedy/.keystore";
/**
* configure with padding method to use
*/
private static final String PADDING = "PKCS1Padding";
/**
* alias of the RSA certificate in .keystore in JKS format.
Contains private key of recipient.
*/
private static final String RECEIVERS_PRIVATE_CERTIFICATE_ALIAS =
"mindprodcert2008rsa";
/**
* receiver's public key in standalone certificate, in x.509
format
*/
private static final String RECEIVERS_PUBLIC_CERTIFICATE =
"E:/mindprod/contact/mindprodcert2008rsa.cer";
/**
* the encoding to use when converting bytes <--> String
*/
private static final Charset CHARSET = Charset.forName( "UTF-8" );
// -------------------------- STATIC METHODS
--------------------------
/**
* read an enciphered file and retrieve its plaintext message.
*
* @param cipher method used to encrypt the file
* @param privateCert certificate, including private key of
recipient.
* @param file file where the message was written.
* @return the reconstituted decrypted message.
* @throws java.security.InvalidKeyException
* if something wrong with the key.
* @throws java.io.IOException if problems reading the file.
*/
@SuppressWarnings( { "JavaDoc" } )
private static String readCiphered( Cipher cipher, X509Certificate
privateCert, File file )
throws InvalidKeyException, IOException,
InvalidAlgorithmParameterException
{
cipher.init( Cipher.DECRYPT_MODE, privateCert );
final CipherInputStream cin = new CipherInputStream( new
FileInputStream( file ), cipher );
// read big endian short length, msb then lsb
final int messageLengthInBytes = ( cin.read() << 8 ) |
cin.read();
System.out.println( file.length() + " enciphered bytes in
file" );
System.out.println( messageLengthInBytes + " reconstituted
bytes" );
final byte[] reconstitutedBytes = new
byte[messageLengthInBytes];
// we can't trust CipherInputStream to give us all the data in
one shot
int bytesReadSoFar = 0;
int bytesRemaining = messageLengthInBytes;
while ( bytesRemaining > 0 )
{
final int bytesThisChunk = cin.read( reconstitutedBytes,
bytesReadSoFar, bytesRemaining );
if ( bytesThisChunk == 0 )
{
throw new IOException( file.toString() + " corrupted."
);
}
bytesReadSoFar += bytesThisChunk;
bytesRemaining -= bytesThisChunk;
}
cin.close();
return new String( reconstitutedBytes, CHARSET );
}
/**
* write a plaintext message to a file enciphered.
*
* @param cipher the method to use to encrypt the file.
* @param publicCert the certificate, containing public key
of recipient.
* @param file the file to write the encrypted message to.
* @param plainText the plaintext of the message to write.
* @throws java.security.InvalidKeyException
* if something is wrong with they key
* @throws java.io.IOException if there are problems writing the
file.
* @throws java.security.InvalidAlgorithmParameterException
* if problems with CBC_SALT.
*/
private static void writeCiphered( Cipher cipher, X509Certificate
publicCert, File file, String plainText )
throws InvalidKeyException, IOException,
InvalidAlgorithmParameterException
{
cipher.init( Cipher.ENCRYPT_MODE, publicCert );
final CipherOutputStream cout = new CipherOutputStream( new
FileOutputStream( file ), cipher );
final byte[] plainTextBytes = plainText.getBytes( CHARSET );
System.out.println( plainTextBytes.length + " plaintext bytes
written" );
// prepend with big-endian short message length, will be
encrypted too.
cout.write( plainTextBytes.length >>> 8 );// msb
cout.write( plainTextBytes.length & 0xff );// lsb
cout.write( plainTextBytes );
cout.close();
}
// --------------------------- main() method
---------------------------
/**
* Demonstrate use of CipherOutputStream and CipherInputStream to
encipher and decipher a message.
*
* @param args not used
* @throws java.security.NoSuchAlgorithmException
* if DES is not supported
* @throws javax.crypto.NoSuchPaddingException
* if PKCS5 padding is not supported.
* @throws java.security.InvalidKeyException
* if there is something wrong with
the key.
* @throws java.io.IOException if there are problems reading or
writing the file.
* @throws java.security.InvalidAlgorithmParameterException
* if problems with CBC_SALT.
*/
public static void main( String[] args ) throws
CertificateException,
InvalidAlgorithmParameterException,
InvalidKeyException,
IOException,
KeyStoreException,
NoSuchAlgorithmException,
NoSuchPaddingException,
NoSuchProviderException
{
// The secret message we want to send to our secret agent in
London.
final String plainText = "W. to visit Abu Ghraib for a hands
on, wink wink, tomorrow at 19:05.";
// instead of generating a secret key, we use a certificate,
contanining the receiver's public key
final FileInputStream fis = new FileInputStream(
RECEIVERS_PUBLIC_CERTIFICATE );
final CertificateFactory cf = CertificateFactory.getInstance(
"X.509" );
final X509Certificate publicCert = ( X509Certificate )
cf.generateCertificate( fis );
// use default Sun provider
final Cipher cipher = Cipher.getInstance( ALGORITHM + "/" +
BLOCK_MODE + "/" + PADDING );
// write out the ciphered message
writeCiphered( cipher, publicCert, new File( "transport.bin"
), plainText );
// now try reading message back in deciphering it.
final KeyStore keystore = KeyStore.getInstance( "JKS" );
keystore.load( new FileInputStream( KEYSTORE_FILENAME ), null
);
final X509Certificate privateCert = ( X509Certificate )
keystore.getCertificate( RECEIVERS_PRIVATE_CERTIFICATE_ALIAS );
final String reconstitutedText = readCiphered( cipher,
privateCert, new File( "transport.bin" ) );
System.out.println( "original: " + plainText );
System.out.println( "reconstituted: " + reconstitutedText );
// output is:
// 68 plaintext bytes written
// 128 enciphered bytes in file (indeed there are)
// -1 reconstituted bytes -- OOPS. Not deciphering
properly
}
}