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
Related
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 have an existing application that uses the org.restlet.engine.ssl.DefaultSslContextFactory and a keystore file that is loaded when the server is started.
I have another application that creates certificates that have to be added
dynamically to the keystore file while the server is running. To perform this,
I created the certificate and the private key in the code and then write it
to a directory. The directory is watched by a bash script that checks for new files, and if one appears it will be imported into the existing keystore file.
But when trying to access the server with the newly imported certificate the handshake fails. Only when restarting the server, the access can be completed successfully, which I assume means that the added certificate will not be reloaded by the server.
Is there a way to update the running application with the new entry in the keystore file?
Importing the new certificate into your keystore doesn't refresh your current SSLConext as nothing tells the JVM that the keystore has changed.
To do that you'll have to tell your application that a new certificate was added into your keystore but instead of reloading the keystore -as far as I know it shouldn't be possible- , what is possible by the way is that your can add the new certificate into your current SSLContext See here.
To achieve that, you've to provide a bean aware of the new certificate -maybe the component that call your bash script- in which you injected an SSLContext instance.
It's also interesting if you split your application using a micro service architecture, delegate to one module the fact to deal with certificates and reload it (using proper configure LB) as keystore is updated.
Since this seems to be quite an impossible task to accomplish, I decided to do a workaround. I used nginx as a proxy in front of the application. Nginx is able to perform client authentication with multiple CA root certificates which is exactly what I need. The connection between the application and nginx can simply be done via a HTTP since they are residing on the same host (just different ports).
Ugly Hack Alert
The following works for me. I overwrite DefaultSSLContextFactory, store each created SSLContext and call its init method again.
To invoke the reload I simply call UglyHackSSLContextFactory.reloadKeyStore()
package test;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import javax.net.ssl.SSLContext;
import org.restlet.engine.ssl.DefaultSslContextFactory;
public class UglyHackSSLContextFactory extends DefaultSslContextFactory {
private SSLContext _context = null;
public static ArrayList<UglyHackSSLContextFactory> instances = new ArrayList<UglyHackSSLContextFactory>();
// we need all used SSLContextFactories later, so store them
public UglyHackSSLContextFactory() {
instances.add(this);
}
// create a new context once and store it.
#Override
public SSLContext createSslContext() throws Exception {
if (this._context == null) {
this._context = super.createSslContext();
}
return this._context;
}
// re-init all _context instances
public static void reload() throws KeyManagementException, UnrecoverableKeyException,
KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException,
CertificateException, IOException {
for (final UglyHackSSLContextFactory f : instances) {
f.reinit();
}
}
// this is mostly copied from
// org.restlet.engine.ssl.DefaultSslContextFactory
private void reinit() throws KeyManagementException, KeyStoreException,
NoSuchProviderException, NoSuchAlgorithmException, CertificateException, IOException,
UnrecoverableKeyException {
javax.net.ssl.KeyManagerFactory kmf = null;
if ((getKeyStorePath() != null) || (getKeyStoreProvider() != null)
|| (getKeyStoreType() != null)) {
// Loads the key store.
final KeyStore keyStore = (getKeyStoreProvider() != null) ? KeyStore.getInstance(
(getKeyStoreType() != null) ? getKeyStoreType() : KeyStore.getDefaultType(),
getKeyStoreProvider()) : KeyStore
.getInstance((getKeyStoreType() != null) ? getKeyStoreType() : KeyStore
.getDefaultType());
FileInputStream keyStoreInputStream = null;
try {
keyStoreInputStream = ((getKeyStorePath() != null) && (!"NONE"
.equals(getKeyStorePath()))) ? new FileInputStream(getKeyStorePath())
: null;
keyStore.load(keyStoreInputStream, getKeyStorePassword());
} finally {
if (keyStoreInputStream != null) {
keyStoreInputStream.close();
}
}
// Creates the key-manager factory.
kmf = javax.net.ssl.KeyManagerFactory.getInstance(getKeyManagerAlgorithm());
kmf.init(keyStore, getKeyStoreKeyPassword());
}
javax.net.ssl.TrustManagerFactory tmf = null;
if ((getTrustStorePath() != null) || (getTrustStoreProvider() != null)
|| (getTrustStoreType() != null)) {
// Loads the trust store.
final KeyStore trustStore = (getTrustStoreProvider() != null) ? KeyStore
.getInstance(
(getTrustStoreType() != null) ? getTrustStoreType() : KeyStore
.getDefaultType(), getTrustStoreProvider()) : KeyStore
.getInstance((getTrustStoreType() != null) ? getTrustStoreType() : KeyStore
.getDefaultType());
FileInputStream trustStoreInputStream = null;
try {
trustStoreInputStream = ((getTrustStorePath() != null) && (!"NONE"
.equals(getTrustStorePath()))) ? new FileInputStream(getTrustStorePath())
: null;
trustStore.load(trustStoreInputStream, getTrustStorePassword());
} finally {
if (trustStoreInputStream != null) {
trustStoreInputStream.close();
}
}
// Creates the trust-manager factory.
tmf = javax.net.ssl.TrustManagerFactory.getInstance(getTrustManagerAlgorithm());
tmf.init(trustStore);
}
SecureRandom sr = null;
if (getSecureRandomAlgorithm() != null) {
sr = SecureRandom.getInstance(getSecureRandomAlgorithm());
}
this._context.init(kmf != null ? kmf.getKeyManagers() : null,
tmf != null ? tmf.getTrustManagers() : null, sr);
}
}
Hope this helps!
I am writing a JBenchX method that calculates a keys of CMSS signature using flexiprovider. I want to get timings for my method createKeys, but that is very very slow. Without annnotation #Bench that is too fast < 1 sec. Could you help to understand What's happen here?
import de.flexiprovider.api.exceptions.NoSuchAlgorithmException;
import de.flexiprovider.api.keys.KeyPair;
import de.flexiprovider.api.keys.KeyPairGenerator;
import org.jbenchx.annotations.Bench;
import org.jbenchx.annotations.ForEachInt;
import org.jbenchx.annotations.ForEachString;
import org.jbenchx.annotations.SingleRun;
public class CMSSTest {
#Bench
public Object createKeys(#ForEachString({ "CMSSwithSHA1andWinternitzOTS_1" }) String cmss) throws NoSuchAlgorithmException {
Security.addProvider(new FlexiPQCProvider());
//byte[] signatureBytes = null;
KeyPairGenerator kpg = (CMSSKeyPairGenerator) Registry
.getKeyPairGenerator(cmss);
KeyPair keyPair = kpg.genKeyPair();
}
}
The actual output is and is active yet.
Initializing Benchmarking Framework...
Running on Linux Linux
Max heap = 1345847296 System Benchmark = 11,8ns
Performing 1 benchmarking tasks..
[0] CMSSTest.createObjectArray(CMSSwithSHA1andWinternitzOTS_1)!*!**!!!******!!******!****!****!!******!!!!*******!******!****!*********************************
The problem seems to be that Registry.getKeyPairGenerator creates a new KeyPairGenerator which is initialized using a 'true' random seed. For this, the system potentially has to wait for enough entropy to be available. Therefore, you should not do this as part of the code that you want to benchmark.
Try something like this:
import java.security.Security;
import org.jbenchx.annotations.Bench;
import org.jbenchx.annotations.ForEachString;
import de.flexiprovider.api.Registry;
import de.flexiprovider.api.exceptions.NoSuchAlgorithmException;
import de.flexiprovider.api.keys.KeyPair;
import de.flexiprovider.api.keys.KeyPairGenerator;
import de.flexiprovider.pqc.FlexiPQCProvider;
public class CMSSTest {
static {
Security.addProvider(new FlexiPQCProvider());
}
private final KeyPairGenerator kpg;
public CMSSTest(#ForEachString({"CMSSwithSHA1andWinternitzOTS_1"}) String cmss) throws NoSuchAlgorithmException {
this.kpg = Registry.getKeyPairGenerator(cmss);
}
#Bench
public Object createKeys() {
KeyPair keyPair = kpg.genKeyPair();
return keyPair;
}
}
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.
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)