Sign and encrypt a file using S/MIME

北战南征 提交于 2019-12-11 11:32:50

问题


I am currently trying to adapt a few scripts we use to sign an encrypt/decrypt xml files using OpenSSL and S/MIME using Java and BouncyCastle.

The command to sign and encrypt our file:

openssl smime -sign -signer Pub1.crt -inkey Priv.key -in foo.xml | openssl smime -encrypt -out foo.xml.smime Pub2.crt Pub1.crt

This generates a signed and encrypted smime-file containing our xml file. Currently this happens using a set of shell scripts under linux using the OpenSSL library. In the future we want to integrate this process into our Java application.

I've found out that this should be possible using the BouncyCastle library (see this post). The answer there provides two Java classes showing how to sign and encrypt an email using BouncyCastle and S/MIME. Comparing this to our OpenSSL command it seems that many of the things needed to sign an encrypt an email is not needed in our approach.

Some more meta information from our generated files:

Signed file

MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----709621D94E0377688356FAAE5A2C1321"

Encrypted file

MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/x-pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"
Content-Transfer-Encoding: base64

Is it even possible to sign and encrypt a simple file in the way we did it using OpenSSL? My current knowledge of signing and de/encryption is not very high at the moment so forgive me for not providing code samples. I guess what I am looking for is more input into what I need to do and maybe some expertise from people who have already done this. I hope this is the right place to ask this. If not, please correct me.


回答1:


I had a similar question as you but I managed to solve it. I have to warn you, my knowledge about signing and encryption isn't that high either. But this code seemed to work for me.

In my case I used a personalsign pro 3 certificate from globalsign, Previously I just called openssl from within java. But the I wanted to clean my code and decided to use bouncy castle instead.

 public static boolean signAllFiles(List<File> files) {
    Boolean signingSucceeded = true;
    KeyStore ks = null;
    char[] password = null;

    Security.addProvider(new BouncyCastleProvider());
    try {
        ks = KeyStore.getInstance("PKCS12");
        password = "yourpass".toCharArray();
        ks.load(new FileInputStream("full/path/to/your/original/certificate.pfx"), password);
    } catch (Exception e) {
        signingSucceeded = false;
    }

    // Get privatekey and certificate
    X509Certificate cert = null;
    PrivateKey privatekey = null;

    try {
        Enumeration<String> en = ks.aliases();
        String ALIAS = "";
        Vector<Object> vectaliases = new Vector<Object>();

        while (en.hasMoreElements())
            vectaliases.add(en.nextElement());
        String[] aliases = (String[])(vectaliases.toArray(new String[0]));
        for (int i = 0; i < aliases.length; i++)
            if (ks.isKeyEntry(aliases[i]))
            {
                ALIAS = aliases[i];
                break;
            }
        privatekey = (PrivateKey)ks.getKey(ALIAS, password);
        cert = (X509Certificate)ks.getCertificate(ALIAS);
        // publickey = ks.getCertificate(ALIAS).getPublicKey();
    } catch (Exception e) {
        signingSucceeded = false;
    }

    for (File source : files) {
        String fileName = "the/path/andNameOfYourOutputFile";

        try {
            // Reading files which need to be signed
            File fileToSign = source;
            byte[] buffer = new byte[(int)fileToSign.length()];
            DataInputStream in = new DataInputStream(new FileInputStream(fileToSign));
            in.readFully(buffer);
            in.close();

            // Generate signature
            ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
            certList.add(cert);
            Store<?> certs = new JcaCertStore(certList);
            CMSSignedDataGenerator signGen = new CMSSignedDataGenerator();

            ContentSigner sha1signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(
                    privatekey);
            signGen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
                    new JcaDigestCalculatorProviderBuilder().build()).build(sha1signer, cert));
            signGen.addCertificates(certs);
            CMSTypedData content = new CMSProcessableByteArray(buffer);
            CMSSignedData signedData = signGen.generate(content, false);
            byte[] signeddata = signedData.getEncoded();

            // Write signature to Fi File
            FileOutputStream envfos = new FileOutputStream(fileName);
            byte[] outputString = Base64.encode(signeddata);
            int fullLines = (int)Math.floor(outputString.length / 64);
            for (int i = 0; i < fullLines; i++) {
                envfos.write(outputString, i * 64, 64);
                envfos.write("\r\n".getBytes());
            }

            envfos.write(outputString, fullLines * 64, outputString.length % 64);
            envfos.close();
        } catch (Exception e) {
            signingSucceeded = false;
        }
    }
    return signingSucceeded;
}

This is only the code to sign a file, I hope it helps.



来源:https://stackoverflow.com/questions/29257451/sign-and-encrypt-a-file-using-s-mime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!