This has been asked a couple of times, but none provide coded test cases. Here I give an example of the problem:
programmatic generation of a Keystore (works)
creation of certificate within that store (works)
saving keystore to disk (works)
listing keystore with keytool (works)
loading the keystore programmatically (fails with IOException: InvalidKeystoreFormat)
What I dont get is that in both save and load, I use KeyStore.getInstance("JKS"), but its failing. Any suggestions welcome!
Runtime output:
Creating private keystore at 'private.keystore'.
Created keystore, now created signer cert
Created signer cert, saving cert
Reloading keystore:
Failed to load the keystore after creation: Invalid keystore format
Test case source:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import sun.security.x509.X500Name;
public class KeystoreCreator
{
private String fPrivateKeyStore;
private String fPrivateKeyStorePassword;
private String fPrivateKeyStoreKeyPassword;
private String fPublicKeyCipherPassword;
private String fPrivateKeyAlias;
/**
* #param args
* #throws Exception
*/
public static void main(String[] args) throws Exception
{
KeystoreCreator creator = new KeystoreCreator();
creator.setPrivateKeyStore("private.keystore");
creator.setPrivateKeyStorePassword("beer123");
creator.setPrivateKeyAlias("myalias");
creator.setPrivateKeyStoreKeyPassword("beer123");
creator.setPublicKeyCipherPassword("beer123");
creator.initKeyStores();
}
public KeystoreCreator()
{
}
public void setPrivateKeyStore(String name)
{
fPrivateKeyStore=name;
}
public void setPrivateKeyStorePassword(String pass)
{
fPrivateKeyStorePassword=pass;
}
public void setPrivateKeyStoreKeyPassword(String pass)
{
fPrivateKeyStoreKeyPassword=pass;
}
public void setPublicKeyCipherPassword(String pass)
{
fPublicKeyCipherPassword=pass;
}
public void setPrivateKeyAlias(String alias)
{
fPrivateKeyAlias=alias;
}
public void initKeyStores() throws Exception
{
OutputStream out = null;
File f=new File(fPrivateKeyStore);
if (f.exists())
{
f.delete();
if (f.exists())
{
throw new IOException("Want to remove the keystore but can't, still reported as present after removal");
}
}
try
{
System.out.println("Creating private keystore at '" + fPrivateKeyStore + "'.");
out = new FileOutputStream(fPrivateKeyStore);
KeyStore privateKeyStore = KeyStore.getInstance("JKS");
privateKeyStore.load(null, fPrivateKeyStorePassword.toCharArray());
System.out.println("Created keystore, now created signer cert");
X500Name x500name=getCA();
Certificate cert = createCertificate(fPrivateKeyAlias, fPrivateKeyStoreKeyPassword, x500name, privateKeyStore);
System.out.println("Created signer cert, saving cert");
privateKeyStore.store(out, fPublicKeyCipherPassword.toCharArray());
out.flush();
out.close();
//try to load it.
KeyStore reloadedKeyStore = KeyStore.getInstance("JKS");
try
{
InputStream reloadedIs=getClass().getClassLoader().getResourceAsStream(fPrivateKeyStore);
if (reloadedIs!=null)
{
System.out.println("Reloading keystore:");
reloadedKeyStore.load(reloadedIs, fPrivateKeyStorePassword.toCharArray());
}
}
catch (Exception e)
{
System.err.println("Failed to load the keystore after creation: "+e.getLocalizedMessage());
}
}
catch (Exception e)
{
System.err.println("Failed to save the keystore: "+e.getLocalizedMessage());
}
}
private X500Name getCA() throws IOException
{
return new sun.security.x509.X500Name("a","b", "c","d","e", "GB");
}
public Certificate createCertificate( String alias, String keyPassword,
sun.security.x509.X500Name x500Name, KeyStore keyStore ) throws NoSuchAlgorithmException,
InvalidKeyException, CertificateException, SignatureException, NoSuchProviderException,
KeyStoreException {
sun.security.x509.CertAndKeyGen keypair = new sun.security.x509.CertAndKeyGen( "RSA", "MD5WithRSA" );
keypair.generate( 1024 );
PrivateKey privKey = keypair.getPrivateKey();
X509Certificate[] chain = new X509Certificate[1];
chain[0] = keypair.getSelfCertificate( x500Name, 7000 * 24 * 60 * 60 );
keyStore.setKeyEntry( alias, privKey, keyPassword.toCharArray(), chain );
Certificate cert = keyStore.getCertificate( alias );
return cert;
}
}
You create the private key store in the current working directory, by writing to a file: new FileOutputStream(fPrivateKeyStore);
Later, you read from the class path by using getClass().getClassLoader().getResourceAsStream(fPrivateKeyStore);
I think you're reading the wrong files. And there is already another one with the name private.keystore from previous tests. To verify, you may want to print out the absolute file path of both files, e.g. new File(fPrivateKeyStore).getAbsolutePath() and compare it to getClass().getClassLoader().getResource(fPrivateKeyStore).toFileURL();
I may be missing something, but why not just re-load the private key store using FileInputStream?
InputStream reloadedIs = new FileInputStream(fPrivateKeyStore);
(I'm not certain this fixes the problem, I just noticed it while scanning your code)
Related
I am trying to use Https over http, I generated the CA certificate with bouncy castle and generated from the .cer file the jks file, spring boot started successfully with the properties provided with an embedded tomcat.
The problem is that I'm getting always insecure ssl certificate from the browser (for example from chrome : This CA Root certificate is not trusted because it is not in the Trusted Root Certification Authorities store.) while I add the trust store programatically with another config class.
Here is my code:
import org.apache.commons.codec.binary.Base64; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.cmp.CertRepMessage; import org.bouncycastle.asn1.cmp.PKIBody; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.cert.CertException; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.cmp.CMPException; import org.bouncycastle.cert.cmp.ProtectedPKIMessage; import org.bouncycastle.cert.cmp.ProtectedPKIMessageBuilder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.ContentVerifierProvider; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.security.*; import java.security.cert.X509Certificate; import java.util.Date;
public class generateService {
private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
private static X509CertificateHolder makeV3Certificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN)
throws GeneralSecurityException, IOException, OperatorCreationException, CertException
{
PublicKey subPub = subKP.getPublic();
PrivateKey issPriv = issKP.getPrivate();
PublicKey issPub = issKP.getPublic();
X509v3CertificateBuilder v1CertGen = new JcaX509v3CertificateBuilder(
new X500Name(_issDN),
BigInteger.valueOf(System.currentTimeMillis()),
new Date(System.currentTimeMillis()),
new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
new X500Name(_subDN),
subPub);
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").setProvider(BC).build(issPriv);
X509CertificateHolder certHolder = v1CertGen.build(signer);
ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(BC).build(issPub);
return certHolder;
}
public X509Certificate test(KeyPair kp) throws OperatorCreationException, GeneralSecurityException, CertException, IOException, CMPException {
Provider bcProvider = new BouncyCastleProvider();
Security.addProvider(bcProvider);
X509CertificateHolder cert = makeV3Certificate(kp, "CN=CA", kp, "CN=CA");
GeneralName sender = new GeneralName(new X500Name("CN=CA"));
GeneralName recipient = new GeneralName(new X500Name("CN=CA"));
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BC).build(kp.getPrivate());
ProtectedPKIMessage message = new ProtectedPKIMessageBuilder(sender, recipient)
.setBody(new PKIBody(PKIBody.TYPE_INIT_REP, CertRepMessage.getInstance(new DERSequence(new DERSequence()))))
.addCMPCertificate(cert)
.build(signer);
X509Certificate jcaCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(message.getCertificates()[0]);
return jcaCert;
}
public void generateJKS() throws GeneralSecurityException, IOException, OperatorCreationException, CMPException, CertException {
Provider bcProvider = new BouncyCastleProvider();
Security.addProvider(bcProvider);
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
X509Certificate certificate = test(keyPair);
final FileOutputStream os = new FileOutputStream("E:\\cert4.cer");
os.write("-----BEGIN CERTIFICATE-----\n".getBytes("US-ASCII"));
os.write(Base64.encodeBase64(certificate.getEncoded(), true));
os.write("-----END CERTIFICATE-----\n".getBytes("US-ASCII"));
os.close();
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null,null);
X509Certificate[] certChain = new X509Certificate[1];
certChain[0] = certificate;
keyStore.setKeyEntry("myaliaskey", (Key)keyPair.getPrivate(), "secret".toCharArray(), certChain);
OutputStream outputStream = new FileOutputStream("E:\\keystoreRSA4.jks");
keyStore.store(outputStream, "secret".toCharArray());
outputStream.flush();
outputStream.close();
}
public static void main(String[] args) throws Exception {
new generateService().generateJKS();
} }
Application.properties:
server.port = 8443 server.http.port = 8080 server.ssl.key-store = E:\\keystoreRSA4.jks server.ssl.key-password = secret server.ssl.keyAlias = myaliaskey
/***************************************************************************/
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
#Configuration public class SSLConfig {
#PostConstruct
private void configureSSL() {
System.setProperty("https.protocols", "TLSv1.2");
System.setProperty("javax.net.ssl.trustStore", "E:\\keystoreRSA4.jks");
System.setProperty("javax.net.ssl.keyStore", "E:\\keystoreRSA4.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "secret");
} }
import org.apache.catalina.Context; import org.apache.catalina.connector.Connector; import org.apache.tomcat.util.descriptor.web.SecurityCollection; import org.apache.tomcat.util.descriptor.web.SecurityConstraint; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
#Configuration public class TomcatConfig {
#Value("${server.http.port}")
private int httpPort;
#Value("${server.port}")
private int httpsPort;
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
#Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
return tomcat;
}
public Connector initiateHttpConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("https");
connector.setPort(httpPort);
connector.setSecure(true);
connector.setRedirectPort(httpsPort);
return connector;
} }
Any help will be appreciated and thank you in advance.
how i can figure it to let the browser accept it as trust certificate?
Fortunately, you can't. There's a discussion about the topic in this question:
If we simply said "HTTPS is now possible with self-signed certificates", your browser could not distinguish whether a site you are trying to visit has a self-signed cert because it is supposed to, or because you are being attacked. Thus, it would decrease security.
You have to add an exception to your browser to accept your certificate. Normally during development. For production use, you have to buy a certificate from a trusted vendor like Verisign.
To add an exception to your browser, please see this other question.
Cheers!
I have a method which extracts a X.509 certificate from a given PEM-formatted file, using the bouncycastle library.
Imports:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.openssl.PEMParser;
Method:
/**
* Reads an X509 certificate from a PEM file.
*
* #param certificateFile The PEM file.
* #return the X509 certificate, or null.
* #throws IOException if reading the file fails
* #throws CertificateException if parsing the certificate fails
*/
public static X509Certificate readCertificatePEMFile(File certificateFile) throws IOException, CertificateException {
if (certificateFile.exists() && certificateFile.canRead()) {
try (InputStream inStream = new FileInputStream(certificateFile)) {
try (PEMParser pemParser = new PEMParser(new InputStreamReader(inStream))) {
Object object = pemParser.readObject();
if (object != null && object instanceof X509CertificateHolder) {
return new JcaX509CertificateConverter().getCertificate( (X509CertificateHolder)object );
}
}
}
}
return null;
}
This works well for "normal" certificate files, e.g. a server certificate.
If I have a CA chain certificate file, containing multiple certificates, how could I achieve extracting all certificates from this file (the method shown only extracts the first certificate in the file).
Try this code, it handles multiple certificates and Private key entry im PEM file
Security.addProvider(new BouncyCastleProvider());
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
while((object = pemParser.readObject())!=null)
{
if(object instanceof X509CertificateHolder)
{
X509Certificate x509Cert = (X509Certificate) new JcaX509CertificateConverter().getCertificate((X509CertificateHolder) object);
}
else if(object instanceof PEMEncryptedKeyPair)
{
if(password==null) throw new IllegalArgumentException("Password required for parsing RSA Private key");
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
}
else if(object instanceof PEMKeyPair)
{
converter.getKeyPair((PEMKeyPair) object);
}
}
I am totally new to security and signature verification and so far I couldn't find a place which explained the basics of signature verification. I need to verify the signature of a file by obtaining the public key from the appropriate certificate available from certificate store. the tutorial in Java (https://docs.oracle.com/javase/tutorial/security/apisign/versig.html) doesn't teach how to obtain a certificate from the trusted certificate store and verify using that. I went through Bouncy castle WIKI http://www.bouncycastle.org/wiki/display/JA1/BC+Version+2+APIs but its not really explanatory for a beginner. How do I do this? Given a signed file, how can I check for its public key from the certificate store and verify if its the right person who has sent the file? Please advice.
Because you did not provide what build management you use, I assume it will be Maven.
First, include BouncyCastle in your dependency
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.53</version>
</dependency>
After that, you need to make a util class that you will be using for sign or verify the certificate. Something like this:
package your.pack.location;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* Author: harunalfat
*/
public class SignatureUtils {
private static final Logger log = LogManager.getLogger(SignatureUtils.class);
public static String sign(String plainText, PrivateKey privateKey) throws Exception {
byte[] data = plainText.getBytes("ISO-8859-1");
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initSign(privateKey);
signature.update(data);
return Base64.toBase64String(signature.sign());
}
public static boolean verify(String plainText, String signString, PublicKey publicKey) throws Exception{
byte[] data = plainText.getBytes("ISO-8859-1");
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initVerify(publicKey);
signature.update(data);
byte[] signByte = Base64.decode(signString);
return signature.verify(signByte);
}
private static PemObject getPemObjectFromResource(String fileLocation) throws IOException {
Resource resource = new ClassPathResource(fileLocation);
InputStream is = resource.getInputStream();
PemObject pemObject = new PemReader(new InputStreamReader( is )).readPemObject();
return pemObject;
}
private static X509EncodedKeySpec getPubKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {
PemObject pemObject = getPemObjectFromResource(fileLocation);
byte[] data = pemObject.getContent();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(data);
return keySpec;
}
private static PKCS8EncodedKeySpec getPriKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {
PemObject pemObject = getPemObjectFromResource(fileLocation);
byte[] data = pemObject.getContent();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data);
return keySpec;
}
public static PublicKey getPublicKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
KeySpec keySpec = getPubKeySpec(fileLocation);
return kf.generatePublic(keySpec);
}
public static PrivateKey getPrivateKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
KeySpec keySpec = getPriKeySpec(fileLocation);
return kf.generatePrivate(keySpec);
}
}
And then you will use it like this
package your.another.pack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import static org.junit.Assert.assertTrue;
/**
* Author: harunalfat
*/
public class SignatureUtilsTest {
private static final Logger log = LogManager.getLogger(SignatureUtilsTest.class);
private static final String PLAIN = "attack at dawn";
#Test
public void testSignAndVerify() throws Exception {
Security.addProvider(new BouncyCastleProvider()); // <-- IMPORTANT!!! This will add BouncyCastle as provider in Java Security
PrivateKey privateKey = SignatureUtils.getPrivateKey("key/private2.pem"); // This is located on src/main/resources/key/private2.pem
PublicKey publicKey = SignatureUtils.getPublicKey("key/public2.pem"); // This is located on src/main/resources/key/public2.pem
// In this example, I use junit test, so it will be on src/test/resources/...
log.info("Private Key : "+Base64.encodeBase64String(privateKey.getEncoded()));
log.info("Public Key : "+Base64.encodeBase64String(publicKey.getEncoded()));
String sign = SignatureUtils.sign(PLAIN, privateKey);
log.info("Plain String : "+PLAIN);
log.info("Sign : "+sign);
boolean result = SignatureUtils.verify(PLAIN,sign, publicKey);
log.info("Result : "+result);
assertTrue(result);
}
}
Of course, you can change the Signature instance with another Algorithm. In my case I use "SHA1WithRSA", but you get the point right?
With this, someone will encrypt their data using their private key, and send it to you. After that, you will verify the data using the public key they give.
In example, Bob send to you message about money amount he sent to you ($5000), and sign it using their private key, become encrypted. When the data arrived to you, you know Bob supposed to send $5000, then you verify the encrypted data with text $5000 and public key Bob share, but is it really $5000 OR does it comes from Bob?
If the data has been changed, OR when someday you ask for some Money to Bob, but the message tapped by someone else and s/he send you the amount message with private key other than Bob's, you will know.
Feel free to ask :)
I'm now on developing digital signature app on android.
however, I failed to make a apk file because eclipse show following message
[2013-01-27 20:43:25 - BlowfishCipher] Dx
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Lorg/bouncycastle/mozilla/SignedPublicKeyAndChallenge;
[2013-01-27 20:43:25 - BlowfishCipher] Dx at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:123)
[2013-01-27 20:43:25 - BlowfishCipher] Dx at com.android.dx.dex.file.DexFile.add(DexFile.java:163)
I know that the error message indicates that duplicated jar files but I don't know how to
solve it since the duplicated jar (Lorg/bouncycastle/mozilla/SignedPublicKeyAndChallenge;) is the core file of the bouncy caslte library.
and follwing java code shows no syntax error but it cause java.lang.IllegalArgumentException: already added exception
package exam.blowfishcipher;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.security.KeyPair;
import java.security.SecureRandom;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.openssl.PEMWriter;
import android.os.Environment;
import chapter6.PKCS10ExtensionExample;
public class PKCS10Generater
{
public static PKCS10CertificationRequest generateRequest(
KeyPair pair)
throws Exception
{
return new PKCS10CertificationRequest(
"SHA256withRSA",
new X500Principal("CN=Test CA Certificate"),
//new X500Principal("CN=end"),
pair.getPublic(),
null,
pair.getPrivate());
}
public static void pemEncodeToFile(String filename, Object obj, char[] password) throws Exception{
PEMWriter pw = new PEMWriter(new FileWriter(filename));
if (password != null && password.length > 0) {
pw.writeObject(obj, "DESEDE", password, new SecureRandom());
} else {
pw.writeObject(obj);
}
pw.flush();
pw.close();
}
public static void reqGen() throws Exception
{
//create the keys
/*
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
//KeyPairGenerator kpGen = KeyPairGenerator.getInstance()
kpGen.initialize(512, chapter4.Utils.createFixedRandom());
KeyPair pair=kpGen.generateKeyPair();
*/
//PKCS10CertificationRequest request = generateRequest(pair);
KeyPair pair = chapter8.Utils.generateRSAKeyPair();
PKCS10CertificationRequest request = PKCS 10ExtensionExample.generateRequest(pair);
pemEncodeToFile(Environment.getExternalStorageDirectory()+"pkcs10.req", request, null);
PEMWriter pemWrt = new PEMWriter( new OutputStreamWriter(System.out));
pemWrt.writeObject(request);
pemWrt.close();
}
}
Android already includes BouncyCastle in the system, that is why you are getting the error when trying to add it again (on recent versions it is actually in com.android.org.bouncycastle or some such so you shouldn't get the error, in theory). You have to rename the package of BC if you want to include it in your project (with jarjar, etc.). One project that already does this for you is SpongyCastle. Try using that instead of the regular BC jar.
https://github.com/rtyley/spongycastle
I want to sign a text file (may be a .exe file or something else in the future)
using PKCS#7 and verify the signature using Java.
What do I need to know?
Where will I find an API (.jar and documentation)?
What are the steps I need to follow in order to sign data and verify the data?
Please provide me code snippet if possible.
I reckon you need the following 2 Bouncy Castle jars to generate the PKCS7 digital signature:
bcprov-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)
bcmail-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)
You can download the Bouncy Castle jars from here.
You need to setup your keystore with the public & private key pair.
You need only the private key to generate the digital signature & the public key to verify it.
Here's how you'd pkcs7 sign content (Exception handling omitted for brevity) :
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.encoders.Base64;
public final class PKCS7Signer {
private static final String PATH_TO_KEYSTORE = "/path/to/keyStore";
private static final String KEY_ALIAS_IN_KEYSTORE = "My_Private_Key";
private static final String KEYSTORE_PASSWORD = "MyPassword";
private static final String SIGNATUREALGO = "SHA1withRSA";
public PKCS7Signer() {
}
KeyStore loadKeyStore() throws Exception {
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream is = new FileInputStream(PATH_TO_KEYSTORE);
keystore.load(is, KEYSTORE_PASSWORD.toCharArray());
return keystore;
}
CMSSignedDataGenerator setUpProvider(final KeyStore keystore) throws Exception {
Security.addProvider(new BouncyCastleProvider());
Certificate[] certchain = (Certificate[]) keystore.getCertificateChain(KEY_ALIAS_IN_KEYSTORE);
final List<Certificate> certlist = new ArrayList<Certificate>();
for (int i = 0, length = certchain == null ? 0 : certchain.length; i < length; i++) {
certlist.add(certchain[i]);
}
Store certstore = new JcaCertStore(certlist);
Certificate cert = keystore.getCertificate(KEY_ALIAS_IN_KEYSTORE);
ContentSigner signer = new JcaContentSignerBuilder(SIGNATUREALGO).setProvider("BC").
build((PrivateKey) (keystore.getKey(KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD.toCharArray())));
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").
build()).build(signer, (X509Certificate) cert));
generator.addCertificates(certstore);
return generator;
}
byte[] signPkcs7(final byte[] content, final CMSSignedDataGenerator generator) throws Exception {
CMSTypedData cmsdata = new CMSProcessableByteArray(content);
CMSSignedData signeddata = generator.generate(cmsdata, true);
return signeddata.getEncoded();
}
public static void main(String[] args) throws Exception {
PKCS7Signer signer = new PKCS7Signer();
KeyStore keyStore = signer.loadKeyStore();
CMSSignedDataGenerator signatureGenerator = signer.setUpProvider(keyStore);
String content = "some bytes to be signed";
byte[] signedBytes = signer.signPkcs7(content.getBytes("UTF-8"), signatureGenerator);
System.out.println("Signed Encoded Bytes: " + new String(Base64.encode(signedBytes)));
}
}
PKCS#7 is known as CMS now (Cryptographic Message Syntax), and you will need the Bouncy Castle PKIX libraries to create one. It has ample documentation and a well established mailing list.
I won't supply code snippet, it is against house rules. Try yourself first.