1package signtool;
2
3import java.io.*;
4import java.util.Properties;
5import java.util.ArrayList;
6
7import javax.mail.internet.*;
8import javax.mail.MessagingException;
9import javax.mail.Session;
10import javax.activation.MailcapCommandMap;
11import javax.activation.CommandMap;
12
13import java.security.PrivateKey;
14import java.security.Security;
15import java.security.KeyFactory;
16import java.security.KeyStore;
17import java.security.NoSuchAlgorithmException;
18import java.security.spec.PKCS8EncodedKeySpec;
19import java.security.spec.InvalidKeySpecException;
20import java.security.cert.X509Certificate;
21import java.security.cert.CertificateFactory;
22import java.security.cert.Certificate;
23import java.security.cert.CertificateException;
24import java.security.cert.CertificateEncodingException;
25
26import org.bouncycastle.jce.provider.BouncyCastleProvider;
27import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
28import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
29import org.bouncycastle.operator.ContentSigner;
30import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
31import org.bouncycastle.cms.CMSProcessableByteArray;
32import org.bouncycastle.cms.CMSSignedGenerator;
33import org.bouncycastle.cms.CMSSignedDataGenerator;
34import org.bouncycastle.cms.CMSSignedGenerator;
35import org.bouncycastle.cms.CMSProcessable;
36import org.bouncycastle.cms.CMSSignedData;
37import org.bouncycastle.cms.CMSTypedData;
38import org.bouncycastle.cert.jcajce.JcaCertStore;
39import org.bouncycastle.util.Store;
40import org.bouncycastle.asn1.ASN1InputStream;
41import org.bouncycastle.asn1.DEROutputStream;
42import org.bouncycastle.asn1.ASN1Object;
43
44
45public class SignImg {
46
47    /* It reads private key in pkcs#8 formate
48     * Conversion:
49     * openssl pkcs8 -topk8 -nocrypt -outform DER < inkey.pem > outkey.pk8
50     */
51    private static PrivateKey getPrivateKey(String path) throws IOException, FileNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException {
52        File file = new File(path);
53        FileInputStream fis = new FileInputStream(file);
54        byte[] data = new byte[(int)file.length()];
55        fis.read(data);
56        fis.close();
57
58        PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(data);
59        KeyFactory kf = KeyFactory.getInstance("RSA");
60        PrivateKey privateKey = kf.generatePrivate(kspec);
61
62        return privateKey;
63    }
64
65    private static MimeBodyPart getContent(String path) throws IOException, FileNotFoundException, MessagingException {
66        MimeBodyPart body = new MimeBodyPart();
67
68        File file = new File(path);
69        FileInputStream fis = new FileInputStream(file);
70        byte[] data = new byte[(int)file.length()];
71        fis.read(data);
72        fis.close();
73
74        body.setContent(data, "application/octet-stream");
75
76        return body;
77    }
78
79    private static CMSProcessableByteArray getCMSContent(String path) throws IOException, FileNotFoundException, MessagingException {
80        File file = new File(path);
81        FileInputStream fis = new FileInputStream(file);
82        byte[] data = new byte[(int)file.length()];
83        fis.read(data);
84        fis.close();
85        CMSProcessableByteArray cms = new CMSProcessableByteArray(data);
86
87        return cms;
88    }
89
90    private static X509Certificate readCert(String path) throws IOException, FileNotFoundException, CertificateException {
91        File file = new File(path);
92        FileInputStream is = new FileInputStream(file);
93
94        CertificateFactory cf = CertificateFactory.getInstance("X.509");
95        Certificate cert = cf.generateCertificate(is);
96        is.close();
97
98        return (X509Certificate) cert;
99    }
100
101    private static void save(MimeBodyPart content, String path) throws IOException, FileNotFoundException, MessagingException {
102        File file = new File(path);
103        FileOutputStream os = new FileOutputStream(file);
104
105        content.writeTo(os);
106
107        os.close();
108    }
109
110    private static Store certToStore(X509Certificate certificate) throws CertificateEncodingException {
111        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
112        certList.add(certificate);
113        return new JcaCertStore(certList);
114    }
115
116    public static void setDefaultMailcap()
117    {
118        MailcapCommandMap _mailcap =
119            (MailcapCommandMap)CommandMap.getDefaultCommandMap();
120
121        _mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
122        _mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
123        _mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
124        _mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
125        _mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
126
127        CommandMap.setDefaultCommandMap(_mailcap);
128    }
129
130    public static void main(String[] args) {
131        try {
132            if (args.length < 4) {
133                System.out.println("Usage: signimg data private_key certificate output");
134                return;
135            }
136            System.out.println("Signing the image");
137            setDefaultMailcap();
138
139            Security.addProvider(new BouncyCastleProvider());
140
141            PrivateKey key = getPrivateKey(args[1]);
142            System.out.println("File read sucessfully");
143
144            CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
145
146            CMSTypedData body = getCMSContent(args[0]);
147            System.out.println("Content read sucessfully");
148
149            X509Certificate cert = (X509Certificate) readCert(args[2]);
150            System.out.println("Certificate read sucessfully");
151
152            ContentSigner sha256Signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(key);
153
154            Store certs = certToStore(cert);
155
156            generator.addCertificates(certs);
157            generator.addSignerInfoGenerator(
158                          new JcaSignerInfoGeneratorBuilder(
159                                new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
160                          .build(sha256Signer, cert));
161
162            CMSSignedData signed = generator.generate(body, true);
163            System.out.println("Signed");
164
165            Properties props = System.getProperties();
166            Session session = Session.getDefaultInstance(props, null);
167
168            File file = new File(args[3]);
169            FileOutputStream os = new FileOutputStream(file);
170
171            ASN1InputStream asn1 = new ASN1InputStream(signed.getEncoded());
172            ByteArrayOutputStream out = new ByteArrayOutputStream();
173            DEROutputStream dOut = new DEROutputStream(os);
174            dOut.writeObject(ASN1Object.fromByteArray(signed.getEncoded()));
175
176        }
177        catch (Exception ex) {
178            System.out.println("Exception during programm execution: " + ex.getMessage());
179        }
180    }
181}
182